From dd1daa7a85c169829aae2e61320ccbd48546238f Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Wed, 13 Feb 2008 20:34:29 +0000 Subject: [PATCH] [179102] Re-aligned plugin and package names to confirm with Eclipse policy. --- plugins/org.eclipse.dd.gdb.ui/.classpath | 7 + plugins/org.eclipse.dd.gdb.ui/.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 65 + .../META-INF/MANIFEST.MF | 21 + plugins/org.eclipse.dd.gdb.ui/about.html | 24 + .../org.eclipse.dd.gdb.ui/build.properties | 8 + .../icons/full/obj16/c_app.gif | Bin 0 -> 1042 bytes plugins/org.eclipse.dd.gdb.ui/plugin.xml | 54 + .../dd/gdb/internal/ui/GdbAdapterFactory.java | 213 +++ .../dd/gdb/internal/ui/GdbUIPlugin.java | 59 + .../ui/actions/DsfTerminateCommand.java | 96 + .../CBreakpointGdbThreadFilterPage.java | 84 + .../ui/breakpoints/GdbThreadFilterEditor.java | 537 ++++++ .../DsfMIlRunLaunchConfigurationTabGroup.java | 36 + .../ui/viewmodel/GdbViewModelAdapter.java | 60 + .../ui/viewmodel/launch/ContainerVMNode.java | 146 ++ .../ui/viewmodel/launch/LaunchVMProvider.java | 129 ++ .../ui/viewmodel/launch/ThreadVMNode.java | 308 +++ plugins/org.eclipse.dd.mi/.classpath | 7 + plugins/org.eclipse.dd.mi/.options | 1 + plugins/org.eclipse.dd.mi/.project | 28 + .../.settings/org.eclipse.jdt.core.prefs | 65 + .../.settings/org.eclipse.jdt.ui.prefs | 3 + .../org.eclipse.dd.mi/META-INF/MANIFEST.MF | 24 + plugins/org.eclipse.dd.mi/about.html | 24 + plugins/org.eclipse.dd.mi/build.properties | 7 + plugins/org.eclipse.dd.mi/plugin.properties | 13 + plugins/org.eclipse.dd.mi/plugin.xml | 4 + .../org/eclipse/dd/mi/internal/MIPlugin.java | 94 + .../eclipse/dd/mi/service/CSourceLookup.java | 140 ++ .../dd/mi/service/ExpressionService.java | 898 +++++++++ .../dd/mi/service/IMIExecutionDMContext.java | 27 + .../dd/mi/service/MIBreakpointDMData.java | 267 +++ .../eclipse/dd/mi/service/MIBreakpoints.java | 956 ++++++++++ .../service/MIBreakpointsActionManager.java | 185 ++ .../dd/mi/service/MIBreakpointsManager.java | 1484 +++++++++++++++ .../org/eclipse/dd/mi/service/MIFormat.java | 109 ++ .../org/eclipse/dd/mi/service/MIMemory.java | 895 +++++++++ .../org/eclipse/dd/mi/service/MIModules.java | 217 +++ .../eclipse/dd/mi/service/MIRegisters.java | 583 ++++++ .../eclipse/dd/mi/service/MIRunControl.java | 668 +++++++ .../org/eclipse/dd/mi/service/MIStack.java | 559 ++++++ .../dd/mi/service/MIVariableManager.java | 1648 +++++++++++++++++ .../service/command/AbstractCLIProcess.java | 320 ++++ .../mi/service/command/AbstractMIControl.java | 736 ++++++++ .../mi/service/command/CLIEventProcessor.java | 353 ++++ .../service/command/MIControlDMContext.java | 62 + .../mi/service/command/MIInferiorProcess.java | 396 ++++ .../command/MIRunControlEventProcessor.java | 225 +++ .../service/command/commands/CLICommand.java | 26 + .../command/commands/CLIExecAbort.java | 30 + .../commands/CLIInfoSharedLibrary.java | 47 + .../command/commands/CLIInfoThreads.java | 45 + .../command/commands/ExprMetaCommand.java | 61 + .../commands/ExprMetaGetAttributes.java | 21 + .../commands/ExprMetaGetChildCount.java | 21 + .../command/commands/ExprMetaGetChildren.java | 21 + .../command/commands/ExprMetaGetValue.java | 21 + .../command/commands/ExprMetaGetVar.java | 21 + .../command/commands/MIBreakAfter.java | 32 + .../command/commands/MIBreakCondition.java | 36 + .../command/commands/MIBreakDelete.java | 42 + .../command/commands/MIBreakDisable.java | 41 + .../command/commands/MIBreakEnable.java | 40 + .../command/commands/MIBreakInsert.java | 120 ++ .../service/command/commands/MIBreakList.java | 62 + .../command/commands/MIBreakWatch.java | 55 + .../service/command/commands/MICommand.java | 256 +++ .../commands/MIDataEvaluateExpression.java | 53 + .../commands/MIDataListRegisterNames.java | 52 + .../commands/MIDataListRegisterValues.java | 145 ++ .../command/commands/MIDataReadMemory.java | 150 ++ .../command/commands/MIDataWriteMemory.java | 118 ++ .../command/commands/MIExecContinue.java | 31 + .../command/commands/MIExecFinish.java | 37 + .../command/commands/MIExecInterrupt.java | 36 + .../service/command/commands/MIExecNext.java | 36 + .../commands/MIExecNextInstruction.java | 37 + .../command/commands/MIExecReturn.java | 42 + .../service/command/commands/MIExecRun.java | 37 + .../service/command/commands/MIExecStep.java | 38 + .../commands/MIExecStepInstruction.java | 38 + .../service/command/commands/MIExecUntil.java | 39 + .../service/command/commands/MIGDBExit.java | 30 + .../command/commands/MIGDBShowExitCode.java | 37 + .../command/commands/MIInterpreterExec.java | 44 + .../commands/MIInterpreterExecConsole.java | 32 + .../command/commands/MIStackInfoDepth.java | 39 + .../commands/MIStackListArguments.java | 72 + .../command/commands/MIStackListFrames.java | 69 + .../command/commands/MIStackListLocals.java | 45 + .../command/commands/MIStackSelectFrame.java | 33 + .../command/commands/MIThreadListIds.java | 37 + .../command/commands/MIThreadSelect.java | 35 + .../service/command/commands/MIVarAssign.java | 36 + .../service/command/commands/MIVarCreate.java | 68 + .../service/command/commands/MIVarDelete.java | 38 + .../commands/MIVarEvaluateExpression.java | 41 + .../command/commands/MIVarInfoExpression.java | 41 + .../commands/MIVarInfoNumChildren.java | 37 + .../commands/MIVarInfoPathExpression.java | 42 + .../command/commands/MIVarInfoType.java | 39 + .../command/commands/MIVarListChildren.java | 40 + .../command/commands/MIVarSetFormat.java | 62 + .../command/commands/MIVarShowAttributes.java | 41 + .../command/commands/MIVarShowFormat.java | 38 + .../service/command/commands/MIVarUpdate.java | 42 + .../service/command/commands/RawCommand.java | 36 + .../events/MIBreakpointChangedEvent.java | 40 + .../command/events/MIBreakpointHitEvent.java | 65 + .../command/events/MIDetachedEvent.java | 34 + .../service/command/events/MIErrorEvent.java | 101 + .../dd/mi/service/command/events/MIEvent.java | 57 + .../events/MIFunctionFinishedEvent.java | 83 + .../command/events/MIGDBExitEvent.java | 28 + .../command/events/MIInferiorExitEvent.java | 64 + .../events/MIInferiorSignalExitEvent.java | 68 + .../events/MILocationReachedEvent.java | 38 + .../command/events/MIRunningEvent.java | 59 + .../command/events/MISharedLibEvent.java | 39 + .../command/events/MISignalChangedEvent.java | 40 + .../service/command/events/MISignalEvent.java | 75 + .../command/events/MISteppingRangeEvent.java | 39 + .../command/events/MIStoppedEvent.java | 73 + .../command/events/MIThreadCreatedEvent.java | 40 + .../command/events/MIThreadExitEvent.java | 40 + .../events/MIWatchpointScopeEvent.java | 66 + .../events/MIWatchpointTriggerEvent.java | 122 ++ .../output/CLIInfoSharedLibraryInfo.java | 105 ++ .../command/output/CLIInfoThreadsInfo.java | 95 + .../output/ExprMetaGetAttributesInfo.java | 29 + .../output/ExprMetaGetChildCountInfo.java | 29 + .../output/ExprMetaGetChildrenInfo.java | 30 + .../command/output/ExprMetaGetValueInfo.java | 29 + .../command/output/ExprMetaGetVarInfo.java | 38 + .../dd/mi/service/command/output/MIArg.java | 132 ++ .../service/command/output/MIAsyncRecord.java | 76 + .../command/output/MIBreakInsertInfo.java | 80 + .../command/output/MIBreakListInfo.java | 86 + .../service/command/output/MIBreakpoint.java | 294 +++ .../command/output/MIConsoleStreamOutput.java | 19 + .../dd/mi/service/command/output/MIConst.java | 124 ++ .../output/MIDataEvaluateExpressionInfo.java | 46 + .../output/MIDataListRegisterNamesInfo.java | 79 + .../output/MIDataListRegisterValuesInfo.java | 104 ++ .../command/output/MIDataReadMemoryInfo.java | 248 +++ .../command/output/MIDataWriteMemoryInfo.java | 35 + .../command/output/MIExecAsyncOutput.java | 19 + .../dd/mi/service/command/output/MIFrame.java | 136 ++ .../command/output/MIGDBShowExitCodeInfo.java | 38 + .../dd/mi/service/command/output/MIInfo.java | 100 + .../dd/mi/service/command/output/MIList.java | 61 + .../command/output/MILogStreamOutput.java | 20 + .../command/output/MINotifyAsyncOutput.java | 20 + .../service/command/output/MIOOBRecord.java | 19 + .../mi/service/command/output/MIOutput.java | 58 + .../mi/service/command/output/MIParser.java | 559 ++++++ .../command/output/MIRegisterValue.java | 98 + .../mi/service/command/output/MIResult.java | 53 + .../command/output/MIResultRecord.java | 66 + .../command/output/MIStackInfoDepthInfo.java | 52 + .../output/MIStackListArgumentsInfo.java | 79 + .../command/output/MIStackListFramesInfo.java | 78 + .../command/output/MIStackListLocalsInfo.java | 55 + .../command/output/MIStatusAsyncOutput.java | 21 + .../command/output/MIStreamRecord.java | 41 + .../command/output/MITargetStreamOutput.java | 21 + .../command/output/MIThreadListIdsInfo.java | 71 + .../dd/mi/service/command/output/MITuple.java | 60 + .../dd/mi/service/command/output/MIValue.java | 19 + .../dd/mi/service/command/output/MIVar.java | 79 + .../command/output/MIVarAssignInfo.java | 45 + .../service/command/output/MIVarChange.java | 54 + .../command/output/MIVarCreateInfo.java | 90 + .../command/output/MIVarDeleteInfo.java | 50 + .../output/MIVarEvaluateExpressionInfo.java | 44 + .../output/MIVarInfoExpressionInfo.java | 53 + .../output/MIVarInfoNumChildrenInfo.java | 50 + .../output/MIVarInfoPathExpressionInfo.java | 47 + .../command/output/MIVarInfoTypeInfo.java | 44 + .../command/output/MIVarListChildrenInfo.java | 84 + .../command/output/MIVarSetFormatInfo.java | 43 + .../output/MIVarShowAttributesInfo.java | 47 + .../command/output/MIVarShowFormatInfo.java | 57 + .../command/output/MIVarUpdateInfo.java | 103 ++ 185 files changed, 21317 insertions(+) create mode 100644 plugins/org.eclipse.dd.gdb.ui/.classpath create mode 100644 plugins/org.eclipse.dd.gdb.ui/.project create mode 100644 plugins/org.eclipse.dd.gdb.ui/.settings/org.eclipse.jdt.core.prefs create mode 100644 plugins/org.eclipse.dd.gdb.ui/META-INF/MANIFEST.MF create mode 100644 plugins/org.eclipse.dd.gdb.ui/about.html create mode 100644 plugins/org.eclipse.dd.gdb.ui/build.properties create mode 100644 plugins/org.eclipse.dd.gdb.ui/icons/full/obj16/c_app.gif create mode 100644 plugins/org.eclipse.dd.gdb.ui/plugin.xml create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/GdbAdapterFactory.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/GdbUIPlugin.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/DsfTerminateCommand.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/CBreakpointGdbThreadFilterPage.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/DsfMIlRunLaunchConfigurationTabGroup.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java create mode 100644 plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ThreadVMNode.java create mode 100644 plugins/org.eclipse.dd.mi/.classpath create mode 100644 plugins/org.eclipse.dd.mi/.options create mode 100644 plugins/org.eclipse.dd.mi/.project create mode 100644 plugins/org.eclipse.dd.mi/.settings/org.eclipse.jdt.core.prefs create mode 100644 plugins/org.eclipse.dd.mi/.settings/org.eclipse.jdt.ui.prefs create mode 100644 plugins/org.eclipse.dd.mi/META-INF/MANIFEST.MF create mode 100644 plugins/org.eclipse.dd.mi/about.html create mode 100644 plugins/org.eclipse.dd.mi/build.properties create mode 100644 plugins/org.eclipse.dd.mi/plugin.properties create mode 100644 plugins/org.eclipse.dd.mi/plugin.xml create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/internal/MIPlugin.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/CSourceLookup.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/ExpressionService.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIExecutionDMContext.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointDMData.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpoints.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsActionManager.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIFormat.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIMemory.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIModules.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRegisters.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControl.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIStack.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIVariableManager.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractCLIProcess.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIControlDMContext.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIInferiorProcess.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLICommand.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIExecAbort.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIInfoSharedLibrary.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIInfoThreads.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaCommand.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetAttributes.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetChildCount.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetChildren.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetValue.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetVar.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakAfter.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakCondition.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakDelete.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakDisable.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakEnable.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakInsert.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakList.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakWatch.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MICommand.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataEvaluateExpression.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataListRegisterNames.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataListRegisterValues.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataReadMemory.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataWriteMemory.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecContinue.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecFinish.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecInterrupt.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNext.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNextInstruction.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecReturn.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecRun.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStep.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStepInstruction.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecUntil.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIGDBExit.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIGDBShowExitCode.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIInterpreterExec.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIInterpreterExecConsole.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackInfoDepth.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListArguments.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListFrames.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListLocals.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackSelectFrame.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadListIds.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadSelect.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarAssign.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarCreate.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarDelete.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarEvaluateExpression.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoExpression.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoNumChildren.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoPathExpression.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoType.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarListChildren.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarSetFormat.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarShowAttributes.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarShowFormat.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarUpdate.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/RawCommand.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointChangedEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointHitEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIDetachedEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIErrorEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIFunctionFinishedEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIGDBExitEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIInferiorExitEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIInferiorSignalExitEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MILocationReachedEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIRunningEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISharedLibEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalChangedEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISteppingRangeEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIStoppedEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointScopeEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointTriggerEvent.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoSharedLibraryInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoThreadsInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetAttributesInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetChildCountInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetChildrenInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetValueInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetVarInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIArg.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIAsyncRecord.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakInsertInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakListInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakpoint.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIConsoleStreamOutput.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIConst.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataEvaluateExpressionInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataListRegisterNamesInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataListRegisterValuesInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataReadMemoryInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataWriteMemoryInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIExecAsyncOutput.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIFrame.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIGDBShowExitCodeInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIList.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MILogStreamOutput.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MINotifyAsyncOutput.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIOOBRecord.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIOutput.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIParser.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIRegisterValue.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIResult.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIResultRecord.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackInfoDepthInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListArgumentsInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListFramesInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListLocalsInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStatusAsyncOutput.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStreamRecord.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MITargetStreamOutput.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIThreadListIdsInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MITuple.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIValue.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVar.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarAssignInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarChange.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarCreateInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarDeleteInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarEvaluateExpressionInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoExpressionInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoNumChildrenInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoPathExpressionInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoTypeInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarListChildrenInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarSetFormatInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarShowAttributesInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarShowFormatInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarUpdateInfo.java diff --git a/plugins/org.eclipse.dd.gdb.ui/.classpath b/plugins/org.eclipse.dd.gdb.ui/.classpath new file mode 100644 index 00000000000..304e86186aa --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/org.eclipse.dd.gdb.ui/.project b/plugins/org.eclipse.dd.gdb.ui/.project new file mode 100644 index 00000000000..82e21a8083e --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/.project @@ -0,0 +1,28 @@ + + + org.eclipse.dd.gdb.ui + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/plugins/org.eclipse.dd.gdb.ui/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.dd.gdb.ui/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..ce05db9f058 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,65 @@ +#Thu Jun 07 11:08:08 PDT 2007 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning +org.eclipse.jdt.core.compiler.problem.nullReference=ignore +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/plugins/org.eclipse.dd.gdb.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.gdb.ui/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..004856ef92b --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Debug Services Framework GDB UI Plug-in +Bundle-Vendor: Eclipse.org +Bundle-SymbolicName: org.eclipse.dd.gdb.ui;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.dd.gdb.internal.ui.GdbUIPlugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.dd.dsf.debug.ui, + org.eclipse.dd.dsf, + org.eclipse.dd.dsf.ui, + org.eclipse.debug.ui, + org.eclipse.cdt.launch, + org.eclipse.cdt.debug.core, + org.eclipse.dd.mi, + org.eclipse.dd.gdb, + org.eclipse.dd.dsf.debug, + org.eclipse.cdt.debug.ui +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/plugins/org.eclipse.dd.gdb.ui/about.html b/plugins/org.eclipse.dd.gdb.ui/about.html new file mode 100644 index 00000000000..cb740ae8bc8 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/about.html @@ -0,0 +1,24 @@ + + + + +About +

About This Content

+ +

June 5, 2007

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + \ No newline at end of file diff --git a/plugins/org.eclipse.dd.gdb.ui/build.properties b/plugins/org.eclipse.dd.gdb.ui/build.properties new file mode 100644 index 00000000000..61543eefe00 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/build.properties @@ -0,0 +1,8 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + about.html,\ + icons/ + \ No newline at end of file diff --git a/plugins/org.eclipse.dd.gdb.ui/icons/full/obj16/c_app.gif b/plugins/org.eclipse.dd.gdb.ui/icons/full/obj16/c_app.gif new file mode 100644 index 0000000000000000000000000000000000000000..805a1d0ab8b0dc4b86212fc35178db4d5af5a274 GIT binary patch literal 1042 zcmZ?wbhEHb6krfwcs_+eBWape%5?qo83ySyUCLIum9KWISnXN4#}3>Djrk z%_5_3Pe%WqWu4|Z6Zd6L+Pk{jtZ>Tu{K@kH=C2`df zhPA8MHmzk?v(zSI^TVy1g>$z)%HQ^A&koKl8@zU}EZMzN``}*oid|2(ZLB(anBmAl zsg?uJ_U&joa>Vw~{=~DVWF{PYari*P*)t}W&dHoVt9S04&atCqmoJK4zNmEZjQ{!b zLG#YM+Ij5w?&Bvmo_=xXmhS3HZ|~f;xOv<8&TZ?fSIQpVm%Vs9|IuUdhmU2p-+2Gv zLGtap8(zOPIDGHp<0n;b-Wt7mYxDGJ)zcS6Z$6m6eiQNWv;LV!pI^SIy#DaztJj_H zKZU*fnEdMX#LG{=eEq5a=408bSIb|&?|t*3_1Vj#@4uA3{ZjYsm+!a##;@LO`1RNB z(Yw!&KRmno`Tz3|pI(0W{Qm2SS0BE-{P_9Nmp_lb{(bS~`=f9F9)J7y|K1sz?nT;i3$qHU+=kB0C!VlFaEfHjx zXCWxS!QXGyAM)q-19l;mHO(xHmy+9Er`wzTEBtWzgy1!8*QS)h$4Wjj`kqEVJg0E1 zo~h*%Rj^R$xL1#q*dG}umeeCGI+@1~oGgBFY*M|@9|fu24gq;1ivt-8i_?$pXJ6zg v{^~RH$vLua-+ug + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/GdbAdapterFactory.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/GdbAdapterFactory.java new file mode 100644 index 00000000000..c690ec99f9a --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/GdbAdapterFactory.java @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright (c) 2006 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.dd.gdb.internal.ui; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.debug.ui.actions.DsfResumeCommand; +import org.eclipse.dd.dsf.debug.ui.actions.DsfStepIntoCommand; +import org.eclipse.dd.dsf.debug.ui.actions.DsfStepOverCommand; +import org.eclipse.dd.dsf.debug.ui.actions.DsfStepReturnCommand; +import org.eclipse.dd.dsf.debug.ui.actions.DsfSuspendCommand; +import org.eclipse.dd.dsf.debug.ui.contexts.DsfSuspendTrigger; +import org.eclipse.dd.dsf.debug.ui.sourcelookup.MISourceDisplayAdapter; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.internal.ui.actions.DsfTerminateCommand; +import org.eclipse.dd.gdb.internal.ui.viewmodel.GdbViewModelAdapter; +import org.eclipse.dd.gdb.launching.GdbLaunch; +import org.eclipse.dd.gdb.launching.GdbLaunchDelegate; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchesListener2; +import org.eclipse.debug.core.commands.IResumeHandler; +import org.eclipse.debug.core.commands.IStepIntoHandler; +import org.eclipse.debug.core.commands.IStepOverHandler; +import org.eclipse.debug.core.commands.IStepReturnHandler; +import org.eclipse.debug.core.commands.ISuspendHandler; +import org.eclipse.debug.core.commands.ITerminateHandler; +import org.eclipse.debug.core.model.IDebugModelProvider; +import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory; +import org.eclipse.debug.ui.contexts.ISuspendTrigger; +import org.eclipse.debug.ui.sourcelookup.ISourceDisplay; + +/** + * This implementation of platform adapter factory only retrieves the adapters + * for the launch object. But it also manages the creation and descruction + * of the session-based adapters which are returned by the + * IDMContext.getAdapter() methods. + */ +@ThreadSafe +@SuppressWarnings({"restriction"}) +public class GdbAdapterFactory + implements IAdapterFactory, ILaunchesListener2 +{ + @Immutable + class SessionAdapterSet { + final GdbLaunch fLaunch; + final GdbViewModelAdapter fViewModelAdapter; + final MISourceDisplayAdapter fSourceDisplayAdapter; + final DsfStepIntoCommand fStepIntoCommand; + final DsfStepOverCommand fStepOverCommand; + final DsfStepReturnCommand fStepReturnCommand; + final DsfSuspendCommand fSuspendCommand; + final DsfResumeCommand fResumeCommand; + final DsfTerminateCommand fTerminateCommand; + final IDebugModelProvider fDebugModelProvider; + final DsfSuspendTrigger fSuspendTrigger; + + SessionAdapterSet(GdbLaunch launch) { + fLaunch = launch; + DsfSession session = launch.getSession(); + + fViewModelAdapter = new GdbViewModelAdapter(session); + + if (launch.getSourceLocator() instanceof ISourceLookupDirector) { + fSourceDisplayAdapter = new MISourceDisplayAdapter(session, (ISourceLookupDirector)launch.getSourceLocator()); + } else { + fSourceDisplayAdapter = null; + } + session.registerModelAdapter(ISourceDisplay.class, fSourceDisplayAdapter); + + fStepIntoCommand = new DsfStepIntoCommand(session); + fStepOverCommand = new DsfStepOverCommand(session); + fStepReturnCommand = new DsfStepReturnCommand(session); + fSuspendCommand = new DsfSuspendCommand(session); + fResumeCommand = new DsfResumeCommand(session); + fTerminateCommand = new DsfTerminateCommand(session); + fSuspendTrigger = new DsfSuspendTrigger(session, fLaunch); + session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand); + session.registerModelAdapter(IStepOverHandler.class, fStepOverCommand); + session.registerModelAdapter(IStepReturnHandler.class, fStepReturnCommand); + session.registerModelAdapter(ISuspendHandler.class, fSuspendCommand); + session.registerModelAdapter(IResumeHandler.class, fResumeCommand); + session.registerModelAdapter(ITerminateHandler.class, fTerminateCommand); + + fDebugModelProvider = new IDebugModelProvider() { + // @see org.eclipse.debug.core.model.IDebugModelProvider#getModelIdentifiers() + public String[] getModelIdentifiers() { + return new String[] { GdbLaunchDelegate.GDB_DEBUG_MODEL_ID }; + } + }; + session.registerModelAdapter(IDebugModelProvider.class, fDebugModelProvider); + + /* + * Registering the launch as an adapter, ensures that this launch, + * and debug model ID will be associated with all DMContexts from this + * session. + */ + session.registerModelAdapter(ILaunch.class, fLaunch); + } + + void dispose() { + DsfSession session = fLaunch.getSession(); + + fViewModelAdapter.dispose(); + + session.unregisterModelAdapter(ISourceDisplay.class); + if (fSourceDisplayAdapter != null) fSourceDisplayAdapter.dispose(); + + session.unregisterModelAdapter(IStepIntoHandler.class); + session.unregisterModelAdapter(IStepOverHandler.class); + session.unregisterModelAdapter(IStepReturnHandler.class); + session.unregisterModelAdapter(ISuspendHandler.class); + session.unregisterModelAdapter(IResumeHandler.class); + session.unregisterModelAdapter(ITerminateHandler.class); + fStepIntoCommand.dispose(); + fStepOverCommand.dispose(); + fStepReturnCommand.dispose(); + fSuspendCommand.dispose(); + fResumeCommand.dispose(); + fTerminateCommand.dispose(); + fSuspendTrigger.dispose(); + } + + + } + + private Map fLaunchAdapterSets = + Collections.synchronizedMap(new HashMap()); + + public GdbAdapterFactory() { + DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); + } + + /** + * This method only actually returns adapters for the launch object. + */ + @SuppressWarnings("unchecked") + public Object getAdapter(Object adaptableObject, Class adapterType) { + if (!(adaptableObject instanceof GdbLaunch)) return null; + + GdbLaunch launch = (GdbLaunch)adaptableObject; + + // Find the correct set of adapters based on the launch session-ID. If not found + // it means that we have a new launch and new session, and we have to create a + // new set of adapters. + DsfSession session = launch.getSession(); + if (session == null) return null; + + SessionAdapterSet adapterSet; + synchronized(fLaunchAdapterSets) { + adapterSet = fLaunchAdapterSets.get(launch); + if (adapterSet == null) { + adapterSet = new SessionAdapterSet(launch); + fLaunchAdapterSets.put(launch, adapterSet); + } + } + + // Returns the adapter type for the launch object. + if (adapterType.equals(IElementContentProvider.class)) return adapterSet.fViewModelAdapter; + else if (adapterType.equals(IModelProxyFactory.class)) return adapterSet.fViewModelAdapter; + else if (adapterType.equals(IColumnPresentationFactory.class)) return adapterSet.fViewModelAdapter; + else if (adapterType.equals(ISuspendTrigger.class)) return adapterSet.fSuspendTrigger; + else return null; + } + + @SuppressWarnings("unchecked") + public Class[] getAdapterList() { + return new Class[] { + IElementContentProvider.class, IModelProxyFactory.class, ISuspendTrigger.class, + IColumnPresentationFactory.class + }; + } + + public void launchesRemoved(ILaunch[] launches) { + // Dispose the set of adapters for a launch only after the launch is + // removed. + for (ILaunch launch : launches) { + if (launch instanceof GdbLaunch) { + synchronized(fLaunchAdapterSets) { + if ( fLaunchAdapterSets.containsKey(launch) ) { + fLaunchAdapterSets.remove(launch).dispose(); + } + } + } + } + } + + public void launchesTerminated(ILaunch[] launches) { + } + + public void launchesAdded(ILaunch[] launches) { + } + + public void launchesChanged(ILaunch[] launches) { + } + +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/GdbUIPlugin.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/GdbUIPlugin.java new file mode 100644 index 00000000000..f23897223f0 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/GdbUIPlugin.java @@ -0,0 +1,59 @@ +package org.eclipse.dd.gdb.internal.ui; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class GdbUIPlugin extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.dd.gdb.ui"; //$NON-NLS-1$ + + // The shared instance + private static GdbUIPlugin plugin; + + private static BundleContext fgBundleContext; + + /** + * The constructor + */ + public GdbUIPlugin() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + fgBundleContext = context; + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + fgBundleContext = null; + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static GdbUIPlugin getDefault() { + return plugin; + } + + public static BundleContext getBundleContext() { + return fgBundleContext; + } +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/DsfTerminateCommand.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/DsfTerminateCommand.java new file mode 100644 index 00000000000..2a9a1f99c0d --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/DsfTerminateCommand.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2006 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.dd.gdb.internal.ui.actions; + +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.ui.actions.DsfCommandRunnable; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.dd.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.debug.core.commands.IDebugCommandRequest; +import org.eclipse.debug.core.commands.IEnabledStateRequest; +import org.eclipse.debug.core.commands.ITerminateHandler; + +public class DsfTerminateCommand implements ITerminateHandler { + private final DsfExecutor fExecutor; + private final DsfServicesTracker fTracker; + + public DsfTerminateCommand(DsfSession session) { + fExecutor = session.getExecutor(); + fTracker = new DsfServicesTracker(GdbUIPlugin.getBundleContext(), session.getId()); + } + + public void dispose() { + fTracker.dispose(); + } + + // Run control may not be avilable after a connection is terminated and shut down. + public void canExecute(final IEnabledStateRequest request) { + if (request.getElements().length != 1 || + !(request.getElements()[0] instanceof IDMVMContext) ) + { + request.setEnabled(false); + request.done(); + return; + } + + // Javac doesn't like the cast to "(AbstractDMVMLayoutNode.DMVMContext)" need to use the + // construct below and suppress warnings. + IDMVMContext vmc = (IDMVMContext)request.getElements()[0]; + final IExecutionDMContext dmc = DMContexts.getAncestorOfType(vmc.getDMContext(), IExecutionDMContext.class); + if (dmc == null) { + request.setEnabled(false); + request.done(); + return; + } + + fExecutor.execute( + new DsfRunnable() { + public void run() { + // Get the processes service and the exec context. + GDBControl gdbControl = fTracker.getService(GDBControl.class); + if (gdbControl == null || dmc == null) { + // Context or service already invalid. + request.setEnabled(false); + request.done(); + } else { + // Check the teriminate. + request.setEnabled(!gdbControl.isGDBExited()); + request.done(); + } + } + }); + } + + public boolean execute(final IDebugCommandRequest request) { + if (request.getElements().length != 1) { + request.done(); + return false; + } + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + GDBControl gdbControl = fTracker.getService(GDBControl.class); + if (gdbControl != null) { + gdbControl.terminate(new RequestMonitor(fExecutor, null)); + } + } + }); + return false; + } + +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/CBreakpointGdbThreadFilterPage.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/CBreakpointGdbThreadFilterPage.java new file mode 100644 index 00000000000..bec7fdadec9 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/CBreakpointGdbThreadFilterPage.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2004, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.ui.breakpoints; + +import org.eclipse.cdt.debug.core.model.ICBreakpoint; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.dd.gdb.breakpoints.CBreakpointGdbThreadsFilterExtension; +import org.eclipse.dd.gdb.launching.GdbLaunchDelegate; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.dialogs.PropertyPage; + +public class CBreakpointGdbThreadFilterPage extends PropertyPage { + + private GdbThreadFilterEditor fThreadFilterEditor; + + /* (non-Javadoc) + * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createContents( Composite parent ) { + noDefaultAndApplyButton(); + Composite mainComposite = new Composite( parent, SWT.NONE ); + mainComposite.setFont( parent.getFont() ); + mainComposite.setLayout( new GridLayout() ); + mainComposite.setLayoutData( new GridData( GridData.FILL_BOTH ) ); + createThreadFilterEditor( mainComposite ); + setValid( true ); + return mainComposite; + } + + public ICBreakpoint getBreakpoint() { + return (ICBreakpoint)getElement().getAdapter(ICBreakpoint.class); + } + + public CBreakpointGdbThreadsFilterExtension getFilterExtension() { + ICBreakpoint bp = getBreakpoint(); + if (bp != null) { + try { + CBreakpointGdbThreadsFilterExtension filter = + (CBreakpointGdbThreadsFilterExtension) bp.getExtension( + GdbLaunchDelegate.GDB_DEBUG_MODEL_ID, CBreakpointGdbThreadsFilterExtension.class); + filter.initialize(bp); + return filter; + } catch (CoreException e) {} + } + return null; + } + + protected void createThreadFilterEditor( Composite parent ) { + fThreadFilterEditor = new GdbThreadFilterEditor( parent, this ); + } + + protected GdbThreadFilterEditor getThreadFilterEditor() { + return fThreadFilterEditor; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.preference.IPreferencePage#performOk() + */ + @Override + public boolean performOk() { + doStore(); + return super.performOk(); + } + + /** + * Stores the values configured in this page. + */ + protected void doStore() { + fThreadFilterEditor.doStore(); + } +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java new file mode 100644 index 00000000000..eb7017ee052 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java @@ -0,0 +1,537 @@ +/******************************************************************************* + * Copyright (c) 2004, 2005 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.ui.breakpoints; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.debug.ui.CDebugUIPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.ImmediateExecutor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.gdb.breakpoints.CBreakpointGdbThreadsFilterExtension; +import org.eclipse.dd.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.dd.gdb.launching.GdbLaunch; +import org.eclipse.dd.gdb.service.GDBRunControl; +import org.eclipse.dd.gdb.service.GDBRunControl.GDBThreadData; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.jface.viewers.AbstractTreeViewer; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.osgi.util.tracker.ServiceTracker; + +public class GdbThreadFilterEditor { + + /** + * Comment for ThreadFilterEditor. + */ + public class CheckHandler implements ICheckStateListener { + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent) + */ + public void checkStateChanged(CheckStateChangedEvent event) { + Object element = event.getElement(); + if (element instanceof IContainerDMContext) { + checkTarget((IContainerDMContext) element, event.getChecked()); + } else if (element instanceof IExecutionDMContext) { + checkThread((IExecutionDMContext) element, event.getChecked()); + } + } + + /** + * Check or uncheck a debug target in the tree viewer. When a debug + * target is checked, attempt to check all of the target's threads by + * default. When a debug target is unchecked, uncheck all its threads. + */ + protected void checkTarget(IContainerDMContext target, boolean checked) { + getThreadViewer().setChecked(target, checked); + getThreadViewer().setGrayed(target, false); + getThreadViewer().expandToLevel(target, AbstractTreeViewer.ALL_LEVELS); + IExecutionDMContext[] threads = syncGetThreads(target); + for (int i = 0; i < threads.length; i++) { + getThreadViewer().setChecked(threads[i], checked); + getThreadViewer().setGrayed(threads[i], false); + } + } + + /** + * Check or uncheck a thread. Update the thread's debug target. + */ + protected void checkThread(IExecutionDMContext thread, boolean checked) { + getThreadViewer().setChecked(thread, checked); + IContainerDMContext target = DMContexts.getAncestorOfType(thread, IContainerDMContext.class); + IExecutionDMContext[] threads = syncGetThreads(target); + int checkedNumber = 0; + for (int i = 0; i < threads.length; i++) { + if (getThreadViewer().getChecked(threads[i])) { + ++checkedNumber; + } + } + if (checkedNumber == 0) { + getThreadViewer().setChecked(target, false); + getThreadViewer().setGrayed(target, false); + } else if (checkedNumber == threads.length) { + getThreadViewer().setChecked(target, true); + getThreadViewer().setGrayed(target, false); + } else { + getThreadViewer().setGrayChecked(target, true); + } + } + } + + /** + * Comment for ThreadFilterEditor. + */ + public class ThreadFilterContentProvider implements ITreeContentProvider { + + /** + * Constructor for ThreadFilterContentProvider. + */ + public ThreadFilterContentProvider() { + super(); + // TODO Auto-generated constructor stub + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) + */ + public Object[] getChildren(Object parent) { + if (parent instanceof IContainerDMContext) { + return syncGetThreads((IContainerDMContext) parent); + } + + if (parent instanceof ILaunchManager) { + List children = new ArrayList(); + ILaunch[] launches = ((ILaunchManager) parent).getLaunches(); + IContainerDMContext target; + for (int i = 0; i < launches.length; i++) { + if (launches[i] instanceof GdbLaunch) { + target = syncGetContainer((GdbLaunch) launches[i]); + if (target != null) { + children.add(target); + } + } + } + return children.toArray(); + } + return new Object[0]; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) + */ + public Object getParent(Object element) { + if (element instanceof IContainerDMContext) { + return DebugPlugin.getDefault().getLaunchManager(); + } + if (element instanceof IExecutionDMContext) { + return DMContexts.getAncestorOfType((IExecutionDMContext) element, IContainerDMContext.class); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) + */ + public boolean hasChildren(Object element) { + return getChildren(element).length > 0; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) + */ + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IContentProvider#dispose() + */ + public void dispose() { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, + * java.lang.Object, java.lang.Object) + */ + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + } + + public class ThreadFilterLabelProvider extends LabelProvider { + + @Override + public Image getImage(Object element) { + if (element instanceof IContainerDMContext) { + return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_DEBUG_TARGET); + } else { + return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_THREAD_RUNNING); + } + } + + @Override + public String getText(Object element) { + if (element instanceof IContainerDMContext) { + return syncGetContainerLabel((IContainerDMContext)element); + } else { + return syncGetThreadLabel((IExecutionDMContext)element); + } + } + } + + + private CBreakpointGdbThreadFilterPage fPage; + + private CheckboxTreeViewer fThreadViewer; + + private ThreadFilterContentProvider fContentProvider; + + private CheckHandler fCheckHandler; + + /** + * Constructor for ThreadFilterEditor. + */ + public GdbThreadFilterEditor(Composite parent, CBreakpointGdbThreadFilterPage page) { + fPage = page; + fContentProvider = new ThreadFilterContentProvider(); + fCheckHandler = new CheckHandler(); + createThreadViewer(parent); + } + + protected CBreakpointGdbThreadFilterPage getPage() { + return fPage; + } + + private void createThreadViewer(Composite parent) { + Label label = new Label(parent, SWT.NONE); + label.setText("&Restrict to Selected Targets and Threads:"); //$NON-NLS-1$ + label.setFont(parent.getFont()); + label.setLayoutData(new GridData()); + GridData data = new GridData(GridData.FILL_BOTH); + data.heightHint = 100; + fThreadViewer = new CheckboxTreeViewer(parent, SWT.BORDER); + fThreadViewer.addCheckStateListener(fCheckHandler); + fThreadViewer.getTree().setLayoutData(data); + fThreadViewer.getTree().setFont(parent.getFont()); + fThreadViewer.setContentProvider(fContentProvider); + fThreadViewer.setLabelProvider(new ThreadFilterLabelProvider()); + fThreadViewer.setInput(DebugPlugin.getDefault().getLaunchManager()); + setInitialCheckedState(); + } + + /** + * Returns the debug targets that appear in the tree + */ + protected IContainerDMContext[] getDebugTargets() { + Object input = fThreadViewer.getInput(); + if (!(input instanceof ILaunchManager)) { + return new IContainerDMContext[0]; + } + List targets = new ArrayList(); + ILaunch[] launches = ((ILaunchManager) input).getLaunches(); + IContainerDMContext target; + for (int i = 0; i < launches.length; i++) { + if (launches[i] instanceof GdbLaunch) { + target = syncGetContainer((GdbLaunch) launches[i]); + if (target != null) { + targets.add(target); + } + } + } + return targets.toArray(new IContainerDMContext[targets.size()]); + } + + protected CheckboxTreeViewer getThreadViewer() { + return fThreadViewer; + } + + /** + * Sets the initial checked state of the tree viewer. The initial state + * should reflect the current state of the breakpoint. If the breakpoint has + * a thread filter in a given thread, that thread should be checked. + */ + protected void setInitialCheckedState() { + CBreakpointGdbThreadsFilterExtension filterExtension = fPage.getFilterExtension(); + try { + IContainerDMContext[] targets = filterExtension.getTargetFilters(); + + // TODO: Hack to properly initialize the target/thread list + // Should be done in filterExtension.initialize() but we don't know + // how to get the target list from an ICBreakpoint... + if (targets.length == 0) { + targets = getDebugTargets(); + for (IContainerDMContext target : targets) { + filterExtension.setTargetFilter(target); + } + } + // TODO: End of hack + + for (int i = 0; i < targets.length; i++) { + IExecutionDMContext[] filteredThreads = filterExtension.getThreadFilters(targets[i]); + if (filteredThreads != null) { + for (int j = 0; j < filteredThreads.length; ++j) + fCheckHandler.checkThread(filteredThreads[j], true); + } else { + fCheckHandler.checkTarget(targets[i], true); + } + } + } catch (CoreException e) { + CDebugUIPlugin.log(e); + } + } + + protected void doStore() { + CBreakpointGdbThreadsFilterExtension filterExtension = fPage.getFilterExtension(); + IContainerDMContext[] targets = getDebugTargets(); + for (int i = 0; i < targets.length; ++i) { + try { + if (getThreadViewer().getChecked(targets[i])) { + if (getThreadViewer().getGrayed(targets[i])) { + IExecutionDMContext[] threads = getTargetThreadFilters(targets[i]); + filterExtension.setThreadFilters(threads); + } else { + filterExtension.setTargetFilter(targets[i]); + } + } else { + filterExtension.removeTargetFilter(targets[i]); + } + DebugPlugin.getDefault().getBreakpointManager().fireBreakpointChanged(fPage.getBreakpoint()); + } catch (CoreException e) { + CDebugUIPlugin.log(e); + } + } + } + + private IExecutionDMContext[] getTargetThreadFilters(IContainerDMContext target) { + Object[] threads = ((ITreeContentProvider) getThreadViewer().getContentProvider()).getChildren(target); + ArrayList list = new ArrayList(threads.length); + for (int i = 0; i < threads.length; ++i) { + if (getThreadViewer().getChecked(threads[i])) + list.add(threads[i]); + } + return list.toArray(new IExecutionDMContext[list.size()]); + } + + private IContainerDMContext syncGetContainer(final GdbLaunch launch) { + final DsfSession session = launch.getSession(); + + class ContainerQuery extends Query { + @Override + protected void execute(DataRequestMonitor rm) { + if (!session.isActive()) { + rm.setStatus(getFailStatus(IDsfService.INVALID_STATE, "Launch's session not active.")); //$NON-NLS-1$ + rm.done(); + return; + } + + ServiceTracker tracker = new ServiceTracker(GdbUIPlugin.getBundleContext(), GDBControl.class + .getName(), null); + tracker.open(); + GDBControl gdbControl = (GDBControl) tracker.getService(); + if (gdbControl != null) { + rm.setData(gdbControl.getGDBDMContext()); + } else { + rm.setStatus(getFailStatus(IDsfService.INVALID_STATE, "GDB Control not accessible.")); //$NON-NLS-1$ + } + rm.done(); + tracker.close(); + } + } + + ContainerQuery query = new ContainerQuery(); + try { + session.getExecutor().execute(query); + return query.get(); + } catch (RejectedExecutionException e) { + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + return null; + } + + private IExecutionDMContext[] syncGetThreads(final IContainerDMContext container) { + final DsfSession session = DsfSession.getSession(container.getSessionId()); + if (session == null) { + return new IExecutionDMContext[0]; + } + + class ThreadsQuery extends Query { + @Override + protected void execute(DataRequestMonitor rm) { + if (!session.isActive()) { + rm.setStatus(getFailStatus(IDsfService.INVALID_STATE, "Container's session not active.")); //$NON-NLS-1$ + rm.done(); + return; + } + + ServiceTracker tracker = new ServiceTracker(GdbUIPlugin.getBundleContext(), IRunControl.class + .getName(), null); + tracker.open(); + IRunControl runControl = (IRunControl) tracker.getService(); + if (runControl != null) { + runControl.getExecutionContexts(container, rm); + } else { + rm.setStatus(getFailStatus(IDsfService.INVALID_STATE, "GDB Control not accessible.")); //$NON-NLS-1$ + rm.done(); + } + tracker.close(); + } + } + + ThreadsQuery query = new ThreadsQuery(); + try { + session.getExecutor().execute(query); + return query.get(); + } catch (RejectedExecutionException e) { + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + return new IExecutionDMContext[0]; + } + + private String syncGetContainerLabel(final IContainerDMContext container) { + final DsfSession session = DsfSession.getSession(container.getSessionId()); + if (session == null) { + return "Error reading data"; //$NON-NLS-1$ + } + + class ContainerLabelQuery extends Query { + @Override + protected void execute(DataRequestMonitor rm) { + if (!session.isActive()) { + rm.setStatus(getFailStatus(IDsfService.INVALID_STATE, "Container's session not active.")); //$NON-NLS-1$ + rm.done(); + return; + } + + ServiceTracker tracker = new ServiceTracker(GdbUIPlugin.getBundleContext(), GDBControl.class + .getName(), null); + tracker.open(); + GDBControl gdbControl = (GDBControl) tracker.getService(); + if (gdbControl != null) { + rm.setData(gdbControl.getExecutablePath().toOSString()); + } else { + rm.setStatus(getFailStatus(IDsfService.INVALID_STATE, "GDB Control not accessible.")); //$NON-NLS-1$ + } + rm.done(); + tracker.close(); + } + } + + ContainerLabelQuery query = new ContainerLabelQuery(); + try { + session.getExecutor().execute(query); + return query.get(); + } catch (RejectedExecutionException e) { + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + return "Error reading data"; //$NON-NLS-1$ + } + + private String syncGetThreadLabel(final IExecutionDMContext thread) { + final DsfSession session = DsfSession.getSession(thread.getSessionId()); + if (session == null) { + return "Error reading data"; //$NON-NLS-1$ + } + + class ThreadLabelQuery extends Query { + @Override + protected void execute(final DataRequestMonitor rm) { + if (!session.isActive()) { + rm.setStatus(getFailStatus(IDsfService.INVALID_STATE, "Container's session not active.")); //$NON-NLS-1$ + rm.done(); + return; + } + + ServiceTracker tracker = new ServiceTracker(GdbUIPlugin.getBundleContext(), GDBRunControl.class + .getName(), null); + tracker.open(); + GDBRunControl runControl = (GDBRunControl) tracker.getService(); + if (runControl != null) { + runControl.getThreadData((IMIExecutionDMContext) thread, new DataRequestMonitor( + ImmediateExecutor.getInstance(), rm) { + @Override + protected void handleOK() { + final StringBuilder builder = new StringBuilder("Thread["); //$NON-NLS-1$ + builder.append(((IMIExecutionDMContext)thread).getThreadId()); + builder.append("] "); //$NON-NLS-1$ + builder.append(getData().getId()); + builder.append(getData().getName()); + + rm.setData(builder.toString()); + rm.done(); + } + }); + } else { + rm.setStatus(getFailStatus(IDsfService.INVALID_STATE, "GDB Control not accessible.")); //$NON-NLS-1$ + rm.done(); + } + tracker.close(); + } + } + + ThreadLabelQuery query = new ThreadLabelQuery(); + try { + session.getExecutor().execute(query); + return query.get(); + } catch (RejectedExecutionException e) { + } catch (InterruptedException e) { + } catch (ExecutionException e) { + } + return "Error reading data"; //$NON-NLS-1$ + } + + private Status getFailStatus(int code, String message) { + return new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, code, message, null); + } +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/DsfMIlRunLaunchConfigurationTabGroup.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/DsfMIlRunLaunchConfigurationTabGroup.java new file mode 100644 index 00000000000..7c15f7b8ebb --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/DsfMIlRunLaunchConfigurationTabGroup.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2005 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.ui.launching; + +import org.eclipse.cdt.launch.ui.CDebuggerTab; +import org.eclipse.cdt.launch.ui.CMainTab; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup; +import org.eclipse.debug.ui.CommonTab; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.debug.ui.ILaunchConfigurationTab; +import org.eclipse.debug.ui.sourcelookup.SourceLookupTab; + +public class DsfMIlRunLaunchConfigurationTabGroup extends AbstractLaunchConfigurationTabGroup { + + /* (non-Javadoc) + * @see org.eclipse.debug.ui.ILaunchConfigurationTabGroup#createTabs(org.eclipse.debug.ui.ILaunchConfigurationDialog, java.lang.String) + */ + public void createTabs(ILaunchConfigurationDialog dialog, String mode) { + ILaunchConfigurationTab[] tabs = new ILaunchConfigurationTab[] { + new CMainTab(true), + new CDebuggerTab(false), + new SourceLookupTab(), + new CommonTab() + }; + setTabs(tabs); + } + +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java new file mode 100644 index 00000000000..a8f003eddf0 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2006 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.dd.gdb.internal.ui.viewmodel; + +import org.eclipse.cdt.debug.ui.ICDebugUIConstants; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider; +import org.eclipse.dd.dsf.debug.ui.viewmodel.modules.ModulesVMProvider; +import org.eclipse.dd.dsf.debug.ui.viewmodel.register.RegisterVMProvider; +import org.eclipse.dd.dsf.debug.ui.viewmodel.variable.VariableVMProvider; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMAdapter; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.gdb.internal.ui.viewmodel.launch.LaunchVMProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; +import org.eclipse.debug.ui.IDebugUIConstants; + +/* + * + */ +@ThreadSafe +@SuppressWarnings("restriction") +public class GdbViewModelAdapter extends AbstractDMVMAdapter +{ + public GdbViewModelAdapter(DsfSession session) { + super(session); + getSession().registerModelAdapter(IColumnPresentationFactory.class, this); + } + + @Override + public void dispose() { + getSession().unregisterModelAdapter(IColumnPresentationFactory.class); + super.dispose(); + } + + @Override + protected AbstractDMVMProvider createViewModelProvider(IPresentationContext context) { + if ( IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId()) ) { + return new LaunchVMProvider(this, context, getSession()); + } else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(context.getId()) ) { + return new VariableVMProvider(this, context, getSession()); + } else if (IDebugUIConstants.ID_REGISTER_VIEW.equals(context.getId()) ) { + return new RegisterVMProvider(this, context, getSession()); + } else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(context.getId()) ) { + return new ExpressionVMProvider(this, context, getSession()); + } else if (ICDebugUIConstants.ID_MODULES_VIEW.equals(context.getId()) ) { + return new ModulesVMProvider(this, context, getSession()); + } + return null; + } +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java new file mode 100644 index 00000000000..3cecaccba41 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2006 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.gdb.internal.ui.viewmodel.launch; + + +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.IDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExitedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.gdb.service.GDBRunControl; +import org.eclipse.dd.gdb.service.GDBRunControl.GDBProcessData; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.gdb.service.command.GDBControlDMContext; +import org.eclipse.dd.gdb.service.command.GDBControl.StartedEvent; +import org.eclipse.dd.mi.service.command.AbstractMIControl; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.events.MIInferiorExitEvent; +import org.eclipse.dd.mi.service.command.events.MIInferiorSignalExitEvent; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; + +@SuppressWarnings("restriction") +public class ContainerVMNode extends AbstractDMVMNode + implements IElementLabelProvider +{ + + public ContainerVMNode(AbstractDMVMProvider provider, DsfSession session) { + super(provider, session, IRunControl.IExecutionDMContext.class); + } + + @Override + protected void updateElementsInSessionThread(IChildrenUpdate update) { + if (!checkService(AbstractMIControl.class, null, update)) return; + + MIControlDMContext containerCtx = getServicesTracker().getService(AbstractMIControl.class).getControlDMContext(); + update.setChild(createVMContext(containerCtx), 0); + update.done(); + } + + + public void update(final ILabelUpdate[] updates) { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + updateLabelInSessionThread(updates); + }}); + } catch (RejectedExecutionException e) { + for (ILabelUpdate update : updates) { + handleFailedUpdate(update); + } + } + } + + protected void updateLabelInSessionThread(ILabelUpdate[] updates) { + for (final ILabelUpdate update : updates) { + if (!checkService(GDBRunControl.class, null, update)) continue; + final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + + final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class); + + String imageKey = null; + if (runControl.isSuspended(dmc)) { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED; + } else { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING; + } + update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0); + + runControl.getProcessData( + dmc, + new DataRequestMonitor(getExecutor(), null) { + @Override + public void handleCompleted() { + if (!getStatus().isOK()) { + update.done(); + return; + } + update.setLabel(getData().getName(), 0); + update.done(); + } + }); + } + } + + public int getDeltaFlags(Object e) { + if(e instanceof IStartedDMEvent || e instanceof IExitedDMEvent) { + return IModelDelta.CONTENT; + } else if(e instanceof IRunControl.IContainerResumedDMEvent || + e instanceof IRunControl.IContainerSuspendedDMEvent) + { + return IModelDelta.CONTENT; + } else if (e instanceof GDBControl.ExitedEvent || + e instanceof MIInferiorExitEvent || + e instanceof MIInferiorSignalExitEvent) + { + return IModelDelta.CONTENT; + } + if (e instanceof StartedEvent) { + return IModelDelta.EXPAND | IModelDelta.SELECT; + } + return IModelDelta.NO_CHANGE; + } + + public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) { + + if(e instanceof IRunControl.IContainerResumedDMEvent || + e instanceof IRunControl.IContainerSuspendedDMEvent) + { + parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + } else if (e instanceof IStartedDMEvent || e instanceof IExitedDMEvent) { + parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + } else if (e instanceof GDBControl.ExitedEvent || + e instanceof MIInferiorExitEvent || + e instanceof MIInferiorSignalExitEvent) + { + parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + } + if (e instanceof StartedEvent) { + parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.EXPAND | IModelDelta.SELECT); + } + + requestMonitor.done(); + } +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java new file mode 100644 index 00000000000..87675c2b6f9 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * Ericsson - Modified for new functionality + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.ui.viewmodel.launch; + +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.debug.ui.viewmodel.launch.LaunchRootVMNode; +import org.eclipse.dd.dsf.debug.ui.viewmodel.launch.StackFramesVMNode; +import org.eclipse.dd.dsf.debug.ui.viewmodel.launch.StandardProcessVMNode; +import org.eclipse.dd.dsf.debug.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; +import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; +import org.eclipse.dd.dsf.ui.viewmodel.IVMNode; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchesListener2; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; + + +/** + * + */ +@SuppressWarnings("restriction") +public class LaunchVMProvider extends AbstractDMVMProvider + implements IDebugEventSetListener, ILaunchesListener2 +{ + @ThreadSafe + public LaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) + { + super(adapter, presentationContext, session); + + IRootVMNode launchNode = new LaunchRootVMNode(this); + setRootNode(launchNode); + + // Container node to contain all processes and threads + IVMNode containerNode = new ContainerVMNode(this, getSession()); + IVMNode processesNode = new StandardProcessVMNode(this); + addChildNodes(launchNode, new IVMNode[] { containerNode, processesNode}); + + IVMNode threadsNode = new ThreadVMNode(this, getSession()); + addChildNodes(containerNode, new IVMNode[] { threadsNode }); + + IVMNode stackFramesNode = new StackFramesVMNode(this, getSession()); + addChildNodes(threadsNode, new IVMNode[] { stackFramesNode }); + + + DebugPlugin.getDefault().addDebugEventListener(this); + DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this); + } + + + public void handleDebugEvents(final DebugEvent[] events) { + if (isDisposed()) return; + + // We're in session's executor thread. Re-dispach to VM Adapter + // executor thread and then call root layout node. + try { + getExecutor().execute(new Runnable() { + public void run() { + if (isDisposed()) return; + + for (final DebugEvent event : events) { + handleEvent(event); + } + }}); + } catch (RejectedExecutionException e) { + // Ignore. This exception could be thrown if the provider is being + // shut down. + } + } + + @Override + public void dispose() { + DebugPlugin.getDefault().removeDebugEventListener(this); + DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this); + super.dispose(); + } + + public void launchesAdded(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED)); + } + + public void launchesRemoved(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED)); + } + + public void launchesChanged(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED)); + } + + public void launchesTerminated(ILaunch[] launches) { + handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED)); + } + + private void handleLaunchesEvent(final LaunchesEvent event) { + if (isDisposed()) return; + + // We're in session's executor thread. Re-dispach to VM Adapter + // executor thread and then call root layout node. + try { + getExecutor().execute(new Runnable() { + public void run() { + if (isDisposed()) return; + + IRootVMNode rootLayoutNode = getRootVMNode(); + if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) { + handleEvent(event); + } + }}); + } catch (RejectedExecutionException e) { + // Ignore. This exception could be thrown if the provider is being + // shut down. + } + } +} diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ThreadVMNode.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ThreadVMNode.java new file mode 100644 index 00000000000..fefd36c28a9 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ThreadVMNode.java @@ -0,0 +1,308 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * Ericsson - Modified for multi threaded functionality + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.ui.viewmodel.launch; + +import java.util.List; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.datamodel.IDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerResumedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData; +import org.eclipse.dd.dsf.debug.service.IRunControl.IResumedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.internal.ui.DsfUIPlugin; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.dsf.ui.viewmodel.IVMContext; +import org.eclipse.dd.dsf.ui.viewmodel.ModelProxyInstalledEvent; +import org.eclipse.dd.dsf.ui.viewmodel.VMChildrenUpdate; +import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; +import org.eclipse.dd.gdb.service.GDBRunControl; +import org.eclipse.dd.gdb.service.GDBRunControl.GDBThreadData; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; +import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta; +import org.eclipse.debug.ui.DebugUITools; +import org.eclipse.debug.ui.IDebugUIConstants; + + +@SuppressWarnings("restriction") +public class ThreadVMNode extends AbstractDMVMNode + implements IElementLabelProvider +{ + public ThreadVMNode(AbstractDMVMProvider provider, DsfSession session) { + super(provider, session, IExecutionDMContext.class); + } + + @Override + protected void updateElementsInSessionThread(final IChildrenUpdate update) { + if (!checkService(IRunControl.class, null, update)) return; + final IContainerDMContext contDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IContainerDMContext.class); + + if (contDmc == null) { + handleFailedUpdate(update); + return; + } + + getServicesTracker().getService(IRunControl.class).getExecutionContexts(contDmc, + new DataRequestMonitor(getSession().getExecutor(), null){ + @Override + public void handleCompleted() { + if (!getStatus().isOK()) { + handleFailedUpdate(update); + return; + } + fillUpdateWithVMCs(update, getData()); + update.done(); + } + }); + } + + + public void update(final ILabelUpdate[] updates) { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + updateLabelInSessionThread(updates); + }}); + } catch (RejectedExecutionException e) { + for (ILabelUpdate update : updates) { + handleFailedUpdate(update); + } + } + } + + @Override + public void getContextsForEvent(VMDelta parentDelta, Object e, final DataRequestMonitor rm) { + if(e instanceof IContainerResumedDMEvent) { + IDMContext triggerContext = ((IContainerResumedDMEvent)e).getTriggeringContext(); + if (triggerContext != null) { + rm.setData(new IVMContext[] { createVMContext(triggerContext) }); + rm.done(); + return; + } + } else if(e instanceof IContainerSuspendedDMEvent) { + IDMContext triggerContext = ((IContainerSuspendedDMEvent)e).getTriggeringContext(); + if (triggerContext != null) { + rm.setData(new IVMContext[] { createVMContext(triggerContext) }); + rm.done(); + return; + } + } else if (e instanceof ModelProxyInstalledEvent) { + getThreadVMCForModelProxyInstallEvent( + parentDelta, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + rm.setData(new IVMContext[] { getData().fVMContext }); + } else { + rm.setData(new IVMContext[0]); + } + rm.done(); + } + }); + return; + } + super.getContextsForEvent(parentDelta, e, rm); + } + + private static class VMContextInfo { + final IVMContext fVMContext; + final int fIndex; + final boolean fIsSuspended; + VMContextInfo(IVMContext vmContext, int index, boolean isSuspended) { + fVMContext = vmContext; + fIndex = index; + fIsSuspended = isSuspended; + } + } + + private void getThreadVMCForModelProxyInstallEvent(VMDelta parentDelta, final DataRequestMonitor rm) { + getVMProvider().updateNode(this, new VMChildrenUpdate( + parentDelta, getVMProvider().getPresentationContext(), -1, -1, + new DataRequestMonitor>(getExecutor(), rm) { + @Override + protected void handleOK() { + try { + getSession().getExecutor().execute(new DsfRunnable() { + public void run() { + final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + if (runControl != null) { + int vmcIdx = -1; + int suspendedVmcIdx = -1; + + for (int i = 0; i < getData().size(); i++) { + if (getData().get(i) instanceof IDMVMContext) { + IDMVMContext vmc = (IDMVMContext)getData().get(i); + IExecutionDMContext execDmc = DMContexts.getAncestorOfType( + vmc.getDMContext(), IExecutionDMContext.class); + if (execDmc != null) { + vmcIdx = vmcIdx < 0 ? i : vmcIdx; + if (runControl.isSuspended(execDmc)) { + suspendedVmcIdx = suspendedVmcIdx < 0 ? i : suspendedVmcIdx; + } + } + } + } + if (suspendedVmcIdx >= 0) { + rm.setData(new VMContextInfo( + (IVMContext)getData().get(suspendedVmcIdx), suspendedVmcIdx, true)); + } else if (vmcIdx >= 0) { + rm.setData(new VMContextInfo((IVMContext)getData().get(vmcIdx), vmcIdx, false)); + } else { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, "No threads available", null)); //$NON-NLS-1$ + } + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, "No threads available", null)); //$NON-NLS-1$ + rm.done(); + } + } + }); + } catch (RejectedExecutionException e) { + rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "", null)); //$NON-NLS-1$ + rm.done(); + } + } + })); + } + + protected void updateLabelInSessionThread(ILabelUpdate[] updates) { + for (final ILabelUpdate update : updates) { + if (!checkService(GDBRunControl.class, null, update)) continue; + final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + + final IMIExecutionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IMIExecutionDMContext.class); + + String imageKey = null; + if (getServicesTracker().getService(IRunControl.class).isSuspended(dmc)) { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED; + } else { + imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING; + } + update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0); + + // Find the Reason for the State + runControl.getExecutionData(dmc, + new DataRequestMonitor(getSession().getExecutor(), null) { + @Override + public void handleCompleted(){ + if (!getStatus().isOK()) { + handleFailedUpdate(update); + return; + } + + // We're in a new dispatch cycle, and we have to check whether the + // service reference is still valid. + if (!checkService(GDBRunControl.class, null, update)) return; + + final StateChangeReason reason = getData().getStateChangeReason(); + + // Retrieve the rest of the thread information + runControl.getThreadData( + dmc, + new DataRequestMonitor(getSession().getExecutor(), null) { + @Override + public void handleCompleted() { + if (!getStatus().isOK()) { + update.done(); + return; + } + // Create Labels of type Thread[GDBthreadId]RealThreadID/Name (State: Reason) + // Thread[1] 3457 (Suspended:BREAKPOINT) + final StringBuilder builder = new StringBuilder("Thread["); //$NON-NLS-1$ + builder.append(dmc.getThreadId()); + builder.append("] "); //$NON-NLS-1$ + builder.append(getData().getId()); + builder.append(getData().getName()); + if(getServicesTracker().getService(IRunControl.class).isSuspended(dmc)) + builder.append(" (Suspended"); //$NON-NLS-1$ + else + builder.append(" (Running"); //$NON-NLS-1$ + // Reason will be null before ContainerSuspendEvent is fired + if(reason != null) { + builder.append(" : "); //$NON-NLS-1$ + builder.append(reason); + } + builder.append(")"); //$NON-NLS-1$ + update.setLabel(builder.toString(), 0); + update.done(); + } + }); + } + }); + + } + } + + public int getDeltaFlags(Object e) { + if(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) { + return IModelDelta.CONTENT; + } + if (e instanceof ModelProxyInstalledEvent) { + return IModelDelta.SELECT | IModelDelta.EXPAND; + } + return IModelDelta.NO_CHANGE; + } + + public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) { + if(e instanceof IContainerResumedDMEvent) { + IDMContext triggeringContext = ((IContainerResumedDMEvent)e).getTriggeringContext(); + if (triggeringContext != null) { + parentDelta.addNode(createVMContext(triggeringContext), IModelDelta.CONTENT); + } + rm.done(); + } else if (e instanceof IContainerSuspendedDMEvent) { + IDMContext triggeringContext = ((IContainerSuspendedDMEvent)e).getTriggeringContext(); + if (triggeringContext != null) { + parentDelta.addNode(createVMContext(triggeringContext), IModelDelta.CONTENT); + } + rm.done(); + } else if(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) { + parentDelta.addNode(createVMContext(((IDMEvent)e).getDMContext()), IModelDelta.CONTENT); + rm.done(); + } else if (e instanceof ModelProxyInstalledEvent) { + getThreadVMCForModelProxyInstallEvent( + parentDelta, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + parentDelta.addNode( + getData().fVMContext, nodeOffset + getData().fIndex, + IModelDelta.EXPAND | (getData().fIsSuspended ? 0 : IModelDelta.SELECT)); + } + rm.done(); + } + }); + } + + } +} diff --git a/plugins/org.eclipse.dd.mi/.classpath b/plugins/org.eclipse.dd.mi/.classpath new file mode 100644 index 00000000000..65ed610be7e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/org.eclipse.dd.mi/.options b/plugins/org.eclipse.dd.mi/.options new file mode 100644 index 00000000000..1d23c88ae93 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/.options @@ -0,0 +1 @@ +org.eclipse.dd.mi.core/debug = false diff --git a/plugins/org.eclipse.dd.mi/.project b/plugins/org.eclipse.dd.mi/.project new file mode 100644 index 00000000000..30d6696665e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/.project @@ -0,0 +1,28 @@ + + + org.eclipse.dd.mi + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/plugins/org.eclipse.dd.mi/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.dd.mi/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..b6f154d6ec4 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,65 @@ +#Thu Jun 07 11:05:32 PDT 2007 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning +org.eclipse.jdt.core.compiler.problem.nullReference=ignore +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/plugins/org.eclipse.dd.mi/.settings/org.eclipse.jdt.ui.prefs b/plugins/org.eclipse.dd.mi/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..77e5bae8c55 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,3 @@ +#Sun Aug 06 18:13:46 CEST 2006 +eclipse.preferences.version=1 +internal.default.compliance=default diff --git a/plugins/org.eclipse.dd.mi/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.mi/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..0378107a447 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/META-INF/MANIFEST.MF @@ -0,0 +1,24 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: GDB/MI Protocol-based DSF Debugger Integration Core +Bundle-Vendor: Eclipse.org +Bundle-SymbolicName: org.eclipse.dd.mi;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.dd.mi.internal.MIPlugin +Bundle-Localization: plugin +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.debug.core, + org.eclipse.core.resources, + org.eclipse.core.variables, + org.eclipse.dd.dsf, + org.eclipse.dd.dsf.debug, + org.eclipse.cdt.debug.core, + org.eclipse.cdt.core +Export-Package: + org.eclipse.dd.mi.service, + org.eclipse.dd.mi.service.command, + org.eclipse.dd.mi.service.command.commands, + org.eclipse.dd.mi.service.command.events, + org.eclipse.dd.mi.service.command.output +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-ActivationPolicy: lazy diff --git a/plugins/org.eclipse.dd.mi/about.html b/plugins/org.eclipse.dd.mi/about.html new file mode 100644 index 00000000000..cb740ae8bc8 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/about.html @@ -0,0 +1,24 @@ + + + + +About +

About This Content

+ +

June 5, 2007

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/build.properties b/plugins/org.eclipse.dd.mi/build.properties new file mode 100644 index 00000000000..bc3b0f2bf1f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/build.properties @@ -0,0 +1,7 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.properties,\ + about.html diff --git a/plugins/org.eclipse.dd.mi/plugin.properties b/plugins/org.eclipse.dd.mi/plugin.properties new file mode 100644 index 00000000000..740bb7f6d18 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/plugin.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2006 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 +############################################################################### +pluginName=DSDP/DD GDB/MI Debugger Implementation using DSF +providerName=Eclipse.org + diff --git a/plugins/org.eclipse.dd.mi/plugin.xml b/plugins/org.eclipse.dd.mi/plugin.xml new file mode 100644 index 00000000000..4d8a6316736 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/plugin.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/internal/MIPlugin.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/internal/MIPlugin.java new file mode 100644 index 00000000000..c7804d164c3 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/internal/MIPlugin.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2006 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.dd.mi.internal; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.osgi.framework.BundleContext; + +/** + * Plugin class. + */ +public class MIPlugin extends Plugin { + + public static final String PLUGIN_ID = "org.eclipse.dsdp.debug.gdb.core"; //$NON-NLS-1$ + + // Debugging flag + public static boolean DEBUG = false; + + //The shared instance. + private static MIPlugin fgPlugin; + + private static BundleContext fgBundleContext; + + /** + * The constructor. + */ + public MIPlugin() { + fgPlugin = this; + } + + /** + * This method is called upon plug-in activation + */ + @Override + public void start(BundleContext context) throws Exception { + fgBundleContext = context; + super.start(context); + DEBUG = "true".equals(Platform.getDebugOption("org.eclipse.dd.mi.core/debug")); //$NON-NLS-1$//$NON-NLS-2$ + } + + /** + * This method is called when the plug-in is stopped + */ + @Override + public void stop(BundleContext context) throws Exception { + super.stop(context); + fgBundleContext = null; + } + + /** + * Returns the shared instance. + * + * @return the shared instance. + */ + public static MIPlugin getDefault() { + return fgPlugin; + } + + public static BundleContext getBundleContext() { + return fgBundleContext; + } + + public static void debug(String message) { + if (DEBUG) { + System.out.print(message); + } + } + + public static String getDebugTime() { + StringBuilder traceBuilder = new StringBuilder(); + + // Record the time + long time = System.currentTimeMillis(); + long seconds = (time / 1000) % 1000; + if (seconds < 100) traceBuilder.append('0'); + if (seconds < 10) traceBuilder.append('0'); + traceBuilder.append(seconds); + traceBuilder.append(','); + long millis = time % 1000; + if (millis < 100) traceBuilder.append('0'); + if (millis < 10) traceBuilder.append('0'); + traceBuilder.append(millis); + return traceBuilder.toString(); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/CSourceLookup.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/CSourceLookup.java new file mode 100644 index 00000000000..f13439a23fc --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/CSourceLookup.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2007 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.dd.mi.service; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.debug.service.ISourceLookup; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.osgi.framework.BundleContext; + +/** + * ISourceLookup service implementation based on the CDT CSourceLookupDirector. + */ +public class CSourceLookup extends AbstractDsfService implements ISourceLookup { + + private Map fDirectors = new HashMap(); + + public CSourceLookup(DsfSession session) { + super(session); + } + + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + + public void setSourceLookupDirector(ISourceLookupDMContext ctx, CSourceLookupDirector director) { + fDirectors.put(ctx, director); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + doInitialize(requestMonitor); + }}); + } + + private void doInitialize(final RequestMonitor requestMonitor) { + // Register this service + register(new String[] { CSourceLookup.class.getName(), ISourceLookup.class.getName() }, new Hashtable()); + requestMonitor.done(); + } + + @Override + public void shutdown(final RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } + + public void getDebuggerPath(ISourceLookupDMContext sourceLookupCtx, Object source, final DataRequestMonitor rm) + { + if (! (source instanceof String)) { + // In future if needed other elements such as URIs could be supported. + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "Only string source element is supported", null)); //$NON-NLS-1$); + rm.done(); + return; + } + final String sourceString = (String) source; + + if (!fDirectors.containsKey(sourceLookupCtx) ){ + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "No source director configured for given context", null)); //$NON-NLS-1$); + rm.done(); + return; + } + final CSourceLookupDirector director = fDirectors.get(sourceLookupCtx); + + new Job("Lookup Debugger Path") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + IPath debuggerPath = director.getCompilationPath(sourceString); + if (debuggerPath != null) { + rm.setData(debuggerPath.toString()); + } else { + rm.setData(sourceString); + } + rm.done(); + + return Status.OK_STATUS; + } + }.schedule(); + + } + + public void getSource(ISourceLookupDMContext sourceLookupCtx, final String debuggerPath, final DataRequestMonitor rm) + { + if (!fDirectors.containsKey(sourceLookupCtx) ){ + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "No source director configured for given context", null)); //$NON-NLS-1$); + rm.done(); + return; + } + final CSourceLookupDirector director = fDirectors.get(sourceLookupCtx); + + new Job("Lookup Source") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + Object[] sources; + try { + sources = director.findSourceElements(debuggerPath); + if (sources == null || sources.length == 0) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, "No sources found", null)); //$NON-NLS-1$); + } else { + rm.setData(sources[0]); + } + } catch (CoreException e) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, "Source lookup failed", e)); //$NON-NLS-1$); + } finally { + rm.done(); + } + + return Status.OK_STATUS; + } + }.schedule(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/ExpressionService.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/ExpressionService.java new file mode 100644 index 00000000000..9fb5aec2dcc --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/ExpressionService.java @@ -0,0 +1,898 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * Ericsson - Modified for handling of multiple execution contexts + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.utils.Addr32; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryChangedEvent; +import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.debug.service.command.CommandCache; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetAttributes; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetChildCount; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetChildren; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetValue; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetVar; +import org.eclipse.dd.mi.service.command.commands.MIDataEvaluateExpression; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetAttributesInfo; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetChildCountInfo; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetChildrenInfo; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetValueInfo; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetVarInfo; +import org.eclipse.dd.mi.service.command.output.MIDataEvaluateExpressionInfo; +import org.osgi.framework.BundleContext; + +/** + * This class implements a debugger expression evaluator as a DSF service. The + * primary interface that clients of this class should use is IExpressions. + */ +public class ExpressionService extends AbstractDsfService implements IExpressions { + + /** + * This class represents the two expressions that characterize an Expression Context. + */ + public static class ExpressionInfo { + private final String fullExpression; + private final String relativeExpression; + + public ExpressionInfo(String full, String relative) { + fullExpression = full; + relativeExpression = relative; + } + + public String getFullExpr() { return fullExpression; } + public String getRelExpr() { return relativeExpression; } + + @Override + public boolean equals(Object other) { + if (other instanceof ExpressionInfo) { + if (fullExpression == null ? ((ExpressionInfo) other).fullExpression == null : + fullExpression.equals(((ExpressionInfo) other).fullExpression)) { + if (relativeExpression == null ? ((ExpressionInfo) other).relativeExpression == null : + relativeExpression.equals(((ExpressionInfo) other).relativeExpression)) { + return true; + } + } + } + return false; + } + + @Override + public int hashCode() { + return (fullExpression == null ? 0 : fullExpression.hashCode()) ^ + (relativeExpression == null ? 0 : relativeExpression.hashCode()); + } + + @Override + public String toString() { + return "[" + fullExpression +", " + relativeExpression + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + } + } + /** + * This class represents an expression. + */ + protected static class MIExpressionDMC extends AbstractDMContext implements IExpressionDMContext { + /** + * This field holds an expression to be evaluated. + */ + private ExpressionInfo exprInfo; + + /** + * ExpressionDMC Constructor for expression to be evaluated in context of + * a stack frame. + * + * @param sessionId + * The session ID in which this context is created. + * @param expression + * The expression to be described by this ExpressionDMC + * @param relExpr + * The relative expression if this expression was created as a child + * @param frameCtx + * The parent stack frame context for this ExpressionDMC. + */ + public MIExpressionDMC(String sessionId, String expression, String relExpr, IFrameDMContext frameCtx) { + this(sessionId, expression, relExpr, (IDMContext)frameCtx); + } + + /** + * ExpressionDMC Constructor for expression to be evaluated in context of + * an thread. + * + * @param sessionId + * The session ID in which this context is created. + * @param expression + * The expression to be described by this ExpressionDMC + * @param relExpr + * The relative expression if this expression was created as a child + * @param execCtx + * The parent thread context for this ExpressionDMC. + */ + public MIExpressionDMC(String sessionId, String expression, String relExpr, IMIExecutionDMContext execCtx) { + this(sessionId, expression, relExpr, (IDMContext)execCtx); + } + + /** + * ExpressionDMC Constructor for expression to be evaluated in context of + * a memory space. + * + * @param sessionId + * The session ID in which this context is created. + * @param expression + * The expression to be described by this ExpressionDMC + * @param relExpr + * The relative expression if this expression was created as a child + * @param memoryCtx + * The parent memory space context for this ExpressionDMC. + */ + public MIExpressionDMC(String sessionId, String expression, String relExpr, IMemoryDMContext memoryCtx) { + this(sessionId, expression, relExpr, (IDMContext)memoryCtx); + } + + private MIExpressionDMC(String sessionId, String expr, String relExpr, IDMContext parent) { + super(sessionId, new IDMContext[] { parent }); + exprInfo = new ExpressionInfo(expr, relExpr); + } + + /** + * @return True if the two objects are equal, false otherwise. + */ + @Override + public boolean equals(Object other) { + return super.baseEquals(other) && exprInfo.equals(((MIExpressionDMC)other).exprInfo); + } + + /** + * + * @return The hash code of this ExpressionDMC object. + */ + @Override + public int hashCode() { + return super.baseHashCode() + exprInfo.hashCode(); + } + + /** + * + * @return A string representation of this ExpressionDMC (including the + * expression to which it is bound). + */ + @Override + public String toString() { + return baseToString() + ".expr" + exprInfo.toString(); //$NON-NLS-1$ + } + + /** + * @return The full expression string represented by this ExpressionDMC + */ + public String getExpression() { + return exprInfo.getFullExpr(); + } + + /** + * @return The relative expression string represented by this ExpressionDMC + */ + public String getRelativeExpression() { + return exprInfo.getRelExpr(); + } + } + + 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; + } + } + + + /** + * Contains the address of an expression as well as the size of its type. + */ + protected static class ExpressionDMAddress implements IExpressionDMAddress { + IAddress fAddr; + int fSize; + + public ExpressionDMAddress(IAddress addr, int size) { + fAddr = addr; + fSize = size; + } + + public ExpressionDMAddress(String addrStr, int size) { + fSize = size; + // We must count the "0x" and that + // is why we compare with 10 characters + // instead of 8 + if (addrStr.length() <= 10) { + fAddr = new Addr32(addrStr); + } else { + fAddr = new Addr64(addrStr); + } + } + + public IAddress getAddress() { return fAddr; } + public int getSize() { return fSize; } + + @Override + public boolean equals(Object other) { + if (other instanceof ExpressionDMAddress) { + ExpressionDMAddress otherAddr = (ExpressionDMAddress) other; + return (fSize == otherAddr.getSize()) && + (fAddr == null ? otherAddr.getAddress() == null : fAddr.equals(otherAddr.getAddress())); + } + return false; + } + + @Override + public int hashCode() { + return (fAddr == null ? 0 :fAddr.hashCode()) + fSize; + } + + @Override + public String toString() { + return (fAddr == null ? "null" : "(0x" + fAddr.toString()) + ", " + fSize + ")"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ + } + } + + /** + * This class represents the static data referenced by an instance of ExpressionDMC, + * such as its type and number of children; it does not contain the value or format + * of the expression. + */ + protected static class ExpressionDMData implements IExpressionDMData { + // This is the relative expression, such as the name of a field within a structure, + // in contrast to the fully-qualified expression contained in the ExpressionDMC, + // which refers to the full name, including parent structure. + private final String relativeExpression; + private final String exprType; + private final int numChildren; + private final boolean editable; + + /** + * ExpressionDMData constructor. + */ + public ExpressionDMData(String expr, String type, int num, boolean edit) { + relativeExpression = expr; + exprType = type; + numChildren = num; + editable = edit; + } + + public BasicType getBasicType() { + return null; + } + + public String getEncoding() { + return null; + } + + public Map getEnumerations() { + return new HashMap(); + } + + public String getName() { + return relativeExpression; + } + + public IRegisterDMContext getRegister() { + return null; + } + + // See class VariableVMNode for an example of usage of this method + public String getStringValue() { + return null; + } + + public String getTypeId() { + return null; + } + + public String getTypeName() { + return exprType; + } + + public int getNumChildren() { + return numChildren; + } + + public boolean isEditable() { + return editable; + } + + @Override + public boolean equals(Object other) { + if (other instanceof ExpressionDMData) { + ExpressionDMData otherData = (ExpressionDMData) other; + return (getNumChildren() == otherData.getNumChildren()) && + (getTypeName() == null ? otherData.getTypeName() == null : getTypeName().equals(otherData.getTypeName())) && + (getName() == null ? otherData.getName() == null : getName().equals(otherData.getName())); + } + return false; + } + + @Override + public int hashCode() { + return relativeExpression == null ? 0 : relativeExpression.hashCode() + + exprType == null ? 0 : exprType.hashCode() + numChildren; + } + + @Override + public String toString() { + return "relExpr=" + relativeExpression + ", type=" + exprType + ", numchildren=" + numChildren; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ + } + } + + /** + * Event generated every time an expression is changed by the ExpressionService. + * + * A client wishing to receive such events has to register as a service + * event listener and implement the corresponding eventDispatched method. + * + * E.g.: + * + * getSession().addServiceEventListener(listenerObject, null); + * + * @DsfServiceEventHandler + * public void eventDispatched(ExpressionChangedEvent e) { + * IExpressionDMContext context = e.getDMContext(); + * // do something... + * } + */ + protected static class ExpressionChangedEvent extends AbstractDMEvent + implements IExpressionChangedDMEvent { + + public ExpressionChangedEvent(IExpressionDMContext context) { + super(context); + } + } + + // This field holds a reference to to the data model context for this service. + private CommandCache fExpressionCache; + private MIVariableManager varManager; + + + public ExpressionService(DsfSession session) { + super(session); + } + + /** + * This method initializes this service. + * + * @param requestMonitor + * The request monitor indicating the operation is finished + */ + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize(new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + doInitialize(requestMonitor); + } + }); + } + + /** + * This method initializes this service after our superclass's initialize() + * method succeeds. + * + * @param requestMonitor + * The call-back object to notify when this service's + * initialization is done. + */ + private void doInitialize(RequestMonitor requestMonitor) { + + // Register to receive service events for this session. + getSession().addServiceEventListener(this, null); + + // Register this service. + register(new String[] { IExpressions.class.getName(), + ExpressionService.class.getName() }, + new Hashtable()); + + // Create the expressionService-specific CommandControl which is our + // variable object manager. + // It will deal with the meta-commands, before sending real MI commands + // to the back-end, through the MICommandControl service + // It must be created after the ExpressionService is registered + // since it will need to find it. + varManager = new MIVariableManager(getSession(), getServicesTracker()); + + // Create the meta command cache which will use the variable manager + // to actually send MI commands to the back-end + fExpressionCache = new CommandCache(varManager); + + requestMonitor.done(); + } + + /** + * This method shuts down this service. It unregisters the service, stops + * receiving service events, and calls the superclass shutdown() method to + * finish the shutdown process. + * + * @return void + */ + @Override + public void shutdown(RequestMonitor requestMonitor) { + unregister(); + varManager.shutdown(); + getSession().removeServiceEventListener(this); + super.shutdown(requestMonitor); + } + + /** + * @return The bundle context of the plug-in to which this service belongs. + */ + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + /** + * Create an expression context with the same full and relative expression + */ + public IExpressionDMContext createExpression(IDMContext ctx, String expression) { + return createExpression(ctx, expression, expression); + } + + /** + * Create an expression context. + */ + public IExpressionDMContext createExpression(IDMContext ctx, String expression, String relExpr) { + IFrameDMContext frameDmc = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class); + if (frameDmc != null) { + return new MIExpressionDMC(getSession().getId(), expression, relExpr, frameDmc); + } + + IMIExecutionDMContext execCtx = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + if (execCtx != null) { + return new MIExpressionDMC(getSession().getId(), expression, relExpr, execCtx); + } + + IMemoryDMContext memoryCtx = DMContexts.getAncestorOfType(ctx, IMemoryDMContext.class); + if (memoryCtx != null) { + return new MIExpressionDMC(getSession().getId(), expression, relExpr, memoryCtx); + } + + // Don't care about the relative expression at this point + return new InvalidContextExpressionDMC(getSession().getId(), expression, ctx); + } + + /** + * @see IFormattedValues.getFormattedValueContext(IFormattedDataDMContext, String) + * + * @param dmc + * The context describing the data for which we want to create + * a Formatted context. + * @param formatId + * The format that will be used to create the Formatted context + * + * @return A FormattedValueDMContext that can be used to obtain the value + * of an expression in a specific format. + */ + + public FormattedValueDMContext getFormattedValueContext( + IFormattedDataDMContext dmc, String formatId) { + return new FormattedValueDMContext(this, dmc, formatId); + } + + /** + * @see IFormattedValues.getAvailableFormats(IFormattedDataDMContext, DataRequestMonitor) + * + * @param dmc + * The context describing the data for which we want to know + * which formats are available. + * @param rm + * The data request monitor for this asynchronous operation. + * + */ + + public void getAvailableFormats(IFormattedDataDMContext dmc, + final DataRequestMonitor rm) { + rm.setData(new String[] { IFormattedValues.BINARY_FORMAT, + IFormattedValues.NATURAL_FORMAT, IFormattedValues.HEX_FORMAT, + IFormattedValues.OCTAL_FORMAT, IFormattedValues.DECIMAL_FORMAT }); + rm.done(); + } + + /** + * This method obtains the model data for a given ExpressionDMC object or + * for a FormattedValueDMC, or for this DSF service. + * + * @param dmc + * The context for which we are requesting the data + * @param rm + * The request monitor that will contain the requested data + */ + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, DataRequestMonitor rm) { + if (dmc instanceof MIExpressionDMC) { + getExpressionData((MIExpressionDMC) dmc, + (DataRequestMonitor) rm); + } else if (dmc instanceof FormattedValueDMContext) { + getFormattedExpressionValue((FormattedValueDMContext) dmc, + (DataRequestMonitor) rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * Obtains the static data of an expression represented + * by an ExpressionDMC object (dmc). + * + * @param dmc + * The ExpressionDMC for the expression to be evaluated. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getExpressionData( + final IExpressionDMContext dmc, + final DataRequestMonitor rm) + { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetVar(dmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(new ExpressionDMData(getData().getExpr(), + getData().getType(), getData().getNumChildren(), getData().getEditable())); + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * Obtains the address of an expression and the size of its type. + * + * @param dmc + * The ExpressionDMC for the expression. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getExpressionAddressData( + IExpressionDMContext dmc, + final DataRequestMonitor rm) { + + // First create an address expression and a size expression + // to be used in back-end calls + final IExpressionDMContext addressDmc = + createExpression( dmc, "&(" + dmc.getExpression() + ")" );//$NON-NLS-1$//$NON-NLS-2$ + final IExpressionDMContext sizeDmc = + createExpression( dmc, "sizeof(" + dmc.getExpression() + ")" ); //$NON-NLS-1$//$NON-NLS-2$ + + if (addressDmc instanceof InvalidContextExpressionDMC || sizeDmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + fExpressionCache.execute( + new MIDataEvaluateExpression(addressDmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + final String addrStr = getData().getValue(); + fExpressionCache.execute( + new MIDataEvaluateExpression(sizeDmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + try { + int size = Integer.parseInt(getData().getValue()); + rm.setData(new ExpressionDMAddress(addrStr, size)); + } catch (NumberFormatException e) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, + "Unexpected size format from backend: " + getData().getValue(), null)); //$NON-NLS-1$ + } + rm.done(); + } + }); + } + }); + } + } + + /** + * Obtains the value of an expression in a specific format. + * + * @param dmc + * The context for the format of the value requested and + * for the expression to be evaluated. The expression context + * should be a parent of the FormattedValueDMContext. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getFormattedExpressionValue( + final FormattedValueDMContext dmc, + final DataRequestMonitor rm) + { + // We need to make sure the FormattedValueDMContext also holds an ExpressionContext, + // or else this method cannot do its work. + // Note that we look for MIExpressionDMC and not IExpressionDMC, because getting + // looking for IExpressionDMC could yield InvalidContextExpressionDMC which is still + // not what we need to have. + if (DMContexts.getAncestorOfType(dmc, MIExpressionDMC.class) == null ) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + fExpressionCache.execute( + new ExprMetaGetValue(dmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(new FormattedValueDMData(getData().getValue())); + rm.done(); + } + }); + } + } + + /* Not implemented + * + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IExpressions#getBaseExpressions(org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getBaseExpressions(IExpressionDMContext exprContext, + DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, + NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + /** + * Retrieves the children expressions of the specified expression + * + * @param exprCtx + * The context for the expression for which the children + * should be retrieved. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getSubExpressions(final IExpressionDMContext dmc, + final DataRequestMonitor rm) + { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetChildren(dmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + ExpressionInfo[] childrenExpr = getData().getChildrenExpressions(); + IExpressionDMContext[] childArray = new IExpressionDMContext[childrenExpr.length]; + for (int i=0; i rm) { + getSubExpressions( + exprCtx, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData((IExpressionDMContext[])Arrays.asList(getData()).subList(startIndex, startIndex + length).toArray()); + rm.done(); + } + }); + } + + /** + * Retrieves the count of children expressions of the specified expression + * + * @param exprCtx + * The context for the expression for which the children count + * should be retrieved. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getSubExpressionCount(IExpressionDMContext dmc, + final DataRequestMonitor rm) + { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetChildCount(dmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(getData().getChildNum()); + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * This method indicates if an expression can be written to. + * + * @param dmc: The data model context representing an expression. + * + * @param rm: Data Request monitor containing True if this expression's value can be edited. False otherwise. + */ + + public void canWriteExpression(IExpressionDMContext dmc, final DataRequestMonitor rm) { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetAttributes(dmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(getData().getEditable()); + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + + /** + * Changes the value of the specified expression based on the new value and format. + * + * @param expressionContext + * The context for the expression for which the value + * should be changed. + * @param expressionValue + * The new value for the specified expression + * @param formatId + * The format in which the value is specified + * @param rm + * The request monitor that will indicate the completion of the operation + */ + public void writeExpression(final IExpressionDMContext dmc, String expressionValue, + String formatId, final RequestMonitor rm) { + + if (dmc instanceof MIExpressionDMC) { + // This command must not be cached, since it changes the state of the back-end. + // We must send it directly to the variable manager + varManager.writeValue( + dmc, + expressionValue, + formatId, + new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // A value has changed, we should remove any references to that + // value in our cache. Since we don't have such granularity, + // we must clear the entire cache. + // We cannot use the context to do a more-specific reset, because + // the same global variable can be set with different contexts + fExpressionCache.reset(); + + // Issue event that the expression has changed + getSession().dispatchEvent(new ExpressionChangedEvent(dmc), getProperties()); + + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.IResumedDMEvent e) { + fExpressionCache.setTargetAvailable(false); + if (e.getReason() != StateChangeReason.STEP) { + fExpressionCache.reset(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.ISuspendedDMEvent e) { + fExpressionCache.setTargetAvailable(true); + fExpressionCache.reset(); + } + + @DsfServiceEventHandler + public void eventDispatched(IMemoryChangedEvent e) { + fExpressionCache.reset(); + // We must also deal with our MIVariableManager since it + // caches variable values, which may now have changed + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIExecutionDMContext.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIExecutionDMContext.java new file mode 100644 index 00000000000..2413909f075 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIExecutionDMContext.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2007 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.dd.mi.service; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; + +/** + * An execution context object. In the GDB/MI protocol, threads are represented + * by an integer identifier, which is the basis for this context. The parent of this + * context should always be a container context. + */ +public interface IMIExecutionDMContext extends IExecutionDMContext +{ + /** + * Returns the GDB/MI thread identifier of this context. + * @return + */ + public int getThreadId(); +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointDMData.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointDMData.java new file mode 100644 index 00000000000..ce595d76bce --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointDMData.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointDMData; +import org.eclipse.dd.mi.service.command.output.MIBreakpoint; + +public class MIBreakpointDMData implements IBreakpointDMData { + + /** + * MI-specific breakpoint attributes markers. + */ + public static final String DSFMIBREAKPOINT = "org.eclipse.dd.dsf.debug.breakpoint.mi"; //$NON-NLS-1$ + public static final String NUMBER = DSFMIBREAKPOINT + ".number"; //$NON-NLS-1$ + public static final String TYPE = DSFMIBREAKPOINT + ".type"; //$NON-NLS-1$ + public static final String THREAD_ID = DSFMIBREAKPOINT + ".threadId"; //$NON-NLS-1$ + public static final String FULL_NAME = DSFMIBREAKPOINT + ".fullName"; //$NON-NLS-1$ + public static final String HITS = DSFMIBREAKPOINT + ".hits"; //$NON-NLS-1$ + public static final String IS_TEMPORARY = DSFMIBREAKPOINT + ".isTemporary"; //$NON-NLS-1$ + public static final String IS_HARDWARE = DSFMIBREAKPOINT + ".isHardware"; //$NON-NLS-1$ + public static final String LOCATION = DSFMIBREAKPOINT + ".location"; //$NON-NLS-1$ + + // Back-end breakpoint object + private final MIBreakpoint fBreakpoint; + private final Map fProperties; + + // Breakpoint types + public static enum MIBreakpointNature { UNKNOWN, BREAKPOINT, WATCHPOINT, CATCHPOINT }; + private final MIBreakpointNature fNature; + + + /////////////////////////////////////////////////////////////////////////// + // Constructors + /////////////////////////////////////////////////////////////////////////// + + /** + * Copy constructor + * + * @param other + */ + public MIBreakpointDMData(MIBreakpointDMData other) { + + fBreakpoint = new MIBreakpoint(other.fBreakpoint); + fProperties = new HashMap(other.fProperties); + fNature = other.fNature; + } + + /** + * Constructs a DsfMIBreakpoint from a back-end object + * + * @param dsfMIBreakpoint back-end breakpoint + */ + public MIBreakpointDMData(MIBreakpoint dsfMIBreakpoint) { + + // We only support breakpoint and watchpoint (so far) + fBreakpoint = dsfMIBreakpoint; + fNature = dsfMIBreakpoint.isWatchpoint() ? MIBreakpointNature.WATCHPOINT : MIBreakpointNature.BREAKPOINT; + + fProperties = new HashMap(); + switch (fNature) { + + case BREAKPOINT: + { + // Generic breakpoint attributes + fProperties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.BREAKPOINT); + fProperties.put(MIBreakpoints.FILE_NAME, dsfMIBreakpoint.getFile()); + fProperties.put(MIBreakpoints.LINE_NUMBER, dsfMIBreakpoint.getLine()); + fProperties.put(MIBreakpoints.FUNCTION, dsfMIBreakpoint.getFunction()); + fProperties.put(MIBreakpoints.ADDRESS, dsfMIBreakpoint.getAddress()); + fProperties.put(MIBreakpoints.CONDITION, dsfMIBreakpoint.getCondition()); + fProperties.put(MIBreakpoints.IGNORE_COUNT, dsfMIBreakpoint.getIgnoreCount()); + fProperties.put(MIBreakpoints.IS_ENABLED, new Boolean(dsfMIBreakpoint.isEnabled())); + + // MI-specific breakpoint attributes + fProperties.put(NUMBER, dsfMIBreakpoint.getNumber()); + fProperties.put(TYPE, dsfMIBreakpoint.getType()); + fProperties.put(THREAD_ID, dsfMIBreakpoint.getThreadId()); + fProperties.put(FULL_NAME, dsfMIBreakpoint.getFullName()); + fProperties.put(HITS, dsfMIBreakpoint.getTimes()); + fProperties.put(IS_TEMPORARY, new Boolean(dsfMIBreakpoint.isTemporary())); + fProperties.put(IS_HARDWARE, new Boolean(dsfMIBreakpoint.isHardware())); + fProperties.put(LOCATION, formatLocation()); + break; + } + + case WATCHPOINT: + { + // Generic breakpoint attributes + fProperties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.WATCHPOINT); + fProperties.put(MIBreakpoints.EXPRESSION, dsfMIBreakpoint.getExpression()); + fProperties.put(MIBreakpoints.READ, dsfMIBreakpoint.isAccessWatchpoint() || dsfMIBreakpoint.isReadWatchpoint()); + fProperties.put(MIBreakpoints.WRITE, dsfMIBreakpoint.isAccessWatchpoint() || dsfMIBreakpoint.isWriteWatchpoint()); + + // MI-specific breakpoint attributes + fProperties.put(NUMBER, dsfMIBreakpoint.getNumber()); + break; + } + + // Not reachable + default: + { + fProperties.put(MIBreakpoints.BREAKPOINT_TYPE, null); + break; + } + } + } + + /** + * Formats the LOCATION synthetic property from the existing fields + * + * @return The location string + */ + private String formatLocation() { + + // Unlikely default location + String location = fBreakpoint.getAddress(); + + // Get the relevant parameters + String fileName = fBreakpoint.getFile(); + Integer lineNumber = fBreakpoint.getLine(); + String function = fBreakpoint.getFunction(); + + if (!fileName.equals("")) { //$NON-NLS-1$ + if (lineNumber != -1) { + location = fileName + ":" + lineNumber; //$NON-NLS-1$ + } else { + location = fileName + ":" + function; //$NON-NLS-1$ + } + } + + return location; + } + + /** + * Checks for equality + * + * @param other + * @return + */ + public boolean equals(MIBreakpointDMData other) { + return (fNature == other.fNature) && (fProperties.equals(other.fProperties)); + } + + /////////////////////////////////////////////////////////////////////////// + // IBreakpointDMData + /////////////////////////////////////////////////////////////////////////// + + public String getBreakpointType() { + return (String) fProperties.get(MIBreakpoints.BREAKPOINT_TYPE); + } + + public int getReference() { + return fBreakpoint.getNumber(); + } + + public IAddress[] getAddresses() { + IAddress[] addresses = new IAddress[1]; + addresses[0] = new Addr64(fBreakpoint.getAddress()); + return addresses; + } + + public String getCondition() { + return fBreakpoint.getCondition(); + } + + public String getExpression() { + return fBreakpoint.getExpression(); + } + + public String getFileName() { + return fBreakpoint.getFile(); + } + + public String getFunctionName() { + return fBreakpoint.getFunction(); + } + + public int getIgnoreCount() { + return fBreakpoint.getIgnoreCount(); + } + + public int getLineNumber() { + return fBreakpoint.getLine(); + } + + public boolean isEnabled() { + return fBreakpoint.isEnabled(); + } + + /////////////////////////////////////////////////////////////////////////// + // MIBreakpointDMData + /////////////////////////////////////////////////////////////////////////// + + public int getNumber() { + return fBreakpoint.getNumber(); + } + + public String getThreadId() { + return fBreakpoint.getThreadId(); + } + + public boolean isTemporary() { + return fBreakpoint.isTemporary(); + } + + public boolean isHardware() { + return fBreakpoint.isHardware(); + } + + public String getLocation() { + return (String) fProperties.get(LOCATION); + } + + public int getHits() { + return fBreakpoint.getTimes(); + } + + public String getFullName() { + return fBreakpoint.getFullName(); + } + + public String getType() { + return fBreakpoint.getType(); + } + + public void setCondition(String condition) { + fBreakpoint.setCondition(condition); + fProperties.put(MIBreakpoints.CONDITION, condition); + } + + public void setIgnoreCount(int ignoreCount) { + fBreakpoint.setIgnoreCount(ignoreCount); + fProperties.put(MIBreakpoints.IGNORE_COUNT, ignoreCount); + } + + public void setEnabled(boolean isEnabled) { + fBreakpoint.setEnabled(isEnabled); + fProperties.put(MIBreakpoints.IS_ENABLED, isEnabled); + } + + public boolean isReadWatchpoint() { + return fBreakpoint.isReadWatchpoint(); + } + + public boolean isWriteWatchpoint() { + return fBreakpoint.isWriteWatchpoint(); + } + + public boolean isAccessWatchpoint() { + return fBreakpoint.isAccessWatchpoint(); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpoints.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpoints.java new file mode 100644 index 00000000000..8f97eb51a53 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpoints.java @@ -0,0 +1,956 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.MIBreakAfter; +import org.eclipse.dd.mi.service.command.commands.MIBreakCondition; +import org.eclipse.dd.mi.service.command.commands.MIBreakDelete; +import org.eclipse.dd.mi.service.command.commands.MIBreakDisable; +import org.eclipse.dd.mi.service.command.commands.MIBreakEnable; +import org.eclipse.dd.mi.service.command.commands.MIBreakInsert; +import org.eclipse.dd.mi.service.command.commands.MIBreakList; +import org.eclipse.dd.mi.service.command.commands.MIBreakWatch; +import org.eclipse.dd.mi.service.command.events.MIGDBExitEvent; +import org.eclipse.dd.mi.service.command.events.MIWatchpointScopeEvent; +import org.eclipse.dd.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.dd.mi.service.command.output.MIBreakListInfo; +import org.eclipse.dd.mi.service.command.output.MIBreakpoint; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.osgi.framework.BundleContext; + +/** + * Initial breakpoint service implementation. + * Implements the IBreakpoints interface. + */ +public class MIBreakpoints extends AbstractDsfService implements IBreakpoints +{ + /** + * Breakpoint attributes markers used in the map parameters of insert/updateBreakpoint(). + * All are optional with the possible exception of TYPE. It is the responsibility of the + * service to ensure that the set of attributes provided is sufficient to create/update + * a valid breakpoint on the back-end. + */ + public static final String PREFIX = "org.eclipse.dd.dsf.debug.breakpoint"; //$NON-NLS-1$ + + // General markers + public static final String BREAKPOINT_TYPE = PREFIX + ".type"; //$NON-NLS-1$ + public static final String BREAKPOINT = "breakpoint"; //$NON-NLS-1$ + public static final String WATCHPOINT = "watchpoint"; //$NON-NLS-1$ + public static final String CATCHPOINT = "catchpoint"; //$NON-NLS-1$ + + // Basic set of breakpoint attribute markers + public static final String FILE_NAME = PREFIX + ".fileName"; //$NON-NLS-1$ + public static final String LINE_NUMBER = PREFIX + ".lineNumber"; //$NON-NLS-1$ + public static final String FUNCTION = PREFIX + ".function"; //$NON-NLS-1$ + public static final String ADDRESS = PREFIX + ".address"; //$NON-NLS-1$ + public static final String CONDITION = PREFIX + ".condition"; //$NON-NLS-1$ + public static final String IGNORE_COUNT = PREFIX + ".ignoreCount"; //$NON-NLS-1$ + public static final String IS_ENABLED = PREFIX + ".isEnabled"; //$NON-NLS-1$ + + // Basic set of watchpoint attribute markers + public static final String EXPRESSION = PREFIX + ".expression"; //$NON-NLS-1$ + public static final String READ = PREFIX + ".read"; //$NON-NLS-1$ + public static final String WRITE = PREFIX + ".write"; //$NON-NLS-1$ + + + // Services + ICommandControl fConnection; + + // Service breakpoints tracking + // The breakpoints are stored per context and keyed on the back-end breakpoint reference + private Map> fBreakpoints = + new HashMap>(); + + // Error messages + final String NULL_STRING = ""; //$NON-NLS-1$ + final String UNKNOWN_EXECUTION_CONTEXT = "Unknown execution context"; //$NON-NLS-1$ + final String UNKNOWN_BREAKPOINT_CONTEXT = "Unknown breakpoint context"; //$NON-NLS-1$ + final String UNKNOWN_BREAKPOINT_TYPE = "Unknown breakpoint type"; //$NON-NLS-1$ + final String UNKNOWN_BREAKPOINT = "Unknown breakpoint"; //$NON-NLS-1$ + final String BREAKPOINT_INSERTION_FAILURE = "Breakpoint insertion failure"; //$NON-NLS-1$ + final String WATCHPOINT_INSERTION_FAILURE = "Watchpoint insertion failure"; //$NON-NLS-1$ + final String INVALID_CONDITION = "Invalid condition"; //$NON-NLS-1$ + + /////////////////////////////////////////////////////////////////////////// + // Breakpoint Events + /////////////////////////////////////////////////////////////////////////// + + public class BreakpointsChangedEvent extends AbstractDMEvent implements IBreakpointsChangedEvent { + private IBreakpointDMContext[] fEventBreakpoints; + + public BreakpointsChangedEvent(IBreakpointDMContext bp) { + super(DMContexts.getAncestorOfType(bp, IBreakpointsTargetDMContext.class)); + fEventBreakpoints = new IBreakpointDMContext[] { bp }; + } + public IBreakpointDMContext[] getBreakpoints() { + return fEventBreakpoints; + } + } + + public class BreakpointAddedEvent extends BreakpointsChangedEvent implements IBreakpointsAddedEvent { + public BreakpointAddedEvent(IBreakpointDMContext context) { + super(context); + } + } + + public class BreakpointUpdatedEvent extends BreakpointsChangedEvent implements IBreakpointsUpdatedEvent { + public BreakpointUpdatedEvent(IBreakpointDMContext context) { + super(context); + } + } + + public class BreakpointRemovedEvent extends BreakpointsChangedEvent implements IBreakpointsRemovedEvent { + public BreakpointRemovedEvent(IBreakpointDMContext context) { + super(context); + } + } + + /////////////////////////////////////////////////////////////////////////// + // IBreakpointDMContext + // Used to hold the back-end breakpoint references. The reference can then + // be used to get the actual DsfMIBreakpoint. + /////////////////////////////////////////////////////////////////////////// + @Immutable + public static final class MIBreakpointDMContext extends AbstractDMContext implements IBreakpointDMContext { + + // The breakpoint reference + private final Integer fReference; + + /** + * @param service the Breakpoint service + * @param parents the parent contexts + * @param reference the DsfMIBreakpoint reference + */ + public MIBreakpointDMContext(MIBreakpoints service, IDMContext[] parents, int reference) { + super(service.getSession().getId(), parents); + fReference = reference; + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IBreakpoints.IDsfBreakpointDMContext#getReference() + */ + public int getReference() { + return fReference; + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.datamodel.AbstractDMContext#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + return baseEquals(obj) && (fReference == ((MIBreakpointDMContext) obj).fReference); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.datamodel.AbstractDMContext#hashCode() + */ + @Override + public int hashCode() { + return baseHashCode() + fReference.hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return baseToString() + ".reference(" + fReference + ")"; //$NON-NLS-1$//$NON-NLS-2$*/ + } + } + + /////////////////////////////////////////////////////////////////////////// + // AbstractDsfService + /////////////////////////////////////////////////////////////////////////// + + /** + * The service constructor + * + * @param session The debugging session + */ + public MIBreakpoints(DsfSession session) { + super(session); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#initialize(org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + @Override + public void initialize(final RequestMonitor rm) { + super.initialize(new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + doInitialize(rm); + } + }); + } + + /* + * Asynchronous service initialization + */ + private void doInitialize(final RequestMonitor rm) { + + // Get the services references + fConnection = getServicesTracker().getService(ICommandControl.class); + + // Register for the useful events + getSession().addServiceEventListener(this, null); + + // Register this service + register(new String[] { IBreakpoints.class.getName(), MIBreakpoints.class.getName() }, + new Hashtable()); + + rm.done(); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#shutdown(org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + @Override + public void shutdown(final RequestMonitor rm) { + unregister(); + getSession().removeServiceEventListener(this); + rm.done(); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#getBundleContext() + */ + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + /////////////////////////////////////////////////////////////////////////// + // IServiceEventListener + /////////////////////////////////////////////////////////////////////////// + + /* + * When a watchpoint goes out of scope, it is automatically removed from + * the back-end. To keep our internal state synchronized, we have to + * remove it from our breakpoints map. + */ + @DsfServiceEventHandler + public void eventDispatched(MIWatchpointScopeEvent e) { + // PP: + IBreakpointsTargetDMContext bpContext = DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class); + if (bpContext != null) { + Map contextBps = fBreakpoints.get(bpContext); + if (contextBps != null) { + contextBps.remove(e.getNumber()); + } + } + } + + @DsfServiceEventHandler + public void eventDispatched(MIGDBExitEvent e) { + // TODO: Remove the installed breakpoints from the back-end + } + + /////////////////////////////////////////////////////////////////////////// + // IBreakpoints interface + /////////////////////////////////////////////////////////////////////////// + + //------------------------------------------------------------------------- + // getBreakpoints + //------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IBreakpoints#getBreakpoints(org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getBreakpoints(final IBreakpointsTargetDMContext context, final DataRequestMonitor drm) + { + // Validate the context + if (context == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null)); + drm.done(); + return; + } + + // Select the breakpoints context map + // If it doesn't exist then no breakpoint was ever inserted for this breakpoint space. + // In that case, return an empty list. + final Map breakpointContext = fBreakpoints.get(context); + if (breakpointContext == null) { + drm.setData(new IBreakpointDMContext[0]); + drm.done(); + return; + } + + // Execute the command + fConnection.queueCommand(new MIBreakList(context), + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + // Refresh the breakpoints map and format the result + breakpointContext.clear(); + MIBreakpoint[] breakpoints = getData().getMIBreakpoints(); + IBreakpointDMContext[] result = new IBreakpointDMContext[breakpoints.length]; + for (int i = 0; i < breakpoints.length; i++) { + MIBreakpointDMData breakpoint = new MIBreakpointDMData(breakpoints[i]); + int reference = breakpoint.getReference(); + result[i] = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context }, reference); + breakpointContext.put(reference, breakpoint); + } + drm.setData(result); + drm.done(); + } + }); + } + + //------------------------------------------------------------------------- + // getBreakpointDMData + //------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IBreakpoints#getBreakpointDMData(org.eclipse.dd.dsf.debug.service.IBreakpoints.IDsfBreakpointDMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getBreakpointDMData(IBreakpointDMContext dmc, DataRequestMonitor drm) + { + // Validate the breakpoint context + if (dmc == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + drm.done(); + return; + } + + // Validate the breakpoint type + MIBreakpointDMContext breakpoint; + if (dmc instanceof MIBreakpointDMContext) { + breakpoint = (MIBreakpointDMContext) dmc; + } + else { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null)); + drm.done(); + return; + } + + // Validate the target context + IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(breakpoint, IBreakpointsTargetDMContext.class); + if (context == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null)); + drm.done(); + return; + } + + // Select the breakpoints context map + Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + drm.done(); + return; + } + + // No need to go to the back-end for this one + IBreakpointDMData breakpointCopy = new MIBreakpointDMData(contextBreakpoints.get(breakpoint.getReference())); + drm.setData(breakpointCopy); + drm.done(); + } + + //------------------------------------------------------------------------- + // insertBreakpoint + //------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IBreakpoints#insertBreakpoint(org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext, java.util.Map, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void insertBreakpoint(IBreakpointsTargetDMContext context, Map attributes, DataRequestMonitor drm) { + + // Validate the context + if (context == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null)); + drm.done(); + return; + } + + // Select the breakpoints context map. If it doesn't exist, create it. + Map breakpointContext = fBreakpoints.get(context); + if (breakpointContext == null) { + breakpointContext = new HashMap(); + fBreakpoints.put(context, breakpointContext); + } + + // Validate the breakpoint type + String type = (String) attributes.get(BREAKPOINT_TYPE); + if (type == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null)); + drm.done(); + return; + } + + // And go... + if (type.equals(BREAKPOINT)) { + addBreakpoint(context, attributes, drm); + } + else if (type.equals(WATCHPOINT)) { + addWatchpoint(context, attributes, drm); + } + else { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null)); + drm.done(); + } + } + + /** + * @param map + * @param key + * @param defaultValue + * @return + */ + public Object getProperty(Map map, String key, Object defaultValue) { + return (map.containsKey(key) && (map.get(key) != null)) ? map.get(key) : defaultValue; + } + + /** + * @param attributes + * @return + */ + private String formatLocation(Map attributes) { + + // Unlikely default location + String location = (String) getProperty(attributes, ADDRESS, NULL_STRING); + + // Get the relevant parameters + String fileName = (String) getProperty(attributes, FILE_NAME, NULL_STRING); + Integer lineNumber = (Integer) getProperty(attributes, LINE_NUMBER, -1); + String function = (String) getProperty(attributes, FUNCTION, NULL_STRING); + + if (!fileName.equals(NULL_STRING)) { + if (lineNumber != -1) { + location = fileName + ":" + lineNumber; //$NON-NLS-1$ + } else { + location = fileName + ":" + function; //$NON-NLS-1$ + } + } + + return location; + } + + /** + * Add a breakpoint of type BREAKPOINT + * + * @param context + * @param breakpoint + * @param drm + */ + private void addBreakpoint(final IBreakpointsTargetDMContext context, final Map attributes, final DataRequestMonitor drm) + { + // Select the context breakpoints map + final Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + drm.done(); + return; + } + + // Extract the relevant parameters (providing default values to avoid potential NPEs) + String location = formatLocation(attributes); + Boolean isTemporary = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_TEMPORARY, false); + Boolean isHardware = (Boolean) getProperty(attributes, MIBreakpointDMData.IS_HARDWARE, false); + final String condition = (String) getProperty(attributes, CONDITION, NULL_STRING); + Integer ignoreCount = (Integer) getProperty(attributes, IGNORE_COUNT, 0 ); + String threadId = (String) getProperty(attributes, MIBreakpointDMData.THREAD_ID, "0"); //$NON-NLS-1$ + int tid = Integer.parseInt(threadId); + + // The DataRequestMonitor for the add request + DataRequestMonitor addBreakpointDRM = + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + + // With MI, an invalid location won't generate an error + if (getData().getMIBreakpoints().length == 0) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + drm.done(); + return; + } + + // Create a breakpoint object and store it in the map + final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]); + int reference = newBreakpoint.getNumber(); + if (reference == -1) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + drm.done(); + return; + } + contextBreakpoints.put(reference, newBreakpoint); + + // Format the return value + MIBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context }, reference); + drm.setData(dmc); + + // Flag the event + getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); + + // By default the breakpoint is enabled at creation + // If it wasn't supposed to be, then disable it right away + Map delta = new HashMap(); + delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true)); + modifyBreakpoint(dmc, delta, drm, false); + } + + @Override + protected void handleError() { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, BREAKPOINT_INSERTION_FAILURE, null)); + drm.done(); + } + }; + + // Execute the command + fConnection.queueCommand( + new MIBreakInsert(context, isTemporary, isHardware, condition, ignoreCount, location, tid), addBreakpointDRM); + } + + /** + * Add a breakpoint of type WATCHPOINT + * + * @param context + * @param watchpoint + * @param drm + */ + private void addWatchpoint(final IBreakpointsTargetDMContext context, final Map attributes, final DataRequestMonitor drm) + { + // Pick the context breakpoints map + final Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + drm.done(); + return; + } + + // Extract the relevant parameters (providing default values to avoid potential NPEs) + String expression = (String) getProperty(attributes, EXPRESSION, NULL_STRING); + boolean isRead = (Boolean) getProperty(attributes, READ, false); + boolean isWrite = (Boolean) getProperty(attributes, WRITE, false); + + // The DataRequestMonitor for the add request + DataRequestMonitor addWatchpointDRM = + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + + // With MI, an invalid location won't generate an error + if (getData().getMIBreakpoints().length == 0) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, WATCHPOINT_INSERTION_FAILURE, null)); + drm.done(); + return; + } + + // Create a breakpoint object and store it in the map + final MIBreakpointDMData newBreakpoint = new MIBreakpointDMData(getData().getMIBreakpoints()[0]); + int reference = newBreakpoint.getNumber(); + if (reference == -1) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, WATCHPOINT_INSERTION_FAILURE, null)); + drm.done(); + return; + } + contextBreakpoints.put(reference, newBreakpoint); + + // Format the return value + IBreakpointDMContext dmc = new MIBreakpointDMContext(MIBreakpoints.this, new IDMContext[] { context }, reference); + drm.setData(dmc); + + // Flag the event + getSession().dispatchEvent(new BreakpointAddedEvent(dmc), getProperties()); + + // Condition, ignore count and state can not be specified at watchpoint creation time. + // Therefore, we have to update the watchpoint if any of these is present + Map delta = new HashMap(); + delta.put(CONDITION, getProperty(attributes, CONDITION, NULL_STRING)); + delta.put(IGNORE_COUNT, getProperty(attributes, IGNORE_COUNT, 0 )); + delta.put(IS_ENABLED, getProperty(attributes, IS_ENABLED, true)); + modifyBreakpoint(dmc, delta, drm, false); + } + + @Override + protected void handleError() { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, WATCHPOINT_INSERTION_FAILURE, null)); + drm.done(); + } + }; + + // Execute the command + fConnection.queueCommand(new MIBreakWatch(context, isRead, isWrite, expression), addWatchpointDRM); + } + + //------------------------------------------------------------------------- + // removeBreakpoint + //------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IBreakpoints#removeBreakpoint(org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointDMContext, org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + public void removeBreakpoint(final IBreakpointDMContext dmc, final RequestMonitor rm) { + + // Validate the breakpoint context + if (dmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + rm.done(); + return; + } + + // Validate the breakpoint type + MIBreakpointDMContext breakpointCtx; + if (dmc instanceof MIBreakpointDMContext) { + breakpointCtx = (MIBreakpointDMContext) dmc; + } + else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null)); + rm.done(); + return; + } + + // Validate the target context + IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); + if (context == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null)); + rm.done(); + return; + } + + // Pick the context breakpoints map + final Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + + // Validate the breakpoint + final int reference = breakpointCtx.getReference(); + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + + // Queue the command + fConnection.queueCommand( + new MIBreakDelete(context, new int[] { reference }), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + getSession().dispatchEvent(new BreakpointRemovedEvent(dmc), getProperties()); + contextBreakpoints.remove(reference); + } + rm.done(); + } + }); + } + + // ------------------------------------------------------------------------- + // updateBreakpoint + //------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IBreakpoints#updateBreakpoint(org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointDMContext, java.util.Map, org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + public void updateBreakpoint(IBreakpointDMContext dmc, Map properties, RequestMonitor rm) + { + // Validate the breakpoint context + if (dmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + rm.done(); + return; + } + + // Validate the breakpoint type + MIBreakpointDMContext breakpointCtx; + if (dmc instanceof MIBreakpointDMContext) { + breakpointCtx = (MIBreakpointDMContext) dmc; + } + else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_TYPE, null)); + rm.done(); + return; + } + + // Validate the context + IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); + if (context == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null)); + rm.done(); + return; + } + + // Pick the context breakpoints map + final Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + + // Validate the breakpoint + final int reference = breakpointCtx.getReference(); + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + + modifyBreakpoint(dmc, properties, rm, true); + } + + /** + * @param dmc + * @param properties + * @param rm + * @param generateUpdateEvent + */ + private void modifyBreakpoint(final IBreakpointDMContext dmc, Map attributes, final RequestMonitor rm, final boolean generateUpdateEvent) + { + // Use a working copy of the attributes since we are going to tamper happily with them + Map properties = new HashMap(attributes); + + // Retrieve the breakpoint parameters + // At this point, we know their are OK so there is no need to re-validate + MIBreakpointDMContext breakpointCtx = (MIBreakpointDMContext) dmc; + IBreakpointsTargetDMContext context = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class); + final Map contextBreakpoints = fBreakpoints.get(context); + final int reference = breakpointCtx.getReference(); + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + + // Track the number of change requests + int numberOfChanges = 0; + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + if (generateUpdateEvent) + getSession().dispatchEvent(new BreakpointUpdatedEvent(dmc), getProperties()); + rm.done(); + } + }; + + // Determine if the breakpoint condition changed + String conditionAttribute = CONDITION; + if (properties.containsKey(conditionAttribute)) { + String oldValue = breakpoint.getCondition(); + String newValue = (String) properties.get(conditionAttribute); + if (newValue == null) newValue = NULL_STRING; + if (!oldValue.equals(newValue)) { + changeCondition(context, reference, newValue, countingRm); + numberOfChanges++; + } + properties.remove(conditionAttribute); + } + + // Determine if the breakpoint ignore count changed + String ignoreCountAttribute = IGNORE_COUNT; + if (properties.containsKey(ignoreCountAttribute)) { + Integer oldValue = breakpoint.getIgnoreCount(); + Integer newValue = (Integer) properties.get(ignoreCountAttribute); + if (newValue == null) newValue = 0; + if (!oldValue.equals(newValue)) { + changeIgnoreCount(context, reference, newValue, countingRm); + numberOfChanges++; + } + properties.remove(ignoreCountAttribute); + } + + // Determine if the breakpoint state changed + String enableAttribute = IS_ENABLED; + if (properties.containsKey(enableAttribute)) { + Boolean oldValue = breakpoint.isEnabled(); + Boolean newValue = (Boolean) properties.get(enableAttribute); + if (newValue == null) newValue = false; + if (!oldValue.equals(newValue)) { + numberOfChanges++; + if (newValue) + enableBreakpoint(context, reference, countingRm); + else + disableBreakpoint(context, reference, countingRm); + } + properties.remove(enableAttribute); + } + + // Set the number of completions required + countingRm.setDoneCount(numberOfChanges); + } + + /** + * Update the breakpoint condition + * + * @param context + * @param dmc + * @param condition + * @param rm + */ + private void changeCondition(IBreakpointsTargetDMContext context, + final int reference, final String condition, final RequestMonitor rm) + { + // Pick the context breakpoints map + final Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + rm.done(); + return; + } + + // Queue the command + fConnection.queueCommand( + new MIBreakCondition(context, reference, condition), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + if (getStatus().isOK()) { + breakpoint.setCondition(condition); + } + else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, INVALID_CONDITION, null)); + breakpoint.setCondition(NULL_STRING); + } + rm.done(); + } + }); + } + + + /** + * Update the breakpoint ignoreCount + * + * @param context + * @param reference + * @param ignoreCount + * @param rm + */ + private void changeIgnoreCount(IBreakpointsTargetDMContext context, + final int reference, final int ignoreCount, final RequestMonitor rm) + { + // Pick the context breakpoints map + final Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + rm.done(); + return; + } + + // Queue the command + fConnection.queueCommand( + new MIBreakAfter(context, reference, ignoreCount), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + breakpoint.setIgnoreCount(ignoreCount); + rm.done(); + } + }); + } + + /** + * Enable the breakpoint + * + * @param context + * @param reference + * @param rm + */ + private void enableBreakpoint(IBreakpointsTargetDMContext context, + final int reference, final RequestMonitor rm) + { + // Pick the context breakpoints map + final Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + rm.done(); + return; + } + + // Queue the command + fConnection.queueCommand( + new MIBreakEnable(context, new int[] { reference }), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + breakpoint.setEnabled(true); + rm.done(); + } + }); + } + + /** + * Disable the breakpoint + * + * @param context + * @param dmc + * @param rm + */ + private void disableBreakpoint(IBreakpointsTargetDMContext context, + final int reference, final RequestMonitor rm) + { + // Pick the context breakpoints map + final Map contextBreakpoints = fBreakpoints.get(context); + if (contextBreakpoints == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT_CONTEXT, null)); + rm.done(); + return; + } + + // Queue the command + fConnection.queueCommand( + new MIBreakDisable(context, new int[] { reference }), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + MIBreakpointDMData breakpoint = contextBreakpoints.get(reference); + if (breakpoint == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, UNKNOWN_BREAKPOINT, null)); + rm.done(); + return; + } + breakpoint.setEnabled(false); + rm.done(); + } + }); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsActionManager.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsActionManager.java new file mode 100644 index 00000000000..9cc46e6c481 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsActionManager.java @@ -0,0 +1,185 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.debug.core.breakpointactions.IBreakpointAction; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.model.IBreakpoint; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.DefaultHandler; + +public class MIBreakpointsActionManager { + + public static final String BREAKPOINT_ACTION_ATTRIBUTE = "BREAKPOINT_ACTIONS"; //$NON-NLS-1$ + private static final String BREAKPOINT_ACTION_DATA = "BreakpointActionManager.actionData"; //$NON-NLS-1$ + + private ArrayList breakpointActions = null; + + public MIBreakpointsActionManager() { + } + + public void executeActions(final IBreakpoint breakpoint, final IAdaptable context) { + if (breakpoint != null) { + IMarker marker = breakpoint.getMarker(); + String actionNames = marker.getAttribute(BREAKPOINT_ACTION_ATTRIBUTE, ""); //$NON-NLS-1$ + final String[] actions = actionNames.split(","); + if (actions.length > 0){ + Job job = new Job("Execute breakpoint actions") { + public IStatus run(final IProgressMonitor monitor) { + return doExecuteActions(breakpoint, context, actions, monitor); + } + }; + job.schedule(); + try { + // wait for actions to execute + job.join(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + private IStatus doExecuteActions(final IBreakpoint breakpoint, final IAdaptable context, String[] actions, IProgressMonitor monitor) { + try { + for (int i = 0; i < actions.length && !monitor.isCanceled(); i++) { + String actionName = actions[i]; + IBreakpointAction action = findBreakpointAction(actionName); + if (action != null) { + monitor.setTaskName(action.getSummary()); + IStatus status = action.execute(breakpoint, context, monitor); + if (status.getCode() != IStatus.OK) { + // do not log status if user canceled. + if (status.getCode() != IStatus.CANCEL) + CDebugCorePlugin.log(status); + return status; + } + } + monitor.worked(1); + } + } catch (Exception e) { + return new Status( IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), CDebugCorePlugin.INTERNAL_ERROR, "Internal Error", e ); + } + return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS; + } + + public IBreakpointAction findBreakpointAction(String name) { + for (Iterator iter = getBreakpointActions().iterator(); iter.hasNext();) { + IBreakpointAction action = (IBreakpointAction) iter.next(); + if (action.getName().equals(name)) + return action; + } + return null; + } + + public ArrayList getBreakpointActions() { + if (breakpointActions == null) { + breakpointActions = new ArrayList(); + loadActionData(); + } + return breakpointActions; + } + + private void loadActionData() { + + String actionData = CDebugCorePlugin.getDefault().getPluginPreferences().getString(BREAKPOINT_ACTION_DATA); + + if (actionData == null || actionData.length() == 0) + return; + + Element root = null; + DocumentBuilder parser; + try { + parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + parser.setErrorHandler(new DefaultHandler()); + root = parser.parse(new InputSource(new StringReader(actionData))).getDocumentElement(); + + NodeList nodeList = root.getChildNodes(); + int entryCount = nodeList.getLength(); + + for (int i = 0; i < entryCount; i++) { + Node node = nodeList.item(i); + short type = node.getNodeType(); + if (type == Node.ELEMENT_NODE) { + Element subElement = (Element) node; + String nodeName = subElement.getNodeName(); + if (nodeName.equalsIgnoreCase("actionEntry")) { //$NON-NLS-1$ + String name = subElement.getAttribute("name"); //$NON-NLS-1$ + if (name == null) + throw new Exception(); + String value = subElement.getAttribute("value"); //$NON-NLS-1$ + if (value == null) + throw new Exception(); + String className = subElement.getAttribute("class"); //$NON-NLS-1$ + if (className == null) + throw new Exception(); + + IBreakpointAction action = createActionFromClassName(name, className); + action.initializeFromMemento(value); + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private IBreakpointAction createActionFromClassName(String name, String className) { + + IBreakpointAction action = null; + IExtension[] actionExtensions = CDebugCorePlugin.getDefault().getBreakpointActionManager().getBreakpointActionExtensions(); + + try { + + for (int i = 0; i < actionExtensions.length && action == null; i++) { + IConfigurationElement[] elements = actionExtensions[i].getConfigurationElements(); + for (int j = 0; j < elements.length && action == null; j++) { + IConfigurationElement element = elements[j]; + if (element.getName().equals(CDebugCorePlugin.ACTION_TYPE_ELEMENT)) { + if (element.getAttribute("class").equals(className)) { //$NON-NLS-1$ + action = (IBreakpointAction) element.createExecutableExtension("class"); //$NON-NLS-1$ + action.setName(name); + CDebugCorePlugin.getDefault().getBreakpointActionManager().addAction(action); + } + } + } + } + + } catch (CoreException e) { + e.printStackTrace(); + } + + return action; + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java new file mode 100644 index 00000000000..a4faefb1d5c --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java @@ -0,0 +1,1484 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms 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 - Initial API and implementation + * Ericsson - High-level breakpoints integration + * Ericsson - Added breakpoint filter support + * Ericsson - Re-factored the service and put a few comments + *******************************************************************************/ + +package org.eclipse.dd.mi.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.debug.core.model.ICBreakpoint; +import org.eclipse.cdt.debug.core.model.ICBreakpointExtension; +import org.eclipse.cdt.debug.core.model.ICLineBreakpoint; +import org.eclipse.cdt.debug.core.model.ICWatchpoint; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IMarkerDelta; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.ResourcesPlugin; +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.ISchedulingRule; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.MultiRule; +import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints; +import org.eclipse.dd.dsf.debug.service.IDsfBreakpointExtension; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.ISourceLookup; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.MIRunControl.MIExecutionDMC; +import org.eclipse.dd.mi.service.command.events.MIGDBExitEvent; +import org.eclipse.dd.mi.service.command.events.MIWatchpointScopeEvent; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.IBreakpointListener; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.IBreakpointManagerListener; +import org.eclipse.debug.core.model.IBreakpoint; +import org.osgi.framework.BundleContext; + +/** + * Breakpoint service interface. The breakpoint service tracks CDT breakpoint + * objects, and based on those, it manages breakpoints in the debugger back end. + * + * It relies on MIBreakpoints for the actual back-end interface. + */ +public class MIBreakpointsManager extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener +{ + // Note: Find a way to import this (careful of circular dependencies) + public final static String GDB_DEBUG_MODEL_ID = "org.eclipse.dd.dsf.gdb"; //$NON-NLS-1$ + + // Extra breakpoint attributes + private static final String ATTR_DEBUGGER_PATH = MIPlugin.PLUGIN_ID + ".debuggerPath"; //$NON-NLS-1$ + private static final String ATTR_THREAD_FILTER = MIPlugin.PLUGIN_ID + ".threadFilter"; //$NON-NLS-1$ + private static final String ATTR_THREAD_ID = MIPlugin.PLUGIN_ID + ".threadID"; //$NON-NLS-1$ + + // Services + ICommandControl fConnection; + IRunControl fRunControl; + ISourceLookup fSourceLookup; + IBreakpoints fBreakpoints; + IBreakpointManager fBreakpointManager; // Platform breakpoint manager (not this!) + // FIXME: MIBreakpointsActionManager fBreakpointActionManager; + + /////////////////////////////////////////////////////////////////////////// + // Breakpoints tracking + /////////////////////////////////////////////////////////////////////////// + + private String fDebugModelId; + + // Holds the set of platform breakpoints with their corresponding back-end + // breakpoint attributes, per context (i.e. each platform breakpoint is + // replicated for each execution context). + // - Context entry added/removed on start/stopTrackingBreakpoints() + // - Augmented on breakpointAdded() + // - Modified on breakpointChanged() + // - Diminished on breakpointRemoved() + private Map>> fPlatformBPs = + new HashMap>>(); + + // Holds the set of target breakpoints, per execution context, and their + // mapping to the corresponding platform breakpoint. In a given execution + // context there can only be one platform breakpoint per target breakpoint. + // Acts as a mapping from target (low-level) BP to the corresponding platform + // (high-level) BP. + // Updated when: + // - We start/stop tracking an execution context + // - A platform breakpoint is added/removed + // - A thread filter is applied/removed + private Map> fTargetBPs = + new HashMap>(); + + // Holds the mapping from platform breakpoint to the corresponding target + // breakpoint(s), per context. There can be multiple back-end BPs for a + // single platform BP in the case of [1] multiple target contexts, and/or + // [2] thread filtering. + // Updated when: + // - We start/stop tracking an execution context + // - A platform breakpoint is added/removed + // - A thread filter is applied/removed + private Map>> fBreakpointIDs = + new HashMap>>(); + + // Holds the mapping from platform breakpoint to the corresponding target + // breakpoint threads, per context. + // Updated when: + // - We start/stop tracking an execution context + // - A platform breakpoint is added/removed + // - A thread filter is applied/removed + private Map>> fBreakpointThreads = + new HashMap>>(); + + // Due to the very asynchronous nature of DSF, a new breakpoint request can + // pop up at any time before an ongoing one is completed. The following set + // is used to store requests until the ongoing operation completes. + private Set fPendingRequests = new HashSet(); + private Set fPendingBreakpoints = new HashSet(); + + /////////////////////////////////////////////////////////////////////////// + // String constants + // FIXME: Extract to some centralized location + /////////////////////////////////////////////////////////////////////////// + + private static final String NULL_STRING = ""; //$NON-NLS-1$ + + static final String CONTEXT_ALREADY_INITIALIZED = "Context already initialized"; //$NON-NLS-1$ + static final String INVALID_CONTEXT_TYPE = "Invalid context type"; //$NON-NLS-1$ + static final String INVALID_CONTEXT = "Invalid context"; //$NON-NLS-1$ + + static final String UNABLE_TO_READ_BREAKPOINT = "Unable to read initial breakpoint attributes"; //$NON-NLS-1$ + static final String BREAKPOINT_NOT_INSTALLED = "Breakpoints not installed for given context"; //$NON-NLS-1$ + static final String BREAKPOINT_ALREADY_INSTALLED = "Breakpoint already installed"; //$NON-NLS-1$ + static final String BREAKPOINT_ALREADY_REMOVED = "Breakpoint already removed"; //$NON-NLS-1$ + + static final String INVALID_BREAKPOINT = "Invalid breakpoint"; //$NON-NLS-1$ + static final String UNKNOWN_BREAKPOINT = "Unknown breakpoint"; //$NON-NLS-1$ + static final String INVALID_PARAMETER = "Invalid breakpoint parameter(s)"; //$NON-NLS-1$ + + static final String NO_DEBUGGER_PATH = "No debugger path for breakpoint"; //$NON-NLS-1$ + static final String NO_MARKER_FOR_BREAKPOINT = "No marker associated with breakpoint"; //$NON-NLS-1$ + + /////////////////////////////////////////////////////////////////////////// + // AbstractDsfService + /////////////////////////////////////////////////////////////////////////// + + /** + * The service constructor. + * Performs basic instantiation (method initialize() performs the real + * service initialization asynchronously). + * + * @param session the debugging session + * @param debugModelId the debugging model + */ + public MIBreakpointsManager(DsfSession session, String debugModelId) { + super(session); + fDebugModelId = debugModelId; + } + + //------------------------------------------------------------------------- + // initialize + //------------------------------------------------------------------------- + // - Collect references for the services we interact with + // - Register to interesting events + // - Obtain the list of platform breakpoints + // - Register the service for interested parties + //------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#initialize(org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + @Override + public void initialize(final RequestMonitor rm) { + super.initialize( + new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + doInitialize(rm); + }}); + } + + /** + * @param rm + */ + private void doInitialize(RequestMonitor rm) { + + // Get the required services references from central repository + fConnection = getServicesTracker().getService(ICommandControl.class); + fRunControl = getServicesTracker().getService(IRunControl.class); + fSourceLookup = getServicesTracker().getService(ISourceLookup.class); + fBreakpoints = getServicesTracker().getService(IBreakpoints.class); + fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager(); + // FIXME: fBreakpointActionManager = new MIBreakpointsActionManager(); + + // Register to the useful events + getSession().addServiceEventListener(this, null); + fBreakpointManager.addBreakpointListener(this); + fBreakpointManager.addBreakpointManagerListener(this); + + // And register this service + register(new String[] { MIBreakpointsManager.class.getName() }, + new Hashtable()); + rm.done(); + } + + //------------------------------------------------------------------------- + // shutdown + //------------------------------------------------------------------------- + // - Un-register the service + // - Stop listening to events + // - Remove the breakpoints installed by this service + // + // Since we are shutting down, there is no overwhelming need + // to keep the maps coherent... + //------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#shutdown(org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + @Override + public void shutdown(final RequestMonitor rm) { + + // Stop accepting requests and events + unregister(); + getSession().removeServiceEventListener(this); + fBreakpointManager.removeBreakpointListener(this); + fBreakpointManager.removeBreakpointManagerListener(this); + + // Cleanup the breakpoints that are still installed by the service. + // Use a counting monitor which will call mom to complete the shutdown + // after the breakpoints are un-installed (successfully or not). + CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + MIBreakpointsManager.super.shutdown(rm); + } + }; + + List targetBPKeys = new ArrayList(fTargetBPs.size()); + targetBPKeys.addAll(0, fTargetBPs.keySet()); + for (IBreakpointsTargetDMContext dmc : targetBPKeys) { + stopTrackingBreakpoints(dmc, countingRm); + } + countingRm.setDoneCount(targetBPKeys.size()); + } + + //------------------------------------------------------------------------- + // getBundleContext + //------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#getBundleContext() + */ + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + /////////////////////////////////////////////////////////////////////////// + // IBreakpointsManager + /////////////////////////////////////////////////////////////////////////// + + //------------------------------------------------------------------------- + // startTrackingBreakpoints + //------------------------------------------------------------------------- + // - Augment the maps with the new execution context + // - Install the platform breakpoints on the selected target + //------------------------------------------------------------------------- + + /** + * Install and begin tracking breakpoints for given context. The service + * will keep installing new breakpoints that appear in the IDE for this + * context until {@link #uninstallBreakpoints(IDMContext)} is called for that + * context. + * @param dmc Context to start tracking breakpoints for. + * @param rm Completion callback. + */ + public void startTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { + + // Validate the execution context + if (dmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_CONTEXT, null)); + rm.done(); + return; + } + + // Make sure a mapping for this execution context does not already exist + Map> platformBPs = fPlatformBPs.get(dmc); + Map> breakpointIDs = fBreakpointIDs.get(dmc); + Map targetIDs = fTargetBPs.get(dmc); + Map> threadIDs = fBreakpointThreads.get(dmc); + if ((platformBPs != null) || (breakpointIDs != null) || (targetIDs != null) || (threadIDs != null)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, CONTEXT_ALREADY_INITIALIZED, null)); + rm.done(); + return; + } + + // Create entries in the breakpoint tables for the new context. These entries should only + // be removed when this service stops tracking breakpoints for the given context. + fPlatformBPs.put(dmc, new HashMap>()); + fBreakpointIDs.put(dmc, new HashMap>()); + fTargetBPs.put(dmc, new HashMap()); + fBreakpointThreads.put(dmc, new HashMap>()); + + // Install the platform breakpoints (stored in fPlatformBPs) on the target. + // FIXME: Why bother with a Job? + new Job("DSF BreakpointsManager: Install initial breakpoints on target") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + // Submit the runnable to plant the breakpoints on dispatch thread. + getExecutor().submit(new Runnable() { + public void run() { + installInitialBreakpoints(dmc, rm); + } + }); + + return Status.OK_STATUS; + } + }.schedule(); + } + + /** + * Installs the breakpoints that existed prior to the activation of this + * execution context. + * + * @param dmc + * @param initialPlatformBPs + * @param rm + */ + private void installInitialBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) + { + // Retrieve the set of platform breakpoints for this context + final Map> platformBPs = fPlatformBPs.get(dmc); + if (platformBPs == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); + rm.done(); + return; + } + + // Read current breakpoints from platform and copy their augmented + // attributes into the local reference map + try { + IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(fDebugModelId); + for (IBreakpoint breakpoint : breakpoints) { + if (supportsBreakpoint(breakpoint)) { + @SuppressWarnings("unchecked") + Map attributes = breakpoint.getMarker().getAttributes(); + attributes.put(ATTR_DEBUGGER_PATH, NULL_STRING); + attributes.put(ATTR_THREAD_FILTER, extractThreads(dmc, (ICBreakpoint) breakpoint)); + attributes.put(ATTR_THREAD_ID, NULL_STRING); + platformBPs.put((ICBreakpoint) breakpoint, attributes); + } + } + } catch (CoreException e) { + IStatus status = new Status( + IStatus.ERROR, MIPlugin.PLUGIN_ID, REQUEST_FAILED, UNABLE_TO_READ_BREAKPOINT, e); + rm.setStatus(status); + rm.done(); + } + + // Install the individual breakpoints on the dispatcher thread + // Requires a counting monitor to know when we are done + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm); + countingRm.setDoneCount(platformBPs.size()); + + for (final ICBreakpoint breakpoint : platformBPs.keySet()) { + final Map attributes = platformBPs.get(breakpoint); + // Upon determining the debuggerPath, the breakpoint is installed + determineDebuggerPath(dmc, attributes, new RequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleOK() { + installBreakpoint(dmc, breakpoint, attributes, new RequestMonitor(getExecutor(), countingRm)); + } + }); + } + } + + //------------------------------------------------------------------------- + // stopTrackingBreakpoints + //------------------------------------------------------------------------- + // - Remove the target breakpoints for the given execution context + // - Update the maps + //------------------------------------------------------------------------- + + /** + * Uninstall and stop tracking breakpoints for the given context. + * @param dmc Context to start tracking breakpoints for. + * @param rm Completion callback. + */ + public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) { + + // Validate the context + if (dmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); + rm.done(); + return; + } + + // Retrieve the set of platform breakpoints for this context + final Map> platformBPs = fPlatformBPs.get(dmc); + if (platformBPs == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, INVALID_CONTEXT, null)); + rm.done(); + return; + } + + // Un-install the individual breakpoints on the dispatcher thread + // (requires a counting monitor to know when we are done). + // On completion (success or failure), update the maps. + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + fPlatformBPs.remove(dmc); + fBreakpointIDs.remove(dmc); + fTargetBPs.remove(dmc); + fBreakpointThreads.remove(dmc); + rm.done(); + } + }; + countingRm.setDoneCount(platformBPs.size()); + + for (final ICBreakpoint breakpoint : platformBPs.keySet()) { + uninstallBreakpoint(dmc, breakpoint, + new RequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleCompleted() { + countingRm.done(); + } + }); + } + } + + /////////////////////////////////////////////////////////////////////////// + // Back-end interface functions + /////////////////////////////////////////////////////////////////////////// + + //------------------------------------------------------------------------- + // installBreakpoint + //------------------------------------------------------------------------- + + /** + * Install a platform breakpoint on the back-end. For a given context, a + * platform breakpoint can resolve into multiple back-end breakpoints when + * threads are taken into account. + * + * @param dmc + * @param breakpoint + * @param attributes + * @param rm + */ + private void installBreakpoint(IBreakpointsTargetDMContext dmc, final ICBreakpoint breakpoint, + final Map attributes, final RequestMonitor rm) + { + // Retrieve the breakpoint maps + final Map> platformBPs = fPlatformBPs.get(dmc); + assert platformBPs != null; + + final Map> breakpointIDs = fBreakpointIDs.get(dmc); + assert breakpointIDs != null; + + final Map targetBPs = fTargetBPs.get(dmc); + assert targetBPs != null; + + final Map> threadsIDs = fBreakpointThreads.get(dmc); + assert threadsIDs != null; + + // Minimal validation + if (breakpointIDs.containsKey(breakpoint) || targetBPs.containsValue(breakpoint)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, BREAKPOINT_ALREADY_INSTALLED, null)); + rm.done(); + return; + } + + // Ensure the breakpoint has a valid debugger source path + if (!(breakpoint instanceof ICWatchpoint)) { + String debuggerPath = (String) attributes.get(ATTR_DEBUGGER_PATH); + if (debuggerPath == null || debuggerPath == NULL_STRING) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, REQUEST_FAILED, NO_DEBUGGER_PATH, null)); + rm.done(); + return; + } + } + + // A back-end breakpoint needs to be installed for each specified thread + // Note: This is a bit academic since [1] thread info is not kept by the + // BreakpointManager (so it can not possibly be restored when a target is + // started), and [2] the standard GUI doesn't allow to specify thread at + // breakpoint creation. However, it is conceivable that an enhanced Editor + // would permit it. + final Set threads = getThreads(attributes); + + // Update the breakpoint state when all back-end breakpoints have been installed + final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + // Store the platform breakpoint + platformBPs.put(breakpoint, attributes); + threadsIDs.put(breakpoint, threads); + rm.done(); + } + }; + installRM.setDoneCount(threads.size()); + + // Install the back-end breakpoint(s) + for (final String thread : threads) { + DataRequestMonitor drm = + new DataRequestMonitor(getExecutor(), installRM) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + // Add the new back-end breakpoint to the map + Vector list = breakpointIDs.get(breakpoint); + if (list == null) + list = new Vector(); + IBreakpointDMContext targetBP = getData(); + list.add(targetBP); + breakpointIDs.put(breakpoint, list); + + // Add the reverse mapping + targetBPs.put(targetBP, breakpoint); + + // And update the corresponding thread list + Set thrds = threadsIDs.get(breakpoint); + if (thrds == null) + thrds = new HashSet(); + thrds.add(thread); + threadsIDs.put(breakpoint, thrds); + + // Finally, update the platform breakpoint + attributes.remove(ATTR_THREAD_ID); + try { + breakpoint.incrementInstallCount(); + } catch (CoreException e) { + } + } + installRM.done(); + } + }; + + // Convert the breakpoint attributes for the back-end + attributes.put(ATTR_THREAD_ID, thread); + Map targetAttributes = convertToTargetBreakpoint(breakpoint, attributes); + fBreakpoints.insertBreakpoint(dmc, targetAttributes, drm); + } + } + + //------------------------------------------------------------------------- + // uninstallBreakpoint + //------------------------------------------------------------------------- + + /** + * Un-install an individual breakpoint on the back-end. For one platform + * breakpoint in a given execution context, there could be multiple + * corresponding back-end breakpoints (one per thread). + * + * @param dmc + * @param breakpoint + * @param rm + */ + private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, + final ICBreakpoint breakpoint, final RequestMonitor rm) + { + // Retrieve the breakpoint maps + final Map> platformBPs = fPlatformBPs.get(dmc); + assert platformBPs != null; + + final Map> breakpointIDs = fBreakpointIDs.get(dmc); + assert breakpointIDs != null; + + final Map targetBPs = fTargetBPs.get(dmc); + assert targetBPs != null; + + final Map> threadsIDs = fBreakpointThreads.get(dmc); + assert threadsIDs != null; + + // Minimal validation + if (!platformBPs.containsKey(breakpoint) || !breakpointIDs.containsKey(breakpoint) || !targetBPs.containsValue(breakpoint)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, BREAKPOINT_ALREADY_REMOVED, null)); + rm.done(); + return; + } + + // Remove completion monitor + // Upon completion, update the mappings + CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Update the mappings + platformBPs.remove(breakpoint); + threadsIDs.remove(breakpoint); + + Vector contexts = breakpointIDs.get(breakpoint); + if (contexts != null) { + for (IBreakpointDMContext context : contexts) + targetBPs.remove(context); + } + + breakpointIDs.get(breakpoint).clear(); + breakpointIDs.remove(breakpoint); + + fPendingRequests.remove(breakpoint); + + rm.done(); + } + }; + + // Remove the back-end breakpoints + Vector list = breakpointIDs.get(breakpoint); + int count = 0; + if (list != null) { + for (IBreakpointDMContext bp : list) { + fBreakpoints.removeBreakpoint(bp, removeRM); + try { + breakpoint.decrementInstallCount(); + } catch (CoreException e) { + } + } + count = list.size(); + } + removeRM.setDoneCount(count); + } + + //------------------------------------------------------------------------- + // modifyBreakpoint + //------------------------------------------------------------------------- + + /** + * Modify a platform breakpoint which can translate to quite a few updates + * on the target... + * + * @param dmc + * @param breakpoint + * @param attributes + * @param oldValues + * @param rm + */ + private void modifyBreakpoint(final IBreakpointsTargetDMContext dmc, final ICBreakpoint breakpoint, + final Map attributes, final IMarkerDelta oldValues, final RequestMonitor rm) + { + // Retrieve the breakpoint maps + final Map> platformBPs = fPlatformBPs.get(dmc); + assert platformBPs != null; + + final Map> breakpointIDs = fBreakpointIDs.get(dmc); + assert breakpointIDs != null; + + final Map targetBPs = fTargetBPs.get(dmc); + assert targetBPs != null; + + final Map> threadsIDs = fBreakpointThreads.get(dmc); + assert threadsIDs != null; + + // Minimal validation + if (!platformBPs.containsKey(breakpoint) || !breakpointIDs.containsKey(breakpoint) || !targetBPs.containsValue(breakpoint)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, BREAKPOINT_NOT_INSTALLED, null)); + rm.done(); + return; + } + + // Get the original breakpoint attributes + final Map original_attributes = platformBPs.get(breakpoint); + if (original_attributes == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, INVALID_BREAKPOINT, null)); + rm.done(); + return; + } + + // Determine the attributes delta + final Map oldAttributes = new HashMap(original_attributes); + oldAttributes.put(ATTR_THREAD_FILTER, threadsIDs.get(breakpoint)); + + final Set newThreads = extractThreads(dmc, breakpoint); + Map newAttributes = new HashMap(attributes); + newAttributes.put(ATTR_THREAD_FILTER, newThreads); + + final Map attributesDelta = determineAttributesDelta(oldAttributes, newAttributes); + + // Get the list of back-end breakpoints + final Vector oldTargetBPs = new Vector(breakpointIDs.get(breakpoint)); + if (oldTargetBPs == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, INVALID_BREAKPOINT, null)); + rm.done(); + return; + } + + // We're all set for the breakpoint update. + // + // The path for a simple update is straightforward: + // - For each back-end BP corresponding to a platform BP + // - Send an update command to the back-end + // - If the operation succeeded, update the data structures + // - If the operation failed, try to roll-back + // + // In cases where the the back-end breakpoint cannot be + // simply updated (e.g. thread filter modification), the old + // breakpoint has to be removed and new one(s) inserted. + // + // The path for such an update is: + // - Install the updated breakpoint + // - In the operation succeeded + // - Remove the old breakpoint(s) + // - perform any pending update + + // Update completion monitor + final CountingRequestMonitor updateRM = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Success: simply store the new attributes + platformBPs.put(breakpoint, attributes); + rm.done(); + } + + @Override + protected void handleError() { + // Reset the breakpoint attributes. This will trigger a + // breakpoint change event and the correct delta will be + // computed, resulting in a correctly restored breakpoint + // at the back-end. + rollbackAttributes(breakpoint, oldValues); + platformBPs.put(breakpoint, attributes); + + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); + rm.done(); + } + }; + + // Everything OK: remove the old back-end breakpoints + final Vector newTargetBPs = new Vector(); + final CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // All right! Save the new list and perform the final update + Map> breakpointIDs = fBreakpointIDs.get(dmc); + if (breakpointIDs == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_BREAKPOINT, null)); + rm.done(); + return; + } + breakpointIDs.put(breakpoint, newTargetBPs); + for (IBreakpointDMContext ref : newTargetBPs) { + fBreakpoints.updateBreakpoint(ref, attributesDelta, updateRM); + } + updateRM.setDoneCount(newTargetBPs.size()); + }}; + + // New back-end breakpoints insertion monitor + // Holds the list of new back-end breakpoint contexts of the platform breakpoint + final DataRequestMonitor> insertRM = + new DataRequestMonitor>(getExecutor(), null) { + + @Override + // In theory, we could have had a partial success and the original threads + // list would be invalid. We think it is highly unlikely so we assume that + // either everything went fine or else everything failed. + protected void handleOK() { + // Get the list of new back-end breakpoints contexts + newTargetBPs.addAll(getData()); + threadsIDs.put(breakpoint, newThreads); + for (IBreakpointDMContext ref : oldTargetBPs) { + fBreakpoints.removeBreakpoint(ref, removeRM); + try { + breakpoint.decrementInstallCount(); // A tad early but it should work... + } catch (CoreException e) { + } + } + removeRM.setDoneCount(oldTargetBPs.size()); + } + + @Override + protected void handleError() { + // Keep the old threads list and reset the attributes + // (bad attributes are the likely cause of failure) + updateRM.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); + updateRM.setDoneCount(0); + } + }; + + // If the changes in the breakpoint attributes justify it, install a + // new set of back-end breakpoint(s) and then update them + if (needsResinstallation(attributesDelta)) { + reinstallBreakpoint(dmc, breakpoint, attributes, newThreads, insertRM); + } + else { + // Update the back-end breakpoint(s) state + for (IBreakpointDMContext ref : oldTargetBPs) { + fBreakpoints.updateBreakpoint(ref, attributesDelta, updateRM); + } + updateRM.setDoneCount(oldTargetBPs.size()); + } + } + + /** + * Re-install the back-end breakpoints + * + * @param context the target context + * @param breakpoint the platform breakpoint + * @param attributes breakpoint augmented attributes + * @param threads list of threads where breakpoint is to be installed + * @param drm will contain the list of successfully installed back-end breakpoints + */ + private void reinstallBreakpoint(final IBreakpointsTargetDMContext context, final ICBreakpoint breakpoint, + final Map attributes, Set threads, final DataRequestMonitor> drm) + { + // Our new list of back-end breakpoints. Built as we go. + final Vector breakpointList = new Vector(); + + // Counting monitor for the new back-end breakpoints to install + // Once we're done, return the new list of back-end breakpoints contexts + final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + // Report whatever we have managed to install + // It is very likely installation either succeeded or failed for all + drm.setData(breakpointList); + drm.done(); + } + }; + installRM.setDoneCount(threads.size()); + + // And install the new back-end breakpoints + for (String thread : threads) { + // Convert the breakpoint attributes for the back-end + // Refresh the set of attributes at each iteration just in case... + Map attrs = convertToTargetBreakpoint(breakpoint, attributes); + if (!fBreakpointManager.isEnabled()) { + attrs.put(MIBreakpoints.IS_ENABLED, false); + } + // Add the secret ingredient.. + attrs.put(MIBreakpointDMData.THREAD_ID, thread); + + // Then install the spiked breakpoint + fBreakpoints.insertBreakpoint(context, attrs, + new DataRequestMonitor(getExecutor(), installRM) { + @Override + protected void handleOK() { + // Add the new back-end breakpoint context to the list + breakpointList.add(getData()); + try { + breakpoint.incrementInstallCount(); + } catch (CoreException e) { + } + installRM.done(); + } + + @Override + protected void handleError() { + // Add the new back-end breakpoint context to the list + installRM.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, REQUEST_FAILED, INVALID_PARAMETER, null)); + installRM.done(); + } + }); + } + } + + /////////////////////////////////////////////////////////////////////////// + // IBreakpointManagerListener implementation + /////////////////////////////////////////////////////////////////////////// + + /* (non-Javadoc) + * @see org.eclipse.debug.core.IBreakpointManagerListener#breakpointManagerEnablementChanged(boolean) + */ + public void breakpointManagerEnablementChanged(boolean enabled) { + + // Only modify enabled breakpoints + for (IBreakpointsTargetDMContext context : fBreakpointIDs.keySet()) { + for (ICBreakpoint breakpoint : fBreakpointIDs.get(context).keySet()) { + try { + if (breakpoint.isEnabled()) { + for (IBreakpointDMContext ref : fBreakpointIDs.get(context).get(breakpoint)) { + Map delta = new HashMap(); + delta.put(MIBreakpoints.IS_ENABLED, enabled); + fBreakpoints.updateBreakpoint(ref, delta, new RequestMonitor(getExecutor(), null)); + } + } + } catch (CoreException e) { + } + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // IBreakpointListener implementation + /////////////////////////////////////////////////////////////////////////// + + /* (non-Javadoc) + * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint) + */ + @ThreadSafe + public void breakpointAdded(final IBreakpoint breakpoint) { + + if (supportsBreakpoint(breakpoint)) { + try { + // Retrieve the breakpoint attributes + @SuppressWarnings("unchecked") + final Map attrs = breakpoint.getMarker().getAttributes(); + + getExecutor().execute(new DsfRunnable() { + public void run() { + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { + @Override + protected void handleError() { + if (getStatus().getSeverity() == IStatus.ERROR) { + MIPlugin.getDefault().getLog().log(getStatus()); + } + } + }; + countingRm.setDoneCount(fPlatformBPs.size()); + + // Install the breakpoint in all the execution contexts + for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { + determineDebuggerPath(dmc, attrs, + new RequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleOK() { + installBreakpoint(dmc, (ICBreakpoint) breakpoint, + attrs, new RequestMonitor(getExecutor(), countingRm)); + } + }); + } + } + }); + } catch (CoreException e) { + } catch (RejectedExecutionException e) { + } + } + } + + /** + * @param bp + * @return + * @throws CoreException + */ + private IDsfBreakpointExtension getFilterExtension(ICBreakpoint bp) throws CoreException { + return (IDsfBreakpointExtension) bp.getExtension(GDB_DEBUG_MODEL_ID, ICBreakpointExtension.class); + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) + */ + public void breakpointChanged(final IBreakpoint breakpoint, final IMarkerDelta delta) { + + if (supportsBreakpoint(breakpoint)) { + + try { + // Retrieve the breakpoint attributes + @SuppressWarnings("unchecked") + final Map attrs = breakpoint.getMarker().getAttributes(); + if (!fBreakpointManager.isEnabled()) { + attrs.put(ICBreakpoint.ENABLED, false); + } + + // Modify the breakpoint in all the target contexts + getExecutor().execute( new DsfRunnable() { + public void run() { + + // If the breakpoint is currently being updated, queue the request and exit + if (fPendingRequests.contains(breakpoint)) { + fPendingBreakpoints.add(breakpoint); + return; + } + + // Keep track of the updates + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { + @Override + protected void handleCompleted() { + + if (!getStatus().isOK()) { + if (getStatus().getSeverity() == IStatus.ERROR) { + MIPlugin.getDefault().getLog().log(getStatus()); + } + } + + // Indicate that the pending request has completed + fPendingRequests.remove(breakpoint); + + // Process the next pending update for this breakpoint + if (fPendingBreakpoints.contains(breakpoint)) { + fPendingBreakpoints.remove(breakpoint); + breakpointChanged(breakpoint, delta); + } + } + }; + countingRm.setDoneCount(fPlatformBPs.size()); + + // Mark the breakpoint as being updated and go + fPendingRequests.add(breakpoint); + + // Modify the breakpoint in all the execution contexts + for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { + determineDebuggerPath(dmc, attrs, + new RequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleOK() { + modifyBreakpoint(dmc, (ICBreakpoint) breakpoint, attrs, delta, new RequestMonitor(getExecutor(), countingRm)); + } + }); + } + } + }); + } catch (CoreException e) { + } catch (RejectedExecutionException e) { + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) + */ + public void breakpointRemoved(final IBreakpoint breakpoint, IMarkerDelta delta) { + + if (supportsBreakpoint(breakpoint)) { + try { + getExecutor().execute(new DsfRunnable() { + public void run() { + CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) { + @Override + protected void handleError() { + if (getStatus().getSeverity() == IStatus.ERROR) { + MIPlugin.getDefault().getLog().log(getStatus()); + } + } + }; + countingRm.setDoneCount(fPlatformBPs.size()); + + // Remove the breakpoint in all the execution contexts + for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { + if (fPlatformBPs.get(dmc).containsKey(breakpoint)) { + uninstallBreakpoint(dmc, (ICBreakpoint) breakpoint, countingRm); + } else { + // Breakpoint not installed for given context, do nothing. + } + } + } + }); + } catch (RejectedExecutionException e) { + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // IServiceEventListener + /////////////////////////////////////////////////////////////////////////// + +// /* +// * When a breakpoint is hit, handle associated actions (if any) +// */ +// @DsfServiceEventHandler +// public void eventDispatched(DsfMIBreakpointHitEvent e) { +// IExecutionDMContext context = e.getDMContext(); +// int breakpointNumber = e.getNumber(); +//// IBreakpoint breakpoint = +//// fBreakpointActionManager. +// } + + /* + * When a watchpoint goes out of scope, it is automatically removed from + * the back-end. To keep our internal state synchronized, we have to + * remove it from our breakpoints maps. + * Unfortunately, GDB doesn't generate the correct event... + */ + @DsfServiceEventHandler + public void eventDispatched(MIWatchpointScopeEvent e) { +// fBreakpoints.remove(e.getNumber()); + } + + @DsfServiceEventHandler + public void eventDispatched(MIGDBExitEvent e) { + terminated(); + } + + private void terminated() { + clearBreakpointStatus(fPlatformBPs.keySet().toArray(new ICBreakpoint[fPlatformBPs.size()])); + fPlatformBPs.clear(); + } + + /////////////////////////////////////////////////////////////////////////// + // Breakpoint status handling functions + /////////////////////////////////////////////////////////////////////////// + + /** + * @param bps + */ + private void clearBreakpointStatus(final ICBreakpoint[] bps) + { + new Job("Clear Breakpoints Status") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + IWorkspaceRunnable wr = new IWorkspaceRunnable() { + public void run(IProgressMonitor monitor) throws CoreException { + for (ICBreakpoint breakpoint : bps) { + breakpoint.resetInstallCount(); + } + } + }; + + // Create the scheduling rule to clear all bp planted. + ISchedulingRule rule = null; + List markerRules = new ArrayList(); + for (ICBreakpoint bp : bps) { + IMarker marker = bp.getMarker(); + if (marker != null) { + ISchedulingRule markerRule = + ResourcesPlugin.getWorkspace().getRuleFactory().markerRule( + marker.getResource()); + if (markerRule == null) { + markerRules = null; + break; + } else { + markerRules.add(markerRule); + } + } + } + if (markerRules != null) { + rule = MultiRule.combine(markerRules.toArray(new ISchedulingRule[markerRules.size()])); + } + + try { + ResourcesPlugin.getWorkspace().run(wr, rule, 0, null); + } catch (CoreException e) { + return e.getStatus(); + } + return Status.OK_STATUS; + } + }.schedule(); + } + + /////////////////////////////////////////////////////////////////////////// + // Support functions + /////////////////////////////////////////////////////////////////////////// + + /** + * supportsBreakpoint + * + * Indicates if it is breakpoint we can deal with. For now, it boils down + * to a CDI breakpoint... + * + * @param bp + * @return + */ + private boolean supportsBreakpoint(IBreakpoint bp) { + if (bp instanceof ICBreakpoint && bp.getModelIdentifier().equals(fDebugModelId)) { + IMarker marker = bp.getMarker(); + if (marker != null) { + return true; + } + } + return false; + } + + /** + * determineDebuggerPath + * + * Adds the path to the source file to the set of attributes + * (for the debugger). + * + * @param dmc + * @param attributes + * @param rm + */ + private void determineDebuggerPath(IBreakpointsTargetDMContext dmc, + final Map attributes, final RequestMonitor rm) + { + String hostPath = (String) attributes.get(ICBreakpoint.SOURCE_HANDLE); + + if (hostPath != null) { + ISourceLookupDMContext srcDmc = DMContexts.getAncestorOfType(dmc, ISourceLookupDMContext.class); + if (srcDmc != null) { + fSourceLookup.getDebuggerPath(srcDmc, hostPath, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + attributes.put(ATTR_DEBUGGER_PATH, getData()); + rm.done(); + } + }); + } else { + // Source lookup not available for given context, use the host + // path for the debugger path. + attributes.put(ATTR_DEBUGGER_PATH, hostPath); + rm.done(); + } + } else { + // Some types of breakpoints do not require a path + // (e.g. watchpoints) + rm.done(); + } + } + + /** + * Determine the set of modified attributes. + * Elementary set operations in full action :-) + * + * @param oldAttributes + * @param newAttributes + * @return + */ + private Map determineAttributesDelta(Map oldAttributes, Map newAttributes) { + + Map delta = new HashMap(); + + Set oldKeySet = oldAttributes.keySet(); + Set newKeySet = newAttributes.keySet(); + + Set commonKeys = new HashSet(newKeySet); commonKeys.retainAll(oldKeySet); + Set addedKeys = new HashSet(newKeySet); addedKeys.removeAll(oldKeySet); + Set removedKeys = new HashSet(oldKeySet); removedKeys.removeAll(newKeySet); + + // Add the modified attributes + for (String key : commonKeys) { + if (!(oldAttributes.get(key).equals(newAttributes.get(key)))) + delta.put(key, newAttributes.get(key)); + } + + // Add the new attributes + for (String key : addedKeys) { + delta.put(key, newAttributes.get(key)); + } + + // Remove the deleted attributes + for (String key : removedKeys) { + delta.put(key, null); + } + + return convertedAttributes(delta); + } + + /** + * Converts ICBreakpoint attributes to IBreakpoints attributes. + * + * @param cdt_attributes + * @return + */ + private Map convertedAttributes(Map cdt_attributes) { + + Map result = new HashMap(); + + // IBreakpoint attributes + if (cdt_attributes.containsKey(ATTR_DEBUGGER_PATH)) + result.put(MIBreakpoints.FILE_NAME, cdt_attributes.get(ATTR_DEBUGGER_PATH)); + + if (cdt_attributes.containsKey(IMarker.LINE_NUMBER)) + result.put(MIBreakpoints.LINE_NUMBER, cdt_attributes.get(IMarker.LINE_NUMBER)); + + // ICLineBreakpoint attributes + if (cdt_attributes.containsKey(ICLineBreakpoint.FUNCTION)) + result.put(MIBreakpoints.FUNCTION, cdt_attributes.get(ICLineBreakpoint.FUNCTION)); + + if (cdt_attributes.containsKey(ICLineBreakpoint.ADDRESS)) + result.put(MIBreakpoints.ADDRESS, cdt_attributes.get(ICLineBreakpoint.ADDRESS)); + + // ICBreakpoint attributes + if (cdt_attributes.containsKey(ICBreakpoint.CONDITION)) + result.put(MIBreakpoints.CONDITION, cdt_attributes.get(ICBreakpoint.CONDITION)); + + if (cdt_attributes.containsKey(ICBreakpoint.IGNORE_COUNT)) + result.put(MIBreakpoints.IGNORE_COUNT, cdt_attributes.get(ICBreakpoint.IGNORE_COUNT)); + + if (cdt_attributes.containsKey(ICBreakpoint.ENABLED)) + result.put(MIBreakpoints.IS_ENABLED, cdt_attributes.get(ICBreakpoint.ENABLED)); + + // ICWatchpoint attributes + if (cdt_attributes.containsKey(ICWatchpoint.EXPRESSION)) + result.put(MIBreakpoints.EXPRESSION, cdt_attributes.get(ICWatchpoint.EXPRESSION)); + + if (cdt_attributes.containsKey(ICWatchpoint.READ)) + result.put(MIBreakpoints.READ, cdt_attributes.get(ICWatchpoint.READ)); + + if (cdt_attributes.containsKey(ICWatchpoint.WRITE)) + result.put(MIBreakpoints.WRITE, cdt_attributes.get(ICWatchpoint.WRITE)); + + // Threads + if (cdt_attributes.containsKey(ATTR_THREAD_FILTER)) + result.put(ATTR_THREAD_FILTER, cdt_attributes.get(ATTR_THREAD_FILTER)); + + return result; + } + + /** + * Figure out the corresponding number of back-end breakpoints + * Even though the thread IDs are usually integers, they are + * stored as strings in CBreakpoints. + * + * @param attributes + * @return + */ + @SuppressWarnings("unchecked") + private Set getThreads(Map attributes) { + Set threads = (Set) attributes.get(ATTR_THREAD_FILTER); + if (threads == null) { + threads = new HashSet(); + threads.add("0"); // Thread 0 means all threads //$NON-NLS-1$ + } + return threads; + } + + /** + * Get the list of threads from the platform breakpoint attributes + * + * @param breakpoint + * @return + */ + private Set extractThreads(IBreakpointsTargetDMContext context, ICBreakpoint breakpoint) { + + // Find the ancestor + IContainerDMContext targetContext = DMContexts.getAncestorOfType(context, IContainerDMContext.class); + IExecutionDMContext[] threads = null; + + try { + // Retrieve the targets + IDsfBreakpointExtension filterExtension = getFilterExtension(breakpoint); + IContainerDMContext[] targets = filterExtension.getTargetFilters(); + + // If no target is present, plant one... + if (targets.length == 0) { + for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) { + IContainerDMContext ctx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class); + if (ctx == targetContext) { + filterExtension.setTargetFilter(ctx); + targets = filterExtension.getTargetFilters(); + } + } + } + + // Extract the thread IDs (if there is none, we are covered) + for (IContainerDMContext ctxt : targets) { + if (ctxt == targetContext) { + threads = filterExtension.getThreadFilters(ctxt); + } + } + } catch (CoreException e1) { + } + + Set results = new HashSet(); + if ((threads != null) && (supportsThreads(breakpoint))) { + for (IExecutionDMContext thread : threads) { + if (thread instanceof MIExecutionDMC) { + MIExecutionDMC dmc = (MIExecutionDMC) thread; + results.add(((Integer) dmc.getThreadId()).toString()); + } + } + } else { + results.add("0"); //$NON-NLS-1$ + } + + return results; + } + + /////////////////////////////////////////////////////////////////////////// + // Non-generic (MI-specific) functions + /////////////////////////////////////////////////////////////////////////// + + /** + * Create a target breakpoint from an ICBreakpoint + * + * @param breakpoint + * @param attributes + * @return + */ + protected Map convertToTargetBreakpoint(ICBreakpoint breakpoint, Map attributes) { + + Map properties = new HashMap(); + + if (breakpoint instanceof ICWatchpoint) { + // Convert the CDI watchpoint to an IBreakpoint + properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.WATCHPOINT); + properties.put(MIBreakpoints.EXPRESSION, attributes.get(ICWatchpoint.EXPRESSION)); + properties.put(MIBreakpoints.READ, attributes.get(ICWatchpoint.READ)); + properties.put(MIBreakpoints.WRITE, attributes.get(ICWatchpoint.WRITE)); + } + else { + // Convert the CDI breakpoint to an IBreakpoint + properties.put(MIBreakpoints.BREAKPOINT_TYPE, MIBreakpoints.BREAKPOINT); + properties.put(MIBreakpoints.FILE_NAME, attributes.get(ATTR_DEBUGGER_PATH)); + properties.put(MIBreakpoints.LINE_NUMBER, attributes.get(IMarker.LINE_NUMBER)); + properties.put(MIBreakpoints.FUNCTION, attributes.get(ICLineBreakpoint.FUNCTION)); + properties.put(MIBreakpoints.ADDRESS, attributes.get(ICLineBreakpoint.ADDRESS)); + } + + // Common fields + properties.put(MIBreakpoints.CONDITION, attributes.get(ICBreakpoint.CONDITION)); + properties.put(MIBreakpoints.IGNORE_COUNT, attributes.get(ICBreakpoint.IGNORE_COUNT)); + properties.put(MIBreakpoints.IS_ENABLED, attributes.get(ICBreakpoint.ENABLED)); + properties.put(MIBreakpointDMData.THREAD_ID, attributes.get(ATTR_THREAD_ID)); + + // Adjust for "skip-all" + if (!fBreakpointManager.isEnabled()) { + properties.put(MIBreakpoints.IS_ENABLED, false); + } + + return properties; + } + + /** + * Determine if the modified attributes necessitate + * a breakpoint removal/re-installation + * + * @param delta + * @return + */ + protected boolean needsResinstallation(Map delta) { + + // Check if there is any modified attribute + if (delta == null) + return false; + + // Check the "critical" attributes + if (delta.containsKey(ATTR_DEBUGGER_PATH) // File name + || delta.containsKey(IMarker.LINE_NUMBER) // Line number + || delta.containsKey(ICLineBreakpoint.FUNCTION) // Function name + || delta.containsKey(ICLineBreakpoint.ADDRESS) // Absolute address + || delta.containsKey(ATTR_THREAD_FILTER) // Thread ID + || delta.containsKey(ICWatchpoint.EXPRESSION) // Watchpoint expression + || delta.containsKey(ICWatchpoint.READ) // Watchpoint type + || delta.containsKey(ICWatchpoint.WRITE)) { // Watchpoint type + return true; + } + + return false; + } + + /** + * @param breakpoint + * @param oldValues + */ + protected void rollbackAttributes(ICBreakpoint breakpoint, IMarkerDelta oldValues) { + + try { + String new_condition = breakpoint.getCondition(); + if (new_condition == null) + new_condition = NULL_STRING; + String old_condition = (oldValues != null) ? oldValues.getAttribute(ICBreakpoint.CONDITION, NULL_STRING) : NULL_STRING; + if (!old_condition.equals(new_condition)) { + breakpoint.setCondition(old_condition); + } + else { + breakpoint.setCondition(NULL_STRING); + } + } catch (CoreException e) { + } + } + + /** + * Indicates if the back-end supports multiple threads for + * this type of breakpoint + * + * @param breakpoint + */ + protected boolean supportsThreads(ICBreakpoint breakpoint) { + + return !(breakpoint instanceof ICWatchpoint); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIFormat.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIFormat.java new file mode 100644 index 00000000000..3a2c7ee31b1 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIFormat.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service; + +import java.math.BigInteger; + +/** + * Help class to specify formats. + */ +public final class MIFormat { + public final static int HEXADECIMAL = 0; + public final static int OCTAL = 1; + public final static int BINARY = 2; + public final static int DECIMAL = 3; + public final static int RAW = 4; + public final static int NATURAL = 5; + + public final static int FLOAT = 10; + public final static int ADDRESS = 11; + public final static int INSTRUCTION = 12; + public final static int CHAR = 13; + public final static int STRING = 14; + public final static int UNSIGNED = 15; + + // no instanciation. + private MIFormat() { + } + + /** + * We are assuming that GDB will print the address in hex format + * like: + * 0xbfffe5f0 "hello" + * (int *) 0xbfffe2b8 + * + * @param buffer + * @return + */ + public static BigInteger decodeAdress(String buffer) { + int radix = 10; + int cursor = 0; + int offset = 0; + int len = buffer.length(); + + if ((offset = buffer.indexOf("0x")) != -1 || //$NON-NLS-1$ + (offset = buffer.indexOf("0X")) != -1) { //$NON-NLS-1$ + radix = 16; + cursor = offset + 2; + } + + while (cursor < len && Character.digit(buffer.charAt(cursor), radix) != -1) { + cursor++; + } + + String s = buffer.substring(offset, cursor); + return getBigInteger(s); + } + + public static BigInteger getBigInteger(String address) { + int index = 0; + int radix = 10; + boolean negative = false; + + // Handle zero length + address = address.trim(); + if (address.length() == 0) { + return BigInteger.ZERO; + } + + // Handle minus sign, if present + if (address.startsWith("-")) { //$NON-NLS-1$ + negative = true; + index++; + } + if (address.startsWith("0x", index) || address.startsWith("0X", index)) { //$NON-NLS-1$ //$NON-NLS-2$ + index += 2; + radix = 16; + } else if (address.startsWith("#", index)) { //$NON-NLS-1$ + index ++; + radix = 16; + } else if (address.startsWith("0", index) && address.length() > 1 + index) { //$NON-NLS-1$ + index ++; + radix = 8; + } + + if (index > 0) { + address = address.substring(index); + } + if (negative) { + address = "-" + address; //$NON-NLS-1$ + } + try { + return new BigInteger(address, radix); + } catch (NumberFormatException e) { + // ... + // What can we do ??? + } + return BigInteger.ZERO; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIMemory.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIMemory.java new file mode 100644 index 00000000000..d900414065d --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIMemory.java @@ -0,0 +1,895 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * Ericsson AB - expanded from initial stub + * Ericsson AB - added support for event handling + * Ericsson AB - added memory cache + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.ListIterator; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IMemory; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMAddress; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.debug.service.command.CommandCache; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.ExpressionService.ExpressionChangedEvent; +import org.eclipse.dd.mi.service.command.commands.MIDataReadMemory; +import org.eclipse.dd.mi.service.command.commands.MIDataWriteMemory; +import org.eclipse.dd.mi.service.command.output.MIDataReadMemoryInfo; +import org.eclipse.dd.mi.service.command.output.MIDataWriteMemoryInfo; +import org.eclipse.debug.core.model.MemoryByte; +import org.osgi.framework.BundleContext; + +/** + * Memory service implementation + */ +public class MIMemory extends AbstractDsfService implements IMemory { + + public class MemoryChangedEvent extends AbstractDMEvent + implements IMemoryChangedEvent + { + IAddress[] fAddresses; + IDMContext fContext; + + public MemoryChangedEvent(IMemoryDMContext context, IAddress[] addresses) { + super(context); + fAddresses = addresses; + } + + public IAddress[] getAddresses() { + return fAddresses; + } + } + + @SuppressWarnings("unused") + private MIRunControl fRunControl; + private MIMemoryCache fMemoryCache; + + /** + * Constructor + */ + public MIMemory(DsfSession session) { + super(session); + } + + /////////////////////////////////////////////////////////////////////////// + // AbstractDsfService overrides + /////////////////////////////////////////////////////////////////////////// + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#initialize(org.eclipse.dd.dsf.concurrent.RequestMonitor) + * + * This function is called during the launch sequence (where the service is + * instantiated). See LaunchSequence.java. + */ + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize(new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + doInitialize(requestMonitor); + } + }); + } + + /* + * Initialization function: + * - Register the service + * - Create the command cache + * - Register self to service events + * + * @param requestMonitor + */ + private void doInitialize(final RequestMonitor requestMonitor) { + + // Register this service + register(new String[] { MIMemory.class.getName(), IMemory.class.getName() }, new Hashtable()); + + // Get the RunControl so we can retrieve the current Execution context + fRunControl = getServicesTracker().getService(MIRunControl.class); + + // Create the memory requests cache + fMemoryCache = new MIMemoryCache(); + + // Register as service event listener + getSession().addServiceEventListener(this, null); + + // Done + requestMonitor.done(); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#shutdown(org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + @Override + public void shutdown(final RequestMonitor requestMonitor) { + + // Unregister this service + unregister(); + + // Remove event listener + getSession().removeServiceEventListener(this); + + // Clear the cache + fMemoryCache.reset(); + + // Complete the shutdown + super.shutdown(requestMonitor); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.service.AbstractDsfService#getBundleContext() + */ + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + /////////////////////////////////////////////////////////////////////////// + // IMemory + /////////////////////////////////////////////////////////////////////////// + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IMemory#getMemory(org.eclipse.dd.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, + int word_size, int count, DataRequestMonitor drm) + { + // Validate the context + if (memoryDMC == null) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + drm.done(); + return; + } + + // Validate the word size + // NOTE: We only accept 1 byte words for this implementation + if (word_size != 1) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "Word size not supported (!= 1)", null)); //$NON-NLS-1$ + drm.done(); + return; + } + + // Validate the byte count + if (count < 0) { + drm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Invalid word count (< 0)", null)); //$NON-NLS-1$ + drm.done(); + return; + } + + // All is clear: go for it + fMemoryCache.getMemory(memoryDMC, address.add(offset), word_size, count, drm); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IMemory#setMemory(org.eclipse.dd.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, byte[], org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + public void setMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, + int word_size, int count, byte[] buffer, RequestMonitor rm) + { + // Validate the context + if (memoryDMC == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + rm.done(); + return; + } + + // Validate the word size + // NOTE: We only accept 1 byte words for this implementation + if (word_size != 1) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "Word size not supported (!= 1)", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Validate the byte count + if (count < 0) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Invalid word count (< 0)", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Validate the buffer size + if (buffer.length < count) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Buffer too short", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // All is clear: go for it + fMemoryCache.setMemory(memoryDMC, address, offset, word_size, count, buffer, rm); + } + + /* (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IMemory#fillMemory(org.eclipse.dd.dsf.datamodel.IDMContext, org.eclipse.cdt.core.IAddress, long, int, byte[], org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + public void fillMemory(IMemoryDMContext memoryDMC, IAddress address, long offset, + int word_size, int count, byte[] pattern, RequestMonitor rm) + { + // Validate the context + if (memoryDMC == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown context type", null)); //$NON-NLS-1$); + rm.done(); + return; + } + + // Validate the word size + // NOTE: We only accept 1 byte words for this implementation + if (word_size != 1) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.NOT_SUPPORTED, "Word size not supported (!= 1)", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Validate the repeat count + if (count < 0) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Invalid repeat count (< 0)", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Validate the pattern + if (pattern.length < 1) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Empty pattern", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create an aggregate buffer so we can write in 1 shot + int length = pattern.length; + byte[] buffer = new byte[count * length]; + for (int i = 0; i < count; i++) { + System.arraycopy(pattern, 0, buffer, i * length, length); + } + + // All is clear: go for it + fMemoryCache.setMemory(memoryDMC, address, offset, word_size, count * length, buffer, rm); + } + + ////////////////////////////////////////////////////////////////////////// + // Event handlers + ////////////////////////////////////////////////////////////////////////// + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.IResumedDMEvent e) { + fMemoryCache.setTargetAvailable(false); + if (e.getReason() != StateChangeReason.STEP) { + fMemoryCache.reset(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.ISuspendedDMEvent e) { + fMemoryCache.setTargetAvailable(true); + fMemoryCache.reset(); + } + + @DsfServiceEventHandler + public void eventDispatched(ExpressionChangedEvent e) { + + // Get the context and expression service handle + final IExpressionDMContext context = e.getDMContext(); + IExpressions expressionService = getServicesTracker().getService(IExpressions.class); + + // Get the variable information and update the corresponding memory locations + if (expressionService != null) { + expressionService.getExpressionAddressData(context, + new DataRequestMonitor(getExecutor(), null) { + @Override + protected void handleOK() { + // Figure out which memory area was modified + IExpressionDMAddress expression = getData(); + final int count = expression.getSize(); + IAddress expAddress = expression.getAddress(); + final Addr64 address; + if (expAddress instanceof Addr64) + address = (Addr64) expAddress; + else + address = new Addr64(expAddress.getValue()); + + final IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, IMemoryDMContext.class); + fMemoryCache.refreshMemory(memoryDMC, address, 0, 1, count, + new RequestMonitor(getExecutor(), null)); + } + }); + } + } + + /////////////////////////////////////////////////////////////////////////// + // SortedLinkedlist + /////////////////////////////////////////////////////////////////////////// + + // This class is really the equivalent of a C struct (old habits die hard...) + // For simplicity, everything is public. + private class MemoryBlock { + public IAddress fAddress; + public long fLength; + public MemoryByte[] fBlock; + public MemoryBlock(IAddress address, long length, MemoryByte[] block) { + fAddress = address; + fLength = length; + fBlock = block; + } + } + + // Address-ordered data structure to cache the memory blocks. + // Contiguous blocks are merged if possible. + @SuppressWarnings("serial") + private class SortedMemoryBlockList extends LinkedList { + + public SortedMemoryBlockList() { + super(); + } + + // Insert the block in the sorted linked list and merge contiguous + // blocks if necessary + @Override + @SuppressWarnings("unchecked") + public boolean add(MemoryBlock block) { + + // If the list is empty, just store the block + if (isEmpty()) { + addFirst(block); + return true; + } + + // Insert the block at the correct location and then + // merge the blocks if possible + ListIterator it = listIterator(); + while (it.hasNext()) { + int index = it.nextIndex(); + MemoryBlock item = it.next(); + if (block.fAddress.compareTo(item.fAddress) < 0) { + add(index, block); + compact(index); + return true; + } + } + + // Put at the end of the list and merge if necessary + addLast(block); + compact(size() - 1); + return true; + } + + // Merge this block with its contiguous neighbors (if any) + // Note: Merge is not performed if resulting block size would exceed MAXINT + private void compact(int index) { + + MemoryBlock newBlock = get(index); + + // Case where the block is to be merged with the previous block + if (index > 0) { + MemoryBlock prevBlock = get(index - 1); + IAddress endOfPreviousBlock = prevBlock.fAddress.add(prevBlock.fLength); + if (endOfPreviousBlock.distanceTo(newBlock.fAddress).longValue() == 0) { + long newLength = prevBlock.fLength + newBlock.fLength; + if (newLength <= Integer.MAX_VALUE) { + MemoryByte[] block = new MemoryByte[(int) newLength] ; + System.arraycopy(prevBlock.fBlock, 0, block, 0, (int) prevBlock.fLength); + System.arraycopy(newBlock.fBlock, 0, block, (int) prevBlock.fLength, (int) newBlock.fLength); + newBlock = new MemoryBlock(prevBlock.fAddress, newLength, block); + remove(index); + index -= 1; + set(index, newBlock); + } + } + } + + // Case where the block is to be merged with the following block + int lastIndex = size() - 1; + if (index < lastIndex) { + MemoryBlock nextBlock = get(index + 1); + IAddress endOfNewBlock = newBlock.fAddress.add(newBlock.fLength); + if (endOfNewBlock.distanceTo(nextBlock.fAddress).longValue() == 0) { + long newLength = newBlock.fLength + nextBlock.fLength; + if (newLength <= Integer.MAX_VALUE) { + MemoryByte[] block = new MemoryByte[(int) newLength] ; + System.arraycopy(newBlock.fBlock, 0, block, 0, (int) newBlock.fLength); + System.arraycopy(nextBlock.fBlock, 0, block, (int) newBlock.fLength, (int) nextBlock.fLength); + newBlock = new MemoryBlock(newBlock.fAddress, newLength, block); + set(index, newBlock); + remove(index + 1); + } + } + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // MIMemoryCache + /////////////////////////////////////////////////////////////////////////// + + private class MIMemoryCache { + + // Back-end commands cache + private CommandCache fCommandCache; + + // The memory cache data structure + private SortedMemoryBlockList fMemoryBlockList; + + public MIMemoryCache() { + // Create the command cache + fCommandCache = new CommandCache(getServicesTracker().getService(ICommandControl.class)); + // Create the memory block cache + fMemoryBlockList = new SortedMemoryBlockList(); + } + + public void reset() { + // Clear the command cache + fCommandCache.reset(); + // Clear the memory cache + fMemoryBlockList.clear(); + } + + public void setTargetAvailable(boolean isAvailable) { + fCommandCache.setTargetAvailable(isAvailable); + } + + public boolean isTargetAvailable() { + return fCommandCache.isTargetAvailable(); + } + + /** + * This function walks the address-sorted memory block list to identify + * the 'missing' blocks (i.e. the holes) that need to be fetched on the target. + * + * The idea is fairly simple but an illustration could perhaps help. + * Assume the cache holds a number of cached memory blocks with gaps i.e. + * there is un-cached memory areas between blocks A, B and C: + * + * +---------+ +---------+ +---------+ + * + A + + B + + C + + * +---------+ +---------+ +---------+ + * : : : : : : + * [a] : : [b] : : [c] : : [d] + * : : : : : : + * [e---+--] : [f--+---------+--] : : + * [g---+---------+------+---------+------+---------+----] + * : : : : : : + * : [h] : : [i----+--] : : + * + * + * We have the following cases to consider.The requested block [a-i] either: + * + * [1] Fits entirely before A, in one of the gaps, or after C + * with no overlap and no contiguousness (e.g. [a], [b], [c] and [d]) + * -> Add the requested block to the list of blocks to fetch + * + * [2] Starts before an existing block but overlaps part of it, possibly + * spilling in the gap following the cached block (e.g. [e], [f] and [g]) + * -> Determine the length of the missing part (< count) + * -> Add a request to fill the gap before the existing block + * -> Update the requested block for the next iteration: + * - Start address to point just after the end of the cached block + * - Count reduced by cached block length (possibly becoming negative, e.g. [e]) + * At this point, the updated requested block starts just beyond the cached block + * for the next iteration. + * + * [3] Starts at or into an existing block and overlaps part of it ([h] and [i]) + * -> Update the requested block for the next iteration: + * - Start address to point just after the end of the cached block + * - Count reduced by length to end of cached block (possibly becoming negative, e.g. [h]) + * At this point, the updated requested block starts just beyond the cached block + * for the next iteration. + * + * We iterate over the cached blocks list until there is no entry left or until + * the remaining requested block count is <= 0, meaning the result list contains + * only the sub-blocks needed to fill the gap(s), if any. + * + * (As is often the case, it takes much more typing to explain it than to just do it :-) + * + * @param reqBlockStart The address of the requested block + * @param count Its length + * @return A list of the sub-blocks to fetch in order to fill enough gaps in the memory cache + * to service the request + */ + private LinkedList getListOfMissingBlocks(IAddress reqBlockStart, int count) { + + LinkedList list = new LinkedList(); + ListIterator it = fMemoryBlockList.listIterator(); + + // Look for holes in the list of memory blocks + while (it.hasNext() && count > 0) { + MemoryBlock cachedBlock = it.next(); + IAddress cachedBlockStart = cachedBlock.fAddress; + IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLength); + + // Case where we miss a block before the cached block + if (reqBlockStart.distanceTo(cachedBlockStart).longValue() >= 0) { + int length = (int) Math.min(reqBlockStart.distanceTo(cachedBlockStart).longValue(), count); + // If both blocks start at the same location, no need to create a new cached block + if (length > 0) { + MemoryBlock newBlock = new MemoryBlock(reqBlockStart, length, new MemoryByte[0]); + list.add(newBlock); + } + // Adjust request block start and length for the next iteration + reqBlockStart = cachedBlockEnd; + count -= length + cachedBlock.fLength; + } + + // Case where the requested block starts somewhere in the cached block + else if (cachedBlockStart.distanceTo(reqBlockStart).longValue() > 0 + && reqBlockStart.distanceTo(cachedBlockEnd).longValue() >= 0) + { + // Start of the requested block already in cache + // Adjust request block start and length for the next iteration + count -= reqBlockStart.distanceTo(cachedBlockEnd).longValue(); + reqBlockStart = cachedBlockEnd; + } + } + + // Case where we miss a block at the end of the cache + if (count > 0) { + MemoryBlock newBlock = new MemoryBlock(reqBlockStart, count, new MemoryByte[0]); + list.add(newBlock); + } + + return list; + } + + /** + * This function walks the address-sorted memory block list to get the + * cached memory bytes (possibly from multiple contiguous blocks). + * This function is called *after* the missing blocks have been read from + * the back end i.e. the requested memory is all cached. + * + * Again, this is fairly simple. As we loop over the address-ordered list, + * There are really only 2 cases: + * + * [1] The requested block fits entirely in the cached block ([a] or [b]) + * [2] The requested block starts in a cached block and ends in the + * following (contiguous) one ([c]) in which case it is treated + * as 2 contiguous requests ([c'] and [c"]) + * + * +--------------+--------------+ + * + A + B + + * +--------------+--------------+ + * : [a----] : [b-----] : + * : : : + * : [c-----+------] : + * : [c'---]+[c"---] : + * + * @param reqBlockStart The address of the requested block + * @param count Its length + * @return The cached memory content + */ + private MemoryByte[] getMemoryBlockFromCache(IAddress reqBlockStart, int count) { + + IAddress reqBlockEnd = reqBlockStart.add(count); + MemoryByte[] resultBlock = new MemoryByte[count]; + ListIterator iter = fMemoryBlockList.listIterator(); + + while (iter.hasNext()) { + MemoryBlock cachedBlock = iter.next(); + IAddress cachedBlockStart = cachedBlock.fAddress; + IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLength); + + // Case where the cached block overlaps completely the requested memory block + if (cachedBlockStart.distanceTo(reqBlockStart).longValue() >= 0 + && reqBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) + { + int pos = (int) cachedBlockStart.distanceTo(reqBlockStart).longValue(); + System.arraycopy(cachedBlock.fBlock, pos, resultBlock, 0, count); + } + + // Case where the beginning of the cached block is within the requested memory block + else if (reqBlockStart.distanceTo(cachedBlockStart).longValue() >= 0 + && cachedBlockStart.distanceTo(reqBlockEnd).longValue() > 0) + { + int pos = (int) reqBlockStart.distanceTo(cachedBlockStart).longValue(); + int length = (int) Math.min(cachedBlock.fLength, count - pos); + System.arraycopy(cachedBlock.fBlock, 0, resultBlock, pos, length); + } + + // Case where the end of the cached block is within the requested memory block + else if (cachedBlockStart.distanceTo(reqBlockStart).longValue() >= 0 + && reqBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) + { + int pos = (int) cachedBlockStart.distanceTo(reqBlockStart).longValue(); + int length = (int) Math.min(cachedBlock.fLength - pos, count); + System.arraycopy(cachedBlock.fBlock, pos, resultBlock, 0, length); + } + } + return resultBlock; + } + + /** + * This function walks the address-sorted memory block list and updates + * the content with the actual memory just read from the target. + * + * @param modBlockStart + * @param count + * @param modBlock + */ + private void updateMemoryCache(IAddress modBlockStart, int count, MemoryByte[] modBlock) { + + IAddress modBlockEnd = modBlockStart.add(count); + ListIterator iter = fMemoryBlockList.listIterator(); + + while (iter.hasNext()) { + MemoryBlock cachedBlock = iter.next(); + IAddress cachedBlockStart = cachedBlock.fAddress; + IAddress cachedBlockEnd = cachedBlock.fAddress.add(cachedBlock.fLength); + + // For now, we only bother to update bytes already cached. + // Note: In a better implementation (v1.1), we would augment + // the cache with the missing memory blocks since we went + // through the pains of reading them in the first place. + // (this is left as an exercise to the reader :-) + + // Case where the modified block is completely included in the cached block + if (cachedBlockStart.distanceTo(modBlockStart).longValue() >= 0 + && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) + { + int pos = (int) cachedBlockStart.distanceTo(modBlockStart).longValue(); + System.arraycopy(modBlock, 0, cachedBlock.fBlock, pos, count); + } + + // Case where the beginning of the modified block is within the cached block + else if (cachedBlockStart.distanceTo(modBlockStart).longValue() >= 0 + && modBlockStart.distanceTo(cachedBlockEnd).longValue() > 0) + { + int pos = (int) cachedBlockStart.distanceTo(modBlockStart).longValue(); + int length = (int) cachedBlockStart.distanceTo(modBlockEnd).longValue(); + System.arraycopy(modBlock, 0, cachedBlock.fBlock, pos, length); + } + + // Case where the end of the modified block is within the cached block + else if (cachedBlockStart.distanceTo(modBlockEnd).longValue() > 0 + && modBlockEnd.distanceTo(cachedBlockEnd).longValue() >= 0) + { + int pos = (int) modBlockStart.distanceTo(cachedBlockStart).longValue(); + int length = (int) cachedBlockStart.distanceTo(modBlockEnd).longValue(); + System.arraycopy(modBlock, pos, cachedBlock.fBlock, 0, length); + } + } + return; + } + + /** + * @param memoryDMC + * @param address the memory block address (on the target) + * @param word_size the size, in bytes, of an addressable item + * @param count the number of bytes to read + * @param drm the asynchronous data request monitor + */ + public void getMemory(IMemoryDMContext memoryDMC, final IAddress address, final int word_size, + final int count, final DataRequestMonitor drm) + { + // Determine the number of read requests to issue + LinkedList missingBlocks = getListOfMissingBlocks(address, count); + int numberOfRequests = missingBlocks.size(); + + // A read request will be issued for each block needed + // so we need to keep track of the count + final CountingRequestMonitor countingRM = + new CountingRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + // We received everything so read the result from the memory cache + drm.setData(getMemoryBlockFromCache(address, count)); + drm.done(); + } + }; + countingRM.setDoneCount(numberOfRequests); + + // Issue the read requests + for (int i = 0; i < numberOfRequests; i++) { + MemoryBlock block = missingBlocks.get(i); + final IAddress startAddress = block.fAddress; + final int length = (int) block.fLength; + readMemoryBlock(memoryDMC, startAddress, 0, word_size, length, + new DataRequestMonitor(getSession().getExecutor(), drm) { + @Override + protected void handleOK() { + MemoryByte[] block = new MemoryByte[count]; + block = getData(); + MemoryBlock memoryBlock = new MemoryBlock(startAddress, length, block); + fMemoryBlockList.add(memoryBlock); + countingRM.done(); + } + }); + } + } + + /** + * @param memoryDMC + * @param address the memory block address (on the target) + * @param offset the offset from the start address + * @param word_size the size, in bytes, of an addressable item + * @param count the number of bytes to write + * @param buffer the source buffer + * @param rm the asynchronous request monitor + */ + public void setMemory(final IMemoryDMContext memoryDMC, final IAddress address, + final long offset, final int word_size, final int count, final byte[] buffer, + final RequestMonitor rm) + { + writeMemoryBlock( + memoryDMC, address, offset, word_size, count, buffer, + new RequestMonitor(getSession().getExecutor(), rm) { + @Override + protected void handleOK() { + // Clear the command cache (otherwise we can't guarantee + // that the subsequent memory read will be correct) + fCommandCache.reset(); + + // Asynchronous update of the memory cache + final DataRequestMonitor drm = + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + updateMemoryCache(address.add(offset), count, getData()); + // Send the MemoryChangedEvent + IAddress[] addresses = new IAddress[count]; + for (int i = 0; i < count; i++) { + addresses[i] = address.add(offset + i); + } + getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties()); + // Finally... + rm.done(); + } + }; + + // Re-read the modified memory block + readMemoryBlock(memoryDMC, address, offset, word_size, count, + new DataRequestMonitor(getExecutor(), drm) { + @Override + public void handleOK() { + drm.setData(getData()); + drm.done(); + } + }); + } + }); + } + + /** + * @param memoryDMC + * @param address + * @param offset + * @param word_size + * @param count + * @param rm + */ + public void refreshMemory(final IMemoryDMContext memoryDMC, final IAddress address, + final long offset, final int word_size, final int count, final RequestMonitor rm) + { + // Check if we already cache part of this memory area (which means it + // is used by a memory service client that will have to be updated) + LinkedList list = fMemoryCache.getListOfMissingBlocks(address, count); + int sizeToRead = 0; + for (MemoryBlock block : list) { + sizeToRead += block.fLength; + } + + // If none of the requested memory is in cache, just get out + if (sizeToRead == count) { + rm.done(); + return; + } + + // Prepare the data for the MemoryChangedEvent + final IAddress[] addresses = new IAddress[count]; + for (int i = 0; i < count; i++) { + addresses[i] = address.add(i); + } + + // Read the corresponding memory block + fMemoryCache.fCommandCache.reset(); + fMemoryCache.readMemoryBlock(memoryDMC, address, 0, 1, count, + new DataRequestMonitor(getExecutor(), rm) { + @Override + public void handleOK() { + fMemoryCache.updateMemoryCache(address, count, getData()); + getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties()); + rm.done(); + } + }); + } + + /////////////////////////////////////////////////////////////////////// + // Back-end functions + /////////////////////////////////////////////////////////////////////// + + /** + * @param memoryDMC + * @param address + * @param offset + * @param word_size + * @param count + * @param drm + */ + private void readMemoryBlock(IMemoryDMContext memoryDMC, IAddress address, final long offset, + final int word_size, final int count, final DataRequestMonitor drm) + { + /* To simplify the parsing of the MI result, we request the output to + * be on 1 row of [count] columns, no char interpretation. + */ + int mode = MIFormat.HEXADECIMAL; + int nb_rows = 1; + int nb_cols = count; + Character asChar = null; + + fCommandCache.execute( + new MIDataReadMemory(memoryDMC, offset, address.toString(), mode, word_size, nb_rows, nb_cols, asChar), + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + // Retrieve the memory block + drm.setData(getData().getMIMemoryBlock()); + drm.done(); + } + } + ); + } + + /** + * @param memoryDMC + * @param address + * @param offset + * @param word_size + * @param count + * @param buffer + * @param rm + */ + private void writeMemoryBlock(final IMemoryDMContext memoryDMC, final IAddress address, final long offset, + final int word_size, final int count, final byte[] buffer, final RequestMonitor rm) + { + // Each byte is written individually (GDB power...) + // so we need to keep track of the count + final CountingRequestMonitor countingRM = + new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.done(); + } + }; + countingRM.setDoneCount(count); + + // We will format the individual bytes in decimal + int format = MIFormat.DECIMAL; + String baseAddress = address.toString(); + + // Issue an MI request for each byte to write + for (int i = 0; i < count; i++) { + String value = new Byte(buffer[i]).toString(); + fCommandCache.execute( + new MIDataWriteMemory(memoryDMC, offset + i, baseAddress, format, word_size, value), + new DataRequestMonitor(getExecutor(), countingRM) + ); + } + } + + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIModules.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIModules.java new file mode 100644 index 00000000000..64a8a86b291 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIModules.java @@ -0,0 +1,217 @@ +/******************************************************************************* + * Copyright (c) 2007 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 + * Ericsson AB - Modules implementation for GDB + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import java.math.BigInteger; +import java.util.Hashtable; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IModules; +import org.eclipse.dd.dsf.debug.service.command.CommandCache; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.CLIInfoSharedLibrary; +import org.eclipse.dd.mi.service.command.output.CLIInfoSharedLibraryInfo; +import org.eclipse.dd.mi.service.command.output.CLIInfoSharedLibraryInfo.DsfMISharedInfo; +import org.osgi.framework.BundleContext; + +/** + * + */ +public class MIModules extends AbstractDsfService implements IModules { + private CommandCache fModulesCache; + + public MIModules(DsfSession session) { + super(session); + } + + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + doInitialize(requestMonitor); + }}); + } + + private void doInitialize(RequestMonitor requestMonitor) { + // Cache for holding Modules data + fModulesCache = new CommandCache(getServicesTracker().getService(ICommandControl.class)); + /* + * Make ourselves known so clients can use us. + */ + register(new String[]{IModules.class.getName(), MIModules.class.getName()}, new Hashtable()); + + requestMonitor.done(); + } + + @Override + public void shutdown(RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } + + static class ModuleDMContext extends AbstractDMContext implements IModuleDMContext { + private final String fFile; + ModuleDMContext(MIModules service, IDMContext[] parents, String file) { + super(service, parents); + fFile = file; + } + + @Override + public boolean equals(Object obj) { + return baseEquals(obj) && fFile.equals(((ModuleDMContext)obj).fFile); + } + + @Override + public int hashCode() { + return baseHashCode() + fFile.hashCode(); + } + } + + static class ModuleDMData implements IModuleDMData { + private final String fFile; + private final String fFromAddress; + private final String fToAddress; + private final boolean fIsSymbolsRead; + + public ModuleDMData(ModuleDMContext dmc) { + fFile = dmc.fFile; + fFromAddress = null; + fToAddress = null; + fIsSymbolsRead = false; + } + + public ModuleDMData(String fileName, String fromAddress, String toAddress, boolean isSymsRead){ + fFile = fileName; + fFromAddress = fromAddress; + fToAddress = toAddress; + fIsSymbolsRead = isSymsRead; + } + + public String getFile() { + return fFile; + } + + public String getName() { + return fFile; + } + + public long getTimeStamp() { + return 0; + } + + public String getBaseAddress() { + return fFromAddress; + } + + public String getToAddress() { + return fToAddress; + } + + public boolean isSymbolsLoaded() { + return fIsSymbolsRead; + } + + public long getSize() { + long result = 0; + if(getBaseAddress() == null || getToAddress() == null) + return result; + BigInteger start = MIFormat.getBigInteger(getBaseAddress()); + BigInteger end = MIFormat.getBigInteger(getToAddress()); + if ( end.compareTo( start ) > 0 ) + result = end.subtract( start ).longValue(); + return result; + } + + } + + public void getModules(final ISymbolDMContext symCtx, final DataRequestMonitor rm) { + if(symCtx != null){ + fModulesCache.execute(new CLIInfoSharedLibrary(symCtx), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(makeModuleContexts(symCtx, getData())); + rm.done(); + } + }); + } + else{ + rm.setData(new IModuleDMContext[] { new ModuleDMContext(this, DMContexts.EMPTY_CONTEXTS_ARRAY, "example module 1"), new ModuleDMContext(this, DMContexts.EMPTY_CONTEXTS_ARRAY, "example module 2") }); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + } + } + + private IModuleDMContext[] makeModuleContexts(IDMContext symCtxt, CLIInfoSharedLibraryInfo info){ + + DsfMISharedInfo[] sharedInfos = info.getMIShared(); + ModuleDMContext[] modules = new ModuleDMContext[sharedInfos.length]; + int i = 0; + for(DsfMISharedInfo shared : sharedInfos){ + modules[i++] = new ModuleDMContext(this, new IDMContext[]{symCtxt}, shared.getName()); + } + return modules; + } + + public void getModuleData(final IModuleDMContext dmc, final DataRequestMonitor rm) { + assert dmc != null; + if (dmc instanceof ModuleDMContext) { + fModulesCache.execute(new CLIInfoSharedLibrary(dmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData( createSharedLibInfo((ModuleDMContext)dmc, getData()) ); + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DM Context", null)); //$NON-NLS-1$ + rm.done(); + } + } + + private IModuleDMData createSharedLibInfo(ModuleDMContext dmc, CLIInfoSharedLibraryInfo info){ + for (CLIInfoSharedLibraryInfo.DsfMISharedInfo shared : info.getMIShared()) { + if(shared.getName().equals(dmc.fFile)){ + return new ModuleDMData(shared.getName(), shared.getFrom(), shared.getTo(), shared.isRead()); + } + } + return new ModuleDMData("","", "", false); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + } + + public void calcAddressInfo(ISymbolDMContext symCtx, String file, int line, int col, DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Functionality not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + public void calcLineInfo(ISymbolDMContext symCtx, IAddress address, DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Functionality not supported", null)); //$NON-NLS-1$ + rm.done(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRegisters.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRegisters.java new file mode 100644 index 00000000000..56c17b4eb45 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRegisters.java @@ -0,0 +1,583 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * Ericsson - Modified for additional features in DSF Reference Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import java.util.Hashtable; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IRegisters; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMData; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.debug.service.command.CommandCache; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.MIDataListRegisterNames; +import org.eclipse.dd.mi.service.command.commands.MIDataListRegisterValues; +import org.eclipse.dd.mi.service.command.output.MIDataListRegisterNamesInfo; +import org.eclipse.dd.mi.service.command.output.MIDataListRegisterValuesInfo; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIRegisterValue; +import org.osgi.framework.BundleContext; + + +/** + * + *

+ * Implementation note: + * This class implements event handlers for the events that are generated by + * this service itself. When the event is dispatched, these handlers will + * be called first, before any of the clients. These handlers update the + * service's internal state information to make them consistent with the + * events being issued. Doing this in the handlers as opposed to when + * the events are generated, guarantees that the state of the service will + * always be consistent with the events. + */ + +public class MIRegisters extends AbstractDsfService implements IRegisters { + private static final String BLANK_STRING = ""; //$NON-NLS-1$ + /* + * Support class used to construct Register Group DMCs. + */ + + public static class MIRegisterGroupDMC extends AbstractDMContext implements IRegisterGroupDMContext { + private int fGroupNo; + private String fGroupName; + + public MIRegisterGroupDMC(MIRegisters service, IContainerDMContext contDmc, int groupNo, String groupName) { + super(service.getSession().getId(), new IDMContext[] { contDmc }); + fGroupNo = groupNo; + fGroupName = groupName; + } + + public int getGroupNo() { return fGroupNo; } + public String getName() { return fGroupName; } + + @Override + public boolean equals(Object other) { + return ((super.baseEquals(other)) && (((MIRegisterGroupDMC) other).fGroupNo == fGroupNo) && + (((MIRegisterGroupDMC) other).fGroupName.equals(fGroupName))); + } + + @Override + public int hashCode() { return super.baseHashCode() ^ fGroupNo; } + @Override + public String toString() { return baseToString() + ".group[" + fGroupNo + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + } + + /* + * Support class used to construct Register DMCs. + */ + + public static class MIRegisterDMC extends AbstractDMContext implements IRegisterDMContext { + private int fRegNo; + private String fRegName; + + public MIRegisterDMC(MIRegisters service, MIRegisterGroupDMC group, int regNo, String regName) { + super(service.getSession().getId(), + new IDMContext[] { group }); + fRegNo = regNo; + fRegName = regName; + } + + public MIRegisterDMC(MIRegisters service, MIRegisterGroupDMC group, IMIExecutionDMContext execDmc, int regNo, String regName) { + super(service.getSession().getId(), + new IDMContext[] { execDmc, group }); + fRegNo = regNo; + fRegName = regName; + } + + public int getRegNo() { return fRegNo; } + public String getName() { return fRegName; } + + @Override + public boolean equals(Object other) { + return ((super.baseEquals(other)) && (((MIRegisterDMC) other).fRegNo == fRegNo) && + (((MIRegisterDMC) other).fRegName.equals(fRegName))); + } + + @Override + public int hashCode() { return super.baseHashCode() ^ fRegNo; } + @Override + public String toString() { return baseToString() + ".register[" + fRegNo + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + } + + /* + * Event class to notify register value is changed + */ + public static class RegisterChangedDMEvent implements IRegisters.IRegisterChangedDMEvent { + + private final IRegisterDMContext fRegisterDmc; + + RegisterChangedDMEvent(IRegisterDMContext registerDMC) { + fRegisterDmc = registerDMC; + } + + public IRegisterDMContext getDMContext() { + return fRegisterDmc; + } + } + + /* + * Internal control variables. + */ + + private MIRegisterGroupDMC fGeneralRegistersGroupDMC; + private CommandCache fRegisterNameCache; // Cache for holding the Register Names in the single Group + private CommandCache fRegisterValueCache; // Cache for holding the Register Values + + public MIRegisters(DsfSession session) + { + super(session); + } + + @Override + protected BundleContext getBundleContext() + { + return MIPlugin.getBundleContext(); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + doInitialize(requestMonitor); + }}); + } + + private void doInitialize(RequestMonitor requestMonitor) { + /* + * Create the lower level register cache. + */ + fRegisterValueCache = new CommandCache(getServicesTracker().getService(ICommandControl.class)); + fRegisterNameCache = new CommandCache(getServicesTracker().getService(ICommandControl.class)); + + /* + * Signup so we see events. We use these events to decide how to manage + * any local caches we are providing as well as the lower level register + * cache we create to get/set registers on the target. + */ + getSession().addServiceEventListener(this, null); + + /* + * Make ourselves known so clients can use us. + */ + register(new String[]{IRegisters.class.getName(), MIRegisters.class.getName()}, new Hashtable()); + + requestMonitor.done(); + } + + @Override + public void shutdown(RequestMonitor requestMonitor) + { + unregister(); + getSession().removeServiceEventListener(this); + super.shutdown(requestMonitor); + } + + public boolean isValid() { return true; } + + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, DataRequestMonitor rm) { + /* + * This is the method which is called when actual results need to be returned. We + * can be called either with a service DMC for which we return oureslves or we can + * be called with the DMC's we have handed out. If the latter is the case then we + * datamine by talking to the Debug Engine. + */ + + if (dmc instanceof MIRegisterGroupDMC) { + getRegisterGroupData((MIRegisterGroupDMC)dmc, (DataRequestMonitor)rm); + } else if (dmc instanceof MIRegisterDMC) { + getRegisterData((MIRegisterDMC)dmc, (DataRequestMonitor)rm); + } else if (dmc instanceof FormattedValueDMContext) { + getFormattedExpressionValue((FormattedValueDMContext)dmc, (DataRequestMonitor)rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, -1, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor rm) { + if (dmc.getParents().length == 1 && dmc.getParents()[0] instanceof MIRegisterDMC) { + getRegisterDataValue( (MIRegisterDMC) dmc.getParents()[0], dmc.getFormatID(), rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void getRegisterGroupData(IRegisterGroupDMContext regGroupDmc, DataRequestMonitor rm) { + /** + * For the GDB GDBMI implementation there is only on group. The GPR and FPU registers are grouped into + * one set. We are going to hard wire this set as the "General Registers". + */ + class RegisterGroupData implements IRegisterGroupDMData { + public String getName() { return "General Registers"; } //$NON-NLS-1$ + public String getDescription() { return "General Purpose and FPU Register Group"; } //$NON-NLS-1$ + } + + rm.setData( new RegisterGroupData() ) ; + rm.done(); + } + + public void getBitFieldData(IBitFieldDMContext dmc, DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Bit fields not yet supported", null)); //$NON-NLS-1$ + rm.done(); + } + + /** + * For the GDB GDBMI implementation there is only on group. We represent + * this group as a single list we maintain within this service. So we + * need to search this list to see if we have a current value. + */ + public void getRegisterData(IRegisterDMContext regDmc , final DataRequestMonitor rm) { + if (regDmc instanceof MIRegisterDMC) { + final MIRegisterDMC miRegDmc = (MIRegisterDMC)regDmc; + IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(regDmc, IMIExecutionDMContext.class); + // Create register DMC with name if execution DMC is not present. + if(execDmc == null){ + rm.setData(new RegisterData(miRegDmc.getName(), BLANK_STRING, false)); + rm.done(); + return; + } + + int[] regnos = {miRegDmc.getRegNo()}; + fRegisterValueCache.execute( + new MIDataListRegisterValues(execDmc, MIFormat.HEXADECIMAL, regnos), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Retrieve the register value. + MIRegisterValue[] regValue = getData().getMIRegisterValues(); + + // If the list is empty just return empty handed. + if (regValue.length == 0) { + assert false : "Backend protocol error"; //$NON-NLS-1$ + //done.setStatus(new Status(IStatus.ERROR, IDsfService.INTERNAL_ERROR ,)); + rm.done(); + return; + } + + // We can determine if the register is floating point because + // GDB returns this additional information as part of the value. + MIRegisterValue reg = regValue[0]; + boolean isFloat = false; + + if ( reg.getValue().contains("float")) { //$NON-NLS-1$ + isFloat = true; + } + + // Return the new register attributes. + rm.setData(new RegisterData(miRegDmc.getName(), BLANK_STRING, isFloat)); + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + private void getRegisterDataValue( final MIRegisterDMC regDmc, final String formatId, final DataRequestMonitor rm) { + IMIExecutionDMContext miExecDmc = DMContexts.getAncestorOfType(regDmc, IMIExecutionDMContext.class); + if(miExecDmc == null){ + // Set value to blank if execution dmc is not present + rm.setData( new FormattedValueDMData( BLANK_STRING ) ); + rm.done(); + return; + } + + // Select the format to be shown + int NumberFormat = MIFormat.HEXADECIMAL; + + if ( HEX_FORMAT.equals ( formatId ) ) { NumberFormat = MIFormat.HEXADECIMAL; } + if ( OCTAL_FORMAT.equals ( formatId ) ) { NumberFormat = MIFormat.OCTAL; } + if ( NATURAL_FORMAT.equals( formatId ) ) { NumberFormat = MIFormat.NATURAL; } + if ( BINARY_FORMAT.equals ( formatId ) ) { NumberFormat = MIFormat.BINARY; } + if ( DECIMAL_FORMAT.equals( formatId ) ) { NumberFormat = MIFormat.DECIMAL; } + + int[] regnos = {regDmc.getRegNo()}; + fRegisterValueCache.execute( + new MIDataListRegisterValues(miExecDmc, NumberFormat, regnos), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Retrieve the register value. + MIRegisterValue[] regValue = getData().getMIRegisterValues(); + + // If the list is empty just return empty handed. + if (regValue.length == 0) { + assert false : "Backend protocol error"; //$NON-NLS-1$ + //done.setStatus(new Status(IStatus.ERROR, IDsfService.INTERNAL_ERROR ,)); + rm.done(); + return; + } + + MIRegisterValue reg = regValue[0]; + + // Return the new register value. + rm.setData( new FormattedValueDMData( reg.getValue() ) ); + rm.done(); + } + }); + } + + static class RegisterData implements IRegisterDMData { + + final private String fRegName; + final private String fRegDesc; + final private boolean fIsFloat; + + public RegisterData(String regName, String regDesc, boolean isFloat ) { + + fRegName = regName; + fRegDesc = regDesc; + fIsFloat = isFloat; + } + + public boolean isReadable() { return true; } + public boolean isReadOnce() { return false; } + public boolean isWriteable() { return true; } + public boolean isWriteOnce() { return false; } + public boolean hasSideEffects() { return false; } + public boolean isVolatile() { return true; } + + public boolean isFloat() { return fIsFloat; } + public String getName() { return fRegName; } + public String getDescription() { return fRegDesc; } + } + + // Wraps a list of registers in DMContexts. + private MIRegisterDMC[] makeRegisterDMCs(MIRegisterGroupDMC groupDmc, String[] regNames) { + return makeRegisterDMCs(groupDmc, null, regNames); + } + + // Wraps a list of registers in DMContexts. + private MIRegisterDMC[] makeRegisterDMCs(MIRegisterGroupDMC groupDmc, IMIExecutionDMContext execDmc, String[] regNames) { + MIRegisterDMC[] regDmcList = new MIRegisterDMC[regNames.length]; + int regNo = 0 ; + for (String regName : regNames) { + if(execDmc != null) + regDmcList[regNo] = new MIRegisterDMC(this, groupDmc, execDmc, regNo, regName); + else + regDmcList[regNo] = new MIRegisterDMC(this, groupDmc, regNo, regName); + regNo++; + } + + return regDmcList; + } + + /* + * Event handling section. These event handlers control the caching state of the + * register caches. This service creates several cache objects. Not all of which + * need to be flushed. These handlers maintain the state of the caches. + */ + + @DsfServiceEventHandler public void eventDispatched(IRunControl.IResumedDMEvent e) { + fRegisterValueCache.setTargetAvailable(false); + if (e.getReason() != StateChangeReason.STEP) { + fRegisterValueCache.reset(); + } + } + + @DsfServiceEventHandler public void eventDispatched( + IRunControl.ISuspendedDMEvent e) { + fRegisterValueCache.setTargetAvailable(true); + fRegisterValueCache.reset(); + } + + @DsfServiceEventHandler + public void eventDispatched(final IRegisters.IRegisterChangedDMEvent e) { + fRegisterValueCache.reset(); + } + + /* + * These are the public interfaces for this service. + * + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IRegisters#getRegisterGroups(org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getRegisterGroups(IDMContext ctx, DataRequestMonitor rm ) { + IContainerDMContext contDmc = DMContexts.getAncestorOfType(ctx, IContainerDMContext.class); + if (contDmc == null) { + rm.setStatus( new Status( IStatus.ERROR , MIPlugin.PLUGIN_ID , INVALID_HANDLE , "Container context not found", null ) ) ; //$NON-NLS-1$ + rm.done(); + return; + } + + if (fGeneralRegistersGroupDMC == null) { + fGeneralRegistersGroupDMC = new MIRegisterGroupDMC( this , contDmc, 0 , "General Registers" ) ; //$NON-NLS-1$ + } + MIRegisterGroupDMC[] groupDMCs = new MIRegisterGroupDMC[] { fGeneralRegistersGroupDMC }; + rm.setData(groupDMCs) ; + rm.done() ; + } + + + /* + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IRegisters#getRegisters(org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterGroupDMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getRegisters(final IDMContext dmc, final DataRequestMonitor rm) { + final MIRegisterGroupDMC groupDmc = DMContexts.getAncestorOfType(dmc, MIRegisterGroupDMC.class); + if ( groupDmc == null ) { + rm.setStatus( new Status( IStatus.ERROR , MIPlugin.PLUGIN_ID , INVALID_HANDLE , "RegisterGroup context not found", null ) ) ; //$NON-NLS-1$ + rm.done(); + return; + } + + final IContainerDMContext containerDmc = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class); + if ( containerDmc == null ) { + rm.setStatus( new Status( IStatus.ERROR , MIPlugin.PLUGIN_ID , INVALID_HANDLE , "Container context not found" , null ) ) ; //$NON-NLS-1$ + rm.done(); + return; + } + + // There is only one group and its number must be 0. + if ( groupDmc.getGroupNo() == 0 ) { + final IMIExecutionDMContext executionDmc = DMContexts.getAncestorOfType(dmc, IMIExecutionDMContext.class); + fRegisterNameCache.execute( + new MIDataListRegisterNames(containerDmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Retrieve the register names. + String[] regNames = getData().getRegisterNames() ; + + // If the list is empty just return empty handed. + if ( regNames.length == 0 ) { + rm.done(); + return; + } + // Create DMContexts for each of the register names. + if(executionDmc == null) + rm.setData(makeRegisterDMCs(groupDmc, regNames)); + else + rm.setData(makeRegisterDMCs(groupDmc, executionDmc, regNames)); + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR , MIPlugin.PLUGIN_ID , INTERNAL_ERROR , "Invalid group = " + groupDmc , null)); //$NON-NLS-1$ + rm.done(); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IRegisters#getBitFields(org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor) + */ + public void getBitFields( IRegisterDMContext regDmc , DataRequestMonitor rm ) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "BitField not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IRegisters#writeRegister(org.eclipse.dd.dsf.debug.service.IRegisters.IRegisterDMContext, java.lang.String, java.lang.String, org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + public void writeRegister(IRegisterDMContext regCtx, final String regValue, final String formatId, final RequestMonitor rm) { + MIRegisterGroupDMC grpDmc = DMContexts.getAncestorOfType(regCtx, MIRegisterGroupDMC.class); + if ( grpDmc == null ) { + rm.setStatus( new Status( IStatus.ERROR , MIPlugin.PLUGIN_ID , INVALID_HANDLE , "RegisterGroup context not found" , null ) ) ; //$NON-NLS-1$ + rm.done(); + return; + } + + final MIRegisterDMC regDmc = (MIRegisterDMC)regCtx; + // There is only one group and its number must be 0. + if ( grpDmc.getGroupNo() == 0 ) { + final ExpressionService exprService = getServicesTracker().getService(ExpressionService.class); + String regName = regDmc.getName(); + final IExpressionDMContext exprCtxt = exprService.createExpression(regCtx, "$" + regName); //$NON-NLS-1$ + exprService.getModelData(exprCtxt, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Evaluate the expression - request HEX since it works in every case + final FormattedValueDMContext valueDmc = exprService.getFormattedValueContext(exprCtxt, formatId); + exprService.getModelData( + valueDmc, + new DataRequestMonitor(getExecutor(), null) { + @Override + protected void handleOK() { + if(! regValue.equals(getData().getFormattedValue()) || ! valueDmc.getFormatID().equals(formatId)){ + exprService.writeExpression(exprCtxt, regValue, formatId, new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + generateRegisterChangedEvent(regDmc); + } + }); + }//if + rm.done(); + }//handleOK + } + ); + } + }); + } + else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Invalid group = " + grpDmc, null)); //$NON-NLS-1$ + rm.done(); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IRegisters#writeBitField(org.eclipse.dd.dsf.debug.service.IRegisters.IBitFieldDMContext, java.lang.String, java.lang.String, org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + public void writeBitField(IBitFieldDMContext bitFieldCtx, String bitFieldValue, String formatId, RequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Writing bit field not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.dd.dsf.debug.service.IRegisters#writeBitField(org.eclipse.dd.dsf.debug.service.IRegisters.IBitFieldDMContext, org.eclipse.dd.dsf.debug.service.IRegisters.IMnemonic, org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + public void writeBitField(IBitFieldDMContext bitFieldCtx, IMnemonic mnemonic, RequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Writing bit field not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor rm) { + + rm.setData(new String[] { HEX_FORMAT, DECIMAL_FORMAT, OCTAL_FORMAT, BINARY_FORMAT, NATURAL_FORMAT }); + rm.done(); + } + + public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId) { + if ( dmc instanceof MIRegisterDMC ) { + MIRegisterDMC regDmc = (MIRegisterDMC) dmc; + return( new FormattedValueDMContext( this, regDmc, formatId)); + } + return null; + } + + private void generateRegisterChangedEvent(IRegisterDMContext dmc ) { + getSession().dispatchEvent(new RegisterChangedDMEvent(dmc), getProperties()); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControl.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControl.java new file mode 100644 index 00000000000..644182278e4 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControl.java @@ -0,0 +1,668 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * Ericsson AB - Modified for handling of multiple threads + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.datamodel.IDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.debug.service.command.CommandCache; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.MIExecContinue; +import org.eclipse.dd.mi.service.command.commands.MIExecFinish; +import org.eclipse.dd.mi.service.command.commands.MIExecInterrupt; +import org.eclipse.dd.mi.service.command.commands.MIExecNext; +import org.eclipse.dd.mi.service.command.commands.MIExecStep; +import org.eclipse.dd.mi.service.command.commands.MIExecUntil; +import org.eclipse.dd.mi.service.command.commands.MIThreadListIds; +import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent; +import org.eclipse.dd.mi.service.command.events.MIErrorEvent; +import org.eclipse.dd.mi.service.command.events.MIEvent; +import org.eclipse.dd.mi.service.command.events.MIGDBExitEvent; +import org.eclipse.dd.mi.service.command.events.MIRunningEvent; +import org.eclipse.dd.mi.service.command.events.MISharedLibEvent; +import org.eclipse.dd.mi.service.command.events.MISignalEvent; +import org.eclipse.dd.mi.service.command.events.MISteppingRangeEvent; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.mi.service.command.events.MIThreadCreatedEvent; +import org.eclipse.dd.mi.service.command.events.MIThreadExitEvent; +import org.eclipse.dd.mi.service.command.events.MIWatchpointTriggerEvent; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIThreadListIdsInfo; +import org.osgi.framework.BundleContext; + + +/** + * + *

+ * Implementation note: + * This class implements event handlers for the events that are generated by + * this service itself. When the event is dispatched, these handlers will + * be called first, before any of the clients. These handlers update the + * service's internal state information to make them consistent with the + * events being issued. Doing this in the handlers as opposed to when + * the events are generated, guarantees that the state of the service will + * always be consistent with the events. + * The purpose of this pattern is to allow clients that listen to service + * events and track service state, to be perfectly in sync with the service + * state. + */ +public class MIRunControl extends AbstractDsfService implements IRunControl +{ + protected class MIExecutionDMC extends AbstractDMContext + implements IMIExecutionDMContext + { + /** + * Integer ID that is used to identify the thread in the GDB/MI protocol. + */ + private final int fThreadId; + + /** + * Constructor for the context. It should not be called directly by clients. + * Instead clients should call {@link MIRunControl#createMIExecutionContext(IContainerDMContext, int)} + * to create instances of this context based on the thread ID. + *

+ * Classes extending {@link MIRunControl} may also extend this class to include + * additional information in the context. + * + * @param sessionId Session that this context belongs to. + * @param containerDmc The container that this context belongs to. + * @param threadId GDB/MI thread identifier. + */ + protected MIExecutionDMC(String sessionId, IContainerDMContext containerDmc, int threadId) { + super(sessionId, containerDmc != null ? new IDMContext[] { containerDmc } : new IDMContext[0]); + fThreadId = threadId; + } + + /** + * Returns the GDB/MI thread identifier of this context. + * @return + */ + public int getThreadId(){ + return fThreadId; + } + + @Override + public String toString() { return baseToString() + ".thread[" + fThreadId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + + @Override + public boolean equals(Object obj) { + return super.baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId == fThreadId; + } + + @Override + public int hashCode() { return super.baseHashCode() ^ fThreadId; } + } + + @Immutable + private static class ExecutionData implements IExecutionDMData { + private final StateChangeReason fReason; + ExecutionData(StateChangeReason reason) { + fReason = reason; + } + public StateChangeReason getStateChangeReason() { return fReason; } + } + + /** + * Base class for events generated by the MI Run Control service. Most events + * generated by the MI Run Control service are directly caused by some MI event. + * Other services may need access to the extended MI data carried in the event. + * + * @param DMC that this event refers to + * @param MIInfo object that is the direct cause of this event + * @see MIRunControl + */ + @Immutable + protected static class RunControlEvent> extends AbstractDMEvent + implements IDMEvent + { + final private T fMIInfo; + public RunControlEvent(V dmc, T miInfo) { + super(dmc); + fMIInfo = miInfo; + } + + public T getMIEvent() { return fMIInfo; } + } + + /** + * Indicates that the given thread has been suspended. + */ + @Immutable + protected static class SuspendedEvent extends RunControlEvent + implements ISuspendedDMEvent + { + SuspendedEvent(IExecutionDMContext ctx, MIStoppedEvent miInfo) { + super(ctx, miInfo); + } + + public StateChangeReason getReason() { + if (getMIEvent() instanceof MIBreakpointHitEvent) { + return StateChangeReason.BREAKPOINT; + } else if (getMIEvent() instanceof MISteppingRangeEvent) { + return StateChangeReason.STEP; + } else if (getMIEvent() instanceof MISharedLibEvent) { + return StateChangeReason.SHAREDLIB; + }else if (getMIEvent() instanceof MISignalEvent) { + return StateChangeReason.SIGNAL; + }else if (getMIEvent() instanceof MIWatchpointTriggerEvent) { + return StateChangeReason.WATCHPOINT; + }else if (getMIEvent() instanceof MIErrorEvent) { + return StateChangeReason.ERROR; + }else { + return StateChangeReason.USER_REQUEST; + } + } + } + + @Immutable + protected static class ContainerSuspendedEvent extends SuspendedEvent + implements IContainerSuspendedDMEvent + { + final IExecutionDMContext triggeringDmc; + ContainerSuspendedEvent(IContainerDMContext containerDmc, MIStoppedEvent miInfo, IExecutionDMContext triggeringDmc) { + super(containerDmc, miInfo); + this.triggeringDmc = triggeringDmc; + } + + public IExecutionDMContext getTriggeringContext() { + return triggeringDmc; + } + } + + @Immutable + protected static class ResumedEvent extends RunControlEvent + implements IResumedDMEvent + { + ResumedEvent(IExecutionDMContext ctx, MIRunningEvent miInfo) { + super(ctx, miInfo); + } + + public StateChangeReason getReason() { + switch(getMIEvent().getType()) { + case MIRunningEvent.CONTINUE: + return StateChangeReason.USER_REQUEST; + case MIRunningEvent.NEXT: + case MIRunningEvent.NEXTI: + return StateChangeReason.STEP; + case MIRunningEvent.STEP: + case MIRunningEvent.STEPI: + return StateChangeReason.STEP; + case MIRunningEvent.FINISH: + return StateChangeReason.STEP; + case MIRunningEvent.UNTIL: + case MIRunningEvent.RETURN: + break; + } + return StateChangeReason.UNKNOWN; + } + } + + @Immutable + protected static class ContainerResumedEvent extends ResumedEvent + implements IContainerResumedDMEvent + { + final IExecutionDMContext triggeringDmc; + + ContainerResumedEvent(IContainerDMContext containerDmc, MIRunningEvent miInfo, IExecutionDMContext triggeringDmc) { + super(containerDmc, miInfo); + this.triggeringDmc = triggeringDmc; + } + + public IExecutionDMContext getTriggeringContext() { + return triggeringDmc; + } + } + + @Immutable + protected static class StartedDMEvent extends RunControlEvent + implements IStartedDMEvent{ + + private final IMIExecutionDMContext fExecutionDmc; + + StartedDMEvent(IContainerDMContext containerDmc, IMIExecutionDMContext executionDmc, MIThreadCreatedEvent miInfo) { + super(containerDmc, miInfo); + fExecutionDmc = executionDmc; + } + + public IExecutionDMContext getExecutionContext(){ + return fExecutionDmc; + } + + } + + @Immutable + protected static class ExitedDMEvent extends RunControlEvent + implements IExitedDMEvent{ + + private final IMIExecutionDMContext fExecutionDmc; + + ExitedDMEvent(IContainerDMContext containerDmc, IMIExecutionDMContext executionDmc, MIThreadExitEvent miInfo) { + super(containerDmc, miInfo); + fExecutionDmc = executionDmc; + } + + public IExecutionDMContext getExecutionContext(){ + return fExecutionDmc; + } + } + + private ICommandControl fConnection; + private CommandCache fMICommandCache; + + // state flags + private boolean fSuspended = true; + private boolean fResumePending = false; + private boolean fStepping = false; + private boolean fTerminated = false; + + private StateChangeReason fStateChangeReason; + private IExecutionDMContext fStateChangeTriggeringContext; + + private static final int NO_THREAD_ID = 0; + + public MIRunControl(DsfSession session) { + super(session); + } + + @Override + public void initialize(final RequestMonitor rm) { + super.initialize( + new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + doInitialize(rm); + }}); + } + + private void doInitialize(final RequestMonitor rm) { + fConnection = getServicesTracker().getService(ICommandControl.class); + fMICommandCache = new CommandCache(fConnection); + getSession().addServiceEventListener(this, null); + + //register(new String[]{IRunControl.class.getName(), MIRunControl.class.getName()}, new Hashtable()); + + rm.done(); + } + + @Override + public void shutdown(final RequestMonitor rm) { + getSession().removeServiceEventListener(this); + fMICommandCache.reset(); + super.shutdown(rm); + } + + public boolean isValid() { return true; } + + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, DataRequestMonitor rm) { + if (dmc instanceof IExecutionDMContext) { + getExecutionData((IExecutionDMContext)dmc, (DataRequestMonitor)rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public CommandCache getCache() { return fMICommandCache; } + + public IMIExecutionDMContext createMIExecutionContext(IContainerDMContext container, int threadId) { + return new MIExecutionDMC(getSession().getId(), container, threadId); + } + + // + // Running event handling + // + @DsfServiceEventHandler + public void eventDispatched(final MIRunningEvent e) { + IDMEvent event = null; + // Find the container context, which is used in multi-threaded debugging. + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class); + if (containerDmc != null) { + // Set the triggering context only if it's different than the container context. + IExecutionDMContext triggeringCtx = !e.getDMContext().equals(containerDmc) ? e.getDMContext() : null; + event = new ContainerResumedEvent(containerDmc, e, triggeringCtx); + } else { + event = new ResumedEvent(e.getDMContext(), e); + } + getSession().dispatchEvent(event, getProperties()); + } + + // + // Suspended event handling + // + @DsfServiceEventHandler + public void eventDispatched(final MIStoppedEvent e) { + IDMEvent event = null; + // Find the container context, which is used in multi-threaded debugging. + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class); + if (containerDmc != null) { + // Set the triggering context only if it's different than the container context. + IExecutionDMContext triggeringCtx = !e.getDMContext().equals(containerDmc) ? e.getDMContext() : null; + event = new ContainerSuspendedEvent(containerDmc, e, triggeringCtx); + } else { + event = new SuspendedEvent(e.getDMContext(), e); + } + getSession().dispatchEvent(event, getProperties()); + } + + // + // Thread Created event handling + // When a new thread is created - OOB Event fired ~"[New Thread 1077300144 (LWP 7973)]\n" + // + @DsfServiceEventHandler + public void eventDispatched(final MIThreadCreatedEvent e) { + IContainerDMContext containerDmc = e.getDMContext(); + IMIExecutionDMContext executionCtx = e.getId() != -1 ? new MIExecutionDMC(getSession().getId(), containerDmc, e.getId()) : null; + getSession().dispatchEvent(new StartedDMEvent(containerDmc, executionCtx, e), getProperties()); + } + + // + // Thread exit event handling + // When a new thread is destroyed - OOB Event fired " + // + @DsfServiceEventHandler + public void eventDispatched(final MIThreadExitEvent e) { + IContainerDMContext containerDmc = e.getDMContext(); + IMIExecutionDMContext executionCtx = e.getId() != -1 ? new MIExecutionDMC(getSession().getId(), containerDmc, e.getId()) : null; + getSession().dispatchEvent(new ExitedDMEvent(containerDmc, executionCtx, e), getProperties()); + } + + @DsfServiceEventHandler + public void eventDispatched(ContainerResumedEvent e) { + fSuspended = false; + fResumePending = false; + fStateChangeReason = e.getReason(); + fMICommandCache.setTargetAvailable(false); + //fStateChangeTriggeringContext = e.getTriggeringContext(); + if (e.getReason().equals(StateChangeReason.STEP)) { + fStepping = true; + } else { + fMICommandCache.reset(); + } + } + + + @DsfServiceEventHandler + public void eventDispatched(ContainerSuspendedEvent e) { + fMICommandCache.setTargetAvailable(true); + fMICommandCache.reset(); + fStateChangeReason = e.getReason(); + fStateChangeTriggeringContext = e.getTriggeringContext(); + fSuspended = true; + fStepping = false; + } + + + @DsfServiceEventHandler + public void eventDispatched(MIGDBExitEvent e) { + fTerminated = true; + } + + + // Event handler when New thread is created + @DsfServiceEventHandler + public void eventDispatched(StartedDMEvent e) { + + } + + // Event handler when a thread is destroyed + @DsfServiceEventHandler + public void eventDispatched(ExitedDMEvent e) { + fMICommandCache.reset(e.getExecutionContext()); + + } + + /////////////////////////////////////////////////////////////////////////// + // AbstractService + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + /////////////////////////////////////////////////////////////////////////// + // IRunControl + public boolean canResume(IExecutionDMContext context) { + return !fTerminated && isSuspended(context) && !fResumePending; + } + + public boolean canSuspend(IExecutionDMContext context) { + return !fTerminated && !isSuspended(context); + } + + public boolean isSuspended(IExecutionDMContext context) { + return !fTerminated && fSuspended; + } + + public boolean isStepping(IExecutionDMContext context) { + return !fTerminated && fStepping; + } + + public void resume(IExecutionDMContext context, final RequestMonitor rm) { + assert context != null; + + if (canResume(context)) { + fResumePending = true; + // Cygwin GDB will accept commands and execute them after the step + // which is not what we want, so mark the target as unavailable + // as soon as we send a resume command. + fMICommandCache.setTargetAvailable(false); + MIExecContinue cmd = null; + if(context instanceof IContainerDMContext) + cmd = new MIExecContinue(context); + else{ + IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (dmc == null){ + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + cmd = new MIExecContinue(dmc);//, new String[0]); + } + fConnection.queueCommand( + cmd, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.done(); + } + } + ); + }else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Given context: " + context + ", is already running.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + } + } + + public void suspend(IExecutionDMContext context, final RequestMonitor rm){ + assert context != null; + + if (canSuspend(context)) { + MIExecInterrupt cmd = null; + if(context instanceof IContainerDMContext){ + cmd = new MIExecInterrupt(context); + } + else { + IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (dmc == null){ + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + cmd = new MIExecInterrupt(dmc); + } + fConnection.queueCommand( + cmd, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.done(); + } + } + ); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Given context: " + context + ", is already suspended.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + } + } + + public boolean canStep(IExecutionDMContext context) { + return canResume(context); + } + + public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) { + assert context != null; + + IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (dmc == null){ + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + if (!canResume(context)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + fResumePending = true; + fStepping = true; + fMICommandCache.setTargetAvailable(false); + switch(stepType) { + case STEP_INTO: + fConnection.queueCommand( + new MIExecStep(dmc, 1), new DataRequestMonitor(getExecutor(), rm) {} + ); + break; + case STEP_OVER: + fConnection.queueCommand( + new MIExecNext(dmc), new DataRequestMonitor(getExecutor(), rm) {}); + break; + case STEP_RETURN: + // The -exec-finish command operates on the selected stack frame, but here we always + // want it to operate on the stop stack frame. So we manually create a top-frame + // context to use with the MI command. + // We get a local instance of the stack service because the stack service can be shut + // down before the run control service is shut down. So it is possible for the + // getService() reqeust below to return null. + MIStack stackService = getServicesTracker().getService(MIStack.class); + if (stackService != null) { + IFrameDMContext topFrameDmc = stackService.createFrameDMContext(dmc, 0); + fConnection.queueCommand( + new MIExecFinish(topFrameDmc), new DataRequestMonitor(getExecutor(), rm) {}); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Cannot create context for command, stack service not available.", null)); //$NON-NLS-1$ + rm.done(); + } + break; + default: + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Given step type not supported", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public boolean canInstructionStep(IExecutionDMContext context) { + return false; + } + + public void instructionStep(IExecutionDMContext context, StepType stepType, RequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Operation not implemented", null)); //$NON-NLS-1$ + rm.done(); + } + + public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor rm) { + fMICommandCache.execute( + new MIThreadListIds(containerDmc), + new DataRequestMonitor( + getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(makeExecutionDMCs(containerDmc, getData())); + rm.done(); + } + }); + } + + + private IExecutionDMContext[] makeExecutionDMCs(IContainerDMContext containerCtx, MIThreadListIdsInfo info) { + if (info.getThreadIds().length == 0) { + //Main thread always exist even if it is not reported by GDB. + //So create thread-id= 0 when no thread is reported + return new IMIExecutionDMContext[]{new MIExecutionDMC(getSession().getId(), containerCtx, NO_THREAD_ID)}; + } else { + IExecutionDMContext[] executionDmcs = new IMIExecutionDMContext[info.getThreadIds().length]; + for (int i = 0; i < info.getThreadIds().length; i++) { + executionDmcs[i] = new MIExecutionDMC(getSession().getId(), containerCtx, info.getThreadIds()[i]); + } + return executionDmcs; + } + } + + public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor rm){ + if (dmc instanceof IContainerDMContext) { + rm.setData( new ExecutionData(fStateChangeReason) ); + } else if (dmc instanceof IMIExecutionDMContext) { + StateChangeReason reason = dmc.equals(fStateChangeTriggeringContext) ? fStateChangeReason : StateChangeReason.CONTAINER; + rm.setData(new ExecutionData(reason)); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Given context: " + dmc + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + } + rm.done(); + } + + /* + * Run selected execution thread to a given line number. + */ + // Later add support for Address and function. + // skipBreakpoints is not used at the moment. Implement later + public void runToLine(IExecutionDMContext context, String fileName, String lineNo, boolean skipBreakpoints, final DataRequestMonitor rm){ + assert context != null; + + IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (dmc == null){ + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "Given context: " + context + " is not an execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + if (canResume(context)) { + fResumePending = true; + fMICommandCache.setTargetAvailable(false); + fConnection.queueCommand(new MIExecUntil(dmc, fileName + ":" + lineNo), //$NON-NLS-1$ + new DataRequestMonitor( + getExecutor(), rm) { + @Override + protected void handleOK() { + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, + "Cannot resume given DMC.", null)); //$NON-NLS-1$ + rm.done(); + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIStack.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIStack.java new file mode 100644 index 00000000000..f18f53765ac --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIStack.java @@ -0,0 +1,559 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * Ericsson - Modified for handling of multiple execution contexts + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import java.util.Hashtable; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.utils.Addr32; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IStack; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.MIStackInfoDepth; +import org.eclipse.dd.mi.service.command.commands.MIStackListArguments; +import org.eclipse.dd.mi.service.command.commands.MIStackListFrames; +import org.eclipse.dd.mi.service.command.commands.MIStackListLocals; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.mi.service.command.output.MIArg; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIStackInfoDepthInfo; +import org.eclipse.dd.mi.service.command.output.MIStackListArgumentsInfo; +import org.eclipse.dd.mi.service.command.output.MIStackListFramesInfo; +import org.eclipse.dd.mi.service.command.output.MIStackListLocalsInfo; +import org.osgi.framework.BundleContext; + +public class MIStack extends AbstractDsfService + implements IStack +{ + protected static class MIFrameDMC extends AbstractDMContext + implements IFrameDMContext + { + private final int fLevel; + // public MIFrameDMC(MIStack service, int level) { + public MIFrameDMC(String sessionId, IExecutionDMContext execDmc, int level) { + super(sessionId, new IDMContext[] { execDmc }); + fLevel = level; + } + + public int getLevel() { return fLevel; } + + @Override + public boolean equals(Object other) { + return super.baseEquals(other) && ((MIFrameDMC)other).fLevel == fLevel; + } + + @Override + public int hashCode() { + return super.baseHashCode() ^ fLevel; + } + + @Override + public String toString() { + return baseToString() + ".frame[" + fLevel + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + protected static class MIVariableDMC extends AbstractDMContext + implements IVariableDMContext + { + public enum Type { ARGUMENT, LOCAL } + final private Type fType; + final private int fIndex; + + public MIVariableDMC(MIStack service, IFrameDMContext frame, Type type, int index) { + super(service, new IDMContext[] { frame }); + fIndex = index; + fType = type; + } + + public int getIndex() { return fIndex; } + public Type getType() { return fType; } + + @Override + public boolean equals(Object other) { + return super.baseEquals(other) && + ((MIVariableDMC)other).fType == fType && + ((MIVariableDMC)other).fIndex == fIndex; + } + + @Override + public int hashCode() { + int typeFactor = 0; + if (fType == Type.LOCAL) typeFactor = 2; + else if (fType == Type.ARGUMENT) typeFactor = 3; + return super.baseHashCode() ^ typeFactor ^ fIndex; + } + + @Override + public String toString() { + return baseToString() + ".variable(" + fType + ")[" + fIndex + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + + private MIRunControl fRunControl; + private MIStoppedEvent fCachedStoppedEvent; + + public MIStack(DsfSession session) + { + super(session); + } + + @Override + protected BundleContext getBundleContext() + { + return MIPlugin.getBundleContext(); + } + + @Override + public void initialize(final RequestMonitor rm) { + super.initialize( + new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + doInitialize(rm); + } + }); + } + + private void doInitialize(RequestMonitor rm) { + fRunControl = getServicesTracker().getService(MIRunControl.class); + getSession().addServiceEventListener(this, null); + register(new String[]{IStack.class.getName(), MIStack.class.getName()}, new Hashtable()); + rm.done(); + } + + @Override + public void shutdown(RequestMonitor rm) + { + unregister(); + getSession().removeServiceEventListener(this); + super.shutdown(rm); + } + + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, DataRequestMonitor rm) { + if (dmc instanceof MIFrameDMC) { + getFrameData((MIFrameDMC)dmc, (DataRequestMonitor)rm); + // getFrameData invokes rm + } else if (dmc instanceof MIVariableDMC) { + getVariableData((MIVariableDMC)dmc, (DataRequestMonitor)rm); + // getVariablesData invokes rm + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * Creates a frame context. This method is intended to be used by other MI + * services and sub-classes which need to create a frame context directly. + *

+ * Sub-classes can override this method to provide custom stack frame + * context implementation. + *

+ * @param execDmc Execution context that this frame is to be a child of. + * @param level Level of the new context. + * @return A new frame context. + */ + public IFrameDMContext createFrameDMContext(IExecutionDMContext execDmc, int level) { + return new MIFrameDMC(getSession().getId(), execDmc, level); + } + + + public boolean isStackAvailable(IDMContext context) { + IExecutionDMContext execCtx = DMContexts.getAncestorOfType(context, IExecutionDMContext.class); + return execCtx != null && (fRunControl.isSuspended(execCtx) || (fRunControl.isStepping(execCtx))); + } + + public void getFrames(final IDMContext ctx, final DataRequestMonitor rm) { + + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + + if (execDmc == null) { + //rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, -1, "No frame context found in " + ctx, null)); //$NON-NLS-1$ + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context" + ctx, null)); //$NON-NLS-1$ + rm.done(); + return; + } + fRunControl.getCache().execute( + new MIStackListFrames(execDmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(getFrames(execDmc, getData())); + rm.done(); + } + }); + } + + public void getTopFrame(final IDMContext ctx, final DataRequestMonitor rm) { + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context" + ctx, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Try to retrieve the top stack frame from the cached stopped event. + if (fCachedStoppedEvent != null && + fCachedStoppedEvent.getFrame() != null && + execDmc.equals(fCachedStoppedEvent.getDMContext())) + { + rm.setData(createFrameDMContext(execDmc, fCachedStoppedEvent.getFrame().getLevel())); + rm.done(); + return; + } + + // If stopped event is not available or doesn't contain frame info, + // query the full list of frames. + getFrames( + ctx, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(getData()[0]); + rm.done(); + } + }); + } + + //private MIFrameDMC[] getFrames(DsfMIStackListFramesInfo info) { + private IFrameDMContext[] getFrames(IMIExecutionDMContext execDmc, MIStackListFramesInfo info) { + IFrameDMContext[] frameDMCs = new MIFrameDMC[info.getMIFrames().length]; + for (int i = 0; i < info.getMIFrames().length; i++) { + //frameDMCs[i] = new MIFrameDMC(this, info.getMIFrames()[i].getLevel()); + frameDMCs[i] = createFrameDMContext(execDmc, info.getMIFrames()[i].getLevel()); + } + return frameDMCs; + } + + + + public void getFrameData(final IFrameDMContext frameDmc, final DataRequestMonitor rm) { + if (!(frameDmc instanceof MIFrameDMC)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "Invalid context type " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + final MIFrameDMC miFrameDmc = (MIFrameDMC)frameDmc; + + IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, "No execution context found in " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + /** + * Base class for the IFrameDMData object that uses an MIFrame object to + * provide the data. Sub-classes must provide the MIFrame object + */ + abstract class FrameData implements IFrameDMData + { + abstract protected MIFrame getMIFrame(); + + public IAddress getAddress() { + String addr = getMIFrame().getAddress(); + if (addr.startsWith("0x")) { //$NON-NLS-1$ + addr = addr.substring(2); + } + if (addr.length() <= 8) { + return new Addr32(getMIFrame().getAddress()); + } else { + return new Addr64(getMIFrame().getAddress()); + } + } + + public int getColumn() { return 0; } + + public String getFile() { return getMIFrame().getFile(); } + public int getLine() { return getMIFrame().getLine(); } + public String getFunction() { return getMIFrame().getFunction(); } + + @Override + public String toString() { return getMIFrame().toString(); } + } + + // If requested frame is the top stack frame, try to retrieve it from + // the stopped event data. + class FrameDataFromStoppedEvent extends FrameData { + private final MIStoppedEvent fEvent; + FrameDataFromStoppedEvent(MIStoppedEvent event) { fEvent = event; } + @Override + protected MIFrame getMIFrame() { return fEvent.getFrame(); } + } + + // Retrieve the top stack frame from the stopped event only if the selected thread is the one on which stopped event + // is raised + if (fCachedStoppedEvent != null && + execDmc.equals(fCachedStoppedEvent.getDMContext()) && + miFrameDmc.fLevel == 0 && + fCachedStoppedEvent.getFrame() != null) + { + rm.setData(new FrameDataFromStoppedEvent(fCachedStoppedEvent)); + rm.done(); + return; + } + + // If not, retrieve the full list of frame data. + class FrameDataFromMIStackFrameListInfo extends FrameData { + private MIStackListFramesInfo fFrameDataCacheInfo; + private int fFrameIndex; + + FrameDataFromMIStackFrameListInfo(MIStackListFramesInfo info, int index) { + fFrameDataCacheInfo = info; + fFrameIndex = index; + } + + @Override + protected MIFrame getMIFrame() { return fFrameDataCacheInfo.getMIFrames()[fFrameIndex]; } + } + + fRunControl.getCache().execute( + new MIStackListFrames(execDmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Find the index to the correct MI frame object. + int idx = findFrameIndex(getData().getMIFrames(), miFrameDmc.fLevel); + if (idx == -1) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid frame " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create the data object. + rm.setData(new FrameDataFromMIStackFrameListInfo(getData(), idx)); + rm.done(); + } + }); + } + + public void getArguments(final IFrameDMContext frameDmc, final DataRequestMonitor rm) { + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "No execution context found in " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + + // If requested frame is the top stack frame, try to retrieve it from + // the stopped event data. + if (frameDmc.getLevel() == 0 && + fCachedStoppedEvent != null && + fCachedStoppedEvent.getFrame() != null && + execDmc.equals(fCachedStoppedEvent.getDMContext()) && + fCachedStoppedEvent.getFrame().getArgs() != null) + { + rm.setData(makeVariableDMCs( + frameDmc, MIVariableDMC.Type.ARGUMENT, fCachedStoppedEvent.getFrame().getArgs().length)); + rm.done(); + return; + } + + // If not, retrieve the full list of frame data. + fRunControl.getCache().execute( + new MIStackListArguments(execDmc, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Find the index to the correct MI frame object. + // Note: this is a short-cut, but it won't work once we implement retrieving + // partial lists of stack frames. + int idx = frameDmc.getLevel(); + if (idx == -1) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, "Invalid frame " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create the variable array out of MIArg array. + MIArg[] args = getData().getMIFrames()[idx].getArgs(); + if (args == null) args = new MIArg[0]; + rm.setData(makeVariableDMCs(frameDmc, MIVariableDMC.Type.ARGUMENT, args.length)); + rm.done(); + } + }); + } + + public void getVariableData(IVariableDMContext variableDmc, final DataRequestMonitor rm) { + if (!(variableDmc instanceof MIVariableDMC)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context type " + variableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + final MIVariableDMC miVariableDmc = (MIVariableDMC)variableDmc; + + // Extract the frame DMC from the variable DMC. + final MIFrameDMC frameDmc = DMContexts.getAncestorOfType(variableDmc, MIFrameDMC.class); + if (frameDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "No frame context found in " + variableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "No execution context found in " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + /** + * Same as with frame objects, this is a base class for the IVariableDMData object that uses an MIArg object to + * provide the data. Sub-classes must supply the MIArg object. + */ + class VariableData implements IVariableDMData { + private MIArg dsfMIArg; + VariableData(MIArg arg){ + dsfMIArg = arg; + } + public String getName() { return dsfMIArg.getName(); } + public String getValue() { return dsfMIArg.getValue(); } + @Override + public String toString() { return dsfMIArg.toString(); } + } + + // Check if the stopped event can be used to extract the variable value. + if (execDmc != null && miVariableDmc.fType == MIVariableDMC.Type.ARGUMENT && + frameDmc.fLevel == 0 && fCachedStoppedEvent != null && fCachedStoppedEvent.getFrame() != null && + execDmc.equals(fCachedStoppedEvent.getDMContext()) && + fCachedStoppedEvent.getFrame().getArgs() != null) + { + if (miVariableDmc.fIndex >= fCachedStoppedEvent.getFrame().getArgs().length) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, -1, "Invalid variable " + miVariableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + rm.setData(new VariableData(fCachedStoppedEvent.getFrame().getArgs()[miVariableDmc.fIndex])); + rm.done(); + return; + } + + if (miVariableDmc.fType == MIVariableDMC.Type.ARGUMENT){ + fRunControl.getCache().execute( + new MIStackListArguments(execDmc, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Find the correct frame and argument + if ( frameDmc.fLevel >= getData().getMIFrames().length || + miVariableDmc.fIndex >= getData().getMIFrames()[frameDmc.fLevel].getArgs().length ) + { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid variable " + miVariableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create the data object. + rm.setData(new VariableData(getData().getMIFrames()[frameDmc.fLevel].getArgs()[miVariableDmc.fIndex])); + rm.done(); + }}); + }//if + if (miVariableDmc.fType == MIVariableDMC.Type.LOCAL){ + fRunControl.getCache().execute( + new MIStackListLocals(frameDmc, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + + // Create the data object. + rm.setData(new VariableData(getData().getLocals()[miVariableDmc.fIndex])); + rm.done(); + } + }); + + }//if + + } + + private MIVariableDMC[] makeVariableDMCs(IFrameDMContext frame, MIVariableDMC.Type type, int count) { + MIVariableDMC[] variables = new MIVariableDMC[count]; + for (int i = 0; i < count; i++) { + variables[i]= new MIVariableDMC(this, frame, type, i); + } + return variables; + } + + private int findFrameIndex(MIFrame[] frames, int level) { + for (int idx = 0; idx < frames.length; idx++) { + if (frames[idx].getLevel() == level) { + return idx; + } + } + return -1; + } + + + public void getLocals(final IFrameDMContext frameDmc, final DataRequestMonitor rm) { + fRunControl.getCache().execute( + new MIStackListLocals(frameDmc, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(makeVariableDMCs(frameDmc, MIVariableDMC.Type.LOCAL, getData().getLocals().length)); + rm.done(); + } + }); + } + + public void getStackDepth(IDMContext dmc, final int maxDepth, final DataRequestMonitor rm) { + IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(dmc, IMIExecutionDMContext.class); + if (execDmc != null) { + MIStackInfoDepth depthCommand = null; + if (maxDepth > 0) depthCommand = new MIStackInfoDepth(execDmc, maxDepth); + else depthCommand = new MIStackInfoDepth(execDmc); + + fRunControl.getCache().execute( + depthCommand, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(getData().getDepth()); + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ + rm.done(); + } + } + // IServiceEventListener + @DsfServiceEventHandler public void eventDispatched(IRunControl.IResumedDMEvent e) { + if (e.getReason() != StateChangeReason.STEP) { + fCachedStoppedEvent = null; + } + } + + // @DsfServiceEventHandler public void eventDispatched(MIRunControl.SuspendedEvent e) { + @DsfServiceEventHandler public void eventDispatched(MIRunControl.ContainerSuspendedEvent e) { + fCachedStoppedEvent = e.getMIEvent(); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIVariableManager.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIVariableManager.java new file mode 100644 index 00000000000..3227e81206f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIVariableManager.java @@ -0,0 +1,1648 @@ +/******************************************************************************* + * Copyright (c) 2008 Monta Vista and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Monta Vista - initial API and implementation + * Ericsson - Modified for handling of multiple execution contexts + * Ericsson - Major updates for GDB/MI implementation + * Ericsson - Major re-factoring to deal with children + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.debug.service.IExpressions; +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IStack; +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMData; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.debug.service.command.ICommandListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.dsf.debug.service.command.IEventListener; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.ExpressionService.ExpressionInfo; +import org.eclipse.dd.mi.service.ExpressionService.MIExpressionDMC; +import org.eclipse.dd.mi.service.command.AbstractMIControl; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetAttributes; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetChildCount; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetChildren; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetValue; +import org.eclipse.dd.mi.service.command.commands.ExprMetaGetVar; +import org.eclipse.dd.mi.service.command.commands.MIDataEvaluateExpression; +import org.eclipse.dd.mi.service.command.commands.MIVarAssign; +import org.eclipse.dd.mi.service.command.commands.MIVarCreate; +import org.eclipse.dd.mi.service.command.commands.MIVarDelete; +import org.eclipse.dd.mi.service.command.commands.MIVarEvaluateExpression; +import org.eclipse.dd.mi.service.command.commands.MIVarInfoPathExpression; +import org.eclipse.dd.mi.service.command.commands.MIVarListChildren; +import org.eclipse.dd.mi.service.command.commands.MIVarSetFormat; +import org.eclipse.dd.mi.service.command.commands.MIVarShowAttributes; +import org.eclipse.dd.mi.service.command.commands.MIVarUpdate; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetAttributesInfo; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetChildCountInfo; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetChildrenInfo; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetValueInfo; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetVarInfo; +import org.eclipse.dd.mi.service.command.output.MIVar; +import org.eclipse.dd.mi.service.command.output.MIVarAssignInfo; +import org.eclipse.dd.mi.service.command.output.MIVarChange; +import org.eclipse.dd.mi.service.command.output.MIVarCreateInfo; +import org.eclipse.dd.mi.service.command.output.MIVarDeleteInfo; +import org.eclipse.dd.mi.service.command.output.MIVarEvaluateExpressionInfo; +import org.eclipse.dd.mi.service.command.output.MIVarInfoPathExpressionInfo; +import org.eclipse.dd.mi.service.command.output.MIVarListChildrenInfo; +import org.eclipse.dd.mi.service.command.output.MIVarSetFormatInfo; +import org.eclipse.dd.mi.service.command.output.MIVarShowAttributesInfo; +import org.eclipse.dd.mi.service.command.output.MIVarUpdateInfo; +import org.osgi.framework.BundleContext; + +/** + * Manages a list of variable objects as created through GDB/MI commands. + * + * Note that for the moment, this class is inheriting from AbstractDsfService, + * although it does not register as a service. This class is only used by the Expression + * Service, and therefore, need not be a service of its own. + * However, to be able to implement ICommandControl, we automatically must implement + * IDsfService, so, that is why we extend AbstractDsfService. We must implement + * ICommandControl service, to be able to interface properly with the MICommandCache which + * is using this class. + * + * This class is passed expression-meta-commands which have their own cache. + * Therefore, we don't use the standard MICommandCache in this class. + * In fact, we can't even use it, because many variableObject MI commands, + * should not be cached as they alter the state of the back-end. + * + * Design details: + * ============== + * + * GDB variable object information + * ------------------------------- + * o Variable objects are recursively hierarchical, where children can be created through + * the parent. + * o A varObject created with -var-create is a ROOT + * o A varObject created with -var-list-children, is not a root + * o Only varObject with no children or varObjects that are pointers can change values + * and therefore + * those objects can be used with -var-assign + * o After a program stops, a varObject must be 'updated' before used + * o Only root varObject can be updated with -var-update, which will trigger all + * of the root's descendants to be updated. + * o Once updated, a varObject need not be updated until the program resumes again; + * this is true even after -var-assign is used (because it does an implicit -var-update) + * o -var-update will return the list of all modifiable descendants of the udpated root which + * have changed + * o -var-update will indicate if a root is out-of-scope (which implies that all + * its descendants are out-of-scope) + * o if a varObject is out-of-scope, another varObject may be valid for the same + * expression as the out-of-scope varObject + * o deleting a varObject will delete all its descendants, therefore, it is only + * necessary to delete roots + * + * + * Class details + * ------------- + * - We have an MIVariableObject class which represents a variable object in GDB + * + * - MIVariableObject includes a buffered value for each allowed format. + * + * - We have an MIRootVariableObject class inheriting from MIVariableObject to describe + * root varObjects created with -var-create. Objects created with -var-list-children + * are MIVariableObjects only. The root class will keep track of if the root object + * needs to be updated, if the root object is out-of-scope, and of a list of all + * modifiable descendants of this root. The list of modifiable descendants is + * accessed using the gdb-given name to allow quick updates from the -var-update + * result (see below.) + * + * - we do not use -var-list-children for arrays, but create them manually + * + * - when the program stops, we should mark all roots as needing to be updated. + * To achieve this efficiently, we have a dedicated list of roots that are updated. + * When the program stops, we go through this list, remove each element and mark it + * as needing to be updated. + * + * - when a varObject is accessed, if its root must be updated, the var-update + * command shall be used. The result of that command will indicate all + * modifiable descendants that have changed. We also use --all-values with -var-update + * to get the new value (in the current format) for each modified descendant. Using the list of modifiable + * descendants of the root, we can quickly update the changed ones to invalidate their buffered + * values and store the new current format value. + * + * - all values of non-modifiable varObjects (except arrays) will be set to {...} + * without going to the back-end + * + * - requesting the value of an array varObject will trigger the creation of a new + * varObject for the array's address. Note that we must still use a variable + * object and not the command -data-evaluate-expression, because we still need to get + * the array address in multiple formats. + * + * - we keep an LRU (Least Recently Used) structure of all variable objects. This LRU + * will be bounded to a maximum allowed number of variable objects. Whenever we get an + * object from the LRU cleanup will be done if the maximum size has been reached. + * The LRU will not delete a parent varObject until all its children are deleted; this is + * achieved by touching each of the parents of an object whenever that object is put or get + * + * - It may happen that when accessing a varObject we find its root to be + * out-of-scope. The expression for which we are trying to access a varObject + * could still be valid, and therefore we should try to create a new varObject for + * that expression. This can happen for example if two methods use the same name + * for a variable. In the case when we find that a varObject is out-of-scope (when + * its root is out-of-scope) the following should be done: + * - replace the varObject in the LRU with a newly created one in GDB + * - if the old object was a root, delete it in GDB. + * + * - In GDB, -var-update will only report a change if -var-evaluate-expression has + * changed -- in the current format--. This means that situations like + * double z = 1.2; + * z = 1.4; + * Will not report a change if the format is anything else than natural. + * This is because 1.2 and 1.4 are both printed as 1, 0x1, etc + * Since we cache the values of every format, we must know if the value has + * change in -any- format, not just the current one. + * To solve this, we always keep the display format of variable objects (and their + * children) to the natural format; we believe that if the value changes in any + * format, it guarantees that it will change in the natural format. + * The simplest way to do this is that whenever we change the format + * of a variable object, we immediately set it back to natural with a second + * var-set-format command. + * Note that versions of GDB after 6.7 will allows to issue -var-evaluate-expression + * with a specified format, therefore allowing us to never use -var-set-format, and + * consequently, to easily keep the display format of all variable objects to natural. + */ +public class MIVariableManager extends AbstractDsfService implements ICommandControl { + + + /** + * Utility class to track the progress and information of MI variable objects + */ + public class MIVariableObject { + + // Don't use an enumeration to allow subclasses to extend this + protected static final int STATE_READY = 0; + protected static final int STATE_UPDATING = 1; + + protected int currentState; + + // This is the lock used when we must run multiple + // operations at once. This lock should be independent of the + // UPDATING state, which is why we don't make it part of the state + private boolean locked = false; + + // This id is the one used to search for this object in our hash-map + private final VariableObjectId internalId; + // This is the name of the variable object, as given by GDB (e.g., var1 or var1.public.x) + private String gdbName = null; + // The current format of this variable object, within GDB + private String format = IFormattedValues.NATURAL_FORMAT; + + // The full expression that can be used to characterize this object + private String fullExp = null; + private String type = null; + private int numChildren = 0; + private Boolean editable = null; + + // The current values of the expression for each format. (null if not known yet) + private Map valueMap = null; + + // A queue of request monitors waiting for this object to be ready + private LinkedList operationsPending; + + // A queue of request monitors that requested an update + protected LinkedList> updatesPending; + + // The relative expressions of the children of this variable, if any. + // Null means we didn't fetch them yet, while an empty array means no children + private ExpressionInfo[] children = null; + + // The parent of this variable object within GDB. Null if this object has no parent + private MIVariableObject parent = null; + + // The root parent that must be used to issue -var-update. + // If this object is a root, then the rootToUpdate is itself + private MIRootVariableObject rootToUpdate = null; + + protected boolean outOfScope = false; + + public MIVariableObject(VariableObjectId id, MIVariableObject parentObj) { + currentState = STATE_READY; + + operationsPending = new LinkedList(); + updatesPending = new LinkedList>(); + + internalId = id; + setParent(parentObj); + + // No values are available yet + valueMap = new HashMap(); + resetValues(); + } + + public VariableObjectId getInternalId() { return internalId; } + public String getGdbName() { return gdbName; } + public String getCurrentFormat() { return format; } + public MIVariableObject getParent() { return parent; } + public MIRootVariableObject getRootToUpdate() { return rootToUpdate; } + + public String getExpression() { return fullExp; } + public String getType() { return type; } + public int getNumChildren() { return numChildren; } + public String getValue(String format) { return valueMap.get(format); } + + public ExpressionInfo[] getChildren() { return children; } + + + //FIX replace these methods with CDT's GDBTypeParser (see bug 200897 comment #5) + // int(*)[5] is a pointer to an array (so it is a pointer but not an array) (e.g., &b where int b[5]) + // int *[5] is an array of pointers (so it is an array but not a pointer) (e.g., int *b[5]) + public boolean isArray() { return (getType() == null) ? false : getType().endsWith("]") && !getType().contains("(*)") ; }//$NON-NLS-1$//$NON-NLS-2$ + public boolean isPointer() { return (getType() == null) ? false : getType().contains("*")&& !isArray(); }//$NON-NLS-1$ + public boolean isMethod() { return (getType() == null) ? false : getType().contains("()"); }//$NON-NLS-1$ + // A complex variable is one with children. However, it must not be a pointer since a pointer has one child + // according to GDB, but is still a 'simple' variable + public boolean isComplex() { return (getType() == null) ? false : getNumChildren() > 0 && !isPointer(); } + + public void setGdbName(String n) { gdbName = n; } + public void setCurrentFormat(String f) { format = f; } + + public void setExpressionData(String fullExpression, String t, int num) { + fullExp = fullExpression; + type = t; + numChildren = num; + } + + public void setValue(String format, String val) { valueMap.put(format, val); } + + public void resetValues(String valueInCurrentFormat) { + resetValues(); + setValue(getCurrentFormat(), valueInCurrentFormat); + } + + public void resetValues() { + valueMap.put(IFormattedValues.NATURAL_FORMAT, null); + valueMap.put(IFormattedValues.BINARY_FORMAT, null); + valueMap.put(IFormattedValues.HEX_FORMAT, null); + valueMap.put(IFormattedValues.OCTAL_FORMAT, null); + valueMap.put(IFormattedValues.DECIMAL_FORMAT, null); + } + + public void setChildren(ExpressionInfo[] c) { children = c; } + public void setParent(MIVariableObject p) { + parent = p; + rootToUpdate = (p == null ? (MIRootVariableObject)this : p.getRootToUpdate()); + } + + public void executeWhenNotUpdating(RequestMonitor rm) { + getRootToUpdate().executeWhenNotUpdating(rm); + } + + private void lock() { + locked = true; + } + + private void unlock() { + locked = false; + + while (operationsPending.size() > 0) { + operationsPending.poll().done(); + } + } + + public boolean isOutOfScope() { return outOfScope; } + + /** + * This method updates the variable object. + * Updating a variable object is done by updating its root. + */ + public void update(final DataRequestMonitor rm) { + + // We check to see if we are already out-of-scope + // We must do this to avoid the risk of re-creating this object + // twice, due to race conditions + if (isOutOfScope()) { + rm.setData(false); + rm.done(); + } else if (currentState == STATE_UPDATING) { + // If we were already updating, we just queue the request monitor + // until the on-going update finishes. + updatesPending.add(rm); + } else { + currentState = STATE_UPDATING; + getRootToUpdate().update(new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + currentState = STATE_READY; + + if (getStatus().isOK()) { + outOfScope = getRootToUpdate().isOutOfScope(); + // This request monitor is the one that should re-create + // the variable object if the old one was out-of-scope + rm.setData(outOfScope); + rm.done(); + + // All the other request monitors must be notified but must + // not re-create the object, even if it is out-of-scope + while (updatesPending.size() > 0) { + DataRequestMonitor pendingRm = updatesPending.poll(); + pendingRm.setData(false); + pendingRm.done(); + } + } else { + rm.setStatus(getStatus()); + rm.done(); + + while (updatesPending.size() > 0) { + DataRequestMonitor pendingRm = updatesPending.poll(); + pendingRm.setStatus(getStatus()); + pendingRm.done(); + } + } + } + }); + } + } + + /** + * Variable objects need not be deleted unless they are root. + * This method is specialized in the MIRootVariableObject class. + */ + public void deleteInGdb() {} + + /** + * This method returns the value of the variable object attributes by + * using -var-show-attributes. + * Currently, the only attribute available is 'editable'. + * + * @param rm + * The data request monitor that will hold the value returned + */ + private void getAttributes(final DataRequestMonitor rm) { + if (editable != null) { + rm.setData(editable); + rm.done(); + } if (isComplex()) { + editable = false; + rm.setData(editable); + rm.done(); + } else { + fCommandControl.queueCommand( + new MIVarShowAttributes(fControlDmc, getGdbName()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + editable = getData().isEditable(); + + rm.setData(editable); + rm.done(); + } + }); + } + } + + /** + * This method returns the value of the variable object. + * This operation translates to multiple MI commands which affect the state of the + * variable object in the back-end; therefore, we must make sure the object is not + * locked doing another operation, and we must lock the object once it is our turn + * to use it. + * + * @param dmc + * The context containing the format to be used for the evaluation + * @param rm + * The data request monitor that will hold the value returned + */ + private void getValue(final FormattedValueDMContext dmc, + final DataRequestMonitor rm) { + + // We might already know the value + String value = getValue(dmc.getFormatID()); + if (value != null) { + rm.setData(new FormattedValueDMData(value)); + rm.done(); + return; + } + + // If the variable is a complex structure, there is no need to ask the back-end for a value, + // we can give it the {...} ourselves + // Unless we are dealing with an array, in which case, we want to get the address of it + if (isComplex()) { + if (isArray()) { + // Figure out the address + IExpressionDMContext exprCxt = DMContexts.getAncestorOfType(dmc, IExpressionDMContext.class); + IExpressionDMContext addrCxt = fExpressionService.createExpression(exprCxt, "&(" + exprCxt.getExpression() + ")"); //$NON-NLS-1$//$NON-NLS-2$ + + final FormattedValueDMContext formatCxt = new FormattedValueDMContext( + fExpressionService.getSession().getId(), + addrCxt, + dmc.getFormatID() + ); + + getVariable( + addrCxt, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + getData().getValue(formatCxt, rm); + + } + }); + } else { + // Other complex structure + String complexValue = "{...}"; //$NON-NLS-1$ + setValue(dmc.getFormatID(), complexValue); + rm.setData(new FormattedValueDMData(complexValue)); + rm.done(); + } + + return; + } + + if (locked) { + operationsPending.add(new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + getValue(dmc, rm); + } + }); + } else { + lock(); + + // If the format is already the one set for this variable object, + // we don't need to set it again + if (dmc.getFormatID().equals(getCurrentFormat())) { + evaluate(rm); + } else { + // We must first set the new format and then evaluate the variable + fCommandControl.queueCommand( + new MIVarSetFormat(fControlDmc, getGdbName(), dmc.getFormatID()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + setCurrentFormat(dmc.getFormatID()); + + // If set-format returned the value, no need to evaluate + // This is only valid after GDB 6.7 + if (getData().getValue() != null) { + setValue(dmc.getFormatID(), getData().getValue()); + rm.setData(new FormattedValueDMData(getData().getValue())); + rm.done(); + + // Unlock is done within this method + resetFormatToNatural(); + } else { + evaluate(rm); + } + } else { + rm.setStatus(getStatus()); + rm.done(); + + unlock(); + } + } + }); + } + } + } + + /** + * This method evaluates a variable object + */ + private void evaluate(final DataRequestMonitor rm) { + fCommandControl.queueCommand( + new MIVarEvaluateExpression(fControlDmc, getGdbName()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + setValue(getCurrentFormat(), getData().getValue()); + rm.setData(new FormattedValueDMData(getData().getValue())); + rm.done(); + } else { + rm.setStatus(getStatus()); + rm.done(); + } + + // Unlock is done within this method + resetFormatToNatural(); + } + }); + } + + // In GDB, var-update will only report a change if -var-evaluate-expression has + // changed -- in the current format--. This means that situations like + // double z = 1.2; + // z = 1.4; + // Will not report a change if the format is anything else than natural. + // This is because 1.2 and 1.4 are both printed as 1, 0x1, etc + // Since we cache the values of every format, we must know if -any- format has + // changed, not just the current one. + // To solve this, we always do an update in the natural format; I am not aware + // of any case where the natural format would stay the same, but another format + // would change. However, since a var-update update all children as well, + // we must make sure these children are also in the natural format + // The simplest way to do this is that whenever we change the format + // of a variable object, we immediately set it back to natural with a second + // var-set-format command. + private void resetFormatToNatural() { + if (!getCurrentFormat().equals(IFormattedValues.NATURAL_FORMAT)) { + fCommandControl.queueCommand( + new MIVarSetFormat(fControlDmc, getGdbName(), IFormattedValues.NATURAL_FORMAT), + new DataRequestMonitor(getExecutor(), null) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + setCurrentFormat(IFormattedValues.NATURAL_FORMAT); + } + unlock(); + } + }); + } else { + unlock(); + } + } + + /** + * This method returns the list of children of the variable object passed as a parameter. + * + * @param rm + * The data request monitor that will hold the children returned + */ + private void getChildren(final MIExpressionDMC exprDmc, final DataRequestMonitor rm) { + + // If we already know the children, no need to go to the back-end + ExpressionInfo[] childrenArray = getChildren(); + if (childrenArray != null) { + rm.setData(childrenArray); + rm.done(); + return; + } + + // If the variable does not have children, we can return an empty list right away + if (getNumChildren() == 0) { + // First store the empty list, for the next time + setChildren(new ExpressionInfo[0]); + rm.setData(getChildren()); + rm.done(); + return; + } + + // For arrays (which could be very large), we create the children ourselves. This is + // to avoid creating an enormous amount of children variable objects that the view may + // never need. Using -var-list-children will create a variable object for every child + // immediately, that is why won't don't want to use it for arrays. + if (isArray()) { + ExpressionInfo[] childrenOfArray = new ExpressionInfo[getNumChildren()]; + for (int i= 0; i < childrenOfArray.length; i++) { + String indexStr = "[" + i + "]";//$NON-NLS-1$//$NON-NLS-2$ + String fullExpr = exprDmc.getExpression() + indexStr; + String relExpr = exprDmc.getRelativeExpression() + indexStr; + + childrenOfArray[i] = new ExpressionInfo(fullExpr, relExpr); + } + + // First store these children, for the next time + setChildren(childrenOfArray); + rm.setData(getChildren()); + rm.done(); + return; + } + + // No need to wait for the object to be ready since listing children can be performed + // at any time, as long as the object is created, which we know it is, since we can only + // be called here with a fully created object. + // Also no need to lock the object, since getting the children won't affect other operations + fCommandControl.queueCommand( + new MIVarListChildren(fControlDmc, getGdbName()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + MIVar[] children = getData().getMIVars(); + final List realChildren = new ArrayList(); + + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + // Store the children in our variable object cache + setChildren(realChildren.toArray(new ExpressionInfo[realChildren.size()])); + rm.setData(getChildren()); + rm.done(); + } + }; + + int numSubRequests = 0; + for (final MIVar child : children) { + // These children get created automatically as variable objects in GDB, so we should + // add them to the LRU. + // Note that if this variable object already exists, we can be in three scenarios: + // 1- the existing object is the same variable object in GDB. In this case, + // the existing and new one are identical so we can keep either one. + // 2- the existing object is out-of-scope and should be replaced by the new one. + // This can happen if a root was found to be out-of-scope, but this child + // had not been accessed and therefore had not been removed. + // 3- the existing object is an in-scope root object representing the same expression. + // In this case, either object can be kept and the other one can be deleted. + // The existing root could currently be in-use by another operation and may + // not be deleted; but since we can only have one entry in the LRU, we are + // forced to keep the existing root. Note that we need not worry about + // the newly created child since it will automatically be deleted when + // its root is deleted. + + numSubRequests++; + + final DataRequestMonitor childPathRm = + new DataRequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleOK() { + String childFullExpression = getData(); + + // For children that do not map to a real expression (such as f.public) + // GDB returns an empty string. In this case, we can use another unique + // name, such as the variable name + boolean fakeChild = false; + if (childFullExpression.length() == 0) { + fakeChild = true; + childFullExpression = child.getVarName(); + } + + // Now try to see if we already have this variable object in our Map + // Since our map names use the expression, and not the GDB given + // name, we must determine the correct map name from the varName + VariableObjectId childId = new VariableObjectId(); + childId.generateId(childFullExpression, getInternalId()); + MIVariableObject childVar = lruVariableList.get(childId); + + // Note that we must check the root to know if it is out-of-scope. + // We cannot check the child as it has not be updated and its + // outOfScope variable is not updated either. + if (childVar != null && childVar.getRootToUpdate().isOutOfScope()) { + childVar.deleteInGdb(); + childVar = null; + } + + if (childVar == null) { + childVar = new MIVariableObject(childId, MIVariableObject.this); + childVar.setGdbName(child.getVarName()); + childVar.setExpressionData( + childFullExpression, + child.getType(), + child.getNumChild()); + + // This will replace any existing entry + lruVariableList.put(childId, childVar); + + // Is this new child a modifiable descendant of the root? + if (childVar.isModifiable()) { + getRootToUpdate().addModifiableDescendant(child.getVarName(), childVar); + } + } + + if (fakeChild) { + // This is just a qualifier level of C++, and we must + // get the children of this child to get the real children + childVar.getChildren( + exprDmc, + new DataRequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleOK() { + ExpressionInfo[] vars = getData(); + for (ExpressionInfo realChild : vars) { + realChildren.add(realChild); + } + countingRm.done(); + } + }); + } else { + // This is a real child + realChildren.add(new ExpressionInfo(childFullExpression, child.getExp())); + countingRm.done(); + } + } + }; + + + if (isAccessQualifier(child.getExp())) { + // This is just a qualifier level of C++, so we don't need + // to call -var-info-path-expression for real, but just pretend we did. + childPathRm.setData(""); //$NON-NLS-1$ + childPathRm.done(); + } else { + // To build the child id, we need the fully qualified expression which we + // can get from -var-info-path-expression starting from GDB 6.7 + fCommandControl.queueCommand( + new MIVarInfoPathExpression(fControlDmc, child.getVarName()), + new DataRequestMonitor(getExecutor(), childPathRm) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + childPathRm.setData(getData().getFullExpression()); + } else { + // If we don't have var-info-path-expression + // build the expression ourselves + // Note that this does not work well yet + childPathRm.setData(buildChildExpression(exprDmc.getExpression(), child.getExp())); + } + childPathRm.done(); + } + }); + } + } + + countingRm.setDoneCount(numSubRequests); + } + }); + } + + /** + * This method builds a child expression based on its parent's expression. + * + * Currently, this does not support inherited class such as + * class foo : bar { + * ... + * } + * because we'll create foo.bar instead of (bar)foo. + */ + private String buildChildExpression(String parentExp, String childExp) { + return parentExp + "." + childExp; //$NON-NLS-1$ + // No need for a special case for arrays since we deal with arrays differently + // and don't call this method for them + } + + /** + * This method returns the count of children of the variable object passed as a parameter. + * + * @param rm + * The data request monitor that will hold the count of children returned + */ + private void getChildrenCount(final DataRequestMonitor rm) { + // No need to lock the object or wait for it to be ready since this operation does not + // affect other operations + rm.setData(getNumChildren()); + rm.done(); + } + + + + /** + * This method request the back-end to change the value of the variable object. + * + * @param value + * The new value. + * @param formatId + * The format the new value is specified in. + * @param rm + * The request monitor to indicate the operation is finished + */ + private void writeValue(String value, final String formatId, final RequestMonitor rm) { + + // If the variable is a complex structure (including an array), then we cannot write to it + if (isComplex()) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, + "Cannot change the value of a complex expression", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // First deal with the format. For GDB, the way to specify a format is to prefix the value with + // 0x for hex, 0 for octal etc So we need to make sure that 'value' has this prefix. + // Note that there is no way to specify a binary format for GDB so we convert 'value' + // into a decimal format. + // If the formatId is NATURAL, we do nothing for now because it is more complicated. + // For example for a bool, a value of "true" is correct and should be left as is, + // but for a pointer a value of 16 should be sent to GDB as 0x16. To figure this out, + // we need to know the type of the variable, which we don't have yet. + + if (formatId.equals(IFormattedValues.HEX_FORMAT)) { + if (!value.startsWith("0x")) value = "0x" + value; //$NON-NLS-1$ //$NON-NLS-2$ + } + else if (formatId.equals(IFormattedValues.OCTAL_FORMAT)) { + if (!value.startsWith("0")) value = "0" + value; //$NON-NLS-1$ //$NON-NLS-2$ + } + else if (formatId.equals(IFormattedValues.BINARY_FORMAT)) { + // convert from binary to decimal + if (value.startsWith("0b")) value = value.substring(2, value.length()); //$NON-NLS-1$ + try { + value = Integer.toString(Integer.parseInt(value, 2)); + } catch (NumberFormatException e) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, + "Invalid binary number: " + value, e)); //$NON-NLS-1$ + rm.done(); + return; + } + } + else if (formatId.equals(IFormattedValues.DECIMAL_FORMAT)) { + // nothing to do + } + else if (formatId.equals(IFormattedValues.NATURAL_FORMAT)) { + // we do nothing for now and let the user have put in the proper value + } + else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_HANDLE, + "Unknown format: " + formatId, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // No need to be in ready state or to lock the object + fCommandControl.queueCommand( + new MIVarAssign(fControlDmc, getGdbName(), value), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + resetValues(getData().getValue()); + rm.done(); + } + }); + } + + private boolean isAccessQualifier(String str) { + return str.equals("private") || str.equals("public") || str.equals("protected"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + public boolean isModifiable() { + if (!isComplex()) return true; + return false; + } + } + + private class MIRootVariableObject extends MIVariableObject { + + // Only root variables go through the GDB creation process + protected static final int STATE_NOT_CREATED = 10; + protected static final int STATE_CREATING = 11; + + private boolean outOfDate = false; + + // Modifiable descendants are any variable object that is a descendant or itself for + // which the value can change. + private Map modifiableDescendants; + + public MIRootVariableObject(VariableObjectId id) { + super(id, null); + currentState = STATE_NOT_CREATED; + modifiableDescendants = new HashMap(); + } + + public boolean isUpdating() { return currentState == STATE_UPDATING; } + + public boolean isOutOfDate() { return outOfDate; } + public void markAsOutOfDate() { outOfDate = true; } + + // Remember that we must add ourself as a modifiable descendant if our value can change + public void addModifiableDescendant(String gdbName, MIVariableObject descendant) { + modifiableDescendants.put(gdbName, descendant); + } + + public void processChanges(MIVarChange[] updates) { + for (MIVarChange update : updates) { + MIVariableObject descendant = modifiableDescendants.get(update.getVarName()); + // Descendant should never be null, but just to be safe + if (descendant != null) descendant.resetValues(update.getValue()); + } + } + + public void create(final IExpressionDMContext exprCtx, + final RequestMonitor rm) { + + if (currentState == STATE_NOT_CREATED) { + + currentState = STATE_CREATING; + + fCommandControl.queueCommand( + new MIVarCreate(exprCtx, exprCtx.getExpression()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + setGdbName(getData().getName()); + setExpressionData( + exprCtx.getExpression(), + getData().getType(), + getData().getNumChildren()); + + // Store the value returned at create (available in GDB 6.7) + // Don't store if it is an array, since we want to show + // the address of an array as its value + if (getData().getValue() != null && !isArray()) { + setValue(getCurrentFormat(), getData().getValue()); + } + + // If we are modifiable, we should be in our modifiable list + if (isModifiable()) { + addModifiableDescendant(getData().getName(), MIRootVariableObject.this); + } + + rm.done(); + + // Object can now be used by others + creationCompleted(true); + } else { + rm.setStatus(getStatus()); + rm.done(); + // Object must tell any waiting monitors that it failed + creationCompleted(false); + } + } + }); + } else { + assert false; + } + } + + private void creationCompleted(boolean success) { + // A creation completed we must be up-to-date, so we + // can tell any pending monitors that updates are done + if (success) { + currentState = STATE_READY; + while (updatesPending.size() > 0) { + DataRequestMonitor rm = updatesPending.poll(); + // Nothing to be re-created + rm.setData(false); + rm.done(); + } + } else { + currentState = STATE_NOT_CREATED; + + // Creation failed, inform anyone waiting. + while (updatesPending.size() > 0) { + RequestMonitor rm = updatesPending.poll(); + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, + "Unable to create variable object", null)); //$NON-NLS-1$ + rm.done(); + } + } + } + + @Override + public void update(final DataRequestMonitor rm) { + + if (isOutOfScope()) { + rm.setData(false); + rm.done(); + } else if (currentState != STATE_READY) { + // Object is not fully created or is being updated + // so add RequestMonitor to pending queue + updatesPending.add(rm); + } else if (outOfDate == false) { + rm.setData(false); + rm.done(); + } else { + // Object needs to be updated in the back-end + currentState = STATE_UPDATING; + + // In GDB, var-update will only report a change if -var-evaluate-expression has + // changed -- in the current format--. This means that situations like + // double z = 1.2; + // z = 1.4; + // Will not report a change if the format is anything else than natural. + // This is because 1.2 and 1.4 are both printed as 1, 0x1, etc + // Since we cache the values of every format, we must know if -any- format has + // changed, not just the current one. + // To solve this, we always do an update in the natural format; I am not aware + // of any case where the natural format would stay the same, but another format + // would change. However, since a var-update update all children as well, + // we must make sure these children are also in the natural format + // The simplest way to do this is that whenever we change the format + // of a variable object, we immediately set it back to natural with a second + // var-set-format command. This is done in the getValue() method + fCommandControl.queueCommand( + new MIVarUpdate(fControlDmc, getGdbName()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + currentState = STATE_READY; + + if (getStatus().isOK()) { + outOfDate = false; + + MIVarChange[] changes = getData().getMIVarChanges(); + if (changes.length > 0 && changes[0].isInScope() == false) { + // Object is out-of-scope + outOfScope = true; + + // We can delete this root in GDB right away. This is safe, even + // if the root has children, because they are also out-of-scope. + // We -must- also remove this entry from our LRU. If we don't + // we can end-up with a race condition that create this object + // twice, or have an infinite loop while never re-creating the object. + // The can happen if we update a child first then we request + // the root later, + lruVariableList.remove(getInternalId()); + + rm.setData(true); + rm.done(); + } else { + // The root object is now up-to-date, we must parse the changes, if any. + processChanges(changes); + + // We only mark this root as updated in our list if it is in-scope. + // For out-of-scope object, we don't ever need to re-update them so + // we don't need to add them to this list. + updatedRootList.add(MIRootVariableObject.this); + + rm.setData(false); + rm.done(); + } + + while (updatesPending.size() > 0) { + DataRequestMonitor pendingRm = updatesPending.poll(); + pendingRm.setData(false); + pendingRm.done(); + } + } else { + // We were not able to update for some reason + rm.setData(false); + rm.done(); + + while (updatesPending.size() > 0) { + DataRequestMonitor pendingRm = updatesPending.poll(); + pendingRm.setStatus(getStatus()); + pendingRm.done(); + } + } + } + }); + } + } + + /** + * This method request the back-end to delete a variable object. + * We check if the GDB name has been filled to confirm that this object + * was actually successfully created on the back-end. + * Only root variable objects are deleted, while children are left in GDB + * to be deleted automatically when their root is deleted. + */ + @Override + public void deleteInGdb() { + if (getGdbName() != null) { + fCommandControl.queueCommand( + new MIVarDelete(fControlDmc, getGdbName()), + new DataRequestMonitor(getExecutor(), null)); + // Nothing to do in the requestMonitor, since the object was already + // removed from our list before calling this method. + + // Set the GDB name to null to make sure we don't attempt to delete + // this variable a second time. This can happen if the LRU triggers + // an automatic delete. + setGdbName(null); + } else { + // Variable was never created or was already deleted, no need to do anything. + } + } + + + } + + /** + * This class represents an unique identifier for a variable object. + * + * The following must be considered to obtain a unique name: + * - the expression itself + * - the threadId specified in the execution context + * - relative depth of frame based on the frame context and the total depth of the stack + * + * Note that if no frameContext is specified (only Execution, or even only Container), which can + * characterize a global variable for example, we will only use the available information. + */ + private class VariableObjectId { + String fExpression = null; + Integer fThreadId = null; + Integer fFrameId = null; + + @Override + public boolean equals(Object other) { + if (other instanceof VariableObjectId) { + VariableObjectId otherId = (VariableObjectId) other; + return (fExpression == null ? otherId.fExpression == null : fExpression.equals(otherId.fExpression)) && + (fThreadId == null ? otherId.fThreadId == null : fThreadId.equals(otherId.fThreadId)) && + (fFrameId == null ? otherId.fFrameId == null : fFrameId.equals(otherId.fFrameId)); + } + return false; + } + + @Override + public int hashCode() { + return (fExpression == null ? 0 : fExpression.hashCode()) + + (fThreadId == null ? 0 : fThreadId.hashCode()) + + (fFrameId == null ? 0 : fFrameId.hashCode()); + } + + public void generateId(IExpressionDMContext exprCtx, final RequestMonitor rm) { + fExpression = exprCtx.getExpression(); + + IMIExecutionDMContext execCtx = DMContexts.getAncestorOfType(exprCtx, IMIExecutionDMContext.class); + if (execCtx == null) { + rm.done(); + return; + } + + fThreadId = new Integer(execCtx.getThreadId()); + + final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class); + if (frameCtx == null) { + rm.done(); + return; + } + + // We need the current stack depth to be able to make a unique and reproducible name + // for this expression. This is pretty efficient since the stackDepth will be retrieved + // from the StackService command cache after the first time. + fStackService.getStackDepth( + execCtx, 0, + new DataRequestMonitor(getExecutor(), rm) { + @Override + public void handleOK() { + fFrameId = new Integer(getData() - frameCtx.getLevel()); + rm.done(); + } + }); + } + + public void generateId(String childFullExp, VariableObjectId parentId) { + // The thread and frame are the same as the parent + fThreadId = parentId.fThreadId; + fFrameId = parentId.fFrameId; + // The expression here must be the one that is part of IExpressionContext for this child + // This will allow us to find a variable object directly + fExpression = childFullExp; + } + } + + /** + * This is the real work horse of managing our objects. Not only must every + * value be unique to get inserted, this also creates an LRU (least recently + * used). When we hit our size limitation, the LRUsed will be removed to + * make space. Removing means that a GDB request to delete the object is + * generated. We must also take into consideration the fact that GDB will + * automatically delete children of a variable object, when deleting the parent + * variable object. Our solution to that is to tweak the LRU to make sure that + * children are always older than their parents, to guarantee the children will + * always be delete before their parents. + * + */ + private class LRUVariableCache extends LinkedHashMap { + public static final long serialVersionUID = 0; + + // Maximum allowed concurrent variables + private static final int MAX_VARIABLE_LIST = 1000; + + public LRUVariableCache() { + super(0, // Initial load capacity + 0.75f, // Load factor as defined in JAVA 1.5 + true); // Order is dictated by access, not insertion + } + + // We never remove doing put operations. Instead, we rely on our get() operations + // to trigger the remove. See bug 200897 + @Override + public boolean removeEldestEntry(Map.Entry eldest) { + return false; + } + + @Override + public MIVariableObject get(Object key) { + MIVariableObject varObj = super.get(key); + touchAncestors(varObj); + + // If we're over our max size, attempt to remove eldest entry. + if (size() > MAX_VARIABLE_LIST) { + Map.Entry eldest = entrySet().iterator().next(); + // First make sure we are not deleting ourselves! + if (!eldest.getValue().equals(varObj)) { + if (eldest.getValue().currentState == MIVariableObject.STATE_READY) { + remove(eldest.getKey()); + } + } + } + return varObj; + } + + private void touchAncestors(MIVariableObject varObj) { + while (varObj != null) { + varObj = varObj.getParent(); + // If there is a parent, touch it + if (varObj != null) super.get(varObj.getInternalId()); + } + } + + @Override + public MIVariableObject put(VariableObjectId key, MIVariableObject varObj) { + MIVariableObject retVal = super.put(key, varObj); + + // Touch all parents of this element so as + // to guarantee they are not deleted before their children. + touchAncestors(varObj); + + return retVal; + } + + @Override + public MIVariableObject remove(Object key) { + MIVariableObject varObj = super.remove(key); + varObj.deleteInGdb(); + return varObj; + } + } + + /** Provides access to the GDB/MI back-end */ + private final ICommandControl fCommandControl; + // The stack service needs to be used to get information such + // as the stack depth to differentiate between expressions that have the + // same name but refer to a different context + private final IStack fStackService; + private IExpressions fExpressionService; + + // The top level context. It is used to operate on variable objects + // that have already been created, since those objects are referenced + // by name, irrespective of context. + // We do need a context, for when we will have multiple MIRunControls (multiple GDBs) + private final MIControlDMContext fControlDmc; + + // Typically, there will only be one listener, since only the ExpressionService will use this class + private final List fCommandProcessors = new ArrayList(); + + /** Our least recently used cache */ + private final LRUVariableCache lruVariableList; + + /** The list of root variable objects that have been updated */ + private final LinkedList updatedRootList = new LinkedList(); + + /** + * MIVariableManager constructor + * + * @param session + * The session we are working with + * @param tracker + * The service tracker that can be used to find other services + */ + public MIVariableManager(DsfSession session, DsfServicesTracker tracker) { + super(session); + lruVariableList = new LRUVariableCache(); + fCommandControl = tracker.getService(ICommandControl.class); + fStackService = tracker.getService(IStack.class); + fExpressionService = tracker.getService(IExpressions.class); + fControlDmc = ((AbstractMIControl)fCommandControl).getControlDMContext(); + + // Register to receive service events for this session. + getSession().addServiceEventListener(this, null); + } + + public void shutdown() { + getSession().removeServiceEventListener(this); + } + + /** + * This method returns a variable object based on the specified + * ExpressionDMC, creating it in GDB if it was not created already. + * The method guarantees that the variable is finished creating and that + * is it not out-of-scope. + * + * @param exprCtx + * The expression context to which the variable object is applied to. + * + * @param rm + * The data request monitor that will contain the requested variable object + */ + private void getVariable(final IExpressionDMContext exprCtx, + final DataRequestMonitor rm) { + // Generate an id for this expression so that we can determine if we already + // have a variable object tracking it. If we don't we'll need to create one. + final VariableObjectId id = new VariableObjectId(); + id.generateId( + exprCtx, + new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + getVariable(id, exprCtx, rm); + } + }); + } + + private void getVariable(final VariableObjectId id, + final IExpressionDMContext exprCtx, + final DataRequestMonitor rm) { + + final MIVariableObject varObj = lruVariableList.get(id); + + if (varObj == null) { + // We do not have this varObject, so we create it + createVariable(id, exprCtx, rm); + } else { + // We have found a varObject, but it may not be updated yet. + // Updating the object will also tell us if it is out-of-scope + // and if we should re-create it. + varObj.update(new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + + boolean shouldCreateNew = getData().booleanValue(); + + if (varObj.isOutOfScope()) { + // The variable object is out-of-scope and we + // should not use it. + if (shouldCreateNew) { + /** + * It may happen that when accessing a varObject we find it to be + * out-of-scope. The expression for which we are trying to access a varObject + * could still be valid, and therefore we should try to create a new varObject for + * that expression. This can happen for example if two methods use the same name + * for a variable. In the case when we find that a varObject is out-of-scope (when + * its root is out-of-scope) the following should be done: + * + * - create a new varObject for the expression (as a root varObject) and insert it + * in the LRU. Make sure that when creating children of this new varObject, they + * will replace any old children with the same name in the LRU (this is ok since the + * children being replaced are also out-of-scope). + */ + + createVariable(id, exprCtx, rm); + } else { + // Just request the variable object again + // We must use this call to handle the fact that + // the new object might be in the middle of being + // created. + getVariable(id, exprCtx, rm); + } + } else { + // The variable object is up-to-date and valid + rm.setData(varObj); + rm.done(); + } + } + }); + } + } + + + + /** + * This method creates a variable object in GDB. + */ + private void createVariable(final VariableObjectId id, + final IExpressionDMContext exprCtx, + final DataRequestMonitor rm) { + + // Variable objects that are created directly like this, are considered ROOT variable objects + // in comparison to variable objects that are children of other variable objects. + final MIRootVariableObject newVarObj = new MIRootVariableObject(id); + + // We must put this object in our map right away, in case it is + // requested again, before it completes its creation. + // Note that this will replace any old entry with the same id. + lruVariableList.put(id, newVarObj); + + newVarObj.create(exprCtx, new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (getStatus().isOK()) { + // Also store the object as a varObj that is up-to-date + updatedRootList.add(newVarObj); + + rm.setData(newVarObj); + rm.done(); + } else { + // Object was not created, remove it from our list + lruVariableList.remove(id); + + rm.setStatus(getStatus()); + rm.done(); + } + } + }); + } + + /** + * This method requests the back-end to change the value of an expression. + * + * @param expressionContext + * The context of the expression we want to change + * @param expressionValue + * The new value of the expression + * @param formatId + * The format in which the expressionValue is specified in + * @param rm + * The request monitor to indicate the operation is finished + */ + // This method can be called directly from the ExpressionService, since it cannot be cached + public void writeValue(final IExpressionDMContext ctx, final String expressionValue, + final String formatId, final RequestMonitor rm) { + + getVariable( + ctx, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleOK() { + getData().writeValue(expressionValue, formatId, rm); + } + }); + } + + public void queueCommand(final ICommand command, DataRequestMonitor rm) { + + // The MIVariableManager does not buffer commands itself, but sends them directly to the real + // MICommandControl service. Therefore, we must immediately tell our calling cache that the command + // has been sent, since we can never cancel it. Note that this removes any option of coalescing, + // but coalescing was not applicable to variableObjects anyway. + processCommandSent(command); + + if (command instanceof ExprMetaGetVar) { + @SuppressWarnings("unchecked") + final DataRequestMonitor drm = (DataRequestMonitor)rm; + final MIExpressionDMC exprCtx = (MIExpressionDMC)(command.getContext()); + + getVariable( + exprCtx, + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + drm.setData( + new ExprMetaGetVarInfo( + exprCtx.getRelativeExpression(), + getData().getNumChildren(), + getData().getType(), + !getData().isComplex())); + drm.done(); + } + }); + } else if (command instanceof ExprMetaGetAttributes) { + @SuppressWarnings("unchecked") + final DataRequestMonitor drm = (DataRequestMonitor)rm; + final IExpressionDMContext exprCtx = (IExpressionDMContext)(command.getContext()); + + getVariable( + exprCtx, + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + getData().getAttributes( + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + drm.setData(new ExprMetaGetAttributesInfo(getData())); + drm.done(); + } + }); + } + }); + + + } else if (command instanceof ExprMetaGetValue) { + @SuppressWarnings("unchecked") + final DataRequestMonitor drm = (DataRequestMonitor)rm; + final FormattedValueDMContext valueCtx = (FormattedValueDMContext)(command.getContext()); + final IExpressionDMContext exprCtx = DMContexts.getAncestorOfType(valueCtx, IExpressionDMContext.class); + + getVariable( + exprCtx, + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + getData().getValue( + valueCtx, + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + drm.setData( + new ExprMetaGetValueInfo(getData().getFormattedValue())); + drm.done(); + } + }); + } + }); + + } else if (command instanceof ExprMetaGetChildren) { + @SuppressWarnings("unchecked") + final DataRequestMonitor drm = (DataRequestMonitor)rm; + final MIExpressionDMC exprCtx = (MIExpressionDMC)(command.getContext()); + + getVariable( + exprCtx, + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + getData().getChildren( + exprCtx, + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + drm.setData(new ExprMetaGetChildrenInfo(getData())); + drm.done(); + } + }); + } + }); + + } else if (command instanceof ExprMetaGetChildCount) { + @SuppressWarnings("unchecked") + final DataRequestMonitor drm = (DataRequestMonitor)rm; + final IExpressionDMContext exprCtx = (IExpressionDMContext)(command.getContext()); + + getVariable( + exprCtx, + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + getData().getChildrenCount( + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleOK() { + drm.setData(new ExprMetaGetChildCountInfo(getData())); + drm.done(); + } + }); + } + }); + + } else if (command instanceof MIDataEvaluateExpression) { + // This does not use the variable objects but sends the command directly to the back-end + fCommandControl.queueCommand(command, rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, + "Unexpected Expression Meta command", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /* + * This is the command which allows the user to retract a previously issued command. The + * state of the command is that it is in the waiting queue and has not yet been handed + * to the back-end yet. + * + * (non-Javadoc) + * @see org.eclipse.dd.mi.service.command.IDebuggerControl#removeCommand(org.eclipse.dd.mi.service.command.commands.ICommand) + */ + public void removeCommand(ICommand command) { + // It is impossible to remove a command from the MIVariableManager. + // This should never be called, if we did things right. + assert false; + } + + /* + * This command allows the user to try and cancel commands which have been handed off to the + * back-end. Some back-ends support this with extended GDB/MI commands. If the support is there + * then we will attempt it. Because of the bidirectional nature of the GDB/MI command stream + * there is no guarantee that this will work. The response to the command could be on its way + * back when the cancel command is being issued. + * + * (non-Javadoc) + * @see org.eclipse.dd.mi.service.command.IDebuggerControl#cancelCommand(org.eclipse.dd.mi.service.command.commands.ICommand) + */ + public void cancelCommand(ICommand command) {} + public void addCommandListener(ICommandListener processor) { fCommandProcessors.add(processor); } + public void removeCommandListener(ICommandListener processor) { fCommandProcessors.remove(processor); } + public void addEventListener(IEventListener processor) {} + public void removeEventListener(IEventListener processor) {} + + + private void processCommandSent(ICommand command) { + for (ICommandListener processor : fCommandProcessors) { + processor.commandSent(command); + } + } + + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.IResumedDMEvent e) { + // Program has resumed, all variable objects need to be updated. + // Since only roots can actually be updated in GDB, we only need + // to deal with those. Also, to optimize this operation, we have + // a list of all roots that have been updated, so we only have to + // set those to needing to be updated. + MIRootVariableObject root; + while ((root = updatedRootList.poll()) != null) { + root.markAsOutOfDate(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.ISuspendedDMEvent e) { + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractCLIProcess.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractCLIProcess.java new file mode 100644 index 00000000000..c4fd26db62c --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractCLIProcess.java @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for additional features in DSF Reference implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.core.runtime.ILog; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.dsf.debug.service.command.IEventListener; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.CLICommand; +import org.eclipse.dd.mi.service.command.commands.MIInterpreterExecConsole; +import org.eclipse.dd.mi.service.command.commands.RawCommand; +import org.eclipse.dd.mi.service.command.output.MIConsoleStreamOutput; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MILogStreamOutput; +import org.eclipse.dd.mi.service.command.output.MIOOBRecord; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * This Process implementation tracks the process the GDB process. This + * process object is displayed in Debug view and is used to + * accept CLI commands and to write their output to the console. + * + * @see org.eclipse.debug.core.model.IProcess + */ +@ThreadSafe +public abstract class AbstractCLIProcess extends Process + implements IEventListener, ICommandListener +{ + public static final String PRIMARY_PROMPT = "(gdb)"; //$NON-NLS-1$ + public static final String SECONDARY_PROMPT = ">"; //$NON-NLS-1$ + + private final DsfSession fSession; + private final AbstractMIControl fCommandControl; + private final OutputStream fOutputStream = new CLIOutputStream(); + + // Client process console stream. + private final PipedInputStream fMIInConsolePipe; + private final PipedOutputStream fMIOutConsolePipe; + private final PipedInputStream fMIInLogPipe; + private final PipedOutputStream fMIOutLogPipe; + + private final boolean fUseExecConsole; + + private boolean fDisposed = false; + + /** + * Counter for tracking console commands sent by services. + * + * Services may issue console commands when the available MI commands are + * not sufficient. However, these commands may produce console and log + * output which should not be written to the user CLI terminal. + * + * This counter is incremented any time a console command is seen which was + * not generated by this class. It is decremented whenever a service CLI + * command is finished. When counter value is 0, the CLI process writes + * the console output. + */ + private int fSuppressConsoleOutputCounter = 0; + + private int fPrompt = 1; // 1 --> Primary prompt "(gdb)"; 2 --> Secondary Prompt ">" + + @ConfinedToDsfExecutor("fSession#getExecutor") + public AbstractCLIProcess(AbstractMIControl commandControl, boolean useExecConsole) throws IOException { + fSession = commandControl.getSession(); + fCommandControl = commandControl; + fUseExecConsole = useExecConsole; + + commandControl.addEventListener(this); + commandControl.addCommandListener(this); + + PipedInputStream miInConsolePipe = null; + PipedOutputStream miOutConsolePipe = null; + PipedInputStream miInLogPipe = null; + PipedOutputStream miOutLogPipe = null; + + try { + miOutConsolePipe = new PipedOutputStream(); + miInConsolePipe = new PipedInputStream(miOutConsolePipe); + miOutLogPipe = new PipedOutputStream(); + miInLogPipe = new PipedInputStream(miOutLogPipe); + } catch (IOException e) { + ILog log = MIPlugin.getDefault().getLog(); + if (log != null) { + log.log(new Status( + IStatus.ERROR, MIPlugin.PLUGIN_ID, -1, "Error when creating log pipes", e)); //$NON-NLS-1$ + } + } + // Must initialize these outside of the try block because they are final. + fMIOutConsolePipe = miOutConsolePipe; + fMIInConsolePipe = miInConsolePipe; + fMIOutLogPipe = miOutLogPipe; + fMIInLogPipe = miInLogPipe; + } + + protected DsfSession getSession() { return fSession; } + + protected AbstractMIControl getCommandControl() { return fCommandControl; } + + protected boolean isDisposed() { return fDisposed; } + + @ConfinedToDsfExecutor("fSession#getExecutor") + public void dispose() { + fCommandControl.removeEventListener(this); + fCommandControl.removeCommandListener(this); + + closeIO(); + fDisposed = true; + } + + private void closeIO() { + try { + fMIOutConsolePipe.close(); + } catch (IOException e) {} + try { + fMIInConsolePipe.close(); + } catch (IOException e) {} + try { + fMIOutLogPipe.close(); + } catch (IOException e) {} + try { + fMIInLogPipe.close(); + } catch (IOException e) {} + + } + + /** + * @see java.lang.Process#getErrorStream() + */ + @Override + public InputStream getErrorStream() { + return fMIInLogPipe; + } + + /** + * @see java.lang.Process#getInputStream() + */ + @Override + public InputStream getInputStream() { + return fMIInConsolePipe; + } + + /** + * @see java.lang.Process#getOutputStream() + */ + @Override + public OutputStream getOutputStream() { + return fOutputStream; + } + + + public void eventReceived(Object output) { + if (fSuppressConsoleOutputCounter > 0) return; + for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { + if (oobr instanceof MIConsoleStreamOutput) + { + MIConsoleStreamOutput out = (MIConsoleStreamOutput) oobr; + String str = out.getString(); + // Process the console stream too. + setPrompt(str); + try { + fMIOutConsolePipe.write(str.getBytes()); + fMIOutConsolePipe.flush(); + } catch (IOException e) { + } + } else if (oobr instanceof MILogStreamOutput) { + MILogStreamOutput out = (MILogStreamOutput) oobr; + String str = out.getString(); + if (str != null) { + try { + fMIOutLogPipe.write(str.getBytes()); + fMIOutLogPipe.flush(); + } catch (IOException e) { + } + } + } + } + } + + public void commandQueued(ICommand command) { + // Ignore + } + + public void commandSent(ICommand command) { + // Check if the command is a CLI command and if it did not originate from this class. + if (command instanceof CLICommand && + !(command instanceof ProcessCLICommand || command instanceof ProcessMIInterpreterExecConsole)) + { + fSuppressConsoleOutputCounter++; + } + } + + public void commandRemoved(ICommand command) { + // Ignore + } + + public void commandDone(ICommand command, ICommandResult result) { + if (command instanceof CLICommand && + !(command instanceof ProcessCLICommand || command instanceof ProcessMIInterpreterExecConsole)) + { + fSuppressConsoleOutputCounter--; + } + } + + void setPrompt(String line) { + fPrompt = 0; + // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=109733 + if (line == null) + return; + line = line.trim(); + if (line.equals(PRIMARY_PROMPT)) { + fPrompt = 1; + } else if (line.equals(SECONDARY_PROMPT)) { + fPrompt = 2; + } + } + + public boolean inPrimaryPrompt() { + return fPrompt == 1; + } + + public boolean inSecondaryPrompt() { + return fPrompt == 2; + } + + private class CLIOutputStream extends OutputStream { + private final StringBuffer buf = new StringBuffer(); + + @Override + public void write(int b) throws IOException { + buf.append((char)b); + if (b == '\n') { + // Throw away the newline. + final String bufString = buf.toString().trim(); + buf.setLength(0); + try { + fSession.getExecutor().execute(new DsfRunnable() { public void run() { + try { + post(bufString); + } catch (IOException e) { + // Pipe closed. + } + }}); + } catch (RejectedExecutionException e) { + // Session disposed. + } + } + } + + // Encapsulate the string sent to gdb in a fake + // command and post it to the TxThread. + public void post(String str) throws IOException { + if (isDisposed()) return; + ICommand cmd = null; + // 1- + // if We have the secondary prompt it means + // that GDB is waiting for more feedback, use a RawCommand + // 2- + // Do not use the interpreterexec for stepping operation + // the UI will fall out of step. + // 3- + // Normal Command Line Interface. + boolean secondary = inSecondaryPrompt(); + if (secondary) { + cmd = new RawCommand(getCommandControl().getControlDMContext(), str); + } + else if (fUseExecConsole && ! CLIEventProcessor.isSteppingOperation(str)) + { + cmd = new ProcessMIInterpreterExecConsole(getCommandControl().getControlDMContext(), str); + } + else { + cmd = new ProcessCLICommand(getCommandControl().getControlDMContext(), str); + } + final ICommand finalCmd = cmd; + fSession.getExecutor().execute(new DsfRunnable() { public void run() { + if (isDisposed()) return; + // Do not wait around for the answer. + getCommandControl().queueCommand(finalCmd, null); + }}); + } + } + + private class ProcessCLICommand extends CLICommand { + public ProcessCLICommand(IDMContext ctx, String oper) { + super(ctx, oper); + } + } + + private class ProcessMIInterpreterExecConsole extends MIInterpreterExecConsole { + public ProcessMIInterpreterExecConsole(IDMContext ctx, String cmd) { + super(ctx, cmd); + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java new file mode 100644 index 00000000000..96758120a14 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java @@ -0,0 +1,736 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * Ericsson - Modified for handling of multiple stacks and threads + *******************************************************************************/ +package org.eclipse.dd.mi.service.command; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.debug.service.command.ICommandListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.dsf.debug.service.command.IEventListener; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.command.commands.MICommand; +import org.eclipse.dd.mi.service.command.commands.MIStackSelectFrame; +import org.eclipse.dd.mi.service.command.commands.MIThreadSelect; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIList; +import org.eclipse.dd.mi.service.command.output.MIOOBRecord; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIParser; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIResultRecord; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * Base implementation of an MI control service. It provides basic handling + * of input/output channels, and processing of the commands. + *

+ * Extending classes need to implement the initialize() and shutdown() methods. + */ +public abstract class AbstractMIControl extends AbstractDsfService + implements ICommandControl +{ + final static String PROP_INSTANCE_ID = MIPlugin.PLUGIN_ID + ".miControlInstanceId"; //$NON-NLS-1$ + + /* + * Thread control variables for the transmit and receive threads. + */ + + private TxThread fTxThread; + private RxThread fRxThread; + + private int fCurrentStackLevel = -1; + private int fCurrentThreadId = -1; + + + private final BlockingQueue fTxCommands = new LinkedBlockingQueue(); + private final Map fRxCommands = Collections.synchronizedMap(new HashMap()); + + /* + * Various listener control variables used to keep track of listeners who want to monitor + * what the control object is doing. + */ + + private final List fCommandProcessors = new ArrayList(); + private final List fEventProcessors = new ArrayList(); + + /** + * Current command which have not been handed off to the backend yet. + */ + + private final List fCommandQueue = new ArrayList(); + + /** + * Flag indicating that the command control has stopped processing commands. + */ + private boolean fStoppedCommandProcessing = false; + + /* + * Public constructor. + */ + + public AbstractMIControl(DsfSession session) { + super(session); + } + + /** + * Starts the threads that process the debugger input/output channels. + * To be invoked by the initialization routine of the extending class. + * + * @param inStream + * @param outStream + */ + + protected void startCommandProcessing(InputStream inStream, OutputStream outStream) { + + fTxThread = new TxThread(outStream); + fRxThread = new RxThread(inStream); + fTxThread.start(); + fRxThread.start(); + } + + /** + * Stops the threads that process the debugger input/output channels, and notifies the + * results of the outstanding commands. To be invoked by the shutdown routine of the + * extending class. + * + * @param inStream + * @param outStream + */ + + private Status genStatus(String str) { + return new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, str, null); + } + + protected void stopCommandProcessing() { + fStoppedCommandProcessing = true; + + /* + * First go through the commands which have been queueud and not yet sent to the backend. + */ + for (CommandHandle commandHandle : fCommandQueue) { + if (commandHandle.getRequestMonitor() == null) continue; + commandHandle.getRequestMonitor().setStatus(genStatus("Connection is shut down")); //$NON-NLS-1$ + commandHandle.getRequestMonitor().done(); + } + + /* + * Now go through the commands which are outstanding in that they have been sent to the backend. + */ + synchronized(fRxCommands) { + for (CommandHandle commandHandle : fRxCommands.values()) { + if (commandHandle.getRequestMonitor() == null) continue; + commandHandle.getRequestMonitor().setStatus(genStatus( "Connection is shut down")); //$NON-NLS-1$ + commandHandle.getRequestMonitor().done(); + } + fRxCommands.clear(); + } + + /* + * Now handle any requests which have not been transmitted, but weconsider them handed off. + */ + List txCommands = new ArrayList(); + fTxCommands.drainTo(txCommands); + for (CommandHandle commandHandle : txCommands) { + if (commandHandle.getRequestMonitor() == null) continue; + commandHandle.getRequestMonitor().setStatus(genStatus("Connection is shut down")); //$NON-NLS-1$ + commandHandle.getRequestMonitor().done(); + } + } + + /** + * Queues the given MI command to be sent to the debugger back end. + * + * @param command Command to be executed. This parameter must be an + * instance of DsfMICommand, otherwise a ClassCastException will be + * thrown. + * @param rm Request completion monitor + * + * @see org.eclipse.dd.dsf.debug.service.command.ICommandControl#addCommand(org.eclipse.dd.dsf.debug.service.command.ICommand, org.eclipse.dd.dsf.concurrent.RequestMonitor) + */ + + public void queueCommand(ICommand command, DataRequestMonitor rm) { + + // If the command control stopped processing commands, just return an error immediately. + if (fStoppedCommandProcessing) { + rm.setStatus(genStatus("Connection is shut down")); //$NON-NLS-1$ + rm.done(); + return; + } + + // Cast the command to MI Command type. This will cause a cast exception to be + // thrown if the client did not give an MI command as an argument. + @SuppressWarnings("unchecked") + MICommand miCommand = (MICommand) command; + + // Cast the return token to match the result type of MI Command. This is checking + // against an erased type so it should never throw any exceptions. + @SuppressWarnings("unchecked") + DataRequestMonitor miDone = (DataRequestMonitor)rm; + + final CommandHandle handle = new CommandHandle(miCommand, miDone); + + if ( fRxCommands.size() > 3 ) { + + /* + * We only allow three outstanding commands to be on the wire to the backend + * at any one time. This allows for coalesence as well as allowing for canceling + * existing commands on a state change. So we add it to the waiting list and let + * the user know they can now work with this item if need be. + */ + fCommandQueue.add(handle); + processCommandQueued(handle); + } else { + + /* + * We are putting this one on the wire. We need to add it to the waiting list so + * the user has the chance to cancel it when we tell them we are acknowleding it + * has been officially accepted. They could choose to cancel it before we go and + * send it. That is why we put it into the QUEUE and then check to see if it is + * still there. + */ + fCommandQueue.add(handle); + processCommandQueued(handle); + + if ( fCommandQueue.remove(handle) ) { + processCommandSent(handle); + + // Before the command is sent, Check the Thread Id and send it to + // the queue only if the id has been changed. + if( handle.getThreadId()!= null && + handle.getThreadId().intValue() != fCurrentThreadId && handle.getThreadId().intValue() != 0) + { + // Re-set the level + fCurrentThreadId = handle.getThreadId().intValue(); + CommandHandle cmdHandle = new CommandHandle( + new MIThreadSelect(handle.fCommand.getContext(), fCurrentThreadId), null); + fTxCommands.add(cmdHandle); + MIPlugin.debug(MIPlugin.getDebugTime() + " " + cmdHandle.getCommand()); //$NON-NLS-1$ + } + + // Before the command is sent, Check the Stack level and send it to + // the queue only if the level has been changed. + if( handle.getStackFrameId()!= null && + handle.getStackFrameId().intValue() != fCurrentStackLevel) + { + // Re-set the level + fCurrentStackLevel = handle.getStackFrameId().intValue(); + CommandHandle cmdHandle = new CommandHandle( + new MIStackSelectFrame(handle.fCommand.getContext(), fCurrentStackLevel), null); + fTxCommands.add(cmdHandle); + MIPlugin.debug(MIPlugin.getDebugTime() + " " + cmdHandle.getCommand()); //$NON-NLS-1$ + } + fTxCommands.add(handle); + } + } + + } + + /* + * This is the command which allows the user to retract a previously issued command. The + * state of the command is that it is in the waiting queue and has not yet been handed + * to the backend yet. + * + * (non-Javadoc) + * @see org.eclipse.dd.mi.service.command.IDebuggerControl#removeCommand(org.eclipse.dd.mi.service.command.commands.ICommand) + */ + public void removeCommand(ICommand command) { + + synchronized(fCommandQueue) { + + for ( CommandHandle handle : fCommandQueue ) { + if ( handle.getCommand().equals(command)) { + fCommandQueue.remove(handle); + + final CommandHandle finalHandle = handle; + getExecutor().execute(new DsfRunnable() { + public void run() { + processCommandRemoved(finalHandle); + } + }); + break; + } + } + } + } + + /* + * This command allows the user to try and cancel commands which have been handed off to the + * backend. Some backends support this with extended GDB/MI commands. If the support is there + * then we will attempt it. Because of the bidirectional nature of the GDB/MI command stream + * there is no guarantee that this will work. The response to the command could be on its way + * back when the cancel command is being issued. + * + * (non-Javadoc) + * @see org.eclipse.dd.mi.service.command.IDebuggerControl#cancelCommand(org.eclipse.dd.mi.service.command.commands.ICommand) + */ + public void cancelCommand(ICommand command) {} + + /* + * Allows a user ( typically a cache manager ) to sign up a listener to monitor command queue + * activity. + * + * (non-Javadoc) + * @see org.eclipse.dd.mi.service.command.IDebuggerControl#addCommandListener(org.eclipse.dd.mi.service.command.IDebuggerControl.ICommandListener) + */ + public void addCommandListener(ICommandListener processor) { fCommandProcessors.add(processor); } + + /* + * Allows a user ( typically a cache manager ) to remove a monitoring listener. + * (non-Javadoc) + * @see org.eclipse.dd.mi.service.command.IDebuggerControl#removeCommandListener(org.eclipse.dd.mi.service.command.IDebuggerControl.ICommandListener) + */ + public void removeCommandListener(ICommandListener processor) { fCommandProcessors.remove(processor); } + + /* + * Allows a user to sign up to a listener which handles out of band messages ( events ). + * + * (non-Javadoc) + * @see org.eclipse.dd.mi.service.command.IDebuggerControl#addEventListener(org.eclipse.dd.mi.service.command.IDebuggerControl.IEventListener) + */ + public void addEventListener(IEventListener processor) { fEventProcessors.add(processor); } + + /* + * Allows a user to remove a event monitoring listener. + * + * (non-Javadoc) + * @see org.eclipse.dd.mi.service.command.IDebuggerControl#removeEventListener(org.eclipse.dd.mi.service.command.IDebuggerControl.IEventListener) + */ + public void removeEventListener(IEventListener processor) { fEventProcessors.remove(processor); } + + abstract public MIControlDMContext getControlDMContext(); + + /* + * These are the service routines which perform the various callouts back to the listeners. + */ + + private void processCommandQueued(CommandHandle commandHandle) { + for (ICommandListener processor : fCommandProcessors) { + processor.commandQueued(commandHandle.getCommand()); + } + } + private void processCommandRemoved(CommandHandle commandHandle) { + for (ICommandListener processor : fCommandProcessors) { + processor.commandRemoved(commandHandle.getCommand()); + } + } + + private void processCommandSent(CommandHandle commandHandle) { + MIPlugin.debug(MIPlugin.getDebugTime() + " " + commandHandle.getToken() + commandHandle.getCommand()); //$NON-NLS-1$ + for (ICommandListener processor : fCommandProcessors) { + processor.commandSent(commandHandle.getCommand()); + } + } + + private void processCommandDone(CommandHandle commandHandle, ICommandResult result) { + + /* + * Provide tracking for out processing. + */ + if ( result != null ) { + MIInfo cmdResult = (MIInfo) result ; + MIOutput output = cmdResult.getMIOutput(); + MIPlugin.debug(MIPlugin.getDebugTime() + " " + output + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } + else + { + MIPlugin.debug(MIPlugin.getDebugTime() + " result output not available\n"); //$NON-NLS-1$ + } + + /* + * Tell the listeners we have completed this one. + */ + for (ICommandListener processor : fCommandProcessors) { + processor.commandDone(commandHandle == null ? null : commandHandle.getCommand(), result); + } + } + + private void processEvent(MIOutput output) { + MIPlugin.debug(MIPlugin.getDebugTime() + " " + output + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + for (IEventListener processor : fEventProcessors) { + processor.eventReceived(output); + } + } + + /* + * A global counter for all command, the token will be use to identify uniquely a command. + * Unless the value wraps around which is unlikely. + */ + + private static int globalCounter = 0 ; + + private static synchronized int getUniqToken() { + int count = ++globalCounter; + // If we ever wrap around. + if (count <= 0) { + count = globalCounter = 1; + } + return count; + } + + /* + * Support class which creates a convenient wrapper for holding all information about an + * individual request. + */ + + public static class CommandHandle { + + private MICommand fCommand; + private DataRequestMonitor fRequestMonitor; + private int fTokenId ; + + CommandHandle(MICommand c, DataRequestMonitor d) { + fCommand = c; + fRequestMonitor = d; + fTokenId = getUniqToken() ; + } + + public MICommand getCommand() { return fCommand; } + public DataRequestMonitor getRequestMonitor() { return fRequestMonitor; } + public Integer getToken() { return fTokenId; } + //public String getThreadId() { return null; } + public Integer getStackFrameId() { + IFrameDMContext frameCtx = DMContexts.getAncestorOfType(fCommand.getContext(), IFrameDMContext.class); + if(frameCtx != null) + return frameCtx.getLevel(); + return null; + } + + public Integer getThreadId() { + IMIExecutionDMContext execCtx = DMContexts.getAncestorOfType(fCommand.getContext(), IMIExecutionDMContext.class); + if(execCtx != null) + return execCtx.getThreadId(); + return null; + } + } + + /* + * This is the transmitter thread. When a command is given to this thread it has been + * considered to be sent, even if it has not actually been sent yet. This assumption + * makes it easier from state management. Whomever fill this pipeline handles all of + * the required state notofication ( callbacks ). This thread simply physically gives + * the message to the backend. + */ + + private class TxThread extends Thread { + + final private OutputStream fOutputStream; + + public TxThread(OutputStream outStream) { + super("MI TX Thread"); //$NON-NLS-1$ + fOutputStream = outStream; + } + + @Override + public void run () { + while (true) { + CommandHandle commandHandle = null; + + /* + * Note: Acquiring locks for both fRxCommands and fTxCommands collections. + */ + synchronized(fTxCommands) { + try { + commandHandle = fTxCommands.take(); + } catch (InterruptedException e) { + break; // Shutting down. + } + + if (commandHandle == null) { + + break; // Null command is an indicator that we're shutting down. + } + + /* + * We note that this is an outstanding request at this point. + */ + fRxCommands.put(commandHandle.getToken(), commandHandle); + } + + /* + * Construct the new command and push this command out the pipeline. + */ + + String str = commandHandle.getToken() + commandHandle.getCommand().constructCommand(); + + try { + if (fOutputStream != null) { + fOutputStream.write(str.getBytes()); + fOutputStream.flush(); + } + } catch (IOException e) { + // Shutdown thread in case of IO error. + break; + } + } + } + } + + private class RxThread extends Thread { + private final InputStream fInputStream; + private final MIParser fMiParser = new MIParser(); + + /** + * List of out of band records since the last result record. Out of band records are + * required for processing the results of CLI commands. + */ + private final List fAccumulatedOOBRecords = new ArrayList(); + public RxThread(InputStream inputStream) { + super("MI RX Thread"); //$NON-NLS-1$ + fInputStream = inputStream; + } + + @Override + public void run() { + BufferedReader reader = new BufferedReader(new InputStreamReader(fInputStream)); + try { + String line; + while ((line = reader.readLine()) != null) { + if (line.length() != 0) { + processMIOutput(line); + } + } + } catch (IOException e) { + // Socket is shut down. + } catch (RejectedExecutionException e) { + // Dispatch thread is down. + } + } + + private MIResult findResultRecord(MIResult[] results, String variable) { + for (int i = 0; i < results.length; i++) { + if (variable.equals(results[i].getVariable())) { + return results[i]; + } + } + return null; + } + + private String getStatusString(MICommand origCommand, MIOutput response ) { + + // Attempt to extract a message from the result record: + String message = null; + String[] parameters = null; + if (response != null && response.getMIResultRecord() != null) { + MIResult[] results = response.getMIResultRecord().getMIResults(); + + // Extract the parameters + MIResult paramsRes = findResultRecord(results, "parameters"); //$NON-NLS-1$ + if (paramsRes != null && paramsRes.getMIValue() instanceof MIList) { + MIValue[] paramValues = ((MIList)paramsRes.getMIValue()).getMIValues(); + parameters = new String[paramValues.length]; + for (int i = 0; i < paramValues.length; i++) { + if (paramValues[i] instanceof MIConst) { + parameters[i] = ((MIConst)paramValues[i]).getString(); + } else { + parameters[i] = ""; //$NON-NLS-1$ + } + } + } + MIResult messageRes = findResultRecord(results, "message"); //$NON-NLS-1$ + if (messageRes != null && messageRes.getMIValue() instanceof MIConst) { + message = ((MIConst)messageRes.getMIValue()).getString(); + } + // FRCH: I believe that the actual string is "msg" ... + // FRCH: (at least for the version of gdb I'm using) + else { + messageRes = findResultRecord(results, "msg"); //$NON-NLS-1$ + if (messageRes != null && messageRes.getMIValue() instanceof MIConst) { + message = ((MIConst)messageRes.getMIValue()).getString(); + } + } + } + StringBuilder clientMsg = new StringBuilder(); + clientMsg.append("Failed to execute MI command:\n"); //$NON-NLS-1$ + clientMsg.append(origCommand.toString()); + if (message != null) { + clientMsg.append("Error message from debugger back end:\n"); //$NON-NLS-1$ + if (parameters != null) { + try { + clientMsg.append(MessageFormat.format(message, (Object[])parameters)); + } catch(IllegalArgumentException e2) { + // Message format string invalid. Fallback to just appending the strings. + clientMsg.append(message); + clientMsg.append(parameters); + } + } else { + clientMsg.append(message); + } + } + return clientMsg.toString(); + } + + void processMIOutput(String line) { + MIParser.RecordType recordType = fMiParser.getRecordType(line); + + if (recordType == MIParser.RecordType.ResultRecord) { + final MIResultRecord rr = fMiParser.parseMIResultRecord(line); + final MIOutput response = new MIOutput(rr, + fAccumulatedOOBRecords.toArray(new MIOOBRecord[fAccumulatedOOBRecords.size()]) ); + fAccumulatedOOBRecords.clear(); + + + /* + * Find the command in the current output list. If we cannot then this is + * some form of asynchronous notification. Or perhaps general IO. + */ + int id = rr.getToken(); + final CommandHandle commandHandle = fRxCommands.remove(id); + + if (commandHandle != null) { + + MIInfo result = commandHandle.getCommand().getResult(response); + DataRequestMonitor rm = commandHandle.getRequestMonitor(); + + /* + * Not all users want to get there results. They indicate so by not having + * a completion object. + */ + if ( rm != null ) { + rm.setData(result); + + /* + * We need to indicate if this request had an error or not. + */ + String errorResult = rr.getResultClass(); + + if ( errorResult.equals(MIResultRecord.ERROR) ) { + String status = getStatusString(commandHandle.getCommand(),response); + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.REQUEST_FAILED, status, null)); + } + + /* + * We need to complete the command on the DSF thread for data security. + */ + final ICommandResult finalResult = result; + getExecutor().execute(new DsfRunnable() { + public void run() { + /* + * Complete the specific command. + */ + if (commandHandle.getRequestMonitor() != null) { + commandHandle.getRequestMonitor().done(); + } + + /* + * Now tell the generic listeners about it. + */ + processCommandDone(commandHandle, finalResult); + } + @Override + public String toString() { + return "MI command output received for: " + commandHandle.getCommand(); //$NON-NLS-1$ + } + }); + } else { + /* + * While the specific requestor did not care about the completion we + * need to call any listeners. This could have been a CLI command for + * example and the CommandDone listeners there handle the IO as part + * of the work. + */ + + final ICommandResult finalResult = result; + getExecutor().execute(new DsfRunnable() { + public void run() { + processCommandDone(commandHandle, finalResult); + } + @Override + public String toString() { + return "MI command output received for: " + commandHandle.getCommand(); //$NON-NLS-1$ + } + }); + } + } else { + /* + * GDB apparently can sometimes send multiple responses to the same command. In those cases, + * the command handle is gone, so post the result as an event. Again this must be done on the + * DSF thread for integrity. + */ + getExecutor().execute(new DsfRunnable() { + public void run() { + processEvent(response); + } + @Override + public String toString() { + return "MI asynchronous output received: " + response; //$NON-NLS-1$ + } + }); + } + //} else { + } else if (recordType == MIParser.RecordType.OOBRecord) { + // Process OOBs + final MIOOBRecord oob = fMiParser.parseMIOOBRecord(line); + fAccumulatedOOBRecords.add(oob); + final MIOutput response = new MIOutput(oob); + + + + /* + * OOBS are events. So we pass them to any event listeners who want to see them. Again this must + * be done on the DSF thread for integrity. + */ + getExecutor().execute(new DsfRunnable() { + public void run() { + processEvent(response); + } + @Override + public String toString() { + return "MI asynchronous output received: " + response; //$NON-NLS-1$ + } + }); + } + + getExecutor().execute(new DsfRunnable() { + public void run() { + if ( fCommandQueue.size() > 0 ) { + CommandHandle comHandle = fCommandQueue.remove(0); + if ( comHandle != null ) { + processCommandQueued(comHandle); + processCommandSent(comHandle); + fTxCommands.add(comHandle); + } + } + } + }); + } + } + + public void resetCurrentThreadLevel(){ + fCurrentThreadId = -1; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java new file mode 100644 index 00000000000..c2af69c36d4 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java @@ -0,0 +1,353 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson AB - Additional handling of events + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command; + +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.ISignals.ISignalsDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.dsf.debug.service.command.IEventListener; +import org.eclipse.dd.mi.service.command.commands.CLICommand; +import org.eclipse.dd.mi.service.command.commands.MIInterpreterExecConsole; +import org.eclipse.dd.mi.service.command.events.MIBreakpointChangedEvent; +import org.eclipse.dd.mi.service.command.events.MIDetachedEvent; +import org.eclipse.dd.mi.service.command.events.MIErrorEvent; +import org.eclipse.dd.mi.service.command.events.MIEvent; +import org.eclipse.dd.mi.service.command.events.MIRunningEvent; +import org.eclipse.dd.mi.service.command.events.MISignalChangedEvent; +import org.eclipse.dd.mi.service.command.events.MIThreadCreatedEvent; +import org.eclipse.dd.mi.service.command.output.MIConsoleStreamOutput; +import org.eclipse.dd.mi.service.command.output.MIOOBRecord; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIResultRecord; + +/** + * GDB debugger output listener. + */ +@ConfinedToDsfExecutor("fConnection#getExecutor") +public class CLIEventProcessor + implements ICommandListener, IEventListener +{ + private final AbstractMIControl fCommandControl; + private final MIInferiorProcess fInferior; + private final IContainerDMContext fContainerDmc; + private final List fEventList = new LinkedList(); + + // Last Thread ID created + private static int fLastThreadId; + + + public CLIEventProcessor(AbstractMIControl connection, IContainerDMContext containerDmc, MIInferiorProcess inferior) { + fCommandControl = connection; + fInferior = inferior; + fContainerDmc = containerDmc; + connection.addCommandListener(this); + connection.addEventListener(this); + // Re-set the counter + fLastThreadId = 0; + } + + public void dispose() { + fCommandControl.removeCommandListener(this); + fCommandControl.removeEventListener(this); + } + + public void commandSent(ICommand command) { + if (command instanceof CLICommand) { + processStateChanges( (CLICommand)command ); + } + else if (command instanceof MIInterpreterExecConsole) { + processStateChanges( (MIInterpreterExecConsole)command ); + } + } + + public void commandDone(ICommand command, ICommandResult result) { + if (command instanceof CLICommand) { + processSettingChanges( (CLICommand)command ); + } + else if (command instanceof MIInterpreterExecConsole) { + processSettingChanges( (MIInterpreterExecConsole)command ); + } + fEventList.clear(); + } + + public void commandQueued(ICommand command) { + // No action + } + + public void commandRemoved(ICommand command) { + // No action + } + + public void eventReceived(Object output) { + for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { + fEventList.add(oobr); + + if (oobr instanceof MIConsoleStreamOutput) { + // Process Events of type DsfMIConsoleStreamOutput here + MIConsoleStreamOutput exec = (MIConsoleStreamOutput) oobr; + + // Look for events with Pattern ^[New Thread 1077300144 (LWP 7973) + Pattern pattern = Pattern.compile("(^\\[New Thread.*LWP\\s*)(\\d*)", Pattern.MULTILINE); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(exec.getCString()); + if (matcher.find()) { + //fMapThreadIds.put(matcher.group(2), Integer.valueOf(++fLastThreadId)); + //DsfMIEvent e = new DsfMIThreadCreatedEvent(Integer.valueOf(matcher.group(2))); + MIEvent e = new MIThreadCreatedEvent(fContainerDmc, ++fLastThreadId); + // Dispatch DsfMIThreadCreatedEvent + fCommandControl.getSession().dispatchEvent(e, fCommandControl.getProperties()); + } + // HACK - For GDB thread exit events, we won't use the events generated by GDB. This event is + // raised in GDBRunControl class by polling and comparing the ExecutionContexts returned by + // -thread-list-ids command. This is done as threads reported by exit event are still reported till + // they completely exit the system. + // Look for Thread Exited Event with Pattern [Thread 1077300144 (LWP 23832) exited]\n + // See bug 200615 for details. +// pattern = Pattern.compile("(^\\[Thread.*LWP\\s)(\\d*)(.*exited.*$)", Pattern.MULTILINE); //$NON-NLS-1$ +// matcher = pattern.matcher(exec.getCString()); +// if (matcher.find()) { +// DsfMIEvent e = new DsfMIThreadExitEvent(fMapThreadIds.get(matcher.group(2)).intValue()); +// // Dispatch DsfMIThreadExitEvent +// fConnection.getSession().dispatchEvent(e, fConnection.getProperties()); +// } + } + } + + // GDB can send an error result following sending an OK result. + // In this case the error is routed as an event. + MIResultRecord rr = ((MIOutput)output).getMIResultRecord(); + if (rr != null) { + // Check if the state changed. + String state = rr.getResultClass(); + if (fInferior != null && "error".equals(state)) { //$NON-NLS-1$ + if (fInferior.getState() == MIInferiorProcess.State.RUNNING) { + fInferior.setState(MIInferiorProcess.State.RUNNING); + fCommandControl.getSession().dispatchEvent( + MIErrorEvent.parse(fContainerDmc, rr.getToken(), rr.getMIResults(), null), + fCommandControl.getProperties()); + } + } + } + } + + + private void processStateChanges(CLICommand cmd) { + String operation = cmd.getOperation().trim(); + // In refactoring we are no longer genwerating the token id as + // part of the command. It is passed here and stored away and + // then never really used. So it has just been changed to 0. + processStateChanges(0, operation); + } + + private void processStateChanges(MIInterpreterExecConsole exec) { + String[] operations = exec.getParameters(); + if (operations != null && operations.length > 0) { + // In refactoring we are no longer genwerating the token id as + // part of the command. It is passed here and stored away and + // then never really used. So it has just been changed to 0. + processStateChanges(0, operations[0]); + } + } + + private void processStateChanges(int token, String operation) { + // Get the command name. + int indx = operation.indexOf(' '); + if (indx != -1) { + operation = operation.substring(0, indx).trim(); + } else { + operation = operation.trim(); + } + + // Check the type of command + + int type = getSteppingOperationKind(operation); + if (type != -1) { + // if it was a step instruction set state running + MIEvent event = new MIRunningEvent(fContainerDmc, token, type); + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + + /** + * An attempt to discover the command type and + * fire an event if necessary. + */ + private void processSettingChanges(CLICommand cmd) { + String operation = cmd.getOperation().trim(); + // In refactoring we are no longer genwerating the token id as + // part of the command. It is passed here and stored away and + // then never really used. So it has just been changed to 0. + processSettingChanges(cmd.getContext(), 0, operation); + } + + private void processSettingChanges(MIInterpreterExecConsole exec) { + String[] operations = exec.getParameters(); + if (operations != null && operations.length > 0) { + // In refactoring we are no longer genwerating the token id as + // part of the command. It is passed here and stored away and + // then never really used. So it has just been changed to 0. + processSettingChanges(exec.getContext(), 0, operations[0]); + } + } + + private void processSettingChanges(IDMContext dmc, int token, String operation) { + // Get the command name. + int indx = operation.indexOf(' '); + if (indx != -1) { + operation = operation.substring(0, indx).trim(); + } else { + operation = operation.trim(); + } + + // Check the type of command + + if (isSettingBreakpoint(operation) || + isSettingWatchpoint(operation) || + isChangeBreakpoint(operation) || + isDeletingBreakpoint(operation)) + { + // We know something change, we just do not know what. + // So the easiest way is to let the top layer handle it. + MIEvent event = new MIBreakpointChangedEvent( + DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class), 0); + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } else if (isSettingSignal(operation)) { + // We do no know which signal let the upper layer find it. + MIEvent event = new MISignalChangedEvent( + DMContexts.getAncestorOfType(dmc, ISignalsDMContext.class), ""); //$NON-NLS-1$ + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } else if (isDetach(operation)) { + // if it was a "detach" command change the state. + MIEvent event = new MIDetachedEvent(DMContexts.getAncestorOfType(dmc, MIControlDMContext.class), token); + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + + private static int getSteppingOperationKind(String operation) { + int type = -1; + /* execution commands: n, next, s, step, si, stepi, u, until, finish, + c, continue, fg */ + if (operation.equals("n") || operation.equals("next")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.NEXT; + } else if (operation.equals("ni") || operation.equals("nexti")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.NEXTI; + } else if (operation.equals("s") || operation.equals("step")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.STEP; + } else if (operation.equals("si") || operation.equals("stepi")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.STEPI; + } else if (operation.equals("u") || //$NON-NLS-1$ + (operation.startsWith("unt") && "until".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.UNTIL; + } else if (operation.startsWith("fin") && "finish".indexOf(operation) != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.FINISH; + } else if (operation.equals("c") || operation.equals("fg") || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("cont") && "continue".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.CONTINUE; + } else if (operation.startsWith("sig") && "signal".indexOf(operation) != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.CONTINUE; + } else if (operation.startsWith("j") && "jump".indexOf(operation) != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.CONTINUE; + } else if (operation.equals("r") || operation.equals("run")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.CONTINUE; + } + return type; + } + + /** + * Return true if the operation is a stepping operation. + * + * @param operation + * @return + */ + public static boolean isSteppingOperation(String operation) { + int type = getSteppingOperationKind(operation); + return type != -1; + } + + private boolean isSettingBreakpoint(String operation) { + boolean isbreak = false; + /* breakpoints: b, break, hbreak, tbreak, rbreak, thbreak */ + /* watchpoints: watch, rwatch, awatch, tbreak, rbreak, thbreak */ + if ((operation.startsWith("b") && "break".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("tb") && "tbreak".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("hb") && "hbreak".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("thb") && "thbreak".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("rb") && "rbreak".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + isbreak = true; + } + return isbreak; + } + + private boolean isSettingWatchpoint(String operation) { + boolean isWatch = false; + /* watchpoints: watch, rwatch, awatch, tbreak, rbreak, thbreak */ + if ((operation.startsWith("wa") && "watch".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("rw") && "rwatch".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("aw") && "awatch".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + isWatch = true; + } + return isWatch; + } + + private boolean isDeletingBreakpoint(String operation) { + boolean isDelete = false; + /* deleting breaks: clear, delete */ + if ((operation.startsWith("cl") && "clear".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.equals("d") || (operation.startsWith("del") && "delete".indexOf(operation) != -1))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + isDelete = true; + } + return isDelete; + } + + private boolean isChangeBreakpoint(String operation) { + boolean isChange = false; + /* changing breaks: enable, disable */ + if ((operation.equals("dis") || operation.equals("disa") || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("disa") && "disable".indexOf(operation) != -1)) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.equals("en") || (operation.startsWith("en") && "enable".indexOf(operation) != -1)) || //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + (operation.startsWith("ig") && "ignore".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("cond") && "condition".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + isChange = true; + } + return isChange; + } + + private boolean isSettingSignal(String operation) { + boolean isChange = false; + /* changing signal: handle, signal */ + if (operation.startsWith("ha") && "handle".indexOf(operation) != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + isChange = true; + } + return isChange; + } + + /** + * @param operation + * @return + */ + private boolean isDetach(String operation) { + return (operation.startsWith("det") && "detach".indexOf(operation) != -1); //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIControlDMContext.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIControlDMContext.java new file mode 100644 index 00000000000..bee6c4174d2 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIControlDMContext.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2007 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.dd.mi.service.command; + +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.service.IDsfService; +import org.osgi.framework.Constants; + +/** + * + */ +public class MIControlDMContext extends AbstractDMContext { + + private final String fCommandControlFilter; + private final String fCommandControlId; + + public MIControlDMContext(String sessionId, String commandControlId) { + this(sessionId, DMContexts.EMPTY_CONTEXTS_ARRAY, commandControlId); + } + + public MIControlDMContext(String sessionId, IDMContext[] parents, String commandControlId) { + super(sessionId, parents); + + fCommandControlId = commandControlId; + fCommandControlFilter = + "(&" + //$NON-NLS-1$ + "(" + Constants.OBJECTCLASS + "=" + ICommandControl.class.getName() + ")" + //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + "(" + IDsfService.PROP_SESSION_ID + "=" + sessionId + ")" + //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + "(" + AbstractMIControl.PROP_INSTANCE_ID + "=" + commandControlId + ")" + //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + ")"; //$NON-NLS-1$ + } + + public String getCommandControlFilter() { + return fCommandControlFilter; + } + + @Override + public boolean equals(Object obj) { + return baseEquals(obj) && fCommandControlFilter.equals(((MIControlDMContext)obj).fCommandControlFilter); + } + + @Override + public int hashCode() { + return baseHashCode() + fCommandControlFilter.hashCode(); + } + + @Override + public String toString() { + return baseToString() + ".control(" + fCommandControlId + ")"; //$NON-NLS-1$//$NON-NLS-2$*/ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIInferiorProcess.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIInferiorProcess.java new file mode 100644 index 00000000000..9cbe94eaa20 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIInferiorProcess.java @@ -0,0 +1,396 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Hewlett-Packard Development Company - fix for bug 109733 + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.ImmediateExecutor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.dsf.debug.service.command.IEventListener; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.commands.CLIExecAbort; +import org.eclipse.dd.mi.service.command.commands.MIGDBShowExitCode; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIExecAsyncOutput; +import org.eclipse.dd.mi.service.command.output.MIGDBShowExitCodeInfo; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIOOBRecord; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIResultRecord; +import org.eclipse.dd.mi.service.command.output.MITargetStreamOutput; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * This Process implementation tracks the process that is being debugged + * by GDB. The process object is displayed in Debug view and is used to + * channel the STDIO of the interior process to the console view. + * + * @see org.eclipse.debug.core.model.IProcess + */ +public class MIInferiorProcess extends Process + implements IEventListener, ICommandListener +{ + public enum State { RUNNING, STOPPED, TERMINATED } + + private final OutputStream fOutputStream; + private final InputStream fInputStream; + + private final PipedOutputStream fInputStreamPiped; + + private final PipedInputStream fErrorStream; + private final PipedOutputStream fErrorStreamPiped; + + private final DsfSession fSession; + private final PTY fPty; + + private final AbstractMIControl fCommandControl; + + @ConfinedToDsfExecutor("fSession#getExecutor") + private boolean fDisposed = false; + + Integer fExitCode = null; + + private State fState = State.RUNNING; + + int inferiorPID; + + @ConfinedToDsfExecutor("fSession#getExecutor") + public MIInferiorProcess(AbstractMIControl commandControl, OutputStream gdbOutputStream) { + this(commandControl, gdbOutputStream, null); + } + + @ConfinedToDsfExecutor("fSession#getExecutor") + public MIInferiorProcess(AbstractMIControl commandControl, PTY p) { + this(commandControl, null, p); + } + + @ConfinedToDsfExecutor("fSession#getExecutor") + private MIInferiorProcess(AbstractMIControl commandControl, final OutputStream gdbOutputStream, PTY p) { + fCommandControl = commandControl; + fSession = commandControl.getSession(); + + commandControl.addEventListener(this); + commandControl.addCommandListener(this); + + fPty = p; + if (fPty != null) { + fOutputStream = fPty.getOutputStream(); + fInputStream = fPty.getInputStream(); + fInputStreamPiped = null; + } else { + fOutputStream = new OutputStream() { + @Override + public void write(int b) throws IOException { + // Have to re-dispatch to dispatch thread to check state + if (getState() != State.RUNNING) { + throw new IOException("Target is not running"); //$NON-NLS-1$ + } + gdbOutputStream.write(b); + } + }; + + fInputStreamPiped = new PipedOutputStream(); + PipedInputStream inputStream = null; + try { + inputStream = new PipedInputStream(fInputStreamPiped); + } catch (IOException e) { + } + fInputStream = inputStream; + + } + + // Note: We do not have any err stream from gdb/mi so this gdb + // err channel instead. + fErrorStreamPiped = new PipedOutputStream(); + PipedInputStream errorStream = null; + try { + errorStream = new PipedInputStream(fErrorStreamPiped); + } catch (IOException e) { + } + fErrorStream = errorStream; + } + + @ConfinedToDsfExecutor("fSession#getExecutor") + public void dispose() { + fCommandControl.removeEventListener(this); + fCommandControl.removeCommandListener(this); + + closeIO(); + + setState(State.TERMINATED); + + fDisposed = true; + } + + protected DsfSession getSession() { + return fSession; + } + + protected AbstractMIControl getCommandControl() { return fCommandControl; } + + protected boolean isDisposed() { return fDisposed; } + + @Override + public OutputStream getOutputStream() { + return fOutputStream; + } + + @Override + public InputStream getInputStream() { + return fInputStream; + } + + @Override + public InputStream getErrorStream() { + return fErrorStream; + } + + public synchronized void waitForSync() throws InterruptedException { + while (getState() != State.TERMINATED) { + wait(100); + } + } + + /** + * @see java.lang.Process#waitFor() + */ + @Override + public int waitFor() throws InterruptedException { + waitForSync(); + return exitValue(); + } + + /** + * @see java.lang.Process#exitValue() + */ + @Override + public int exitValue() { + if (fExitCode != null) { + return fExitCode; + } + + try { + Query exitCodeQuery = new Query() { + @Override + protected void execute(final DataRequestMonitor rm) { + // Guard against session disposed. + if (!DsfSession.isSessionActive(fSession.getId())) { + cancel(false); + return; + } + + if (isDisposed()) { + rm.setData(0); + rm.done(); + } else if (getState() != State.TERMINATED) { + // This will cause ExecutionException to be thrown with a CoreException, + // which will in turn contain the IllegalThreadStateException. + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, IDsfService.INVALID_STATE, "GDB is still running.", new IllegalThreadStateException())); //$NON-NLS-1$ + rm.done(); + } else { + getCommandControl().queueCommand( + new MIGDBShowExitCode(getCommandControl().getControlDMContext()), + new DataRequestMonitor(fSession.getExecutor(), rm) { + @Override + protected void handleOK() { + rm.setData(getData().getCode()); + rm.done(); + } + }); + + } + } + }; + fSession.getExecutor().execute(exitCodeQuery); + fExitCode = exitCodeQuery.get(); + return fExitCode; + } catch (RejectedExecutionException e) { + } catch (InterruptedException e) { + } catch (CancellationException e) { + } catch (ExecutionException e) { + // Che + if (e.getCause() instanceof CoreException && + ((CoreException)e.getCause()).getStatus().getException() instanceof RuntimeException ) + { + throw (RuntimeException)((CoreException)e.getCause()).getStatus().getException(); + } + } + return 0; + } + + /** + * @see java.lang.Process#destroy() + */ + @Override + public void destroy() { + try { + fSession.getExecutor().execute(new DsfRunnable() { + public void run() { + doDestroy(); + } + }); + } catch (RejectedExecutionException e) { + // Session disposed. + } + closeIO(); + } + + private void closeIO() { + try { + fOutputStream.close(); + } catch (IOException e) {} + try { + fInputStream.close(); + } catch (IOException e) {} + try { + fInputStreamPiped.close(); + } catch (IOException e) {} + try { + fErrorStream.close(); + } catch (IOException e) {} + try { + fErrorStreamPiped.close(); + } catch (IOException e) {} + } + + @ConfinedToDsfExecutor("fSession#getExecutor") + private void doDestroy() { + if (isDisposed() || !fSession.isActive() || getState() == State.TERMINATED) return; + + // To avoid a RejectedExecutionException, use an executor that + // immediately executes in the same dispatch cycle. + CLIExecAbort cmd = new CLIExecAbort(getCommandControl().getControlDMContext()); + getCommandControl().queueCommand( + cmd, + new DataRequestMonitor(ImmediateExecutor.getInstance(), null) { + @Override + protected void handleCompleted() { + setState(MIInferiorProcess.State.TERMINATED); + } + } + ); + } + + public State getState() { + return fState; + } + + synchronized void setState(State state) { + if (fState == State.TERMINATED) return; + fState = state; + if (fState == State.TERMINATED) { + closeIO(); + } + notifyAll(); + } + + public OutputStream getPipedOutputStream() { + return fInputStreamPiped; + } + + public OutputStream getPipedErrorStream() { + return fErrorStreamPiped; + } + + public PTY getPTY() { + return fPty; + } + + public void eventReceived(Object output) { + for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { + if (oobr instanceof MIExecAsyncOutput) { + MIExecAsyncOutput async = (MIExecAsyncOutput)oobr; + + String state = async.getAsyncClass(); + if ("stopped".equals(state)) { //$NON-NLS-1$ + boolean handled = false; + MIResult[] results = async.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("reason")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String reason = ((MIConst) value).getString(); + if ("exited-signalled".equals(reason) || "exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + setState(State.TERMINATED); + } else { + setState(State.STOPPED); + } + handled = true; + } + } + } + + if (!handled) { + setState(State.STOPPED); + } + } + } else if (oobr instanceof MITargetStreamOutput) { + MITargetStreamOutput tgtOut = (MITargetStreamOutput)oobr; + if (fInputStreamPiped != null && tgtOut.getString() != null) { + try { + fInputStreamPiped.write(tgtOut.getString().getBytes()); + fInputStreamPiped.flush(); + } catch (IOException e) { + } + } + } + } + } + + public void commandQueued(ICommand command) { + // No action + } + + public void commandSent(ICommand command) { + // No action + } + + public void commandRemoved(ICommand command) { + // No action + } + + public void commandDone(ICommand cmd, ICommandResult result) { + MIInfo cmdResult = (MIInfo) result ; + MIOutput output = cmdResult.getMIOutput(); + MIResultRecord rr = output.getMIResultRecord(); + + // Check if the state changed. + String state = rr.getResultClass(); + + if ("running".equals(state)) { setState(State.RUNNING); }//$NON-NLS-1$ + else if ("exit".equals(state)) { setState(State.TERMINATED); }//$NON-NLS-1$ + else if ("error".equals(state)) { setState(State.STOPPED); }//$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java new file mode 100644 index 00000000000..c64069a42d9 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java @@ -0,0 +1,225 @@ +/******************************************************************************* + * Copyright (c) 2006 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 + * Ericsson - Additional handling of events + *******************************************************************************/ +package org.eclipse.dd.mi.service.command; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.dsf.debug.service.command.IEventListener; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.commands.MIExecContinue; +import org.eclipse.dd.mi.service.command.commands.MIExecFinish; +import org.eclipse.dd.mi.service.command.commands.MIExecNext; +import org.eclipse.dd.mi.service.command.commands.MIExecNextInstruction; +import org.eclipse.dd.mi.service.command.commands.MIExecReturn; +import org.eclipse.dd.mi.service.command.commands.MIExecStep; +import org.eclipse.dd.mi.service.command.commands.MIExecStepInstruction; +import org.eclipse.dd.mi.service.command.commands.MIExecUntil; +import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent; +import org.eclipse.dd.mi.service.command.events.MIEvent; +import org.eclipse.dd.mi.service.command.events.MIFunctionFinishedEvent; +import org.eclipse.dd.mi.service.command.events.MIInferiorExitEvent; +import org.eclipse.dd.mi.service.command.events.MIInferiorSignalExitEvent; +import org.eclipse.dd.mi.service.command.events.MILocationReachedEvent; +import org.eclipse.dd.mi.service.command.events.MIRunningEvent; +import org.eclipse.dd.mi.service.command.events.MISignalEvent; +import org.eclipse.dd.mi.service.command.events.MISteppingRangeEvent; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.mi.service.command.events.MIWatchpointScopeEvent; +import org.eclipse.dd.mi.service.command.events.MIWatchpointTriggerEvent; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIExecAsyncOutput; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MINotifyAsyncOutput; +import org.eclipse.dd.mi.service.command.output.MIOOBRecord; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIResultRecord; +import org.eclipse.dd.mi.service.command.output.MIStatusAsyncOutput; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * MI debugger output listener that listens for the parsed MI output, and + * generates corresponding MI events. The generated MI events are then + * received by other services and clients. + */ +public class MIRunControlEventProcessor + implements IEventListener, ICommandListener +{ + /** + * The connection service that this event processor is registered with. + */ + private final AbstractMIControl fCommandControl; + + /** + * Container context used as the context for the run control events generated + * by this processor. + */ + private final IContainerDMContext fContainerDmc; + + /** + * Services tracker used to retrieve the MIRunControl service. + */ + private final DsfServicesTracker fServicesTracker; + + /** + * Creates the event processor and registers it as listener with the debugger + * control. + * @param connection + * @param inferior + */ + public MIRunControlEventProcessor(AbstractMIControl connection, IContainerDMContext containerDmc) { + fCommandControl = connection; + fContainerDmc = containerDmc; + fServicesTracker = new DsfServicesTracker(MIPlugin.getBundleContext(), fCommandControl.getSession().getId()); + connection.addEventListener(this); + connection.addCommandListener(this); + } + + /** + * This processor must be disposed before the control service is un-registered. + */ + public void dispose() { + fCommandControl.removeEventListener(this); + fCommandControl.removeCommandListener(this); + fServicesTracker.dispose(); + } + + public void eventReceived(Object output) { + for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { + if (oobr instanceof MIExecAsyncOutput) { + MIExecAsyncOutput exec = (MIExecAsyncOutput) oobr; + // Change of state. + String state = exec.getAsyncClass(); + if ("stopped".equals(state)) { //$NON-NLS-1$ + // Re-set the thread level to -1 when stopped event is recvd. + // This is to synchronize the state between GDB back-end and AbstractMIControl. + fCommandControl.resetCurrentThreadLevel(); + + List> events = new LinkedList>(); + MIResult[] results = exec.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + if (var.equals("reason")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + String reason = ((MIConst) val).getString(); + MIEvent e = createEvent(reason, exec); + if (e != null) { + events.add(e); + continue; + } + } + } + } + + // We were stopped for some unknown reason, for example + // GDB for temporary breakpoints will not send the + // "reason" ??? still fire a stopped event. + if (events.isEmpty()) { + MIEvent e = MIStoppedEvent.parse( + fServicesTracker.getService(MIRunControl.class), fContainerDmc, exec.getToken(), exec.getMIResults()); + events.add(e); + } + for (MIEvent event : events) { + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + } + else if (oobr instanceof MIStatusAsyncOutput) { + // Nothing done .. but what about +download?? + } else if (oobr instanceof MINotifyAsyncOutput) { + // Nothing + } + } + } + + protected MIEvent createEvent(String reason, MIExecAsyncOutput exec) { + MIRunControl runControl = fServicesTracker.getService(MIRunControl.class); + MIEvent event = null; + if ("breakpoint-hit".equals(reason)) { //$NON-NLS-1$ + event = MIBreakpointHitEvent.parse(runControl, fContainerDmc, exec.getToken(), exec.getMIResults()); + } else if ( + "watchpoint-trigger".equals(reason) //$NON-NLS-1$ + || "read-watchpoint-trigger".equals(reason) //$NON-NLS-1$ + || "access-watchpoint-trigger".equals(reason)) { //$NON-NLS-1$ + event = MIWatchpointTriggerEvent.parse(runControl, fContainerDmc, exec.getToken(), exec.getMIResults()); + } else if ("watchpoint-scope".equals(reason)) { //$NON-NLS-1$ + event = MIWatchpointScopeEvent.parse(runControl, fContainerDmc, exec.getToken(), exec.getMIResults()); + } else if ("end-stepping-range".equals(reason)) { //$NON-NLS-1$ + event = MISteppingRangeEvent.parse(runControl, fContainerDmc, exec.getToken(), exec.getMIResults()); + } else if ("signal-received".equals(reason)) { //$NON-NLS-1$ + event = MISignalEvent.parse(runControl, fContainerDmc, exec.getToken(), exec.getMIResults()); + } else if ("location-reached".equals(reason)) { //$NON-NLS-1$ + event = MILocationReachedEvent.parse(runControl, fContainerDmc, exec.getToken(), exec.getMIResults()); + } else if ("function-finished".equals(reason)) { //$NON-NLS-1$ + event = MIFunctionFinishedEvent.parse(runControl, fContainerDmc, exec.getToken(), exec.getMIResults()); + } else if ("exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$ + event = MIInferiorExitEvent.parse(fCommandControl.getControlDMContext(), exec.getToken(), exec.getMIResults()); + } else if ("exited-signalled".equals(reason)) { //$NON-NLS-1$ + event = MIInferiorSignalExitEvent.parse(fCommandControl.getControlDMContext(), exec.getToken(), exec.getMIResults()); + } + return event; + } + + public void commandQueued(ICommand command) { + // Do nothing. + } + + public void commandSent(ICommand command) { + // Do nothing. + } + + public void commandRemoved(ICommand command) { + // Do nothing. + } + + public void commandDone(ICommand cmd, ICommandResult result) { + MIInfo cmdResult = (MIInfo) result ; + MIOutput output = cmdResult.getMIOutput(); + MIResultRecord rr = output.getMIResultRecord(); + if (rr != null) { + int id = rr.getToken(); + // Check if the state changed. + String state = rr.getResultClass(); + if ("running".equals(state)) { //$NON-NLS-1$ + int type = 0; + // Check the type of command + // if it was a step instruction set state stepping + + if (cmd instanceof MIExecNext) { type = MIRunningEvent.NEXT; } + else if (cmd instanceof MIExecNextInstruction) { type = MIRunningEvent.NEXTI; } + else if (cmd instanceof MIExecStep) { type = MIRunningEvent.STEP; } + else if (cmd instanceof MIExecStepInstruction) { type = MIRunningEvent.STEPI; } + else if (cmd instanceof MIExecUntil) { type = MIRunningEvent.UNTIL; } + else if (cmd instanceof MIExecFinish) { type = MIRunningEvent.FINISH; } + else if (cmd instanceof MIExecReturn) { type = MIRunningEvent.RETURN; } + else if (cmd instanceof MIExecContinue) { type = MIRunningEvent.CONTINUE; } + else { type = MIRunningEvent.CONTINUE; } + + fCommandControl.getSession().dispatchEvent( + new MIRunningEvent(fContainerDmc, id, type), fCommandControl.getProperties()); + } else if ("exit".equals(state)) { //$NON-NLS-1$ + // No need to do anything, terminate() will. + // Send exited? + } else if ("connected".equals(state)) { //$NON-NLS-1$ + } else if ("error".equals(state)) { //$NON-NLS-1$ + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLICommand.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLICommand.java new file mode 100644 index 00000000000..d817934babe --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLICommand.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * Represents a CLI command. + */ +public class CLICommand extends MICommand +{ + public CLICommand(IDMContext ctx, String oper) { + super(ctx, oper); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIExecAbort.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIExecAbort.java new file mode 100644 index 00000000000..7963bb09921 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIExecAbort.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * kill + * + * Terminates the user (MI inferior) process + * + */ +public class CLIExecAbort extends CLICommand +{ + public CLIExecAbort(MIControlDMContext ctx) { + super(ctx, "kill"); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIInfoSharedLibrary.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIInfoSharedLibrary.java new file mode 100644 index 00000000000..88591e704d4 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIInfoSharedLibrary.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + + +import org.eclipse.dd.dsf.debug.service.IModules.IModuleDMContext; +import org.eclipse.dd.dsf.debug.service.IModules.ISymbolDMContext; +import org.eclipse.dd.mi.service.command.output.CLIInfoSharedLibraryInfo; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * + * info sharedlibrary + * + */ +public class CLIInfoSharedLibrary extends CLICommand { + + public CLIInfoSharedLibrary(ISymbolDMContext ctx) { + super(ctx, "info sharedlibrary"); //$NON-NLS-1$ + } + public CLIInfoSharedLibrary(IModuleDMContext ctx) { + super(ctx, "info sharedlibrary"); //$NON-NLS-1$ + } + @Override + public CLIInfoSharedLibraryInfo getResult(MIOutput output) { + return (CLIInfoSharedLibraryInfo)getMIInfo(output); + } + + public MIInfo getMIInfo(MIOutput out) { + MIInfo info = null; + if (out != null) { + info = new CLIInfoSharedLibraryInfo(out); + } + return info; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIInfoThreads.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIInfoThreads.java new file mode 100644 index 00000000000..c3cfecb8009 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/CLIInfoThreads.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + + + +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.mi.service.command.output.CLIInfoThreadsInfo; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * + * info threads + * + */ +public class CLIInfoThreads extends CLICommand { + + public CLIInfoThreads(IContainerDMContext ctx) { + super(ctx, "info threads"); //$NON-NLS-1$ + } + + @Override + public CLIInfoThreadsInfo getResult(MIOutput output) { + return (CLIInfoThreadsInfo)getMIInfo(output); + } + + public MIInfo getMIInfo(MIOutput out) { + MIInfo info = null; + if (out != null) { + info = new CLIInfoThreadsInfo(out); + } + return info; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaCommand.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaCommand.java new file mode 100644 index 00000000000..e20403d2061 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaCommand.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; + +public class ExprMetaCommand implements ICommand { + + private final IDMContext fCtx; + + public ExprMetaCommand(IDMContext ctx) { + fCtx = ctx; + } + + /* + * Takes the supplied command and coalesces it with this one. + * The result is a new third command which represent the two + * original command. + */ + public ICommand coalesceWith( ICommand command ) { + return null ; + } + + public IDMContext getContext(){ + return fCtx; + } + + @Override + public boolean equals(Object other) { + if (other == null) return false; + if (!(other.getClass().equals(getClass()))) return false; + + // Since other is the same class is this, we are sure it is of type DsfExprMetaCommand also + ExprMetaCommand otherCmd = (ExprMetaCommand)other; + return fCtx == null ? otherCmd.fCtx == null : fCtx.equals(otherCmd.fCtx); + } + + @Override + public int hashCode() { + return fCtx == null ? getClass().hashCode() : getClass().hashCode() ^ fCtx.hashCode(); + } + + @Override + public String toString() { + return getClass().toString() + fCtx == null ? "null" : fCtx.toString(); //$NON-NLS-1$ + } + + public String getCommandControlFilter() { + return null; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetAttributes.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetAttributes.java new file mode 100644 index 00000000000..60063bdc8dc --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetAttributes.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetAttributesInfo; + +public class ExprMetaGetAttributes extends ExprMetaCommand { + + public ExprMetaGetAttributes(IExpressionDMContext ctx) { + super(ctx); + } +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetChildCount.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetChildCount.java new file mode 100644 index 00000000000..f5233d074f8 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetChildCount.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetChildCountInfo; + +public class ExprMetaGetChildCount extends ExprMetaCommand { + + public ExprMetaGetChildCount(IExpressionDMContext ctx) { + super(ctx); + } +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetChildren.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetChildren.java new file mode 100644 index 00000000000..7b12ab71d2a --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetChildren.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetChildrenInfo; + +public class ExprMetaGetChildren extends ExprMetaCommand { + + public ExprMetaGetChildren(IExpressionDMContext ctx) { + super(ctx); + } +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetValue.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetValue.java new file mode 100644 index 00000000000..582a3414072 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetValue.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetValueInfo; + +public class ExprMetaGetValue extends ExprMetaCommand { + + public ExprMetaGetValue(FormattedValueDMContext ctx) { + super(ctx); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetVar.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetVar.java new file mode 100644 index 00000000000..342597f7281 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/ExprMetaGetVar.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.mi.service.command.output.ExprMetaGetVarInfo; + +public class ExprMetaGetVar extends ExprMetaCommand { + + public ExprMetaGetVar(IExpressionDMContext ctx) { + super(ctx); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakAfter.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakAfter.java new file mode 100644 index 00000000000..d4cdbcf414e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakAfter.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -break-after NUMBER COUNT + * + * The breakpoint number NUMBER is not in effect until it has been hit + * COUNT times. The count becomes part of the `-break-list' output + * (see the description of the DsfMIBreakList). + */ + +public class MIBreakAfter extends MICommand +{ + public MIBreakAfter(IBreakpointsTargetDMContext ctx, int breakpoint, int ignoreCount) { + super(ctx, "-break-after"); //$NON-NLS-1$ + setParameters(new String[] { Integer.toString(breakpoint), Integer.toString(ignoreCount) }); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakCondition.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakCondition.java new file mode 100644 index 00000000000..9592b9a06b4 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakCondition.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -break-condition NUMBER EXPR + * + * Breakpoint NUMBER will stop the program only if the condition in + * EXPR is true. The condition becomes part of the `-break-list' output + * (see the description of the DsfMIBreakList). + */ + +public class MIBreakCondition extends MICommand +{ + // In this particular case, because of a GDB peculiarity, setParameters() is + // not used and the whole command is formatted on the parent's constructor. + // See bug 213076 for more information. + + public MIBreakCondition(IBreakpointsTargetDMContext ctx, int breakpoint, String condition) { + super(ctx, "-break-condition " + Integer.toString(breakpoint) + " " + condition); //$NON-NLS-1$ //$NON-NLS-2$ +// setParameters(new String[] { Integer.toString(breakpoint), condition }); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakDelete.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakDelete.java new file mode 100644 index 00000000000..35446b72d22 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakDelete.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -break-delete ( BREAKPOINT )+ + * + * Delete the breakpoint(s) whose number(s) are specified in the + * argument list. This is obviously reflected in the breakpoint list. + * + * Result: + * ^done + * + */ + +public class MIBreakDelete extends MICommand +{ + public MIBreakDelete (IBreakpointsTargetDMContext ctx, int[] array) { + super(ctx, "-break-delete"); //$NON-NLS-1$ + if (array != null && array.length > 0) { + String[] brkids = new String[array.length]; + for (int i = 0; i < array.length; i++) { + brkids[i] = Integer.toString(array[i]); + } + setParameters(brkids); + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakDisable.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakDisable.java new file mode 100644 index 00000000000..a71e068cd76 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakDisable.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -break-disable ( BREAKPOINT )+ + * + * Disable the named BREAKPOINT(s). The field `enabled' in the break + * list is now set to `n' for the named BREAKPOINT(s). + * + * Result: + * ^done + */ + +public class MIBreakDisable extends MICommand +{ + public MIBreakDisable (IBreakpointsTargetDMContext ctx, int[] array) { + super(ctx, "-break-disable"); //$NON-NLS-1$ + if (array != null && array.length > 0) { + String[] brkids = new String[array.length]; + for (int i = 0; i < array.length; i++) { + brkids[i] = Integer.toString(array[i]); + } + setParameters(brkids); + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakEnable.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakEnable.java new file mode 100644 index 00000000000..7a0c9eb6d0b --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakEnable.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -break-enable ( BREAKPOINT )+ + * + * Enable (previously disabled) BREAKPOINT(s). + * + * Result: + * ^done + */ + +public class MIBreakEnable extends MICommand +{ + public MIBreakEnable (IBreakpointsTargetDMContext ctx, int[] array) { + super(ctx, "-break-enable"); //$NON-NLS-1$ + if (array != null && array.length > 0) { + String[] brkids = new String[array.length]; + for (int i = 0; i < array.length; i++) { + brkids[i] = Integer.toString(array[i]); + } + setParameters(brkids); + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakInsert.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakInsert.java new file mode 100644 index 00000000000..79446d9b165 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakInsert.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * -break-insert [ -t ] [ -h ] [ -r ] + * [ -c CONDITION ] [ -i IGNORE-COUNT ] + * [ -p THREAD ] [ LINE | ADDR ] + * + * If specified, LINE, can be one of: + * * function + * * filename:linenum + * * filename:function + * * *address + * + * The possible optional parameters of this command are: + * + * '-t' + * Insert a temporary breakpoint. + * + * '-h' + * Insert a hardware breakpoint. + * + * '-r' + * Insert a regular breakpoint in all the functions whose names match + * the given regular expression. Other flags are not applicable to + * regular expression. + * + * '-c CONDITION' + * Make the breakpoint conditional on CONDITION. + * + * '-i IGNORE-COUNT' + * Initialize the IGNORE-COUNT (number of breakpoint hits before breaking). + * + * '-p THREAD' + * THREAD on which to apply the breakpoint + */ +public class MIBreakInsert extends MICommand +{ + public MIBreakInsert(IBreakpointsTargetDMContext ctx, String func) { + this(ctx, false, false, null, 0, func, 0); + } + + public MIBreakInsert(IBreakpointsTargetDMContext ctx, boolean isTemporary, boolean isHardware, + String condition, int ignoreCount, String line, int tid) { + super(ctx, "-break-insert"); //$NON-NLS-1$ + + // Determine the number of optional parameters that are present + // and allocate a corresponding string array + int i = 0; + if (isTemporary) { + i++; + } + if (isHardware) { + i++; + } + if (condition != null && condition.length() > 0) { + i += 2; + } + if (ignoreCount > 0) { + i += 2; + } + if (tid > 0) { + i += 2; + } + String[] opts = new String[i]; + + // Fill in the optional parameters + i = 0; + if (isTemporary) { + opts[i] = "-t"; //$NON-NLS-1$ + i++; + } + if (isHardware) { + opts[i] = "-h"; //$NON-NLS-1$ + i++; + } + if (condition != null && condition.length() > 0) { + opts[i] = "-c"; //$NON-NLS-1$ + i++; + opts[i] = condition; + i++; + } + if (ignoreCount > 0) { + opts[i] = "-i"; //$NON-NLS-1$ + i++; + opts[i] = Integer.toString(ignoreCount); + i++; + } + if (tid > 0) { + opts[i] = "-p"; //$NON-NLS-1$ + i++; + opts[i] = Integer.toString(tid); + } + + if (opts.length > 0) { + setOptions(opts); + } + setParameters(new String[]{line}); + } + + @Override + public MIBreakInsertInfo getResult(MIOutput output) { + return new MIBreakInsertInfo(output); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakList.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakList.java new file mode 100644 index 00000000000..b3472ca9f50 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakList.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.mi.service.command.output.MIBreakListInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * + * -break-list + * + * Displays the list of inserted breakpoints, showing the following + * fields: + * + * `Number' + * number of the breakpoint + * + * `Type' + * type of the breakpoint: `breakpoint' or `watchpoint' + * + * `Disposition' + * should the breakpoint be deleted or disabled when it is hit: `keep' + * or `nokeep' + * + * `Enabled' + * is the breakpoint enabled or no: `y' or `n' + * + * `Address' + * memory location at which the breakpoint is set + * + * `What' + * logical location of the breakpoint, expressed by function name, + * + * `Times' + * number of times the breakpoint has been hit + * + * If there are no breakpoints or watchpoints, the `BreakpointTable' + * `body' field is an empty list. + * + */ +public class MIBreakList extends MICommand +{ + public MIBreakList (IBreakpointsTargetDMContext ctx) { + super(ctx, "-break-list"); //$NON-NLS-1$ + } + + @Override + public MIBreakListInfo getResult(MIOutput output) { + return new MIBreakListInfo(output); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakWatch.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakWatch.java new file mode 100644 index 00000000000..18aa0c94b06 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakWatch.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * -break-watch [ -a | -r ] LOCATION + * + * Create a watchpoint on LOCATION. Without either of the options, the watchpoint + * created is a regular watchpoint, i.e., a watchpoint that triggers when the + * memory LOCATION is accessed for writing. + + * The possible optional parameters of this command are: + * + * '-a' + * Creates an access watchpoint i.e. a watchpoint that triggers either + * on a read from or on a write to the memory location. + * + * '-r' + * Creates a read watchpoint i.e. a watchpoint that triggers only when + * the memory location is accessed for reading. + */ +public class MIBreakWatch extends MICommand +{ + public MIBreakWatch(IBreakpointsTargetDMContext ctx, boolean isRead, boolean isWrite, String expression) + { + super(ctx, "-break-watch"); //$NON-NLS-1$ + + if (isRead) { + if (isWrite) + setOptions(new String[] { "-a" }); //$NON-NLS-1$ + else + setOptions(new String[] { "-r" }); //$NON-NLS-1$ + } + + setParameters(new String[]{ expression }); + } + + @Override + public MIBreakInsertInfo getResult(MIOutput output) { + return new MIBreakInsertInfo(output); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MICommand.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MICommand.java new file mode 100644 index 00000000000..bc85b408536 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MICommand.java @@ -0,0 +1,256 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for additional features in DSF Reference implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * Represents any MI command. + */ +public class MICommand implements ICommand { + + /* + * Variables. + */ + final static String[] empty = new String[0]; + + String[] fOptions = empty; + String[] fParameters = empty; + String fOperation = new String(); + IDMContext fCtx; + + /* + * Constructors. + */ + + /*public DsfMICommand(String operation) { + this(operation, empty, empty); + }*/ + + public MICommand(IDMContext ctx, String operation) { + this(ctx, operation, empty, empty); + } + + /*public DsfMICommand(String operation, String[] options) { + this(operation, options, empty); + }*/ + + public MICommand(IDMContext ctx, String operation, String[] options) { + this(ctx, operation, options, empty); + } + + public MICommand(IDMContext ctx, String operation, String[] options, String[] params) { + assert(ctx != null && DMContexts.getAncestorOfType(ctx, MIControlDMContext.class) != null); + fCtx = ctx; + fOperation = operation; + fOptions = options; + fParameters = params; + } + + public String getCommandControlFilter() { + MIControlDMContext controlDmc = DMContexts.getAncestorOfType(getContext(), MIControlDMContext.class); + return controlDmc.getCommandControlFilter(); + } + + /* + * Returns the operation of this command. + */ + public String getOperation() { + return fOperation; + } + + /* + * Returns an array of command's options. An empty collection is + * returned if there are no options. + */ + public String[] getOptions() { + return fOptions; + } + + public void setOptions(String[] options) { + fOptions = options; + } + + /* + * Returns an array of command's parameters. An empty collection is + * returned if there are no parameters. + */ + public String[] getParameters() { + return fParameters; + } + + public void setParameters(String[] params) { + fParameters = params; + } + + /* + * Returns the constructed command. + */ + public String constructCommand() { + StringBuffer command = new StringBuffer(getOperation()); + String opt = optionsToString(); + if (opt.length() > 0) { + command.append(' ').append(opt); + } + String p = parametersToString(); + if (p.length() > 0) { + command.append(' ').append(p); + } + command.append('\n'); + return command.toString(); + } + +// /* +// * Checks to see if the current command can be coalesced with the +// * supplied command. +// */ +// public boolean canCoalesce( ICommand command ) { +// return false ; +// } + + /* + * Takes the supplied command and coalesces it with this one. + * The result is a new third command which represent the two + * original command. + */ + public ICommand coalesceWith( ICommand command ) { + return null ; + } + + + public IDMContext getContext(){ + return fCtx; + } + /** + * Produces the corresponding ICommandResult result for this + * command. + * + * @return result for this command + */ + public MIInfo getResult(MIOutput MIresult) { + return ( new MIInfo(MIresult) ); + } + + protected String optionsToString() { + String[] options = getOptions(); + StringBuffer sb = new StringBuffer(); + if (options != null && options.length > 0) { + for (int i = 0; i < options.length; i++) { + String option = options[i]; + // If the option argument contains " or \ it must be escaped + if (option.indexOf('"') != -1 || option.indexOf('\\') != -1) { + StringBuffer buf = new StringBuffer(); + for (int j = 0; j < option.length(); j++) { + char c = option.charAt(j); + if (c == '"' || c == '\\') { + buf.append('\\'); + } + buf.append(c); + } + option = buf.toString(); + } + + // If the option contains a space according to + // GDB/MI spec we must surround it with double quotes. + if (option.indexOf('\t') != -1 || option.indexOf(' ') != -1) { + sb.append(' ').append('"').append(option).append('"'); + } else { + sb.append(' ').append(option); + } + } + } + return sb.toString().trim(); + } + + protected String parametersToString() { + String[] parameters = getParameters(); + String[] options = getOptions(); + StringBuffer buffer = new StringBuffer(); + if (parameters != null && parameters.length > 0) { + // According to GDB/MI spec + // Add a "--" separator if any parameters start with "-" + if (options != null && options.length > 0) { + for (int i = 0; i < parameters.length; i++) { + if (parameters[i].startsWith("-")) { //$NON-NLS-1$ + buffer.append('-').append('-'); + break; + } + } + } + + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < parameters.length; i++) { + // We need to escape the double quotes and the backslash. + sb.setLength(0); + String param = parameters[i]; + for (int j = 0; j < param.length(); j++) { + char c = param.charAt(j); + if (c == '"' || c == '\\') { + sb.append('\\'); + } + sb.append(c); + } + + // If the string contains spaces instead of escaping + // surround the parameter with double quotes. + if (containsWhitespace(param)) { + sb.insert(0, '"'); + sb.append('"'); + } + buffer.append(' ').append(sb); + } + } + return buffer.toString().trim(); + } + + protected boolean containsWhitespace(String s) { + for (int i = 0; i < s.length(); i++) { + if (Character.isWhitespace(s.charAt(i))) { + return true; + } + } + return false; + } + + + /** + * Compare commands based on the MI command string that they generate, + * without the token. + */ + @Override + public boolean equals(Object obj) { + if(obj instanceof MICommand){ + MICommand otherCmd = (MICommand)obj; + return ((fCtx == null && otherCmd.fCtx == null) || (fCtx != null && fCtx.equals(otherCmd.fCtx))) && + constructCommand().equals(otherCmd.constructCommand()); + } + return false; + } + + @Override + public int hashCode() { + return constructCommand().hashCode(); + } + + @Override + public String toString() { + return constructCommand(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataEvaluateExpression.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataEvaluateExpression.java new file mode 100644 index 00000000000..bedf2308805 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataEvaluateExpression.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIDataEvaluateExpressionInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * + * -data-evaluate-expression EXPR + * + * Evaluate EXPR as an expression. The expression could contain an + *inferior function call. The function call will execute synchronously. + *If the expression contains spaces, it must be enclosed in double quotes. + * + */ +public class MIDataEvaluateExpression extends MICommand +{ + public MIDataEvaluateExpression(MIControlDMContext ctx, String expr) { + super(ctx, "-data-evaluate-expression", new String[]{expr}); //$NON-NLS-1$ + } + + public MIDataEvaluateExpression(IMIExecutionDMContext execDmc, String expr) { + super(execDmc, "-data-evaluate-expression", new String[]{expr}); //$NON-NLS-1$ + } + + public MIDataEvaluateExpression(IFrameDMContext frameDmc, String expr) { + super(frameDmc, "-data-evaluate-expression", new String[]{expr}); //$NON-NLS-1$ + } + + public MIDataEvaluateExpression(IExpressionDMContext exprDmc) { + super(exprDmc, "-data-evaluate-expression", new String[]{exprDmc.getExpression()}); //$NON-NLS-1$ + } + + @Override + public MIDataEvaluateExpressionInfo getResult(MIOutput output) { + return new MIDataEvaluateExpressionInfo(output); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataListRegisterNames.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataListRegisterNames.java new file mode 100644 index 00000000000..4152a33006c --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataListRegisterNames.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.mi.service.command.output.MIDataListRegisterNamesInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * + * -data-list-register-names [ ( REGNO )+ ] + * + * Show a list of register names for the current target. If no + * arguments are given, it shows a list of the names of all the registers. + * If integer numbers are given as arguments, it will print a list of the + * names of the registers corresponding to the arguments. To ensure + * consistency between a register name and its number, the output list may + * include empty register names. + * + */ +public class MIDataListRegisterNames extends MICommand +{ + public MIDataListRegisterNames(IContainerDMContext ctx) { + super(ctx, "-data-list-register-names"); //$NON-NLS-1$ + } + + public MIDataListRegisterNames(IContainerDMContext ctx, int [] regnos) { + this(ctx); + if (regnos != null && regnos.length > 0) { + String[] array = new String[regnos.length]; + for (int i = 0; i < regnos.length; i++) { + array[i] = Integer.toString(regnos[i]); + } + setParameters(array); + } + } + + @Override + public MIDataListRegisterNamesInfo getResult(MIOutput output) { + return new MIDataListRegisterNamesInfo(output); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataListRegisterValues.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataListRegisterValues.java new file mode 100644 index 00000000000..a3d6031bf92 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataListRegisterValues.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.mi.service.MIFormat; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIDataListRegisterValuesInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * + * -data-list-register-values FMT [ ( REGNO )*] + * + * Display the registers' contents. FMT is the format according to + * which the registers' contents are to be returned, followed by an + * optional list of numbers specifying the registers to display. A + * missing list of numbers indicates that the contents of all the + * registers must be returned. + * + */ +public class MIDataListRegisterValues extends MICommand { + + int[] regnums; + int fFmt; + + public MIDataListRegisterValues(IMIExecutionDMContext ctx, int fmt) { + this(ctx, fmt, null); + } + + public MIDataListRegisterValues(IMIExecutionDMContext ctx, int fmt, int [] regnos) { + super(ctx, "-data-list-register-values"); //$NON-NLS-1$ + regnums = regnos; + + String format = "x"; //$NON-NLS-1$ + switch (fmt) { + case MIFormat.NATURAL: format = "N"; break ; //$NON-NLS-1$ + case MIFormat.RAW: format = "r"; break ; //$NON-NLS-1$ + case MIFormat.DECIMAL: format = "d"; break ; //$NON-NLS-1$ + case MIFormat.BINARY: format = "t"; break ; //$NON-NLS-1$ + case MIFormat.OCTAL: format = "o"; break ; //$NON-NLS-1$ + case MIFormat.HEXADECIMAL: format = "x"; break ; //$NON-NLS-1$ + default: format = "x"; break ; //$NON-NLS-1$ + } + + fFmt = fmt; + + setOptions(new String[]{format}); + + if (regnos != null && regnos.length > 0) { + String[] array = new String[regnos.length]; + for (int i = 0; i < regnos.length; i++) { + array[i] = Integer.toString(regnos[i]); + } + setParameters(array); + } + } + + public int[] getRegList() { + return regnums; + } + + @Override + public MIDataListRegisterValuesInfo getResult(MIOutput output) { + return new MIDataListRegisterValuesInfo(output); + } + + /* + * Takes the supplied command and coalesces it with this one. + * The result is a new third command which represent the two + * original command. + */ + @Override + public MIDataListRegisterValues coalesceWith(ICommand command ) { + /* + * Can coalesce only with other DsfMIDataListRegisterValues commands. + */ + if (! (command instanceof MIDataListRegisterValues) ) return null; + + MIDataListRegisterValues cmd = (MIDataListRegisterValues) command; + + int[] newregnos = new int[ regnums.length + cmd.regnums.length]; + + /* + * We need to add the new register #'s to the list. If one is already there + * then do not add it twice. So copy the original list of this command. + */ + + for ( int idx = 0 ; idx < regnums.length ; idx ++) { + newregnos[ idx ] = regnums[ idx ]; + } + + int curloc = regnums.length; + + for ( int ndx = 0 ; ndx < cmd.regnums.length; ndx ++) { + + int curnum = cmd.regnums[ ndx ] ; + int ldx; + + /* + * Search the current list to see if this entry is in it. + */ + + for ( ldx = 0 ; ldx < regnums.length; ldx ++ ) { + if ( newregnos[ ldx ] == curnum ) { + break ; + } + } + + if ( ldx == regnums.length ) { + + /* + * Since we did not find a match add it at the end of the list. + */ + newregnos[ curloc ] = curnum; + curloc ++; + } + } + + /* + * Create a final proper array set of the new combined list. + */ + int[] finalregnums = new int[ curloc ] ; + + for ( int fdx = 0 ; fdx < curloc ; fdx ++ ) { + finalregnums[ fdx ] = newregnos[ fdx ]; + } + + /* + * Now construct a new one. The format we will use is this command. + */ + return( new MIDataListRegisterValues((IMIExecutionDMContext)getContext(), fFmt, finalregnums)); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataReadMemory.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataReadMemory.java new file mode 100644 index 00000000000..2a7a8880260 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataReadMemory.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson AB - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.MIFormat; +import org.eclipse.dd.mi.service.command.output.MIDataReadMemoryInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * -data-read-memory [ -o BYTE-OFFSET ] + * ADDRESS WORD-FORMAT WORD-SIZE + * NR-ROWS NR-COLS [ ASCHAR ] + * + * where: + * + * 'ADDRESS' + * An expression specifying the address of the first memory word to be + * read. Complex expressions containing embedded white space should + * be quoted using the C convention. + * + * 'WORD-FORMAT' + * The format to be used to print the memory words. The notation is + * the same as for GDB's `print' command (*note Output formats: + * Output Formats.). + * + * 'WORD-SIZE' + * The size of each memory word in bytes. + * + * 'NR-ROWS' + * The number of rows in the output table. + * + * 'NR-COLS' + * The number of columns in the output table. + * + * 'ASCHAR' + * If present, indicates that each row should include an ASCII dump. + * The value of ASCHAR is used as a padding character when a byte is + * not a member of the printable ASCII character set (printable ASCII + * characters are those whose code is between 32 and 126, + * inclusively). + * + * 'BYTE-OFFSET' + * An offset to add to ADDRESS before fetching the memory. + * + */ +public class MIDataReadMemory extends MICommand { + + int fword_size; + + public MIDataReadMemory( + IDMContext ctx, + long offset, + String address, + int word_format, + int word_size, + int rows, + int cols, + Character asChar) + { + super(ctx, "-data-read-memory"); //$NON-NLS-1$ + + // Save this for the result parser + fword_size = word_size; + + if (offset != 0) { + setOptions(new String[] { "-o", Long.toString(offset * word_size)}); //$NON-NLS-1$ + } + + String format = "x"; //$NON-NLS-1$ + switch (word_format) { + case MIFormat.UNSIGNED : + format = "u"; //$NON-NLS-1$ + break; + + case MIFormat.FLOAT : + format = "f"; //$NON-NLS-1$ + break; + + case MIFormat.ADDRESS : + format = "a"; //$NON-NLS-1$ + break; + + case MIFormat.INSTRUCTION : + format = "i"; //$NON-NLS-1$ + break; + + case MIFormat.CHAR : + format = "c"; //$NON-NLS-1$ + break; + + case MIFormat.STRING : + format = "s"; //$NON-NLS-1$ + break; + + case MIFormat.DECIMAL : + case MIFormat.NATURAL : + format = "d"; //$NON-NLS-1$ + break; + + case MIFormat.BINARY : + format = "t"; //$NON-NLS-1$ + break; + + case MIFormat.OCTAL : + format = "o"; //$NON-NLS-1$ + break; + + case MIFormat.HEXADECIMAL : + case MIFormat.RAW : + default : + format = "x"; //$NON-NLS-1$ + break; + } + + if (asChar == null) { + setParameters( + new String[] { + address, + format, + Integer.toString(1), // wordSize + Integer.toString(rows), + Integer.toString(cols * word_size)}); + } else { + setParameters( + new String[] { + address, + format, + Integer.toString(1), // wordSize + Integer.toString(rows), + Integer.toString(cols * word_size), + asChar.toString()}); + } + } + + @Override + public MIDataReadMemoryInfo getResult(MIOutput out) { + return new MIDataReadMemoryInfo(out, fword_size); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataWriteMemory.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataWriteMemory.java new file mode 100644 index 00000000000..383e94bc60a --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIDataWriteMemory.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson Communication - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.MIFormat; +import org.eclipse.dd.mi.service.command.output.MIDataWriteMemoryInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * -data-write-memory [ -o COLUMN_OFFSET ] + * ADDRESS WORD-FORMAT WORD-SIZE VALUE + * + * where: + * + * 'COLUMN_OFFSET' + * The cell offset from the beginning of the memory grid row + * + * 'ADDRESS' + * Row address of the cell to be written + * + * 'WORD-FORMAT' + * The format to be used to print the memory words + * + * 'WORD-SIZE' + * The size of each memory word in bytes + * + * 'VALUE' + * The value to be written into the cell + * + * Writes VALUE into ADDRESS + (COLUMN_OFFSET * WORD_SIZE). + * + */ +public class MIDataWriteMemory extends MICommand { + + public MIDataWriteMemory( + IDMContext ctx, + long offset, + String address, + int wordFormat, + int wordSize, + String value) + { + super(ctx, "-data-write-memory"); //$NON-NLS-1$ + + if (offset != 0) { + setOptions(new String[] { "-o", Long.toString(offset)}); //$NON-NLS-1$ + } + + String format = "x"; //$NON-NLS-1$ + switch (wordFormat) { + case MIFormat.UNSIGNED : + format = "u"; //$NON-NLS-1$ + break; + + case MIFormat.FLOAT : + format = "f"; //$NON-NLS-1$ + break; + + case MIFormat.ADDRESS : + format = "a"; //$NON-NLS-1$ + break; + + case MIFormat.INSTRUCTION : + format = "i"; //$NON-NLS-1$ + break; + + case MIFormat.CHAR : + format = "c"; //$NON-NLS-1$ + break; + + case MIFormat.STRING : + format = "s"; //$NON-NLS-1$ + break; + + case MIFormat.DECIMAL : + case MIFormat.NATURAL : + format = "d"; //$NON-NLS-1$ + break; + + case MIFormat.BINARY : + format = "t"; //$NON-NLS-1$ + break; + + case MIFormat.OCTAL : + format = "o"; //$NON-NLS-1$ + break; + + case MIFormat.HEXADECIMAL : + case MIFormat.RAW : + default : + format = "x"; //$NON-NLS-1$ + break; + } + + setParameters( + new String[] { + address, + format, + Integer.toString(wordSize), + value}); + } + + @Override + public MIDataWriteMemoryInfo getResult(MIOutput out) { + return new MIDataWriteMemoryInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecContinue.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecContinue.java new file mode 100644 index 00000000000..031cbe38e9a --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecContinue.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-continue + * + * Asynchronous command. Resumes the execution of the inferior program + * until a breakpoint is encountered, or until the inferior exits. + * + */ +public class MIExecContinue extends MICommand +{ + public MIExecContinue(IExecutionDMContext dmc) { + super(dmc, "-exec-continue"); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecFinish.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecFinish.java new file mode 100644 index 00000000000..59e18ce7d3e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecFinish.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of execution contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * -exec-finish + *

+ * Asynchronous command. Resumes the execution of the inferior program + * until the current function is exited. Displays the results returned by + * the function. + *

+ *

+ * The -exec-finish command operates on the selected stack + * frame. Therefore the constructor requires a stack frame context. + *

+ * + */ +public class MIExecFinish extends MICommand +{ + public MIExecFinish(IFrameDMContext dmc) { + super(dmc, "-exec-finish"); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecInterrupt.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecInterrupt.java new file mode 100644 index 00000000000..fd38aa16b23 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecInterrupt.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson AB - Modified for Execution Contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-interrupt + * + * Asynchronous command. Interrupts the background execution of the + * target. Note how the token associated with the stop message is the one + * for the execution command that has been interrupted. The token for the + * interrupt itself only appears in the `^done' output. If the user is + * trying to interrupt a non-running program, an error message will be + * printed. + * + */ +public class MIExecInterrupt extends MICommand +{ + public MIExecInterrupt(IExecutionDMContext dmc) { + super(dmc, "-exec-interrupt"); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNext.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNext.java new file mode 100644 index 00000000000..25617b1152c --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNext.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of execution contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-next + * + * Asynchronous command. Resumes execution of the inferior program, + * stopping when the beginning of the next source line is reached. + * + */ +public class MIExecNext extends MICommand +{ + public MIExecNext(IExecutionDMContext dmc) { + super(dmc, "-exec-next"); //$NON-NLS-1$ + } + + public MIExecNext(IExecutionDMContext dmc, int count) { + super(dmc, "-exec-next", new String[] { Integer.toString(count) }); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNextInstruction.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNextInstruction.java new file mode 100644 index 00000000000..0bcf2c83b4e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNextInstruction.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-next-instruction + * + * Asynchronous command. Executes one machine instruction. If the + * instruction is a function call continues until the function returns. If + * the program stops at an instruction in the middle of a source line, the + * address will be printed as well. + * + */ +public class MIExecNextInstruction extends MICommand +{ + public MIExecNextInstruction(IExecutionDMContext dmc) { + super(dmc, "-exec-next-instruction"); //$NON-NLS-1$ + } + + public MIExecNextInstruction(IExecutionDMContext dmc, int count) { + super(dmc, "-exec-next-instruction", new String[] { Integer.toString(count) }); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecReturn.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecReturn.java new file mode 100644 index 00000000000..689c4a2fa02 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecReturn.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-return + * + *

+ * Makes current function return immediately. Doesn't execute the + * inferior. Displays the new current frame. + *

+ *

+ * The -exec-return command operates on the selected stack + * frame. Therefore the constructor requires a stack frame context. + *

+ * + */ +public class MIExecReturn extends MICommand +{ + public MIExecReturn(IFrameDMContext dmc) { + super(dmc, "-exec-return"); //$NON-NLS-1$ + } + + public MIExecReturn(IFrameDMContext dmc, String arg) { + super(dmc, "-exec-return", new String[] { arg }); //$NON-NLS-1$ + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecRun.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecRun.java new file mode 100644 index 00000000000..a5c683a980d --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecRun.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of execution contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-run + * + * Asynchronous command. Starts execution of the inferior from the + * beginning. The inferior executes until either a breakpoint is + * encountered or the program exits. + * + */ +public class MIExecRun extends MICommand +{ + public MIExecRun(IExecutionDMContext dmc) { + super(dmc, "-exec-run"); //$NON-NLS-1$ + } + + public MIExecRun(IExecutionDMContext dmc, String[] args) { + super(dmc, "-exec-run", args); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStep.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStep.java new file mode 100644 index 00000000000..9ed7b0f474e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStep.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of execution contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-step + * + * Asynchronous command. Resumes execution of the inferior program, + * stopping when the beginning of the next source line is reached, if the + * next source line is not a function call. If it is, stop at the first + * instruction of the called function. + * + */ +public class MIExecStep extends MICommand +{ + public MIExecStep(IExecutionDMContext dmc) { + super(dmc, "-exec-step"); //$NON-NLS-1$ + } + + public MIExecStep(IExecutionDMContext dmc, int count) { + super(dmc, "-exec-step", new String[] { Integer.toString(count) }); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStepInstruction.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStepInstruction.java new file mode 100644 index 00000000000..9d4087b95e9 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStepInstruction.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-step-instruction + + * Asynchronous command. Resumes the inferior which executes one + * machine instruction. The output, once GDB has stopped, will vary + * depending on whether we have stopped in the middle of a source line or + * not. In the former case, the address at which the program stopped will + * be printed as well. + * + */ +public class MIExecStepInstruction extends MICommand +{ + public MIExecStepInstruction(IExecutionDMContext dmc) { + super(dmc, "-exec-step-instruction"); //$NON-NLS-1$ + } + + public MIExecStepInstruction(IExecutionDMContext dmc, int count) { + super(dmc, "-exec-step-instruction", new String[] { Integer.toString(count) }); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecUntil.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecUntil.java new file mode 100644 index 00000000000..57b57855267 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecUntil.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of execution contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -exec-until [ LOCATION ] + * + * Asynchronous command. Executes the inferior until the LOCATION + * specified in the argument is reached. If there is no argument, the + * inferior executes until a source line greater than the current one is + * reached. The reason for stopping in this case will be + * `location-reached'. + * + */ +public class MIExecUntil extends MICommand +{ + public MIExecUntil(IExecutionDMContext dmc) { + super(dmc, "-exec-until"); //$NON-NLS-1$ + } + + public MIExecUntil(IExecutionDMContext dmc, String loc) { + super(dmc, "-exec-until", new String[]{loc}); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIGDBExit.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIGDBExit.java new file mode 100644 index 00000000000..f3131dfc3d0 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIGDBExit.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * + * -gdb-exit + * + * Exit GDB immediately. + * + */ +public class MIGDBExit extends MICommand +{ + public MIGDBExit(IDMContext ctx) { + super(ctx, "-gdb-exit"); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIGDBShowExitCode.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIGDBShowExitCode.java new file mode 100644 index 00000000000..f57291136c3 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIGDBShowExitCode.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIGDBShowExitCodeInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + * + *-data-evaluate-expression $_exitcode + * ^done,value="10" + * + * Show the current value of a $_exitcode + * + */ +public class MIGDBShowExitCode extends MIDataEvaluateExpression { + + public MIGDBShowExitCode(MIControlDMContext ctx) { + super(ctx, "$_exitcode"); //$NON-NLS-1$ + } + + @Override + public MIGDBShowExitCodeInfo getResult(MIOutput output) { + return new MIGDBShowExitCodeInfo(output); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIInterpreterExec.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIInterpreterExec.java new file mode 100644 index 00000000000..b355f2443b1 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIInterpreterExec.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for additional features in DSF Reference implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * MIInterpreterExec + * + * -interpreter-exec + * + * -interpreter-exec interpreter command + * + * Execute the specified command in the given interpreter. + * + * -interpreter-exec console "break main" + * &"During symbol reading, couldn't parse type; debugger out of date?.\n" + * &"During symbol reading, bad structure-type format.\n" + * ~"Breakpoint 1 at 0x8074fc6: file ../../src/gdb/main.c, line 743.\n" + * ^done + * + */ +public class MIInterpreterExec extends MICommand { + + /** + * @param oper + */ + public MIInterpreterExec(IDMContext ctx, String interpreter, String cmd) { + super(ctx, "-interpreter-exec", new String[]{interpreter}, new String[] {cmd}); //$NON-NLS-1$ + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIInterpreterExecConsole.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIInterpreterExecConsole.java new file mode 100644 index 00000000000..c635a4f4dd3 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIInterpreterExecConsole.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for additional features in DSF Reference implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + +/** + * MIInterpreterExecConsole + */ +public class MIInterpreterExecConsole extends MIInterpreterExec { + + /** + * @param interpreter + * @param cmd + */ + public MIInterpreterExecConsole(IDMContext ctx, String cmd) { + super(ctx, "console", cmd); //$NON-NLS-1$ + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackInfoDepth.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackInfoDepth.java new file mode 100644 index 00000000000..c0f7a8b63bb --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackInfoDepth.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIStackInfoDepthInfo; + +/** + * + * -stack-info-depth [maxDepth] + * + * + */ +public class MIStackInfoDepth extends MICommand +{ + + public MIStackInfoDepth(IMIExecutionDMContext ctx) { + super(ctx, "-stack-info-depth"); //$NON-NLS-1$ + } + + public MIStackInfoDepth(IMIExecutionDMContext ctx, int maxDepth) { + super(ctx, "-stack-info-depth", new String[]{Integer.toString(maxDepth)}); //$NON-NLS-1$ + } + + @Override + public MIStackInfoDepthInfo getResult(MIOutput out) { + return new MIStackInfoDepthInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListArguments.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListArguments.java new file mode 100644 index 00000000000..d9778e91fec --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListArguments.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of execution contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIStackListArgumentsInfo; + +/** + * + * -stack-list-arguments SHOW-VALUES + * [ LOW-FRAME HIGH-FRAME ] + * + * Display a list of the arguments for the frames between LOW-FRAME and + * HIGH-FRAME (inclusive). If LOW-FRAME and HIGH-FRAME are not provided, + * list the arguments for the whole call stack. + * + * The SHOW-VALUES argument must have a value of 0 or 1. A value of 0 + * means that only the names of the arguments are listed, a value of 1 + * means that both names and values of the arguments are printed. + * + */ +public class MIStackListArguments extends MICommand +{ + public MIStackListArguments(IMIExecutionDMContext execDmc, boolean showValues) { + super(execDmc, "-stack-list-arguments"); //$NON-NLS-1$ + if (showValues) { + setParameters(new String[]{"1"}); //$NON-NLS-1$ + } else { + setParameters(new String[]{"0"}); //$NON-NLS-1$ + } + } + + public MIStackListArguments(IFrameDMContext frameDmc, boolean showValues) { + super(frameDmc, "-stack-list-arguments"); //$NON-NLS-1$ + if (showValues) { + setParameters(new String[]{"1"}); //$NON-NLS-1$ + } else { + setParameters(new String[]{"0"}); //$NON-NLS-1$ + } + } + + public MIStackListArguments(IMIExecutionDMContext execDmc, boolean showValues, int low, int high) { + super(execDmc, "-stack-list-arguments"); //$NON-NLS-1$ + String[] params = new String[3]; + if (showValues) { + params[0] = "1"; //$NON-NLS-1$ + } else { + params[0] = "0"; //$NON-NLS-1$ + } + params[1] = Integer.toString(low); + params[2] = Integer.toString(high); + setParameters(params); + } + + @Override + public MIStackListArgumentsInfo getResult(MIOutput out) { + return new MIStackListArgumentsInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListFrames.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListFrames.java new file mode 100644 index 00000000000..f074292cfab --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListFrames.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of Frame contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + + +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIStackListFramesInfo; + +/** + * + * -stack-list-frames [ LOW-FRAME HIGH-FRAME ] + * + * List the frames currently on the stack. For each frame it displays + * the following info: + * + * `LEVEL' + * The frame number, 0 being the topmost frame, i.e. the innermost + * function. + * + * `ADDR' + * The `$pc' value for that frame. + * + * `FUNC' + * Function name. + * + * `FILE' + * File name of the source file where the function lives. + * + * `FULLNAME' + * Absolute file name of the source file where the function lives. + * @since gdb 6.4 + * + * `LINE' + * Line number corresponding to the `$pc'. + * + * If invoked without arguments, this command prints a backtrace for the + * whole stack. If given two integer arguments, it shows the frames whose + * levels are between the two arguments (inclusive). If the two arguments + * are equal, it shows the single frame at the corresponding level. + * + */ +public class MIStackListFrames extends MICommand +{ + public MIStackListFrames(IMIExecutionDMContext execDmc) { + super(execDmc, "-stack-list-frames"); //$NON-NLS-1$ + } + + public MIStackListFrames(IMIExecutionDMContext execDmc, int low, int high) { + super(execDmc, "-stack-list-frames", new String[]{Integer.toString(low), //$NON-NLS-1$ + Integer.toString(high)}); + } + + @Override + public MIStackListFramesInfo getResult(MIOutput out) { + return new MIStackListFramesInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListLocals.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListLocals.java new file mode 100644 index 00000000000..528212bd7ac --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListLocals.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for additional features in DSF Reference implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIStackListLocalsInfo; + +/** + * + * -stack-list-locals PRINT-VALUES + * + * Display the local variable names for the current frame. With an + * argument of 0 prints only the names of the variables, with argument of 1 + * prints also their values. + * + */ +public class MIStackListLocals extends MICommand +{ + + public MIStackListLocals(IFrameDMContext frameCtx, boolean printValues) { + super(frameCtx, "-stack-list-locals"); //$NON-NLS-1$ + if (printValues) { + setParameters(new String[]{"1"}); //$NON-NLS-1$ + } else { + setParameters(new String[]{"0"}); //$NON-NLS-1$ + } + } + + @Override + public MIStackListLocalsInfo getResult(MIOutput out) { + return new MIStackListLocalsInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackSelectFrame.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackSelectFrame.java new file mode 100644 index 00000000000..aa12b37b68c --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackSelectFrame.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Modified for additional features in DSF Reference implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + + + +/** + * + * -stack-select-frame FRAMENUM + * + * Change the current frame. Select a different frame FRAMENUM on the + * stack. + * + */ +public class MIStackSelectFrame extends MICommand { + + public MIStackSelectFrame(IDMContext ctx, int frameNum) { + super(ctx, "-stack-select-frame", new String[]{Integer.toString(frameNum)}, new String[0]); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadListIds.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadListIds.java new file mode 100644 index 00000000000..c01996912e9 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadListIds.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIThreadListIdsInfo; + +/** + * + * -thread-list-ids + * + * Produces a list of the currently known GDB thread ids. At the end + * of the list it also prints the total number of such threads. + * + */ +public class MIThreadListIds extends MICommand { + + public MIThreadListIds(IContainerDMContext contDmc) { + super(contDmc, "-thread-list-ids"); //$NON-NLS-1$ + } + + @Override + public MIThreadListIdsInfo getResult(MIOutput out) { + return new MIThreadListIdsInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadSelect.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadSelect.java new file mode 100644 index 00000000000..c25fd671079 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadSelect.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson AB - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; + + +/** + * + * -thread-select THREADNUM + * + * Make THREADNUM the current thread. It prints the number of the new + * current thread, and the topmost frame for that thread. + * + */ + +public class MIThreadSelect extends MICommand +{ + + public MIThreadSelect(IDMContext ctx, int threadNum) { + super(ctx, "-thread-select", new String[]{Integer.toString(threadNum)}); //$NON-NLS-1$ + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarAssign.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarAssign.java new file mode 100644 index 00000000000..54582ba617a --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarAssign.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarAssignInfo; + +/** + * + * -var-assign NAME EXPRESSION + * + * Assigns the value of EXPRESSION to the variable object specified by + * NAME. The object must be `editable'. + * + */ +public class MIVarAssign extends MICommand +{ + public MIVarAssign(MIControlDMContext ctx, String name, String expression) { + super(ctx, "-var-assign", new String[]{name, expression}); //$NON-NLS-1$ + } + + @Override + public MIVarAssignInfo getResult(MIOutput out) { + return new MIVarAssignInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarCreate.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarCreate.java new file mode 100644 index 00000000000..6e23766bb0d --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarCreate.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarCreateInfo; + + +/** + * + * -var-create {NAME | "-"} + * {FRAME-ADDR | "*"} EXPRESSION + * + * This operation creates a variable object, which allows the + * monitoring of a variable, the result of an expression, a memory cell or + * a CPU register. + * + * The NAME parameter is the string by which the object can be + * referenced. It must be unique. If `-' is specified, the varobj system + * will generate a string "varNNNNNN" automatically. It will be unique + * provided that one does not specify NAME on that format. The command + * fails if a duplicate name is found. + * + * The frame under which the expression should be evaluated can be + * specified by FRAME-ADDR. A `*' indicates that the current frame should + * be used. + * + * EXPRESSION is any expression valid on the current language set (must + * not begin with a `*'), or one of the following: + * + * * `*ADDR', where ADDR is the address of a memory cell + * + * * `*ADDR-ADDR' -- a memory address range (TBD) + * + * * `$REGNAME' -- a CPU register name + * + */ +public class MIVarCreate extends MICommand +{ + public MIVarCreate(IExpressionDMContext dmc, String expression) { + this(dmc, "-", "*", expression); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public MIVarCreate(IExpressionDMContext dmc,String name, String expression) { + this(dmc, name, "*", expression); //$NON-NLS-1$ + } + + public MIVarCreate(IExpressionDMContext dmc, String name, String frameAddr, String expression) { + super(dmc, "-var-create", new String[]{name, frameAddr, expression}); //$NON-NLS-1$ + } + + @Override + public MIVarCreateInfo getResult(MIOutput out) { + return new MIVarCreateInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarDelete.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarDelete.java new file mode 100644 index 00000000000..50a7d536437 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarDelete.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarDeleteInfo; + +/** + * + * -var-delete NAME + * + * Deletes a previously created variable object and all of its children. + * + * Returns an error if the object NAME is not found. + * + */ +public class MIVarDelete extends MICommand +{ + public MIVarDelete(MIControlDMContext dmc, String name) { + super(dmc, "-var-delete", new String[]{name}); //$NON-NLS-1$ + } + + @Override + public MIVarDeleteInfo getResult(MIOutput out) { + return new MIVarDeleteInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarEvaluateExpression.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarEvaluateExpression.java new file mode 100644 index 00000000000..c675988e5b0 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarEvaluateExpression.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of frame contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarEvaluateExpressionInfo; + +/** + * + * -var-evaluate-expression NAME + * + * Evaluates the expression that is represented by the specified + * variable object and returns its value as a string in the current format + * specified for the object: + * + * value=VALUE + * + */ +public class MIVarEvaluateExpression extends MICommand { + + public MIVarEvaluateExpression(MIControlDMContext dmc, String name) { + super(dmc, "-var-evaluate-expression", new String[] { name }); //$NON-NLS-1$ + } + + @Override + public MIVarEvaluateExpressionInfo getResult(MIOutput out) { + return new MIVarEvaluateExpressionInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoExpression.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoExpression.java new file mode 100644 index 00000000000..501e624426f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoExpression.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarInfoExpressionInfo; + +/** + * + * -var-info-expression NAME + * + * Returns what is represented by the variable object NAME: + * + * lang=LANG-SPEC,exp=EXPRESSION + * + * where LANG-SPEC is `{"C" | "C++" | "Java"}'. + * + */ + +//MIVarInfoExpression.java +public class MIVarInfoExpression extends MICommand +{ + public MIVarInfoExpression(MIControlDMContext ctx, String name) { + super(ctx, "-var-info-expression", new String[]{name}); //$NON-NLS-1$ + } + + @Override + public MIVarInfoExpressionInfo getResult(MIOutput out) { + return new MIVarInfoExpressionInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoNumChildren.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoNumChildren.java new file mode 100644 index 00000000000..9d9263e6b12 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoNumChildren.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarInfoNumChildrenInfo; + +/** + * + * -var-info-num-children NAME + * + * Returns the number of children of a variable object NAME: + * + * numchild=N + * + */ +public class MIVarInfoNumChildren extends MICommand +{ + public MIVarInfoNumChildren(IExpressionDMContext ctx, String name) { + super(ctx, "-var-info-num-children", new String[]{name}); //$NON-NLS-1$ + } + + @Override + public MIVarInfoNumChildrenInfo getResult(MIOutput out) { + return new MIVarInfoNumChildrenInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoPathExpression.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoPathExpression.java new file mode 100644 index 00000000000..5338871e7ae --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoPathExpression.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarInfoPathExpressionInfo; + +/** + * + * -var-info-path-expression NAME + * + * as of GDB 6.7 + * + * Print full expression that this variable object represents: + * + * (gdb) -var-info-path-expression C.Base.public.m_size + * ^done,path_expr=((Base)c).m_size) + * + */ + +public class MIVarInfoPathExpression extends MICommand +{ + public MIVarInfoPathExpression(MIControlDMContext dmc, String name) { + super(dmc, "-var-info-path-expression", new String[]{name}); //$NON-NLS-1$ + } + + @Override + public MIVarInfoPathExpressionInfo getResult(MIOutput out) { + return new MIVarInfoPathExpressionInfo(out); + } +} + diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoType.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoType.java new file mode 100644 index 00000000000..027da7880ae --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarInfoType.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarInfoTypeInfo; + + +/** + * + * -var-info-type NAME + * + * Returns the type of the specified variable NAME. The type is + * returned as a string in the same format as it is output by the GDB CLI: + * + * type=TYPENAME + * + */ +public class MIVarInfoType extends MICommand +{ + public MIVarInfoType(MIControlDMContext ctx, String name) { + super(ctx, "-var-info-type", new String[]{name}); //$NON-NLS-1$ + } + + @Override + public MIVarInfoTypeInfo getResult(MIOutput out) { + return new MIVarInfoTypeInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarListChildren.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarListChildren.java new file mode 100644 index 00000000000..bf240b1b3b4 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarListChildren.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Modified for handling of frame contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarListChildrenInfo; + +/** + * + * -var-list-children NAME + * + * Returns a list of the children of the specified variable object: + * + * numchild=N,children={{name=NAME, + * numchild=N,type=TYPE},(repeats N times)} + * + */ +public class MIVarListChildren extends MICommand +{ + public MIVarListChildren(MIControlDMContext ctx, String name) { + super(ctx, "-var-list-children", new String[]{name}); //$NON-NLS-1$ + } + + @Override + public MIVarListChildrenInfo getResult(MIOutput out) { + return new MIVarListChildrenInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarSetFormat.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarSetFormat.java new file mode 100644 index 00000000000..d3829b39262 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarSetFormat.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of frame contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IFormattedValues; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarSetFormatInfo; + +/** + * + * -var-set-format NAME FORMAT-SPEC + * + * Sets the output format for the value of the object NAME to be + * FORMAT-SPEC. + * + * The syntax for the FORMAT-SPEC is as follows: + * + * FORMAT-SPEC ==> + * {binary | decimal | hexadecimal | octal | natural} + * + */ +public class MIVarSetFormat extends MICommand +{ + public MIVarSetFormat(MIControlDMContext ctx, String name, String fmt) { + super(ctx, "-var-set-format"); //$NON-NLS-1$ + setParameters(new String[]{name, getFormat(fmt)}); + } + + private String getFormat(String fmt){ + String format = "natural"; //$NON-NLS-1$ + + if (IFormattedValues.HEX_FORMAT.equals(fmt)) { + format = "hexadecimal"; //$NON-NLS-1$ + } else if (IFormattedValues.BINARY_FORMAT.equals(fmt)) { + format = "binary"; //$NON-NLS-1$ + } else if (IFormattedValues.OCTAL_FORMAT.equals(fmt)) { + format = "octal"; //$NON-NLS-1$ + } else if (IFormattedValues.NATURAL_FORMAT.equals(fmt)) { + format = "natural"; //$NON-NLS-1$ + } else if (IFormattedValues.DECIMAL_FORMAT.equals(fmt)) { + format = "decimal"; //$NON-NLS-1$ + } + return format; + } + + @Override + public MIVarSetFormatInfo getResult(MIOutput out) { + return new MIVarSetFormatInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarShowAttributes.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarShowAttributes.java new file mode 100644 index 00000000000..fd17c53f116 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarShowAttributes.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarShowAttributesInfo; + +/** + * + * -var-show-attributes NAME + * + * List attributes of the specified variable object NAME: + * + * status=ATTR [ ( ,ATTR )* ] + * + * where ATTR is `{ { editable | noneditable } | TBD }'. + * + */ +//DsfMIVarShowAttributesInfo + +public class MIVarShowAttributes extends MICommand +{ + public MIVarShowAttributes(MIControlDMContext ctx, String name) { + super(ctx, "-var-show-attributes", new String[]{name}); //$NON-NLS-1$ + } + + @Override + public MIVarShowAttributesInfo getResult(MIOutput out) { + return new MIVarShowAttributesInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarShowFormat.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarShowFormat.java new file mode 100644 index 00000000000..781db498cac --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarShowFormat.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarShowFormatInfo; + +/** + * + * -var-show-format NAME + * + * Returns the format used to display the value of the object NAME. + * + * FORMAT ==> + * FORMAT-SPEC + * + */ +public class MIVarShowFormat extends MICommand +{ + public MIVarShowFormat(MIControlDMContext ctx, String name) { + super(ctx, "-var-show-format", new String[]{name}); //$NON-NLS-1$ + } + + @Override + public MIVarShowFormatInfo getResult(MIOutput out) { + return new MIVarShowFormatInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarUpdate.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarUpdate.java new file mode 100644 index 00000000000..b011279e507 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarUpdate.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for handling of frame contexts + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIVarUpdateInfo; + +/** + * + * -var-update [print-values] {NAME | "*"} + * + * Update the value of the variable object NAME by evaluating its + * expression after fetching all the new values from memory or registers. + * A `*' causes all existing variable objects to be updated. + * If print-values has a value for of 0 or --no-values, print only the names of the variables; + * if print-values is 1 or --all-values, also print their values; + * if it is 2 or --simple-values print the name and value for simple data types and just + * the name for arrays, structures and unions. + */ +public class MIVarUpdate extends MICommand { + + public MIVarUpdate(MIControlDMContext dmc, String name) { + super(dmc, "-var-update", new String[] { "1", name }); //$NON-NLS-1$//$NON-NLS-2$ + } + + @Override + public MIVarUpdateInfo getResult(MIOutput out) { + return new MIVarUpdateInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/RawCommand.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/RawCommand.java new file mode 100644 index 00000000000..2e5c86fe787 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/RawCommand.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIOutput; + +/** + */ +public class RawCommand extends MICommand { + + String fRaw; + + public RawCommand(IDMContext ctx, String operation) { + super(ctx, operation); + fRaw = operation; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.mi.core.command.Command#getMIOutput() + */ + public MIOutput getMIOutput() { + return new MIOutput(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointChangedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointChangedEvent.java new file mode 100644 index 00000000000..d5d8e1a0b8a --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointChangedEvent.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; + + +/** + * + */ +@Immutable +public class MIBreakpointChangedEvent extends MIEvent { + + final private int no; + + public MIBreakpointChangedEvent(IBreakpointsTargetDMContext ctx, int number) { + this(ctx, 0, number); + } + + public MIBreakpointChangedEvent(IBreakpointsTargetDMContext ctx, int id, int number) { + super(ctx, id, null); + no = number; + } + + public int getNumber() { + return no; + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointHitEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointHitEvent.java new file mode 100644 index 00000000000..452632cd5ff --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointHitEvent.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * ^stopped,reason="breakpoint-hit",bkptno="1",thread-id="0",frame={addr="0x08048468",func="main",args=[{name="argc",value="1"},{name="argv",value="0xbffff18c"}],file="hello.c",line="4"} + * + */ +@Immutable +public class MIBreakpointHitEvent extends MIStoppedEvent { + + int bkptno; + + protected MIBreakpointHitEvent(IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame, int bkptno) { + super(ctx, token, results, frame); + this.bkptno = bkptno; + } + + public int getNumber() { + return bkptno; + } + + public static MIBreakpointHitEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + int bkptno = -1; + + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value != null && value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + + if (var.equals("bkptno")) { //$NON-NLS-1$ + try { + bkptno = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + } + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); + return new MIBreakpointHitEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), bkptno); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIDetachedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIDetachedEvent.java new file mode 100644 index 00000000000..1f1f82aeb16 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIDetachedEvent.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.mi.service.command.MIControlDMContext; + + +/** + * + * ^running + */ +@Immutable +public class MIDetachedEvent extends MIEvent { + + public MIDetachedEvent(MIControlDMContext ctx, int token) { + super(ctx, token, null); + } + + @Override + public String toString() { + return "Detached"; //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIErrorEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIErrorEvent.java new file mode 100644 index 00000000000..8458ad56bce --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIErrorEvent.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MILogStreamOutput; +import org.eclipse.dd.mi.service.command.output.MIOOBRecord; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIStreamRecord; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * (gdb) + * &"warning: Cannot insert breakpoint 2:\n" + * &"Cannot access memory at address 0x8020a3\n" + * 30^error,msg=3D"Cannot access memory at address 0x8020a3"=20 + */ +@Immutable +public class MIErrorEvent extends MIStoppedEvent { + + final private String msg; + final private String log; + final private MIOOBRecord[] oobs; + + protected MIErrorEvent( + IExecutionDMContext ctx, int token, MIResult[] results, MIOOBRecord[] oobs, String msg, String log) + { + super(ctx, token, results, null); + this.msg = msg; + this.log = log; + this.oobs = oobs; + } + + public String getMessage() { + return msg; + } + + public String getLogMessage() { + return log; + } + + public static MIErrorEvent parse( + IContainerDMContext containerDmc, int token, MIResult[] results, MIOOBRecord[] oobs) + { + String msg = "", log = ""; //$NON-NLS-1$ //$NON-NLS-2$ + + if (results != null) { + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + + if (var.equals("msg")) { //$NON-NLS-1$ + msg = str; + } + } + } + if (oobs != null) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < oobs.length; i++) { + if (oobs[i] instanceof MILogStreamOutput) { + MIStreamRecord o = (MIStreamRecord)oobs[i]; + sb.append(o.getString()); + } + } + log = sb.toString(); + } + return new MIErrorEvent(containerDmc, token, results, oobs, msg, log); + } + + @Override + public String toString() { + if (oobs != null) { + StringBuilder builder = new StringBuilder(); + for (MIOOBRecord oob : oobs) { + builder.append(oob.toString()); + } + builder.append(super.toString()); + return builder.toString(); + } else { + return super.toString(); + } + } +} + diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIEvent.java new file mode 100644 index 00000000000..b0ca3cc601b --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIEvent.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIResult; + + +/** + */ +@Immutable +public abstract class MIEvent extends AbstractDMEvent { + private final int fToken; + private final MIResult[] fResults; + + public MIEvent(V dmc, int token, MIResult[] results) { + super(dmc); + fToken = token; + fResults = results; + } + + public int getToken() { + return fToken; + } + + public MIResult[] getResults() { + return fResults; + } + + @Override + public String toString() { + if (fResults == null) { + return super.toString(); + } else if (fResults.length == 1) { + return fResults[0].toString(); + } else { + StringBuilder builder = new StringBuilder(); + for (MIResult result : fResults) { + builder.append(result); + builder.append('\n'); + } + return builder.toString(); + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIFunctionFinishedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIFunctionFinishedEvent.java new file mode 100644 index 00000000000..2c8cb838873 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIFunctionFinishedEvent.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * *stopped,reason="function-finished",thread-id="0",frame={addr="0x0804855a",func="main",args=[{name="argc",value="1"},{name="argv",value="0xbffff18c"}],file="hello.c",line="17"},gdb-result-var="$1",return-value="10" + */ +@Immutable +public class MIFunctionFinishedEvent extends MIStoppedEvent { + + final private String gdbResult; + final private String returnValue; + final private String returnType; + + protected MIFunctionFinishedEvent( + IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame, String gdbResult, + String returnValue, String returnType) + { + super(ctx, token, results, frame); + this.gdbResult = gdbResult; + this.returnValue = returnValue; + this.returnType = returnType; + } + + public String getGDBResultVar() { + return gdbResult; + } + + public String getReturnValue() { + return returnValue; + } + + public String getReturnType() { + return returnType; + } + + public static MIFunctionFinishedEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + String gdbResult = ""; //$NON-NLS-1$ + String returnValue = ""; //$NON-NLS-1$ + String returnType = ""; //$NON-NLS-1$ + + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + + if (var.equals("gdb-result-var")) { //$NON-NLS-1$ + gdbResult = str; + } else if (var.equals("return-value")) { //$NON-NLS-1$ + returnValue = str; + } else if (var.equals("return-type")) { //$NON-NLS-1$ + returnType = str; + } + } + + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); + return new MIFunctionFinishedEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), gdbResult, returnValue, returnType); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIGDBExitEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIGDBExitEvent.java new file mode 100644 index 00000000000..57bf6595c27 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIGDBExitEvent.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.mi.service.command.MIControlDMContext; + + +/** + * Gdb Session terminated. + */ +@Immutable +public class MIGDBExitEvent extends MIEvent { + + public MIGDBExitEvent(MIControlDMContext ctx, int token) { + super(ctx, token, null); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIInferiorExitEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIInferiorExitEvent.java new file mode 100644 index 00000000000..b129bbb6486 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIInferiorExitEvent.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * *stopped,reason="exited-normally" + * *stopped,reason="exited",exit-code="04" + * ^done,reason="exited",exit-code="04" + * + */ +@Immutable +public class MIInferiorExitEvent extends MIEvent { + + final private int code; + + public MIInferiorExitEvent(MIControlDMContext ctx, int token, MIResult[] results, int code) { + super(ctx, token, results); + this.code = code; + } + + public int getExitCode() { + return code; + } + + public static MIInferiorExitEvent parse(MIControlDMContext ctx, int token, MIResult[] results) + { + int code = 0; + if (results != null) { + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + + if (var.equals("exit-code")) { //$NON-NLS-1$ + try { + code = Integer.decode(str.trim()).intValue(); + } catch (NumberFormatException e) { + } + } + } + } + return new MIInferiorExitEvent(ctx, token, results, code); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIInferiorSignalExitEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIInferiorSignalExitEvent.java new file mode 100644 index 00000000000..025b99d88f7 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIInferiorSignalExitEvent.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * signal 2 + * "signal 2\n" + * ^done,reason="exited-signalled",signal-name="SIGINT",signal-meaning="Interrupt" + * + */ +@Immutable +public class MIInferiorSignalExitEvent extends MIEvent { + + final private String sigName; + final private String sigMeaning; + + public MIInferiorSignalExitEvent(MIControlDMContext ctx, int token, MIResult[] results, String sigName, String sigMeaning) { + super(ctx, token, results); + this.sigName = sigName; + this.sigMeaning = sigMeaning; + } + + public String getName() { + return sigName; + } + + public String getMeaning() { + return sigMeaning; + } + + public static MIInferiorSignalExitEvent parse(MIControlDMContext ctx, int token, MIResult[] results) + { + String sigName = ""; //$NON-NLS-1$ + String sigMeaning = ""; //$NON-NLS-1$ + + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + + if (var.equals("signal-name")) { //$NON-NLS-1$ + sigName = str; + } else if (var.equals("signal-meaning")) { //$NON-NLS-1$ + sigMeaning = str; + } + } + return new MIInferiorSignalExitEvent(ctx, token, results, sigName, sigMeaning); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MILocationReachedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MILocationReachedEvent.java new file mode 100644 index 00000000000..369d6c870bd --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MILocationReachedEvent.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; + +/** + * *stopped,reason="location-reached",thread-id="0",frame={addr="0x0804858e",func="main2",args=[],file="hello.c",line="27"} + */ +@Immutable +public class MILocationReachedEvent extends MIStoppedEvent { + + protected MILocationReachedEvent(IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame) { + super(ctx, token, results, frame); + } + + public static MILocationReachedEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); + return new MILocationReachedEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame()); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIRunningEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIRunningEvent.java new file mode 100644 index 00000000000..4413bcc6237 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIRunningEvent.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; + + +/** + * + * ^running + */ +@Immutable +public class MIRunningEvent extends MIEvent { + public static final int CONTINUE = 0; + public static final int NEXT = 1; + public static final int NEXTI = 2; + public static final int STEP = 3; + public static final int STEPI = 4; + public static final int FINISH = 5; + public static final int UNTIL = 6; + public static final int RETURN = 7; + + final private int type; + final private int threadId; + + public MIRunningEvent(IExecutionDMContext ctx, int token, int t) { + this(ctx, token, t, -1); + } + + public MIRunningEvent(IExecutionDMContext ctx, int token, int t, int threadId) { + super(ctx, token, null); + type = t; + this.threadId = threadId; + } + + public int getType() { + return type; + } + + public int getThreadId() { + return threadId; + } + + @Override + public String toString() { + return "Running"; //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISharedLibEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISharedLibEvent.java new file mode 100644 index 00000000000..fbb7d01ad67 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISharedLibEvent.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; + +/** + * + */ +@Immutable +public class MISharedLibEvent extends MIStoppedEvent { + + protected MISharedLibEvent(IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame) { + super(ctx, token, results, frame); + } + + public static MIStoppedEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); + return new MISharedLibEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame()); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalChangedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalChangedEvent.java new file mode 100644 index 00000000000..dafaa304681 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalChangedEvent.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.ISignals.ISignalsDMContext; + + +/** + * + */ +@Immutable +public class MISignalChangedEvent extends MIEvent { + + final private String name; + + public MISignalChangedEvent(ISignalsDMContext ctx, String n) { + this(ctx, 0, n); + } + + public MISignalChangedEvent(ISignalsDMContext ctx, int id, String n) { + super(ctx, id, null); + name = n; + } + + public String getName() { + return name; + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalEvent.java new file mode 100644 index 00000000000..1938022d21f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalEvent.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * *stopped,reason="signal-received",signal-name="SIGINT",signal-meaning="Interrupt",thread-id="0",frame={addr="0x400e18e1",func="__libc_nanosleep",args=[],file="__libc_nanosleep",line="-1"} + * + */ +@Immutable +public class MISignalEvent extends MIStoppedEvent { + + final private String sigName; + final private String sigMeaning; + + protected MISignalEvent( + IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame, + String sigName, String sigMeaning) + { + super(ctx, token, results, frame); + this.sigName = sigName; + this.sigMeaning = sigMeaning; + } + + public String getName() { + return sigName; + } + + public String getMeaning() { + return sigMeaning; + } + + public static MISignalEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + String sigName = ""; //$NON-NLS-1$ + String sigMeaning = ""; //$NON-NLS-1$ + + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + + if (var.equals("signal-name")) { //$NON-NLS-1$ + sigName = str; + } else if (var.equals("signal-meaning")) { //$NON-NLS-1$ + sigMeaning = str; + } + } + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); + return new MISignalEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), sigName, sigMeaning); + + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISteppingRangeEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISteppingRangeEvent.java new file mode 100644 index 00000000000..6901d9283e0 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISteppingRangeEvent.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; + +/** + * + * *stopped,reason="end-stepping-range",thread-id="0",frame={addr="0x08048538",func="main",args=[{name="argc",value="1"},{name="argv",value="0xbffff18c"}],file="hello.c",line="13"} + */ +@Immutable +public class MISteppingRangeEvent extends MIStoppedEvent { + + protected MISteppingRangeEvent(IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame) { + super(ctx, token, results, frame); + } + + public static MISteppingRangeEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); + return new MISteppingRangeEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame()); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIStoppedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIStoppedEvent.java new file mode 100644 index 00000000000..a1a45b0d47b --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIStoppedEvent.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MITuple; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * *stopped + * + */ +@Immutable +public class MIStoppedEvent extends MIEvent { + + final private MIFrame frame; + + protected MIStoppedEvent(IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame) { + super(ctx, token, results); + this.frame = frame; + } + + public MIFrame getFrame() { + return frame; + } + + public static MIStoppedEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + int threadId = -1; + MIFrame frame = null; + + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + + if (var.equals("thread-id")) { //$NON-NLS-1$ + if (value instanceof MIConst) { + String str = ((MIConst)value).getString(); + try { + threadId = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + } else if (var.equals("frame")) { //$NON-NLS-1$ + if (value instanceof MITuple) { + frame = new MIFrame((MITuple)value); + } + } + } + IExecutionDMContext execDmc = containerDmc; + if (runControl != null && threadId != -1) { + execDmc = runControl.createMIExecutionContext(containerDmc, threadId); + } + return new MIStoppedEvent(execDmc, token, results, frame); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java new file mode 100644 index 00000000000..23583241c39 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; + + +/** + * This can not be detected yet by gdb/mi. + * + */ +@Immutable +public class MIThreadCreatedEvent extends MIEvent { + + final private int tid; + + public MIThreadCreatedEvent(IContainerDMContext ctx, int id) { + this(ctx, 0, id); + } + + public MIThreadCreatedEvent(IContainerDMContext ctx, int token, int id) { + super(ctx, token, null); + tid = id; + } + + public int getId() { + return tid; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java new file mode 100644 index 00000000000..e960f8f9b40 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; + + +/** + * This can not be detected yet by gdb/mi. + * + */ +@Immutable +public class MIThreadExitEvent extends MIEvent { + + final private int tid; + + public MIThreadExitEvent(IContainerDMContext ctx, int id) { + this(ctx, 0, id); + } + + public MIThreadExitEvent(IContainerDMContext ctx, int token, int id) { + super(ctx, token, null); + tid = id; + } + + public int getId() { + return tid; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointScopeEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointScopeEvent.java new file mode 100644 index 00000000000..5de47f2a808 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointScopeEvent.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * *stopped,reason="watchpoint-scope",wpnum="5", + * + */ +@Immutable +public class MIWatchpointScopeEvent extends MIStoppedEvent { + + final private int number; + + protected MIWatchpointScopeEvent( + IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame, int number) + { + super(ctx, token, results, frame); + this.number = number; + } + + public int getNumber() { + return number; + } + + public static MIWatchpointScopeEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + int number = 0; + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + + if (var.equals("wpnum")) { //$NON-NLS-1$ + if (value instanceof MIConst) { + String str = ((MIConst) value).getString(); + try { + number = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + } + } + + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); + return new MIWatchpointScopeEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), number); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointTriggerEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointTriggerEvent.java new file mode 100644 index 00000000000..81d4da3ace9 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointTriggerEvent.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MITuple; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * *stopped,reason="watchpoint-trigger",wpt={number="2",exp="i"},value={old="0",new="1"},thread-id="0",frame={addr="0x08048534",func="main",args=[{name="argc",value="1"},{name="argv",value="0xbffff18c"}],file="hello.c",line="10"} + * + */ +@Immutable +public class MIWatchpointTriggerEvent extends MIStoppedEvent { + + final private int number; + final private String exp; + final private String oldValue; + final private String newValue; + + protected MIWatchpointTriggerEvent( + IExecutionDMContext ctx, int token, MIResult[] results, MIFrame frame, + int number, String exp, String oldValue, String newValue) + { + super(ctx, token, results, frame); + this.number = number; + this.exp = exp; + this.oldValue = oldValue; + this.newValue = newValue; + } + + public int getNumber() { + return number; + } + + public String getExpression() { + return exp; + } + + public String getOldValue() { + return oldValue; + } + + public String getNewValue() { + return newValue; + } + + public static MIWatchpointTriggerEvent parse( + MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + { + int number = 0; + String exp = ""; //$NON-NLS-1$ + String oldValue = ""; //$NON-NLS-1$ + String newValue = ""; //$NON-NLS-1$ + + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + + if (var.equals("wpt") || var.equals("hw-awpt") || var.equals("hw-rwpt")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if (value instanceof MITuple) { + for (MIResult wptResult : ((MITuple) value).getMIResults()) { + String wptVar = wptResult.getVariable(); + MIValue wptValue = wptResult.getMIValue(); + + if (wptVar.equals("number")) { //$NON-NLS-1$ + if (wptValue instanceof MIConst) { + String str = ((MIConst) wptValue).getString(); + try { + number = Integer.parseInt(str); + } catch (NumberFormatException e) { + } + } + } else if (wptVar.equals("exp")) { //$NON-NLS-1$ + if (wptValue instanceof MIConst) { + exp = ((MIConst) wptValue).getString(); + } + } + } + } + } else if (var.equals("value")) { //$NON-NLS-1$ + if (value instanceof MITuple) { + for (MIResult valueResult : ((MITuple)value).getMIResults()) { + String valueVar = valueResult.getVariable(); + MIValue valueValue = valueResult.getMIValue(); + String str = ""; //$NON-NLS-1$ + if (valueValue instanceof MIConst) { + str = ((MIConst) valueValue).getString(); + } + + if (valueVar.equals("old")) { //$NON-NLS-1$ + oldValue = str; + } else if (valueVar.equals("new")) { //$NON-NLS-1$ + newValue = str; + } else if (valueVar.equals("value")) { //$NON-NLS-1$ + oldValue = newValue = str; + } + } + + } + } + } + MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); + return new MIWatchpointTriggerEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame(), number, exp, oldValue, newValue); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoSharedLibraryInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoSharedLibraryInfo.java new file mode 100644 index 00000000000..f54ef23e05e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoSharedLibraryInfo.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson AB - Modified for DSF GDB reference implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + */ +public class CLIInfoSharedLibraryInfo extends MIInfo { + + DsfMISharedInfo[] shared; + + public class DsfMISharedInfo { + + String from; + String to; + boolean isread; + String name; + + public DsfMISharedInfo (String start, String end, boolean read, String location) { + from = start; + to = end; + isread = read; + name = location; + } + + public String getFrom() { + return from; + } + + public String getTo() { + return to; + } + + public boolean isRead() { + return isread; + } + + public String getName() { + return name; + } + + public void setSymbolsRead(boolean read) { + isread = read; + } + } + + public CLIInfoSharedLibraryInfo(MIOutput out) { + super(out); + parse(); + } + + public DsfMISharedInfo[] getMIShared() { + return shared; + } + + void parse() { + List aList = new ArrayList(); + if (isDone()) { + MIOutput out = getMIOutput(); + MIOOBRecord[] oobs = out.getMIOOBRecords(); + for (int i = 0; i < oobs.length; i++) { + if (oobs[i] instanceof MIConsoleStreamOutput) { + MIStreamRecord cons = (MIStreamRecord) oobs[i]; + String str = cons.getString(); + // We are interested in the shared info + parseShared(str.trim(), aList); + } + } + } + shared = new DsfMISharedInfo[aList.size()]; + for (int i = 0; i < aList.size(); i++) { + shared[i] = aList.get(i); + } + } + + void parseShared(String str, List aList) { + if (str.length() > 0) { + // Parsing pattern of type ~"0x40000970 0x4001331f Yes /lib/ld-linux.so.2\n" + Pattern pattern = Pattern.compile("(0x.*)(0x.*)(Yes|No)(\\s*)(.*)", Pattern.MULTILINE); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(str); + if (matcher.find()) { + DsfMISharedInfo s = new DsfMISharedInfo(matcher.group(1), matcher.group(2), + (matcher.group(3).equals("Yes"))?true:false, //$NON-NLS-1$ + matcher.group(5)); + aList.add(s); + + } + } + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoThreadsInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoThreadsInfo.java new file mode 100644 index 00000000000..72dee49824f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoThreadsInfo.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * GDB/MI thread list parsing. +~"\n" +~" 2 Thread 2049 (LWP 29354) " +~"* 1 Thread 1024 (LWP 29353) " + + */ +public class CLIInfoThreadsInfo extends MIInfo { + + protected List info; + + public CLIInfoThreadsInfo(MIOutput out) { + super(out); + parse(); + } + + public class ThreadInfo{ + String fName; + String fGdbId; + String fPid; + boolean fIsCurrentThread = false; + + public ThreadInfo(String tid, String pid, String name, boolean isCurrentThread) + { + this.fName = name; + this.fGdbId = tid; + this.fPid = pid; + this.fIsCurrentThread = isCurrentThread; + } + + public String getName(){ return fName ;} + // GDB id given to a thread. Needed to compare with ID stored in DMC fetched via DsfMIThreadListIds command + public String getId(){ return fGdbId; } + public String getOsId(){return fPid; } + public boolean isCurrentThread(){return fIsCurrentThread; } + } + + public List getThreadInfo(){ + return info; + } + + protected void parse() { + info = new ArrayList(); + if (isDone()) { + MIOutput out = getMIOutput(); + MIOOBRecord[] oobs = out.getMIOOBRecords(); + for (int i = 0; i < oobs.length; i++) { + if (oobs[i] instanceof MIConsoleStreamOutput) { + MIStreamRecord cons = (MIStreamRecord) oobs[i]; + String str = cons.getString(); + // We are interested in finding the current thread + parseThreadInfo(str.trim(), info); + } + } + } + } + + protected void parseThreadInfo(String str, List info) { + // Fetch the OS ThreadId & Find the current thread + if(str.length() > 0 ){ + Pattern pattern = Pattern.compile("(^\\d*|^\\*\\s*\\d*)(\\s*Thread\\s*)(\\d*)(\\s*\\(LWP\\s*)(\\d*)", Pattern.MULTILINE); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(str); + boolean isCurrentThread = false; + if (matcher.find()) { + String id = matcher.group(1); + if (id.charAt(0) == '*') { + isCurrentThread = true; + id = id.substring(1).trim(); + } + info.add(new ThreadInfo(id, matcher.group(5), "", isCurrentThread)); //$NON-NLS-1$ + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetAttributesInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetAttributesInfo.java new file mode 100644 index 00000000000..ca055aa3912 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetAttributesInfo.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; + +public class ExprMetaGetAttributesInfo implements ICommandResult { + + private final boolean editable; + + public ExprMetaGetAttributesInfo(boolean e) { + editable = e; + } + + public boolean getEditable() { return editable; } + + public V getSubsetResult(ICommand command) { + return null; + } +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetChildCountInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetChildCountInfo.java new file mode 100644 index 00000000000..6bd8f229120 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetChildCountInfo.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; + +public class ExprMetaGetChildCountInfo implements ICommandResult { + + private final int childNum; + + public ExprMetaGetChildCountInfo(int n) { + childNum = n; + } + + public int getChildNum() { return childNum; } + + public V getSubsetResult(ICommand command) { + return null; + } +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetChildrenInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetChildrenInfo.java new file mode 100644 index 00000000000..d5573799f42 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetChildrenInfo.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.mi.service.ExpressionService.ExpressionInfo; + +public class ExprMetaGetChildrenInfo implements ICommandResult { + + private final ExpressionInfo[] childrenExpressions; + + public ExprMetaGetChildrenInfo(ExpressionInfo[] c) { + childrenExpressions = c; + } + + public ExpressionInfo[] getChildrenExpressions() { return childrenExpressions; } + + public V getSubsetResult(ICommand command) { + return null; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetValueInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetValueInfo.java new file mode 100644 index 00000000000..d55461cf17f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetValueInfo.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; + +public class ExprMetaGetValueInfo implements ICommandResult { + + private final String value; + + public ExprMetaGetValueInfo(String v) { + value = v; + } + + public String getValue() { return value; } + + public V getSubsetResult(ICommand command) { + return null; + } + } \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetVarInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetVarInfo.java new file mode 100644 index 00000000000..c2cd30560bb --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/ExprMetaGetVarInfo.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; + +public class ExprMetaGetVarInfo implements ICommandResult { + + private final String expression; + private final int numChild; + private final String type; + private final boolean editable; + + public ExprMetaGetVarInfo(String e, int n, String t, boolean edit) { + expression = e; + numChild = n; + type = t; + editable = edit; + } + + public String getExpr() { return expression; } + public int getNumChildren() { return numChild; } + public String getType() { return type; } + public boolean getEditable() { return editable; } + + public V getSubsetResult(ICommand command) { + return null; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIArg.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIArg.java new file mode 100644 index 00000000000..bbc97b809f6 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIArg.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Represents a set name=value. + */ +public class MIArg { + String name; + String value; + + public MIArg(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + /** + * Parsing a DsfMIList of the form: + * [{name="xxx",value="yyy"},{name="xxx",value="yyy"},..] + * [name="xxx",name="xxx",..] + * [{name="xxx"},{name="xxx"}] + */ + public static MIArg[] getMIArgs(MIList miList) { + List aList = new ArrayList(); + MIValue[] values = miList.getMIValues(); + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof MITuple) { + MIArg arg = getMIArg((MITuple)values[i]); + if (arg != null) { + aList.add(arg); + } + } + } + MIResult[] results = miList.getMIResults(); + for (int i = 0; i < results.length; i++) { + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getCString(); + aList.add(new MIArg(str, "")); //$NON-NLS-1$ + } + } + return (aList.toArray(new MIArg[aList.size()])); + } + + /** + * Parsing a DsfMITuple of the form: + * {{name="xxx",value="yyy"},{name="xxx",value="yyy"},..} + * {name="xxx",name="xxx",..} + * {{name="xxx"},{name="xxx"}} + */ + public static MIArg[] getMIArgs(MITuple miTuple) { + List aList = new ArrayList(); + MIValue[] values = miTuple.getMIValues(); + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof MITuple) { + MIArg arg = getMIArg((MITuple)values[i]); + if (arg != null) { + aList.add(arg); + } + } + } + MIResult[] results = miTuple.getMIResults(); + for (int i = 0; i < results.length; i++) { + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getCString(); + aList.add(new MIArg(str, "")); //$NON-NLS-1$ + } + } + return (aList.toArray(new MIArg[aList.size()])); + } + /** + * Parsing a DsfMITuple of the form: + * {name="xxx",value="yyy"} + * {name="xxx"} + */ + public static MIArg getMIArg(MITuple tuple) { + MIResult[] args = tuple.getMIResults(); + MIArg arg = null; + if (args.length > 0) { + // Name + String aName = ""; //$NON-NLS-1$ + MIValue value = args[0].getMIValue(); + if (value != null && value instanceof MIConst) { + aName = ((MIConst)value).getCString(); + } else { + aName = ""; //$NON-NLS-1$ + } + + // Value + String aValue = ""; //$NON-NLS-1$ + if (args.length == 2) { + value = args[1].getMIValue(); + if (value != null && value instanceof MIConst) { + aValue = ((MIConst)value).getCString(); + } else { + aValue = ""; //$NON-NLS-1$ + } + } + + arg = new MIArg(aName, aValue); + } + return arg; + } + + @Override + public String toString() { + return name + "=" + value; //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIAsyncRecord.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIAsyncRecord.java new file mode 100644 index 00000000000..61d7c235ec6 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIAsyncRecord.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * base Abstract class for the OOB stream MI responses. + */ +public abstract class MIAsyncRecord extends MIOOBRecord { + + final static MIResult[] nullResults = new MIResult[0]; + + MIResult[] results = null; + String asynClass = ""; //$NON-NLS-1$ + int token = 0; + + public int getToken() { + return token; + } + + public void setToken(int t) { + token = t; + } + + public String getAsyncClass() { + return asynClass; + } + + public void setAsyncClass(String a) { + asynClass = a; + } + + public MIResult[] getMIResults() { + if (results == null) { + return nullResults; + } + return results; + } + + public void setMIResults(MIResult[] res) { + results = res; + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + if (token != 0) { + buffer.append(token); + } + if (this instanceof MIExecAsyncOutput) { + buffer.append('*'); + } else if (this instanceof MIStatusAsyncOutput) { + buffer.append('+'); + } else if (this instanceof MINotifyAsyncOutput) { + buffer.append('='); + } + buffer.append(asynClass); + if (results != null) { + for (int i = 0; i < results.length; i++) { + buffer.append(','); + buffer.append(results[i].toString()); + } + } + buffer.append('\n'); + return buffer.toString(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakInsertInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakInsertInfo.java new file mode 100644 index 00000000000..79b44cd63d2 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakInsertInfo.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +/** + * -break-insert main + * ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x08048468",func="main",file="hello.c",line="4",times="0"} + * -break-insert -a p + * ^done,hw-awpt={number="2",exp="p"} + * -break-watch -r p + * ^done,hw-rwpt={number="4",exp="p"} + * -break-watch p + * ^done,wpt={number="6",exp="p"} + */ +public class MIBreakInsertInfo extends MIInfo { + + MIBreakpoint[] breakpoints; + + public MIBreakInsertInfo(MIOutput record) { + super(record); + breakpoints = null; + List aList = new ArrayList(1); + if (isDone()) { + MIResultRecord rr = record.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + MIBreakpoint bpt = null; + if (var.equals("wpt")) { //$NON-NLS-1$ + if (val instanceof MITuple) { + bpt = new MIBreakpoint((MITuple)val); + bpt.setEnabled(true); + bpt.setWriteWatchpoint(true); + } + } else if (var.equals("bkpt")) { //$NON-NLS-1$ + if (val instanceof MITuple) { + bpt = new MIBreakpoint((MITuple)val); + bpt.setEnabled(true); + } + } else if (var.equals("hw-awpt")) { //$NON-NLS-1$ + if (val instanceof MITuple) { + bpt = new MIBreakpoint((MITuple)val); + bpt.setAccessWatchpoint(true); + bpt.setEnabled(true); + } + } else if (var.equals("hw-rwpt")) { //$NON-NLS-1$ + if (val instanceof MITuple) { + bpt = new MIBreakpoint((MITuple)val); + bpt.setReadWatchpoint(true); + bpt.setEnabled(true); + } + } + if (bpt != null) { + aList.add(bpt); + } + } + } + } + breakpoints = aList.toArray(new MIBreakpoint[aList.size()]); + } + + public MIBreakpoint[] getMIBreakpoints() { + return breakpoints; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakListInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakListInfo.java new file mode 100644 index 00000000000..23de9da1edf --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakListInfo.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + + + +/** + * A -break-list result-record is the form: + *
+ * ^done,BreakpointTable={nr_rows="1",nr_cols="6",hdr=[..],body=[brkpt={},brkpt={}]}
+ *-break-list
+^done,BreakpointTable={nr_rows="6",nr_cols="6",hdr=[{width="3",alignment="-1",col_name="number",colhdr="Num"},{width="14",alignment="-1",col_name="type",colhdr="Type"},{width="4",alignment="-1",col_name="disp",colhdr="Disp"},{width="3",alignment="-1",col_name="enabled",colhdr="Enb"},{width="10",alignment="-1",col_name="addr",colhdr="Address"},{width="40",alignment="2",col_name="what",colhdr="What"}],body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="2",type="breakpoint",disp="del",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="3",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",cond="1",times="0"},bkpt={number="4",type="hw breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"},bkpt={number="5",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",thread="0",thread="0",times="0"},bkpt={number="6",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",thread="1",thread="1",times="0"}]}
+ * 
+ */ +public class MIBreakListInfo extends MIInfo { + + MIBreakpoint[] breakpoints; + + public MIBreakListInfo(MIOutput rr) { + super(rr); + } + + public MIBreakpoint[] getMIBreakpoints() { + if (breakpoints == null) { + parse(); + } + return breakpoints; + } + + void parse() { + List aList = new ArrayList(1); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("BreakpointTable")) { //$NON-NLS-1$ + parseTable(results[i].getMIValue(), aList); + } + } + } + } + breakpoints = aList.toArray(new MIBreakpoint[aList.size()]); + } + + void parseTable(MIValue val, List aList) { + if (val instanceof MITuple) { + MIResult[] table = ((MITuple)val).getMIResults(); + for (int j = 0; j < table.length; j++) { + String variable = table[j].getVariable(); + if (variable.equals("body")) { //$NON-NLS-1$ + parseBody(table[j].getMIValue(), aList); + } + } + } + } + + void parseBody(MIValue body, List aList) { + if (body instanceof MIList) { + MIResult[] bkpts = ((MIList)body).getMIResults(); + for (int i = 0; i < bkpts.length; i++) { + String b = bkpts[i].getVariable(); + if (b.equals("bkpt")) { //$NON-NLS-1$ + MIValue value = bkpts[i].getMIValue(); + if (value instanceof MITuple) { + aList.add(new MIBreakpoint((MITuple)value)); + } + } + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakpoint.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakpoint.java new file mode 100644 index 00000000000..0047439fc90 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIBreakpoint.java @@ -0,0 +1,294 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for the breakpoint service + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * Contain info about the GDB/MI breakpoint. + * + * (gdb) + * -break-insert main + * ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"} + * (gdb) + * -break-insert -t main + * ^done,bkpt={number="2",type="breakpoint",disp="del",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"} + * (gdb) + * -break-insert -c 1 main + * ^done,bkpt={number="3",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",cond="1",times="0"} + * (gdb) + * -break-insert -h main + * ^done,bkpt={number="4",type="hw breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",times="0"} + * (gdb) + * -break-insert -p 0 main + * ^done,bkpt={number="5",type="breakpoint",disp="keep",enabled="y",addr="0x0804846b",func="main",file="hello.c",line="4",thread="0",thread="0",times="0"} + * (gdb) + * -break-watch -a p + * ^done,hw-awpt={number="2",exp="p"} + * (gdb) + * -break-watch -r p + * ^done,hw-rwpt={number="4",exp="p"} + * (gdb) + * -break-watch p + * ^done,wpt={number="6",exp="p"} + * (gdb) + */ +public class MIBreakpoint { + + int number = -1; + String type = ""; //$NON-NLS-1$ + String disp = ""; //$NON-NLS-1$ + boolean enabled = false; + String address = ""; //$NON-NLS-1$ + String func = ""; //$NON-NLS-1$ + String fullName = ""; //$NON-NLS-1$ + String file = ""; //$NON-NLS-1$ + int line = -1; + String cond = ""; //$NON-NLS-1$ + int times = 0; + String exp = ""; //$NON-NLS-1$ + String threadId = "0"; //$NON-NLS-1$ + int ignore = 0; + + boolean isWpt = false; + boolean isAWpt = false; + boolean isRWpt = false; + boolean isWWpt = false; + boolean isHdw = false; + + public MIBreakpoint() { + } + + public MIBreakpoint(MIBreakpoint other) { + number = other.number; + type = new String(other.type); + disp = new String(other.disp); + enabled = other.enabled; + type = new String(other.type); + address = new String(other.address); + func = new String(other.func); + fullName = new String(other.fullName); + file = new String(other.file); + line = other.line; + cond = new String(other.cond); + times = other.times; + exp = new String(other.exp); + threadId = new String(other.threadId); + ignore = other.ignore; + isWpt = other.isWpt; + isAWpt = other.isAWpt; + isRWpt = other.isRWpt; + isWWpt = other.isWWpt; + isHdw = other.isHdw; + } + + public MIBreakpoint(MITuple tuple) { + parse(tuple); + } + + /////////////////////////////////////////////////////////////////////////// + // Properties getters + /////////////////////////////////////////////////////////////////////////// + + public int getNumber() { + return number; + } + + public String getType() { + return type; + } + + public String getDisposition() { + return disp; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean e) { + enabled = e; + } + + public String getAddress() { + return address; + } + + public String getFunction() { + return func; + } + + public String getFile() { + return file; + } + + public String getFullName() { + return fullName; + } + + public int getLine() { + return line; + } + + public String getCondition() { + return cond; + } + + public void setCondition(String condition) { + cond = condition; + } + + public int getIgnoreCount() { + return ignore; + } + + public void setIgnoreCount(int ignoreCount) { + ignore = ignoreCount; + } + + public String getThreadId() { + return threadId; + } + + public int getTimes() { + return times; + } + + public String getExpression() { + return exp; + } + + public boolean isTemporary() { + return getDisposition().equals("del"); //$NON-NLS-1$ + } + + public boolean isHardware() { + return isHdw; + } + + public void setHardware(boolean b) { + isWpt = b; + isHdw = b; + } + + public boolean isWatchpoint() { + return isWpt; + } + + public void isWatchpoint(boolean b) { + isWpt = b; + } + + public boolean isAccessWatchpoint() { + return isAWpt; + } + + public void setAccessWatchpoint(boolean b) { + isWpt = b; + isAWpt = b; + } + + public boolean isReadWatchpoint() { + return isRWpt; + } + + public void setReadWatchpoint(boolean b) { + isWpt = b; + isRWpt = b; + } + + public boolean isWriteWatchpoint() { + return isWWpt; + } + + public void setWriteWatchpoint(boolean b) { + isWpt = b; + isWWpt = b; + } + + // Parse the result string + void parse(MITuple tuple) { + MIResult[] results = tuple.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value != null && value instanceof MIConst) { + str = ((MIConst)value).getCString(); + } + + if (var.equals("number")) { //$NON-NLS-1$ + try { + number = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("type")) { //$NON-NLS-1$ + type = str; + //type="hw watchpoint" + if (type.startsWith("hw")) { //$NON-NLS-1$ + isHdw = true; + isWWpt = true; + isWpt = true; + } + //type="acc watchpoint" + if (type.startsWith("acc")) { //$NON-NLS-1$ + isAWpt = true; + isWpt = true; + } + //type="read watchpoint" + if (type.startsWith("read")) { //$NON-NLS-1$ + isRWpt = true; + isWpt = true; + } + // type="breakpoint" + // default ok. + } else if (var.equals("disp")) { //$NON-NLS-1$ + disp = str; + } else if (var.equals("enabled")) { //$NON-NLS-1$ + enabled = str.equals("y"); //$NON-NLS-1$ + } else if (var.equals("addr")) { //$NON-NLS-1$ + try { + address = str.trim(); + } catch (NumberFormatException e) { + } + } else if (var.equals("func")) { //$NON-NLS-1$ + func = str; + } else if (var.equals("file")) { //$NON-NLS-1$ + file = str; + } else if (var.equals("fullname")) { //$NON-NLS-1$ + fullName = str; + } else if (var.equals("thread")) { //$NON-NLS-1$ + threadId = str; + } else if (var.equals("line")) { //$NON-NLS-1$ + try { + line = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("times")) { //$NON-NLS-1$ + try { + times = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("what") || var.equals("exp")) { //$NON-NLS-1$ //$NON-NLS-2$ + exp = str; + } else if (var.equals("ignore")) { //$NON-NLS-1$ + try { + ignore = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("cond")) { //$NON-NLS-1$ + cond = str; + } + } + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIConsoleStreamOutput.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIConsoleStreamOutput.java new file mode 100644 index 00000000000..ce01d500c50 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIConsoleStreamOutput.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * @see MIStreamRecord + */ +public class MIConsoleStreamOutput extends MIStreamRecord { +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIConst.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIConst.java new file mode 100644 index 00000000000..793d47a6b53 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIConst.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI const value represents a ios-c string. + */ +public class MIConst extends MIValue { + String cstring = ""; //$NON-NLS-1$ + + public String getCString() { + return cstring; + } + + public void setCString(String str) { + cstring = str; + } + + /** + * Translate gdb c-string. + */ + public String getString() { + return getString(cstring); + } + + public static String getString(String str) { + StringBuffer buffer = new StringBuffer(); + boolean escape = false; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '\\') { + if (escape) { + buffer.append(c); + escape = false; + } else { + escape = true; + } + } else { + if (escape) { + if (isIsoCSpecialChar(c)) { + buffer.append(isoC(c)); + } else { + buffer.append('\\'); + buffer.append(c); + } + } else { + buffer.append(c); + } + escape = false; + } + } + + // If escape is still true it means that the + // last char was an '\'. + if (escape) { + buffer.append('\\'); + } + + return buffer.toString(); + } + + @Override + public String toString() { + return getCString(); + } + + /** + * Assuming that the precedent character was the + * escape sequence '\' + */ + private static String isoC(char c) { + String s = new Character(c).toString(); + if (c == '"') { + s = "\""; //$NON-NLS-1$ + } else if (c == '\'') { + s = "\'"; //$NON-NLS-1$ + } else if (c == '?') { + s = "?"; //$NON-NLS-1$ + } else if (c == 'a') { + s = "\007"; //$NON-NLS-1$ + } else if (c == 'b') { + s = "\b"; //$NON-NLS-1$ + } else if (c == 'f') { + s = "\f"; //$NON-NLS-1$ + } else if (c == 'n') { + s = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ $NON-NLS-2$ + } else if (c == 'r') { + s = "\r"; //$NON-NLS-1$ + } else if (c == 't') { + s = "\t"; //$NON-NLS-1$ + } else if (c == 'v') { + s = "\013"; //$NON-NLS-1$ + } + return s; + } + + private static boolean isIsoCSpecialChar(char c) { + switch (c) { + case '"': + case '\'': + case '?': + case 'a': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': + return true; + } + return false; + + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataEvaluateExpressionInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataEvaluateExpressionInfo.java new file mode 100644 index 00000000000..9bac5e087c0 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataEvaluateExpressionInfo.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI Data evaluate expression parsing response. + */ +public class MIDataEvaluateExpressionInfo extends MIInfo { + + String fValue; + + public MIDataEvaluateExpressionInfo(MIOutput rr) { + super(rr); + fValue = ""; //$NON-NLS-1$ + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord outr = out.getMIResultRecord(); + if (outr != null) { + MIResult[] results = outr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("value")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + fValue = ((MIConst)value).getCString(); + } + } + } + } + } + } + + public String getValue() { + return fValue; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataListRegisterNamesInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataListRegisterNamesInfo.java new file mode 100644 index 00000000000..78acb37e2cd --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataListRegisterNamesInfo.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +/** + * GDB/MI data list regiter names response extraction. + */ +public class MIDataListRegisterNamesInfo extends MIInfo { + + String[] names; + protected int realNameCount = 0; + + public MIDataListRegisterNamesInfo(MIOutput rr) { + super(rr); + names = null; + List aList = new ArrayList(); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord outr = out.getMIResultRecord(); + if (outr != null) { + MIResult[] results = outr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("register-names")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIList) { + parseRegisters((MIList) value, aList); + } + } + } + } + } + names = aList.toArray(new String[aList.size()]); + } + + /* + * Returns the register names. + */ + public String[] getRegisterNames() { + + /* + * The expectation is that we return an empty list. The + * constructor quarantees this so we are good here. + */ + return names; + } + + private void parseRegisters(MIList list, List aList) { + MIValue[] values = list.getMIValues(); + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof MIConst) { + String str = ((MIConst) values[i]).getCString(); + + /* this cannot filter nulls because index is critical in retreival + * and index is assigned in the layers above. The MI spec allows + * empty returns, for some register names. */ + if (str != null && str.length() > 0) { + realNameCount++; + aList.add(str); + } else { + aList.add(""); //$NON-NLS-1$ + } + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataListRegisterValuesInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataListRegisterValuesInfo.java new file mode 100644 index 00000000000..1dd4439431c --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataListRegisterValuesInfo.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.mi.service.command.commands.MIDataListRegisterValues; + +/** + * GDB/MI data list register values extraction. + */ +public class MIDataListRegisterValuesInfo extends MIInfo { + + MIRegisterValue[] registers; + + public MIDataListRegisterValuesInfo(MIOutput rr) { + super(rr); + registers = null; + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord outr = out.getMIResultRecord(); + if (outr != null) { + MIResult[] results = outr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("register-values")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIList) { + registers = MIRegisterValue.getMIRegisterValues((MIList)value); + } + } + } + } + } + if (registers == null) { + registers = new MIRegisterValue[0]; + } + } + + /* + * Returns the array of registers values. + */ + + public MIRegisterValue[] getMIRegisterValues() { + + /* + * The expectation is that we return an empty list. The + * constructor quarantees this so we are good here. + */ + return registers; + } + + /** + * Returns the desired subset of results. When this function is being called + * the data here represents a coalesced request which is a superset of at + * least two original requests. We are extracting the data associated with + * the specified original request which we know is contained in this result. + */ + @Override + public V getSubsetResult(ICommand cmd) { + if (cmd instanceof MIDataListRegisterValues) { + MIDataListRegisterValues command = (MIDataListRegisterValues) cmd; + List aList = new ArrayList(); + int[] wantedRegNos = command.getRegList(); + + /* + * Search through the larger answer set finding the ones we want. + */ + for (MIRegisterValue regVal : registers) { + for ( int curRegNo : wantedRegNos ) { + if ( regVal.getNumber() == curRegNo ) { + aList.add( regVal ); + } + } + } + + /* + * Now construct a new complete answer. + */ + MIRegisterValue[] finalRegSet = aList.toArray(new MIRegisterValue[aList.size()]); + MIDataListRegisterValuesInfo finalSubset = new MIDataListRegisterValuesInfo( getMIOutput()); + finalSubset.registers = finalRegSet; + + @SuppressWarnings("unchecked") + V vFinalSubset = (V)finalSubset; + return vFinalSubset ; + } else { + return super.getSubsetResult(cmd); + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataReadMemoryInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataReadMemoryInfo.java new file mode 100644 index 00000000000..fbe560f05d7 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataReadMemoryInfo.java @@ -0,0 +1,248 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson AB - Modified for new DSF Reference Implementation + * Ericsson AB - Reverted to byte[] and processed multi-line results + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.math.BigInteger; + +import org.eclipse.debug.core.model.MemoryByte; + +/** + * + * -data-read-memory result + * + * (gdb) + * nn-data-read-memory [command parameters] + * nn^done,addr="ADDRESS",nr-bytes="NR_BYTES",total-bytes="TOTAL_BYTES", + * next-row="NEXT_ROW",prev-row="PREV_ROW",next-page="NEXT_PAGE", + * prev-page="PREV_PAGE",memory=[ + * {addr="addr1",data=["0x00","0x01", ...]}, + * {addr="addr2",data=["0x02","0x03", ...]}, + * {addr="addr3",data=["0x04","0x05", ...]}, + * ...] + * (gdb) + * + * where: + * + * 'ADDRESS' + * Address (in hex) of the first byte fetched. + * + * 'NR_BYTES' + * Number of bytes read. + * + * 'TOTAL_BYTES' + * Number of bytes requested (nr-rows * nr-columns * word-size). + * + * 'NEXT_ROW' + * Address (in hex) of the next row. + * + * 'PREV_ROW' + * Address (in hex) of the previous row. + * + * 'NEXT_PAGE' + * Address (in hex) of the next page. + * + * 'PREV_PAGE' + * Address (in hex) of the previous page. + * + * 'MEMORY' + * Memory bytes retrieved, nr-rows of nr-columns words. + * + */ +public class MIDataReadMemoryInfo extends MIInfo { + + // The parsed values of interest + BigInteger fAddress = new BigInteger("0"); //$NON-NLS-1$ + int fBytesRead; + int fBytesRequested; + MemoryByte[] fMemoryBlock; + + /** + * Constructor + * + * @param output + */ + public MIDataReadMemoryInfo(MIOutput output) { + + super(output); + + fMemoryBlock = new MemoryByte[0]; + if (isDone()) { + parseResult(1); + } + } + + /** + * Constructor + * + * @param output + */ + public MIDataReadMemoryInfo(MIOutput output, int word_size) { + + super(output); + + fMemoryBlock = new MemoryByte[0]; + if (isDone()) { + parseResult(word_size); + } + } + + /** + * Parse the back-end-result. The result is an array of the following form: + * + * [0] addr="address" + * [1] nr-bytes="x" + * [2] total-bytes="y" + * [3] next-row="address2" + * [4] prev-row="address3" + * [5] next-page="address4" + * [6] prev-page="address5" + * [7] memory=[{addr="addr1",data=["0x00","0x01",...]}] + * + * At this point, we only have interest in "memory". + */ + private void parseResult(int word_size) { + + // Get the GDB/MI result record + MIOutput output = getMIOutput(); + MIResultRecord record = output.getMIResultRecord(); + + // Parse the result record + if (record != null) { + + // Parse the output results + // Note: we assume that the result respects the output format + // i.e. nothing missing, nothing out of order. + MIResult[] results = record.getMIResults(); + for (int i = 0; i < results.length; i++) { + + // Get the variable name + String var = results[i].getVariable(); + + // Parse 'addr="address"', the address of the first byte to read + if (var.equals("addr")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String address = ((MIConst) value).getCString(); + fAddress = new BigInteger(address.substring(2), 16); // Strip the "0x" + } + } + + // Parse 'nr-bytes="x"', the number of bytes read + if (var.equals("total-bytes")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String size = ((MIConst) value).getCString(); + fBytesRead = Integer.parseInt(size); + } + } + + // Parse '"total-bytes="y"', the number of bytes requested + // Instantiate the corresponding output buffer with invalid bytes + if (var.equals("total-bytes")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String size = ((MIConst) value).getCString(); + fBytesRequested = Integer.parseInt(size); + fMemoryBlock = new MemoryByte[fBytesRequested]; + for (int j = 0; j < fMemoryBlock.length; j++) + fMemoryBlock[j] = new MemoryByte((byte) 0, (byte) 0); + } + } + + // Parse 'memory=[{addr="addr1",data=["0x00","0x01",...]}]' + if (var.equals("memory")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIList) { + parseMemoryLines((MIList) value, word_size); + } + } + } + } + } + + /** + * Parse the actual memory lines of the general form: + * + * [{addr="addr1",data=["0x00","0x01",...]}] + * [{addr="addr2",data=["0x00","0x01",...]}] + * + * Since we haven't implemented coalescing yet, we conveniently simplify + * the processing by assuming that the memory block address matches the + * one of the request. Therefore, we only have to fill the memoryBlock[] + * with the incoming bytes. + * + * This will have to be revisited as soon as we start considering + * multiple (and possibly canceled) requests. + */ + private void parseMemoryLines(MIList lines, int word_size) { + + // Parse each line and append the results to the result block + MIValue[] lineValues = lines.getMIValues(); + for (int i = 0; i < lineValues.length; i++) { + + // Each line has 2 tuples: "addr" and "data" + if (lineValues[i] instanceof MITuple) { + MITuple tuple = (MITuple) lineValues[i]; + MIResult[] results = tuple.getMIResults(); + + // The offset of this particular output line in the result buffer + int offset = 0; + + // The 1st tuple ('addr="addr1"') gives us the address of the first byte read + MIValue addrValue = results[0].getMIValue(); + if (addrValue instanceof MIConst) { + String address = ((MIConst) addrValue).getCString(); + BigInteger startAddress = new BigInteger(address.substring(2), 16); // Strip the "0x" + offset = startAddress.subtract(fAddress).intValue(); + } + + // The 2nd tuple ("data=[...]") gives us the actual bytes + MIValue value = results[1].getMIValue(); + if (value instanceof MIList) { + MIList list = (MIList) value; + MIValue[] values = list.getMIValues(); + + MemoryByte[] byteValues = new MemoryByte[values.length * word_size]; + + // Parse the result array + for (int j = 0; j < values.length; j++) { + if (values[j] instanceof MIConst) { + String str = ((MIConst) values[j]).getCString(); + try { + long word = Long.decode(str.trim()).longValue(); + for (int k = 0; k < word_size; k++) { + int bit_shift = (word_size - k - 1) * 8; + byteValues[j * word_size + k] = new MemoryByte((byte) ((word >> bit_shift) % 256)); + } + } catch (NumberFormatException e) { + for (int k = 0; k < word_size; k++) + byteValues[j * word_size + k] = new MemoryByte((byte) -1, (byte) 0); + } + } + } + // Copy the parsed line to the memory block + System.arraycopy(byteValues, 0, fMemoryBlock, offset, byteValues.length); + } + } + } + } + + /** + * Return the memory block + */ + public MemoryByte[] getMIMemoryBlock() { + return fMemoryBlock; + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataWriteMemoryInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataWriteMemoryInfo.java new file mode 100644 index 00000000000..98f97d7fa48 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIDataWriteMemoryInfo.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson Communication - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * -data-write-memory result + * + * (gdb) + * nn-data-write-memory [command parameters] + * nn^done + * + */ +public class MIDataWriteMemoryInfo extends MIInfo { + + /** + * Constructor + * + * @param output + */ + public MIDataWriteMemoryInfo(MIOutput output) { + + super(output); + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIExecAsyncOutput.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIExecAsyncOutput.java new file mode 100644 index 00000000000..910254e479f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIExecAsyncOutput.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * @see MIAsyncRecord + */ +public class MIExecAsyncOutput extends MIAsyncRecord { +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIFrame.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIFrame.java new file mode 100644 index 00000000000..099b87e0100 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIFrame.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI Frame tuple parsing. + */ +public class MIFrame { + + int level; + String addr; + String func = ""; //$NON-NLS-1$ + String file = ""; //$NON-NLS-1$ + // since gdb 6.4 + String fullname = ""; //$NON-NLS-1$ + int line; + MIArg[] args = new MIArg[0]; + + public MIFrame(MITuple tuple) { + parse(tuple); + } + + public MIArg[] getArgs() { + return args; + } + + public String getFile() { + String fname = getFullname(); + return ( fname.length() != 0 ) ? fname : file; + } + + public String getFullname() { + return fullname; + } + + public String getFunction() { + return func; + } + + public int getLine() { + return line; + } + + public String getAddress() { + return addr; + } + + public int getLevel() { + return level; + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("level=\"" + level + "\""); //$NON-NLS-1$//$NON-NLS-2$ + buffer.append(",addr=\"" + addr + "\""); //$NON-NLS-1$//$NON-NLS-2$ + buffer.append(",func=\"" + func + "\""); //$NON-NLS-1$//$NON-NLS-2$ + buffer.append(",file=\"" + file + "\""); //$NON-NLS-1$//$NON-NLS-2$ + buffer.append(",line=\"").append(line).append('"'); //$NON-NLS-1$ + buffer.append(",args=["); //$NON-NLS-1$ + for (int i = 0; i < args.length; i++) { + if (i != 0) { + buffer.append(','); + } + buffer.append("{name=\"" + args[i].getName() + "\"");//$NON-NLS-1$//$NON-NLS-2$ + buffer.append(",value=\"" + args[i].getValue() + "\"}");//$NON-NLS-1$//$NON-NLS-2$ + } + buffer.append(']'); + return buffer.toString(); + } + + void parse(MITuple tuple) { + MIResult[] results = tuple.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value != null && value instanceof MIConst) { + str = ((MIConst)value).getCString(); + } + + if (var.equals("level")) { //$NON-NLS-1$ + try { + level = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("addr")) { //$NON-NLS-1$ + try { + addr = str.trim(); + } catch (NumberFormatException e) { + } + } else if (var.equals("func")) { //$NON-NLS-1$ + func = null; + if ( str != null ) { + str = str.trim(); + if ( str.equals( "??" ) ) //$NON-NLS-1$ + func = ""; //$NON-NLS-1$ + else + { + // In some situations gdb returns the function names that include parameter types. + // To make the presentation consistent truncate the parameters. PR 46592 + int end = str.indexOf( '(' ); + if ( end != -1 ) + func = str.substring( 0, end ); + else + func = str; + } + } + } else if (var.equals("file")) { //$NON-NLS-1$ + file = str; + } else if (var.equals("fullname")) { //$NON-NLS-1$ + fullname = str; + } else if (var.equals("line")) { //$NON-NLS-1$ + try { + line = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("args")) { //$NON-NLS-1$ + if (value instanceof MIList) { + args = MIArg.getMIArgs((MIList)value); + } else if (value instanceof MITuple) { + args = MIArg.getMIArgs((MITuple)value); + } + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIGDBShowExitCodeInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIGDBShowExitCodeInfo.java new file mode 100644 index 00000000000..48eb29aff33 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIGDBShowExitCodeInfo.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI show parsing. + * (gdb) + * -data-evaluate-expression $_exitcode + * ^done,value="10" + * (gdb) + */ +public class MIGDBShowExitCodeInfo extends MIDataEvaluateExpressionInfo { + + public MIGDBShowExitCodeInfo(MIOutput o) { + super(o); + } + + public int getCode() { + int code = 0; + String exp = getValue(); + try { + code = Integer.parseInt(exp); + } catch (NumberFormatException e) { + } + return code; + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIInfo.java new file mode 100644 index 00000000000..412252b557c --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIInfo.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import org.eclipse.dd.dsf.debug.service.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; + +/** + * Base class for teh parsing/info GDB/MI classes. + */ +public class MIInfo implements ICommandResult { + + private final MIOutput miOutput; + + public MIInfo(MIOutput record) { + miOutput = record; + } + + public MIOutput getMIOutput () { + return miOutput; + } + + public boolean isDone() { + return isResultClass(MIResultRecord.DONE); + } + + public boolean isRunning() { + return isResultClass(MIResultRecord.RUNNING); + } + + public boolean isConnected() { + return isResultClass(MIResultRecord.CONNECTED); + } + + public boolean isError() { + return isResultClass(MIResultRecord.ERROR); + } + + public boolean isExit() { + return isResultClass(MIResultRecord.EXIT); + } + + @Override + public String toString() { + if (miOutput != null) { + return miOutput.toString(); + } + return ""; //$NON-NLS-1$ + } + + boolean isResultClass(String rc) { + if (miOutput != null) { + MIResultRecord rr = miOutput.getMIResultRecord(); + if (rr != null) { + String clazz = rr.getResultClass(); + return clazz.equals(rc); + } + } + return false; + } + + public String getErrorMsg() { + if (miOutput != null) { + MIResultRecord rr = miOutput.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("msg")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String s = ((MIConst)value).getCString(); + return s; + } + } + } + } + } + return ""; //$NON-NLS-1$ + } + + /** + * Default implementation of this method returns null, which means that a subset + * result canot be calculated for the given command. Deriving classes should + * override this method as needed. + */ + public V getSubsetResult(ICommand command) { + return null; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIList.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIList.java new file mode 100644 index 00000000000..4ab77f21916 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIList.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI list semantic. + */ +public class MIList extends MIValue { + + final static MIResult[] nullResults = new MIResult[0]; + final static MIValue[] nullValues = new MIValue[0]; + + MIResult[] results = nullResults; + MIValue[] values = nullValues; + + public MIResult[] getMIResults() { + return results; + } + + public void setMIResults(MIResult[] res) { + results = res; + } + + public MIValue[] getMIValues() { + return values; + } + + public void setMIValues(MIValue[] vals) { + values = vals; + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append('['); + for (int i = 0; i < results.length; i++) { + if (i != 0) { + buffer.append(','); + } + buffer.append(results[i].toString()); + } + for (int i = 0; i < values.length; i++) { + if (i != 0) { + buffer.append(','); + } + buffer.append(values[i].toString()); + } + buffer.append(']'); + return buffer.toString(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MILogStreamOutput.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MILogStreamOutput.java new file mode 100644 index 00000000000..a0e69a554b7 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MILogStreamOutput.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * @see MIStreamRecord + */ +public class MILogStreamOutput extends MIStreamRecord { + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MINotifyAsyncOutput.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MINotifyAsyncOutput.java new file mode 100644 index 00000000000..bdee6afa33d --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MINotifyAsyncOutput.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + + +/** + * @see MIAsyncRecord + */ +public class MINotifyAsyncOutput extends MIAsyncRecord { +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIOOBRecord.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIOOBRecord.java new file mode 100644 index 00000000000..27cddc4651e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIOOBRecord.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * @see MIOOBRecord + */ +public abstract class MIOOBRecord { +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIOutput.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIOutput.java new file mode 100644 index 00000000000..b501d663609 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIOutput.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for additional features in DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI response. + */ +public class MIOutput { + + private final MIResultRecord rr; + private final MIOOBRecord[] oobs; + + public MIOutput() { + this(null, null); + } + + public MIOutput(MIOOBRecord oob) { + this(null, new MIOOBRecord[] { oob }); + } + + + + public MIOutput(MIResultRecord rr, MIOOBRecord[] oobs) { + this.rr = rr; + this.oobs = oobs; + } + + public MIResultRecord getMIResultRecord() { + return rr; + } + + public MIOOBRecord[] getMIOOBRecords() { + return oobs; + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < oobs.length; i++) { + buffer.append(oobs[i].toString()); + } + if (rr != null) { + buffer.append(rr.toString()); + } + return buffer.toString(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIParser.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIParser.java new file mode 100644 index 00000000000..dd18a64d4d2 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIParser.java @@ -0,0 +1,559 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +/** +
+`OUTPUT :'
+     `( OUT-OF-BAND-RECORD )* [ RESULT-RECORD ] "(gdb)" NL'
+
+`RESULT-RECORD :'
+     ` [ TOKEN ] "^" RESULT-CLASS ( "," RESULT )* NL'
+
+`OUT-OF-BAND-RECORD :'
+     `ASYNC-RECORD | STREAM-RECORD'
+
+`ASYNC-RECORD :'
+     `EXEC-ASYNC-OUTPUT | STATUS-ASYNC-OUTPUT | NOTIFY-ASYNC-OUTPUT'
+
+`EXEC-ASYNC-OUTPUT :'
+     `[ TOKEN ] "*" ASYNC-OUTPUT'
+
+`STATUS-ASYNC-OUTPUT :'
+     `[ TOKEN ] "+" ASYNC-OUTPUT'
+
+`NOTIFY-ASYNC-OUTPUT :'
+     `[ TOKEN ] "=" ASYNC-OUTPUT'
+
+`ASYNC-OUTPUT :'
+     `ASYNC-CLASS ( "," RESULT )* NL'
+
+`RESULT-CLASS :'
+     `"done" | "running" | "connected" | "error" | "exit"'
+
+`ASYNC-CLASS :'
+     `"stopped" | OTHERS' (where OTHERS will be added depending on the
+     needs--this is still in development).
+
+`RESULT :'
+     ` VARIABLE "=" VALUE'
+
+`VARIABLE :'
+     ` STRING '
+
+`VALUE :'
+     ` CONST | TUPLE | LIST '
+
+`CONST :'
+     `C-STRING'
+
+`TUPLE :'
+     ` "{}" | "{" RESULT ( "," RESULT )* "}" '
+
+`LIST :'
+     ` "[]" | "[" VALUE ( "," VALUE )* "]" | "[" RESULT ( "," RESULT )*
+     "]" '
+
+`STREAM-RECORD :'
+     `CONSOLE-STREAM-OUTPUT | TARGET-STREAM-OUTPUT | LOG-STREAM-OUTPUT'
+
+`CONSOLE-STREAM-OUTPUT :'
+     `"~" C-STRING'
+
+`TARGET-STREAM-OUTPUT :'
+     `"@" C-STRING'
+
+`LOG-STREAM-OUTPUT :'
+     `"&" C-STRING'
+
+`NL :'
+     `CR | CR-LF'
+
+`TOKEN :'
+     _any sequence of digits_.
+
+`C-STRING :'
+     `""" SEVEN-BIT-ISO-C-STRING-CONTENT """'
+
+ */ +public class MIParser { + public enum RecordType { ResultRecord, OOBRecord, PrimaryPrompt } + + public String primaryPrompt = "(gdb)"; //$NON-NLS-1$ + public String cliPrompt = primaryPrompt; + public String secondaryPrompt = ">"; //$NON-NLS-1$ + + public RecordType getRecordType(String line) { + int i = 0; + if (Character.isDigit(line.charAt(0))) { + i = 1; + while (i < line.length() && Character.isDigit(line.charAt(i))) { + i++; + } + } + + if (i < line.length() && line.charAt(i) == '^') { + return RecordType.ResultRecord; + } else if (line.startsWith(primaryPrompt, i)) { + return RecordType.PrimaryPrompt; + //break; // Do nothing. + } else { + return RecordType.OOBRecord; + } + } + + /** + * + */ + public MIResultRecord parseMIResultRecord(String line) { + StringBuffer buffer = new StringBuffer(line); + // Fetch the Token/Id + int id = parseToken(buffer); + // Consume the '^' + buffer.deleteCharAt(0); + + MIResultRecord rr = new MIResultRecord(); + rr.setToken(id); + if (buffer.toString().startsWith(MIResultRecord.DONE)) { + rr.setResultClass(MIResultRecord.DONE); + buffer.delete(0, MIResultRecord.DONE.length()); + } else if (buffer.toString().startsWith(MIResultRecord.ERROR)) { + rr.setResultClass(MIResultRecord.ERROR); + buffer.delete(0, MIResultRecord.ERROR.length()); + } else if (buffer.toString().startsWith(MIResultRecord.EXIT)) { + rr.setResultClass(MIResultRecord.EXIT); + buffer.delete(0, MIResultRecord.EXIT.length()); + } else if (buffer.toString().startsWith(MIResultRecord.RUNNING)) { + rr.setResultClass(MIResultRecord.RUNNING); + buffer.delete(0, MIResultRecord.RUNNING.length()); + } else if (buffer.toString().startsWith(MIResultRecord.CONNECTED)) { + rr.setResultClass(MIResultRecord.CONNECTED); + buffer.delete(0, MIResultRecord.CONNECTED.length()); + } else { + // Error throw an exception? + } + + // Results are separated by commas. + if (buffer.length() > 0 && buffer.charAt(0) == ',') { + buffer.deleteCharAt(0); + MIResult[] res = processMIResults(new FSB(buffer)); + rr.setMIResults(res); + } + return rr; + } + + /** + * Find OutOfBand Records depending on the starting token. + */ + public MIOOBRecord parseMIOOBRecord(String line) { + StringBuffer buffer = new StringBuffer(line); + int id = parseToken(buffer); + MIOOBRecord oob = null; + char c = buffer.length() != 0 ? buffer.charAt(0) : 0; + if (c == '*' || c == '+' || c == '=') { + // Consume the first char + buffer.deleteCharAt(0); + MIAsyncRecord async = null; + switch (c) { + case '*' : + async = new MIExecAsyncOutput(); + break; + + case '+' : + async = new MIStatusAsyncOutput(); + break; + + case '=' : + async = new MINotifyAsyncOutput(); + break; + } + async.setToken(id); + // Extract the Async-Class + int i = buffer.toString().indexOf(','); + if (i != -1) { + String asyncClass = buffer.substring(0, i); + async.setAsyncClass(asyncClass); + // Consume the async-class and the comma + buffer.delete(0, i + 1); + } else { + async.setAsyncClass(buffer.toString().trim()); + buffer.setLength(0); + } + MIResult[] res = processMIResults(new FSB(buffer)); + async.setMIResults(res); + oob = async; + } else if (c == '~' || c == '@' || c == '&') { + // Consume the first char + buffer.deleteCharAt(0); + MIStreamRecord stream = null; + switch (c) { + case '~' : + stream = new MIConsoleStreamOutput(); + break; + + case '@' : + stream = new MITargetStreamOutput(); + break; + + case '&' : + stream = new MILogStreamOutput(); + break; + } + // translateCString() assumes that the leading " is deleted + if (buffer.length() > 0 && buffer.charAt(0) == '"') { + buffer.deleteCharAt(0); + } + stream.setCString(translateCString(new FSB(buffer))); + oob = stream; + } else { + // Badly format MI line, just pass it to the user as target stream + MIStreamRecord stream = new MITargetStreamOutput(); + stream.setCString(line + "\n"); //$NON-NLS-1$ + oob = stream; + } + return oob; + } + + private int parseToken(StringBuffer buffer) { + int id = -1; + // Fetch the Token/Id + if (Character.isDigit(buffer.charAt(0))) { + int i = 1; + while (i < buffer.length() && Character.isDigit(buffer.charAt(i))) { + i++; + } + String numbers = buffer.substring(0, i); + try { + id = Integer.parseInt(numbers); + } catch (NumberFormatException e) { + } + // Consume the token. + buffer.delete(0, i); + } + return id; + } + + /** + * Assuming that the usual leading comma was consumed. + * Extract the MI Result comma seperated responses. + */ + private MIResult[] processMIResults(FSB buffer) { + List aList = new ArrayList(); + MIResult result = processMIResult(buffer); + if (result != null) { + aList.add(result); + } + while (buffer.length() > 0 && buffer.charAt(0) == ',') { + buffer.deleteCharAt(0); + result = processMIResult(buffer); + if (result != null) { + aList.add(result); + } + } + return aList.toArray(new MIResult[aList.size()]); + } + + /** + * Construct the DsfMIResult. Characters will be consume/delete + * moving forward constructing the AST. + */ + private MIResult processMIResult(FSB buffer) { + MIResult result = new MIResult(); + int equal; + if (buffer.length() > 0 && Character.isLetter(buffer.charAt(0)) && (equal = buffer.indexOf('=')) != -1) { + String variable = buffer.substring(0, equal); + result.setVariable(variable); + buffer.delete(0, equal + 1); + MIValue value = processMIValue(buffer); + result.setMIValue(value); + } else if(buffer.length()>0 && buffer.charAt(0)=='"') { + // This an error but we just swallow it and move on. + MIValue value = processMIValue(buffer); + result.setMIValue(value); + } else { + result.setVariable(buffer.toString()); + result.setMIValue(new MIConst()); // Empty string:??? + buffer.setLength(0); + } + return result; + } + + /** + * Find a DsfMIValue implementation or return null. + */ + private MIValue processMIValue(FSB buffer) { + MIValue value = null; + if (buffer.length() > 0) { + if (buffer.charAt(0) == '{') { + buffer.deleteCharAt(0); + value = processMITuple(buffer); + } else if (buffer.charAt(0) == '[') { + buffer.deleteCharAt(0); + value = processMIList(buffer); + } else if (buffer.charAt(0) == '"') { + buffer.deleteCharAt(0); + MIConst cnst = new MIConst(); + cnst.setCString(translateCString(buffer)); + value = cnst; + } + } + return value; + } + + /** + * Assuming the starting '{' was deleted form the StringBuffer, + * go to the closing '}' consuming/deleting all the characters. + * This is usually call by processMIvalue(); + */ + private MIValue processMITuple(FSB buffer) { + MITuple tuple = new MITuple(); + List valueList = new ArrayList(); + List resultList = new ArrayList(); + // Catch closing '}' + while (buffer.length() > 0 && buffer.charAt(0) != '}') { + // Try for the DsfMIValue first + MIValue value = processMIValue(buffer); + if (value != null) { + valueList.add(value); + } else { + MIResult result = processMIResult(buffer); + if (result != null) { + resultList.add(result); + } + } + if (buffer.length() > 0 && buffer.charAt(0) == ',') { + buffer.deleteCharAt(0); + } + } + if (buffer.length() > 0 && buffer.charAt(0) == '}') { + buffer.deleteCharAt(0); + } + MIValue[] values = valueList.toArray(new MIValue[valueList.size()]); + MIResult[] res = resultList.toArray(new MIResult[resultList.size()]); + tuple.setMIValues(values); + tuple.setMIResults(res); + return tuple; + } + + /** + * Assuming the leading '[' was deleted, find the closing + * ']' consuming/delete chars from the StringBuffer. + */ + private MIValue processMIList(FSB buffer) { + MIList list = new MIList(); + List valueList = new ArrayList(); + List resultList = new ArrayList(); + // catch closing ']' + while (buffer.length() > 0 && buffer.charAt(0) != ']') { + // Try for the DsfMIValue first + MIValue value = processMIValue(buffer); + if (value != null) { + valueList.add(value); + } else { + MIResult result = processMIResult(buffer); + if (result != null) { + resultList.add(result); + } + } + if (buffer.length() > 0 && buffer.charAt(0) == ',') { + buffer.deleteCharAt(0); + } + } + if (buffer.length() > 0 && buffer.charAt(0) == ']') { + buffer.deleteCharAt(0); + } + MIValue[] values = valueList.toArray(new MIValue[valueList.size()]); + MIResult[] res = resultList.toArray(new MIResult[resultList.size()]); + list.setMIValues(values); + list.setMIResults(res); + return list; + } + + /* + * MI C-String rather MICOnst values are enclose in double quotes + * and any double quotes or backslash in the string are escaped. + * Assuming the starting double quote was removed. + * This method will stop at the closing double quote remove the extra + * backslach escaping and return the string __without__ the enclosing double quotes + * The orignal StringBuffer will move forward. + */ + private String translateCString(FSB buffer) { + boolean escape = false; + boolean closingQuotes = false; + + StringBuffer sb = new StringBuffer(); + + int index = 0; + for (; index < buffer.length() && !closingQuotes; index++) { + char c = buffer.charAt(index); + if (c == '\\') { + if (escape) { + sb.append(c); + escape = false; + } else { + escape = true; + } + } else if (c == '"') { + if (escape) { + sb.append(c); + escape = false; + } else { + // Bail out. + closingQuotes = true; + } + } else { + if (escape) { + sb.append('\\'); + } + sb.append(c); + escape = false; + } + } + buffer.delete(0, index); + return sb.toString(); + } + + /** + * Tests if this string starts with the specified prefix beginning + * a specified index. + * + * @param value the string. + * @param prefix the prefix. + * @return true if prefix starts value. + */ + public boolean startsWith(StringBuffer value, String prefix) { + int vlen = value.length(); + int plen = prefix.length(); + + if (vlen < plen) { + return false; + } + for (int i = 0; i < plen; i++) { + if (value.charAt(i) != prefix.charAt(i)) { + return false; + } + } + return true; + } + + /** + * Fast String Buffer class. MIParser does a lot + * of deleting off the front of a string, that's clearly + * an order N operation for StringBuffer which makes + * the MIParser an order N^2 operation. There are "issues" + * with this for large arrays. Use of FSB rather than String + * Buffer makes MIParser N rather than N^2 because FSB can + * delete from the front in constant time. + */ + public class FSB { + StringBuffer buf; + int pos; + boolean shared; + + public FSB(StringBuffer buf) { + this.buf = buf; + pos = 0; + shared = false; + } + + public FSB(FSB fbuf) { + pos = fbuf.pos; + buf = fbuf.buf; + shared = true; + } + + public int length() { + int res = buf.length() - pos; + if (res < 0) + return 0; + + return res; + } + + public char charAt(int index) { + return buf.charAt(index + pos); + } + + private void resolveCopy() { + if (shared) { + buf = new StringBuffer(buf.toString()); + shared = false; + } + } + + public FSB deleteCharAt(int index) { + if (index == 0) { + pos++; + } else { + resolveCopy(); + buf = buf.deleteCharAt(pos + index); + } + + return this; + } + + public FSB delete(int start, int end) { + if (start == 0) { + pos = pos + end - start; + } else { + resolveCopy(); + buf.delete(start + pos, end + pos); + } + + return this; + } + + public void setLength(int a) { + if (a == 0) + pos = buf.length(); + else { + // panic! fortunately we don't do this. + } + } + + public String substring(int start, int end) { + return buf.substring(start + pos, end + pos); + } + + @Override + public String toString() { + return buf.substring(pos, buf.length()); + } + + int indexOf(char c) { + int len = buf.length(); + for (int i = pos; i < len; i++) { + if (buf.charAt(i) == c) + return i - pos; + } + + return -1; + } + + boolean startsWith(String s) { + int len = Math.min(s.length(), length()); + if (len < s.length()) + return false; + + for (int i = 0; i < len; i++) { + if (s.charAt(i) != buf.charAt(pos + i)) + return false; + } + + return true; + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIRegisterValue.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIRegisterValue.java new file mode 100644 index 00000000000..5cd896b4ae8 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIRegisterValue.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +/** + * GDB/MI register response parsing. + */ +public class MIRegisterValue { + int number; + String value; + + public MIRegisterValue(int n, String v) { + number = n; + value = v; + } + + public int getNumber() { + return number; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("number=\"").append(number).append('"'); //$NON-NLS-1$ + buffer.append(',').append("value=\"" + value + "\""); //$NON-NLS-1$ //$NON-NLS-2$ + return buffer.toString(); + } + + /** + * Parsing a MIList of the form: + * [{number="1",value="0xffff"},{number="xxx",value="yyy"},..] + */ + public static MIRegisterValue[] getMIRegisterValues(MIList miList) { + List aList = new ArrayList(); + MIValue[] values = miList.getMIValues(); + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof MITuple) { + MIRegisterValue reg = getMIRegisterValue((MITuple)values[i]); + if (reg != null) { + aList.add(reg); + } + } + } + return (aList.toArray(new MIRegisterValue[aList.size()])); + } + + /** + * Parsing a MITuple of the form: + * {number="xxx",value="yyy"} + */ + public static MIRegisterValue getMIRegisterValue(MITuple tuple) { + MIResult[] args = tuple.getMIResults(); + MIRegisterValue arg = null; + if (args.length == 2) { + // Name + String aName = ""; //$NON-NLS-1$ + MIValue value = args[0].getMIValue(); + if (value != null && value instanceof MIConst) { + aName = ((MIConst)value).getCString(); + } else { + aName = ""; //$NON-NLS-1$ + } + + // Value + String aValue = ""; //$NON-NLS-1$ + value = args[1].getMIValue(); + if (value != null && value instanceof MIConst) { + aValue = ((MIConst)value).getCString(); + } else { + aValue = ""; //$NON-NLS-1$ + } + + try { + int reg = Integer.parseInt(aName.trim()); + arg = new MIRegisterValue(reg, aValue.trim()); + } catch (NumberFormatException e) { + } + } + return arg; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIResult.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIResult.java new file mode 100644 index 00000000000..f60b843d472 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIResult.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI result sematic (Variable=Value) + */ +public class MIResult { + String variable = ""; //$NON-NLS-1$ + MIValue value = null; + + public String getVariable() { + return variable; + } + + public void setVariable(String var) { + variable = var; + } + + public MIValue getMIValue() { + return value; + } + + public void setMIValue(MIValue val) { + value = val; + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(variable); + if (value != null) { + String v = value.toString(); + buffer.append('='); + if (v.length() > 0 && (v.charAt(0) == '[' || v.charAt(0) =='{')) { + buffer.append(v); + } else { + buffer.append("\"" + value.toString() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + return buffer.toString(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIResultRecord.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIResultRecord.java new file mode 100644 index 00000000000..c29e1a6ce2d --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIResultRecord.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI ResultRecord. + */ +public class MIResultRecord { + + public final static String DONE ="done"; //$NON-NLS-1$ + public final static String RUNNING ="running"; //$NON-NLS-1$ + public final static String CONNECTED ="connected"; //$NON-NLS-1$ + public final static String ERROR ="error"; //$NON-NLS-1$ + public final static String EXIT ="exit"; //$NON-NLS-1$ + + static final MIResult[] nullResults = new MIResult[0]; + MIResult[] results = nullResults; + String resultClass = ""; //$NON-NLS-1$ + int token = -1; + + public int getToken() { + return token; + } + + public void setToken(int t) { + token = t; + } + + /** + */ + public String getResultClass() { + return resultClass; + } + + public void setResultClass(String type) { + resultClass = type; + } + + public MIResult[] getMIResults() { + return results; + } + + public void setMIResults(MIResult[] res) { + results = res; + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(token).append('^').append(resultClass); + for (int i = 0; i < results.length; i++) { + buffer.append(',').append(results[i].toString()); + } + return buffer.toString(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackInfoDepthInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackInfoDepthInfo.java new file mode 100644 index 00000000000..abf13de8627 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackInfoDepthInfo.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + + +/** + * -stack-info-depth [max-depth] + * ^done,depth="12" + * + */ +public class MIStackInfoDepthInfo extends MIInfo { + + int depth = 0; + + public MIStackInfoDepthInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + + if (var.equals("depth")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getString(); + try { + depth = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + } + } + } + } + } + + public int getDepth() { + return depth; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListArgumentsInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListArgumentsInfo.java new file mode 100644 index 00000000000..4d7f84cec84 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListArgumentsInfo.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + + +/** + * GDB/MI stack list arguments parsing. + */ +public class MIStackListArgumentsInfo extends MIInfo { + + MIFrame[] frames; + + public MIStackListArgumentsInfo(MIOutput out) { + super(out); + frames = null; + List aList = new ArrayList(1); + if (isDone()) { + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("stack-args")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIList) { + parseStack((MIList)val, aList); + } else if (val instanceof MIList) { + parseStack((MITuple)val, aList); + } + } + } + } + } + frames = aList.toArray(new MIFrame[aList.size()]); + } + + public MIFrame[] getMIFrames() { + return frames; + } + + private void parseStack(MIList miList, List aList) { + MIResult[] results = miList.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("frame")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + aList.add (new MIFrame((MITuple)value)); + } + } + } + } + + private void parseStack(MITuple miTuple, List aList) { + MIResult[] results = miTuple.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("frame")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + aList.add (new MIFrame((MITuple)value)); + } + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListFramesInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListFramesInfo.java new file mode 100644 index 00000000000..94c0a9ed7c7 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListFramesInfo.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +/** + * GDB/MI stack list frames info. + */ +public class MIStackListFramesInfo extends MIInfo { + + MIFrame[] frames; + + public MIStackListFramesInfo(MIOutput out) { + super(out); + frames = null; + List aList = new ArrayList(1); + if (isDone()) { + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("stack")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIList) { + parseStack((MIList)val, aList); + } else if (val instanceof MITuple) { + parseStack((MITuple)val, aList); + } + } + } + } + } + frames = aList.toArray(new MIFrame[aList.size()]); + } + + public MIFrame[] getMIFrames() { + return frames; + } + + void parseStack(MIList miList, List aList) { + MIResult[] results = miList.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("frame")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + aList.add (new MIFrame((MITuple)value)); + } + } + } + } + + // Old gdb use tuple instead of a list. + void parseStack(MITuple tuple, List aList) { + MIResult[] results = tuple.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("frame")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + aList.add (new MIFrame((MITuple)value)); + } + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListLocalsInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListLocalsInfo.java new file mode 100644 index 00000000000..7854276dd3d --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStackListLocalsInfo.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI stack list locals parsing. + * -stack-list-locals 1 + * ^done,locals=[{name="p",value="0x8048600 \"ghislaine\""},{name="buf",value="\"'\", 'x' , \"i,xxxxxxxxx\", 'a' "},{name="buf2",value="\"\\\"?'\\\\()~\""},{name="buf3",value="\"alain\""},{name="buf4",value="\"\\t\\t\\n\\f\\r\""},{name="i",value="0"}] + * + * On MacOS X 10.4 this returns a tuple: + * ^done,locals={{name="p",value="0x8048600 \"ghislaine\""},{name="buf",value="\"'\", 'x' , \"i,xxxxxxxxx\", 'a' "},{name="buf2",value="\"\\\"?'\\\\()~\""},{name="buf3",value="\"alain\""},{name="buf4",value="\"\\t\\t\\n\\f\\r\""},{name="i",value="0"}} + */ +public class MIStackListLocalsInfo extends MIInfo { + + MIArg[] locals; + + public MIStackListLocalsInfo(MIOutput out) { + super(out); + locals = null ; + if (isDone()) { + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("locals")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIList) { + locals = MIArg.getMIArgs((MIList)value); + } else if (value instanceof MITuple) { + locals = MIArg.getMIArgs((MITuple)value); + } + } + } + } + } + if (locals == null) { + locals = new MIArg[0]; + } + } + + public MIArg[] getLocals() { + return locals; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStatusAsyncOutput.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStatusAsyncOutput.java new file mode 100644 index 00000000000..60d7891f7b5 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStatusAsyncOutput.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + + +/** + * @see MIAsyncRecord + */ +public class MIStatusAsyncOutput extends MIAsyncRecord { + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStreamRecord.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStreamRecord.java new file mode 100644 index 00000000000..f245d3263c4 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIStreamRecord.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI stream record response. + */ +public abstract class MIStreamRecord extends MIOOBRecord { + + String cstring = ""; //$NON-NLS-1$ + + public String getCString() { + return cstring; + } + + public void setCString(String str) { + cstring = str; + } + + public String getString () { + return MIConst.getString(getCString()); + } + + @Override + public String toString() { + if (this instanceof MIConsoleStreamOutput) { return "~\"" + cstring + "\"\n"; } //$NON-NLS-1$ //$NON-NLS-2$ + else if (this instanceof MITargetStreamOutput) { return "@\"" + cstring + "\"\n"; } //$NON-NLS-1$ //$NON-NLS-2$ + else if (this instanceof MILogStreamOutput) { return "&\"" + cstring + "\"\n"; } //$NON-NLS-1$ //$NON-NLS-2$ + else { return "\"" + cstring + "\"\n"; } //$NON-NLS-1$ //$NON-NLS-2$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MITargetStreamOutput.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MITargetStreamOutput.java new file mode 100644 index 00000000000..1d8962b391f --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MITargetStreamOutput.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * @see MIStreamRecord + */ +public class MITargetStreamOutput extends MIStreamRecord { + + public static final String startTag = "@"; //$NON-NLS-1$ +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIThreadListIdsInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIThreadListIdsInfo.java new file mode 100644 index 00000000000..956b0a27aa3 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIThreadListIdsInfo.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Ericsson AB - Modified for DSF Reference Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI thread list parsing. + */ +public class MIThreadListIdsInfo extends MIInfo { + + int[] threadIds; + + public MIThreadListIdsInfo(MIOutput out) { + super(out); + } + + public int[] getThreadIds() { + if (threadIds == null) { + parse(); + } + return threadIds; + } + + void parse() { + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("thread-ids")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MITuple) { + parseThreadIds((MITuple)val); + } + } + } + } + } + if (threadIds == null) { + threadIds = new int[0]; + } + } + + void parseThreadIds(MITuple tuple) { + MIResult[] results = tuple.getMIResults(); + threadIds = new int[results.length]; + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("thread-id")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getCString(); + try { + threadIds[i] = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MITuple.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MITuple.java new file mode 100644 index 00000000000..da5ac67c6b0 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MITuple.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI tuple value. + */ +public class MITuple extends MIValue { + + final static MIResult[] nullResults = new MIResult[0]; + final static MIValue[] nullValues = new MIValue[0]; + MIResult[] results = nullResults; + MIValue[] values = nullValues; + + public MIResult[] getMIResults() { + return results; + } + + public void setMIResults(MIResult[] res) { + results = res; + } + + public MIValue[] getMIValues() { + return values; + } + + public void setMIValues(MIValue[] vals) { + values = vals; + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append('{'); + for (int i = 0; i < results.length; i++) { + if (i != 0) { + buffer.append(','); + } + buffer.append(results[i].toString()); + } + for (int i = 0; i < values.length; i++) { + if (i != 0) { + buffer.append(','); + } + buffer.append(values[i].toString()); + } + buffer.append('}'); + return buffer.toString(); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIValue.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIValue.java new file mode 100644 index 00000000000..a1346826992 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIValue.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI value. + */ +public abstract class MIValue { +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVar.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVar.java new file mode 100644 index 00000000000..834f8cd5f09 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVar.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-list-children + * -var-list-children var2 + * ^done,numchild="6",children={child={name="var2.0",exp="0",numchild="0",type="char"},child={name="var2.1",exp="1",numchild="0",type="char"},child={name="var2.2",exp="2",numchild="0",type="char"},child={name="var2.3",exp="3",numchild="0",type="char"},child={name="var2.4",exp="4",numchild="0",type="char"},child={name="var2.5",exp="5",numchild="0",type="char"}} + * + */ +public class MIVar { + + String name = ""; //$NON-NLS-1$ + String type = ""; //$NON-NLS-1$ + String exp = ""; //$NON-NLS-1$ + int numchild; + + + public MIVar(String n, int num, String t) { + name = n; + numchild = num; + type = t; + } + + public MIVar(MITuple tuple) { + parse(tuple); + } + + public String getVarName() { + return name; + } + + public String getType() { + return type; + } + + public int getNumChild() { + return numchild; + } + + public String getExp() { + return exp; + } + + void parse(MITuple tuple) { + MIResult[] results = tuple.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value != null && value instanceof MIConst) { + str = ((MIConst)value).getCString(); + } + + if (var.equals("numchild")) { //$NON-NLS-1$ + try { + numchild = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("name")) { //$NON-NLS-1$ + name = str; + } else if (var.equals("type")) { //$NON-NLS-1$ + type = str; + } else if (var.equals("exp")) { //$NON-NLS-1$ + exp = str; + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarAssignInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarAssignInfo.java new file mode 100644 index 00000000000..f6780355b56 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarAssignInfo.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-assign + * + * ^done,value="3" + */ +public class MIVarAssignInfo extends MIInfo { + + String value = ""; //$NON-NLS-1$ + + public MIVarAssignInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("value")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIConst) { + value = ((MIConst)val).getCString(); + } + } + } + } + } + } + + public String getValue () { + return value; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarChange.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarChange.java new file mode 100644 index 00000000000..b6700cb6b57 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarChange.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-update. + */ + +public class MIVarChange { + String name; + String value; + boolean inScope; + boolean changed; + + public MIVarChange(String n) { + name = n; + } + + public String getVarName() { + return name; + } + + public String getValue() { + return value; + } + + public boolean isInScope() { + return inScope; + } + + public boolean isChanged() { + return changed; + } + + public void setValue(String v) { + value = v; + } + + public void setInScope(boolean b) { + inScope = b; + } + + public void setChanged(boolean c) { + changed = c; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarCreateInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarCreateInfo.java new file mode 100644 index 00000000000..6f68e286943 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarCreateInfo.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-create. + * -var-create "-" * a + * ^done,name="var1",numchild="0",value="11",type="int" + * -var-create "-" * buf + * ^done,name="var1",numchild="6",value=[6]",type="char [6]" + * + * Note that the value is returned in the output, as of GDB6.7 + */ +public class MIVarCreateInfo extends MIInfo { + + String name = ""; //$NON-NLS-1$ + int numChild; + String type = ""; //$NON-NLS-1$ + MIVar child; + String value = null; + + public MIVarCreateInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue resultVal = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (resultVal instanceof MIConst) { + str = ((MIConst)resultVal).getString(); + } + + if (var.equals("name")) { //$NON-NLS-1$ + name = str; + } else if (var.equals("numchild")) { //$NON-NLS-1$ + try { + numChild = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } else if (var.equals("type")) { //$NON-NLS-1$ + type = str; + } else if (var.equals("value")) { //$NON-NLS-1$ + value = str; + } + } + } + } + } + + public String getType() + { + return type; + } + + public int getNumChildren() + { + return numChild; + } + + public String getName() + { + return name; + } + + public String getValue() + { + return value; + } + + public MIVar getMIVar() { + if (child == null) { + child = new MIVar(name, numChild, type); + } + return child; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarDeleteInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarDeleteInfo.java new file mode 100644 index 00000000000..9ea42bd3463 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarDeleteInfo.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-delete. + */ +public class MIVarDeleteInfo extends MIInfo { + + int ndeleted; + + public MIVarDeleteInfo(MIOutput record) { + super(record); + ndeleted=0; + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("ndeleted")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getString(); + try { + ndeleted = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + } + } + } + } + } + + public int getNumberDeleted () { + return ndeleted; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarEvaluateExpressionInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarEvaluateExpressionInfo.java new file mode 100644 index 00000000000..1f136b423c2 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarEvaluateExpressionInfo.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-evalute-expression + */ +public class MIVarEvaluateExpressionInfo extends MIInfo { + + String value = ""; //$NON-NLS-1$ + + public MIVarEvaluateExpressionInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("value")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIConst) { + value = ((MIConst)val).getCString(); + } + } + } + } + } + } + + public String getValue () { + return value; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoExpressionInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoExpressionInfo.java new file mode 100644 index 00000000000..981bbc5dbb6 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoExpressionInfo.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-info-expression. + */ +public class MIVarInfoExpressionInfo extends MIInfo { + + String lang = ""; //$NON-NLS-1$ + String exp = ""; //$NON-NLS-1$ + + public MIVarInfoExpressionInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + String str = ""; //$NON-NLS-1$ + if (value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + + if (var.equals("lang")) { //$NON-NLS-1$ + lang = str; + } else if (var.equals("exp")) { //$NON-NLS-1$ + exp = str; + } + } + } + } + } + + public String getLanguage () { + return lang; + } + + public String getExpression() { + return exp; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoNumChildrenInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoNumChildrenInfo.java new file mode 100644 index 00000000000..d9765f5a311 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoNumChildrenInfo.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.output; + + +/** + * GDB/MI var-info-num-children. + */ +public class MIVarInfoNumChildrenInfo extends MIInfo { + + int children = 0; + + public MIVarInfoNumChildrenInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + + if (var.equals("numchild")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getString(); + try { + children = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + } + } + } + } + } + + public int getChildNumber() { + return children; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoPathExpressionInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoPathExpressionInfo.java new file mode 100644 index 00000000000..b972fba41da --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoPathExpressionInfo.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2007 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-info-path-expression. + * + * (gdb) -var-info-path-expression C.Base.public.m_size + * ^done,path_expr=((Base)c).m_size) + */ +public class MIVarInfoPathExpressionInfo extends MIInfo { + + String exp = ""; //$NON-NLS-1$ + + public MIVarInfoPathExpressionInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("path_expr")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIConst) { + exp = ((MIConst)val).getString(); + } + } + } + } + } + } + public String getFullExpression () { + return exp; + } + +} + diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoTypeInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoTypeInfo.java new file mode 100644 index 00000000000..e57df7147dc --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarInfoTypeInfo.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + + +/** + * GDB/MI var-info-type + */ +public class MIVarInfoTypeInfo extends MIInfo { + + String type = ""; //$NON-NLS-1$ + + public MIVarInfoTypeInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("type")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + type = ((MIConst)value).getString(); + } + } + } + } + } + } + + public String getType() { + return type; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarListChildrenInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarListChildrenInfo.java new file mode 100644 index 00000000000..8073fb6f032 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarListChildrenInfo.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +/** + * GDB/MI var-list-children + * -var-list-children var2 + * ^done,numchild="6",children={child={name="var2.0",exp="0",numchild="0",type="char"},child={name="var2.1",exp="1",numchild="0",type="char"},child={name="var2.2",exp="2",numchild="0",type="char"},child={name="var2.3",exp="3",numchild="0",type="char"},child={name="var2.4",exp="4",numchild="0",type="char"},child={name="var2.5",exp="5",numchild="0",type="char"}} + * + */ +public class MIVarListChildrenInfo extends MIInfo { + + MIVar[] children; + int numchild; + + public MIVarListChildrenInfo(MIOutput record) { + super(record); + List aList = new ArrayList(); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + + if (var.equals("numchild")) { //$NON-NLS-1$ + if (value instanceof MIConst) { + String str = ((MIConst)value).getString(); + try { + numchild = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + } + } + } else if (var.equals("children")) { //$NON-NLS-1$ + parseChildren(value, aList); + } + } + } + } + children = aList.toArray(new MIVar[aList.size()]); + } + + public MIVar[] getMIVars() { + return children; + } + + /* + * Some gdb MacOSX do not return a MITuple so we have + * to check for different format. + * See PR 81019 + */ + private void parseChildren(MIValue val, List aList) { + MIResult[] results = null; + if (val instanceof MITuple) { + results = ((MITuple)val).getMIResults(); + } else if (val instanceof MIList) { + results = ((MIList)val).getMIResults(); + } + if (results != null) { + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("child")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + aList.add(new MIVar((MITuple)value)); + } + } + } + } + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarSetFormatInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarSetFormatInfo.java new file mode 100644 index 00000000000..96774d9a3d6 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarSetFormatInfo.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-set-format + */ +public class MIVarSetFormatInfo extends MIInfo { + + String value = null; + + public MIVarSetFormatInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("value")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIConst) { + value = ((MIConst)val).getCString(); + } + } + } + } + } + } + + public String getValue () { + return value; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarShowAttributesInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarShowAttributesInfo.java new file mode 100644 index 00000000000..20ee3e04bca --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarShowAttributesInfo.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +/** + * GDB/MI var-show-attributes + */ +public class MIVarShowAttributesInfo extends MIInfo { + + String attr = ""; //$NON-NLS-1$ + + public MIVarShowAttributesInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("attr")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + attr = ((MIConst)value).getString(); + } + } + } + } + } + } + + public String getAttributes () { + return attr; + } + + public boolean isEditable() { + return attr.equals("editable"); //$NON-NLS-1$ + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarShowFormatInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarShowFormatInfo.java new file mode 100644 index 00000000000..70708edd31a --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarShowFormatInfo.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import org.eclipse.dd.mi.service.MIFormat; + + +/** + * GDB/MI var-show-format + */ +public class MIVarShowFormatInfo extends MIInfo { + + int format = MIFormat.NATURAL; + + public MIVarShowFormatInfo(MIOutput record) { + super(record); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("name")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getString(); + if ("binary".equals(str)) { //$NON-NLS-1$ + format = MIFormat.BINARY; + } else if ("decimal".equals(str)) { //$NON-NLS-1$ + format = MIFormat.DECIMAL; + } else if ("hexadecimal".equals(str)) { //$NON-NLS-1$ + format = MIFormat.HEXADECIMAL; + } else if ("octal".equals(str)) { //$NON-NLS-1$ + format = MIFormat.OCTAL; + } else if ("natural".equals(str)) { //$NON-NLS-1$ + format = MIFormat.NATURAL; + } + } + } + } + } + } + } + + public int getFormat() { + return format; + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarUpdateInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarUpdateInfo.java new file mode 100644 index 00000000000..a17d43bb4d9 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIVarUpdateInfo.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import java.util.ArrayList; +import java.util.List; + +/** + * GDB/MI var-update. + * -var-update * + * ^done,changelist={name="var3",value="3",in_scope="true",type_changed="false",name="var2",value="4",in_scope="true",type_changed="false"} + */ +public class MIVarUpdateInfo extends MIInfo { + + MIVarChange[] changeList; + + public MIVarUpdateInfo(MIOutput record) { + super(record); + List aList = new ArrayList(); + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("changelist")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + parseChangeList((MITuple)value, aList); + } else if (value instanceof MIList) { + parseChangeList((MIList)value, aList); + } + } + } + } + } + changeList = aList.toArray(new MIVarChange[aList.size()]); + } + + public MIVarChange[] getMIVarChanges() { + return changeList; + } + + /** + * For MI2 the format is now a MIList. + * @param tuple + * @param aList + */ + void parseChangeList(MIList miList, List aList) { + MIValue[] values = miList.getMIValues(); + for (int i = 0; i < values.length; ++i) { + if (values[i] instanceof MITuple) { + parseChangeList((MITuple)values[i], aList); + } else if (values[i] instanceof MIList) { + parseChangeList((MIList)values[i], aList); + } + } + } + + void parseChangeList(MITuple tuple, List aList) { + MIResult[] results = tuple.getMIResults(); + MIVarChange change = null; + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue value = results[i].getMIValue(); + if (value instanceof MITuple) { + parseChangeList((MITuple)value, aList); + } + else + { + String str = ""; //$NON-NLS-1$ + if (value instanceof MIConst) { + str = ((MIConst)value).getString(); + } + if (var.equals("name")) { //$NON-NLS-1$ + change = new MIVarChange(str); + aList.add(change); + } else if (var.equals("value")) { //$NON-NLS-1$ + if (change != null) { + change.setValue(str); + } + } else if (var.equals("in_scope")) { //$NON-NLS-1$ + if (change != null) { + change.setInScope("true".equals(str)); //$NON-NLS-1$ + } + } else if (var.equals("type_changed")) { //$NON-NLS-1$ + if (change != null) { + change.setChanged("true".equals(str)); //$NON-NLS-1$ + } + } + } + } + } +}