Note: If the Debug Platform example
plugins (org.eclipse.debug.examples.*) were previously installed in the
same workspace as the DSF PDA example, the two examples will both have
an editor registered for the ".pda" file type. To ensure that the
right editor is opened, right click on the PDA file in the Navigator,
and select Open With->PDA(DSF) Editor. The editor that is
opened should have the DSF-PDA icon: ![]() |
Note: A Perl
interpreter is required for PDA. Linux®™ comes with Perl. For
Microsoft®
Windows®, we use either ActivePerl (http://www.activeperl.com/) or
Indigo Perl (http://www.indigostar.com/). |
To demonstrate how to write a debugger for Eclipse, we need a language and a run time to debug. For this example, we chose an enhanced push down automata (PDA) assembly language and a simple interpreter implemented in Perl. Each line contains a single operation and any number of arguments. Our language differs from a standard PDA in two major ways:
Here is an annotated example of the Fibonacci computation (note that the annotations themselves are not valid syntax in this language – in this language, all comments must start at column 1 and be the entire line):
samples/fibonacci.pda |
|
push 6 |
Our PDA assembly language interpreter can be started in either run
mode or debug mode. When started in debug mode, the interpreter listens
for debug commands on a specified local TCP/IP socket and sends debug
events to a separate local TCP/IP socket. A detailed description
of
the protocol can be found in org.eclipse.dd.examples.pda/pdavm/docs/protocol.html,
but the lists below show a quick overview.
The commands include:
The debug events that are reported asynchronously to the second socket include:
org.eclipse.dd.examples.pda.launch.PDALaunchDelegate - getLaunch() | |
51: public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException { |
org.eclipse.dd.examples.pda.launch.PDALaunch - <<constructor>> | |
65: public PDALaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator) { |
org.eclipse.dd.examples.pda.launch.PDALaunch - intializeServices() | |
90: @ConfinedToDsfExecutor("getSession().getExecutor()") |
org.eclipse.dd.examples.pda.launch.PDALaunch - shutdownServices() | |
|
202: @ConfinedToDsfExecutor("getSession().getExecutor()") |
org.eclipse.dd.examples.pda.launch.PDAServicesInitSequence - fSteps | |
38: Step[] fSteps = new Step[] { |
![]() |
Image 1: PDA Command Control Diagram |
org.eclipse.dd.examples.pda.service.PDACommandControl - members declaration | |
|
56: // Parameters that the command control is created with. |
org.eclipse.dd.examples.pda.service.PDACommandControl.EventDispatchJob - run() | |
300: protected IStatus run(IProgressMonitor monitor) { |
org.eclipse.dd.examples.pda.service.PDACommandControl - queueCommand() | ||
|
org.eclipse.dd.examples.pda.service.commands.PDADataCommand | |
15: /** |
org.eclipse.dd.examples.pda.service.commands.PDADataCommandResult | |
20: @Immutable |
Note: Command and command results can be stored in a cache as keys and values. Making them immutable helps guard the integrity of these caches. |
The adapter mechanism is something like the glue of Eclipse APIs. It allows objects to be associated together without having any explicit dependencies between each other. Just like glue it works best when the mating parts are clean and closely fitted together, where just a little glue does the job. If too much glue is used to put together many odd parts, the whole thing can turn into a big sticky mess that falls apart at the lightest touch. |
org.eclipse.dd.examples.pda.ui/plugin.xml - PDA adapter factory declaration | |
|
<extension |
org.eclipse.dd.examples.pda.ui.PDAAdapterFactory - getAdapter() | |
157: public Object getAdapter(Object adaptableObject, Class adapterType) { |
org.eclipse.dd.examples.pda.ui.PDAAdapterFactory.LaunchAdapterSet - <<constructor>> | |
|
85: LaunchAdapterSet(PDALaunch launch) { |
Note: Most of the common debug
actions, such as the resume/suspend/step commands in Debug view, have
been converted into re-targetable commands. This means that the
given action uses the adapter mechanism to retrieve the command handler
from the selected element. For a DSF-based debugger integration
these command handlers must be explicitly created and registered with
the session so that they are returned by the Data Model
IDMContext.getAdapter() implementation. |
org.eclipse.dd.examples.pda.ui.PDAAdapterFactory - launchesRemoved() | |
185: public void launchesRemoved(ILaunch[] launches) { |
org.eclipse.dd.examples.pda.ui.viewmodel.PDAVMAdapter - createViewModelProvider() | |
43: protected AbstractDMVMProvider createViewModelProvider(IPresentationContext context) { |
Note: The VM Adapter is responsible for creating providers for all debugger views supported by the given debugger. In case of PDA, the registers and modules views are not supported, therefore the corresponding VM Providers are not created. |
Note: The Memory view is not a
Flexible Hierarchy view and so is not supported by the View
Model. For an example of integrating a memory view, see the
DSF-based GDB debugger integration. |
![]() |
Image 2: Debug view screen capture |
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMProvider - <<constructor>> | |
50: public PDALaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) |
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode - update(IChildrenUpdate[]) | |
|
119: @Override |
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode - update(ILabelUpdate[]) | |
152: public void update(final ILabelUpdate[] updates) { |
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode - updateProgramLabelInSessionThread() | |
174: @ConfinedToDsfExecutor("getSession().getExecutor()") |
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMProvider - handleDebugEvents() | |
|
73: public void handleDebugEvents(final DebugEvent[] events) { |
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDAProgramVMNode - buildDelta() | |
265: public int getDeltaFlags(Object e) { |
Note: In theory, each VM Node should only generate delta flags that only affect its own elements. In this way, the layout of the VM Nodes in a view could be customized as needed. In practice, testing and fine-tuning of the view requires adjustments in the flags returned by the various VM Nodes in a given view. |
org.eclipse.dd.examples.pda.service.PDARunControl - eventReceived() | |
181: public void eventReceived(Object output) { |
Note: Much of the sublety in the
above logic has to do with preventing race conditions. Although,
while executing in the session executor thread, the state of the system
is guaranteed to remain unchanged by other agents, any time a runnable
is submitted to the session executor, by the time that runnable is
executed, the state of the system may completely change. In the above example, a runnable is submitted to the session executor when the DsfSession.dispatchEvent() is called on line 193. Between the time that the eventReceived() method is completed, and the eventDispatched() methods are called, many clients may query the state of the service. By delaying the changing of the state until when in the eventDispatch() handlers, the clients are guaranteed to observe the state of the system be consistent with the events received by these clients. |
org.eclipse.dd.examples.pda.service.PDARunControl - canResume() | |
222: public boolean canResume(IExecutionDMContext context) { |
org.eclipse.dd.examples.pda.service.PDARunControl - resume() | |
238: public void resume(IExecutionDMContext context, final RequestMonitor rm) { |
An Eclipse breakpoint declaration comes in three parts:
org.eclipse.dd.examples.pda.service.PDABreakpoints - BreakpointDMContext | |
50: private static class BreakpointDMContext extends AbstractDMContext implements IBreakpointDMContext { |
org.eclipse.dd.examples.pda.service.PDABreakpoints - insertBreakpoint() | |
180: public void insertBreakpoint(IBreakpointsTargetDMContext context, Map<String, Object> attributes, |
org.eclipse.dd.examples.pda.service.PDABreakpoints - doInsertBreakpoint() | |
212: private void doInsertBreakpoint(PDAProgramDMContext programCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm) |
The PDA debugger allows watchpoints to be updated, but only with
respect to what operations may trigger the watchpoint:
org.eclipse.dd.examples.pda.service.PDABreakpoints - updateBreakpoint() | |
367: public void updateBreakpoint(final IBreakpointDMContext bpCtx, Map<String, Object> attributes, final RequestMonitor rm) { |
![]() |
Image 3: Mediating IDE and Target-Side
breakpoints |
org.eclipse.dd.examples.pda.service.PDABreakpointAttributeTranslator - getBreakpointAttributes() | |
65: public List<Map<String, Object>> getBreakpointAttributes(IBreakpoint bp, boolean bpManagerEnabled) |
org.eclipse.dd.examples.pda.service.PDAStack - getFrames() | |
244: public void getFrames(IDMContext context, final DataRequestMonitor<IFrameDMContext[]> rm) { |
org.eclipse.dd.examples.pda.service.PDAStack - FrameDMContext | |
54: private static class FrameDMContext extends AbstractDMContext implements IFrameDMContext { |
org.eclipse.dd.examples.pda.service.PDAStack - FrameDMData | |
85: private static class FrameDMData implements IFrameDMData { |
![]() |
Image 3: Components involved in Source
Display |
The second step is to register a DSF source display adapter.
This has actually already
been accomplished in Step 3 - View
Model, when registering the View Model adapters.
org.eclipse.dd.examples.pda.service.PDAStack - VariableDMContext | |
117: @Immutable |
org.eclipse.dd.examples.pda.service.PDAStack - getLocals() | |
271: public void getLocals(final IFrameDMContext frameCtx, final DataRequestMonitor<IVariableDMContext[]> rm) { |
org.eclipse.dd.examples.pda.service.PDAExpressions - createExpression() | |
213: public IExpressionDMContext createExpression(IDMContext ctx, String expression) { |
org.eclipse.dd.examples.pda.service.PDAExpressions - getAvailableFormats() | |
262: public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm) { |
org.eclipse.dd.examples.pda.service.PDAExpressions - getFormattedExpressionValue() | |
274: public void getFormattedExpressionValue(FormattedValueDMContext formattedCtx, |