From 1b7b4b9e158d7f37ac90647be7ea9e71086df96b Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Wed, 12 Mar 2008 19:20:51 +0000 Subject: [PATCH] [220446] Updated the "PDA Debugger Introduction" document. --- .../docs/pda/breakpoints_1.dia | Bin 0 -> 2012 bytes .../docs/pda/breakpoints_1.png | Bin 0 -> 26313 bytes .../docs/pda/connecting_1.dia | Bin 0 -> 2441 bytes .../docs/pda/connecting_1.png | Bin 0 -> 21993 bytes .../docs/pda/launch_1.png | Bin 0 -> 7540 bytes .../docs/pda/launch_2.dia | Bin 0 -> 771 bytes .../org.eclipse.dd.doc.dsf/docs/pda/pda.gif | Bin 0 -> 182 bytes .../docs/pda/pda_tutorial_outline.html | 2204 ++++++++++++++++- 8 files changed, 2152 insertions(+), 52 deletions(-) create mode 100644 plugins/org.eclipse.dd.doc.dsf/docs/pda/breakpoints_1.dia create mode 100644 plugins/org.eclipse.dd.doc.dsf/docs/pda/breakpoints_1.png create mode 100644 plugins/org.eclipse.dd.doc.dsf/docs/pda/connecting_1.dia create mode 100644 plugins/org.eclipse.dd.doc.dsf/docs/pda/connecting_1.png create mode 100644 plugins/org.eclipse.dd.doc.dsf/docs/pda/launch_1.png create mode 100644 plugins/org.eclipse.dd.doc.dsf/docs/pda/launch_2.dia create mode 100644 plugins/org.eclipse.dd.doc.dsf/docs/pda/pda.gif diff --git a/plugins/org.eclipse.dd.doc.dsf/docs/pda/breakpoints_1.dia b/plugins/org.eclipse.dd.doc.dsf/docs/pda/breakpoints_1.dia new file mode 100644 index 0000000000000000000000000000000000000000..e07bbeef391a45bdc2419101a8f8fa12956dfe53 GIT binary patch literal 2012 zcmV<22P60&iwFP!000001MQtlZ{s!)fbaelg7@mse2Jnqn=E$G7A??451XD1+F~4a zWyz4}JbLJFFDc3KLy}*z;s`4PNnm+AL((&&k3*XI^!a%fSdTJJ{3yKXBLMrB3@4H2 zhtr$>-*>-V@&4!A-Y3r&AN9{P7Bfq~BTUS*oBo4R^N+*f)6)|OUJ{|A7zF+TBy#wl z2m&$GLc{)T&$8APctQztEx#(1iv96INh=gHdD9<@$&YCqEkduKN#$~rD2QU~Q3N;r z5BKS#Kg`t(H}ve#Jr`3sj-~ifts3fw>z<-|F5_*rvw4*GT136f3nCSI%;y7y2P|1@37EWgusx zNfd`gFgQ<-QUht~DE4ZZHtZUzAEZBhP}RB-0^Ejc4|JL_Kh#4s+6>E*z%*egPwY?f z5Iv1b=yU(A^%yJJhdqjg=P!~S;|7ppQ3g3ZRC zy9z%<0dG9|YV_xj=%c{t0`TVyz&rV@)*=w)5r}I?AO^(IF~Wh1?FJ(eY2bupfE>UH z=O!9$>I^Uh5SWb!@*iF78P zD4lVVLYysMu^x1e%KcGADHK?%S8w{fIG@;3dY(*3YR?69N@_k2Vhk`s{526`1{}_D zdotl#^0Rv1q<%?7ahC?qn+BJ@*d@W1CPCP65-gvO(YiU1=ow3*8dg4kRmi4ID{p+*u6 z9M%RT`LcXR(z}Z_8w4GaoF7S6-iTQTC9Q-KdJ!mLb@L!428Np~6Ke}}Stq70Acjbo z-6WFK>eE3BHI0{w8SF~MZQ>E9b{w*0ZH_k?ixfc4(gF!agkMt*7$a$cgmBgZ8u{aw zUpGp`R_~h##Z-1ga%Lh~`lAE5i#j4{BayJCiA4VE%lJ<}lqF!o+mR44GYQZgAd?u8 zb8XN8V=_PtaO|8|2N=tLM_GD0wtppJ*s#ndaFmoZ9pD@yR<{bD--wMXB-Kt03vDQU z?I>;vy^)CH=xIkN;hL&Pfefd+un(SG<9ao*2P_Y^aOQ+i{a*4$HP;HRa%d;TsI{MXfu9Ibo%0i z81Qgy-XI8-_O7(pgVWZb-Ew+f>KuSeXW+|@gxX9(um%ay3z1Om4ao$ii(rkW5e_IZ zbs?75g%Gg0sSCL+sS7RUp3vgGaRGxm_Gz4b3jW!FPkX_KwqrGn7%PMt7I19Lv(>O{ zv!d%j_6}CV4&fO`Q6yX-CXLsAI58=Myw-jYXYK&oz-a~a zXb1GH-d6ReEBm}5`V_siL!b7d4{OW%m-(_NX6ar?OzgDmgKdfoN)SZwyI24-8=F%& z+gTst=`tAt-Cm%Mf0|hSy3k%ARC|*(P8SsP&86wO55zc49Lu^7b*V-mX7(7i27xM0 z<>*-GEm^44V>=vbFAni`EPFLUF%#1&A}QvwLyyB!5SDg<A1)L^zIH<~?cfH*hb!2~YV1f=I89GmAln~*jTkRK*8 zR{0L-;c^{porpRhx(pDNxNnC;t;Hb>TXV!B1rD)Ux_D0^H$a3axASv7oCb-gqK74d z%(Q0DrXW)mGM(VvH^n+KI^meXcUv98=qzNkSvEa?8essXC$nZ;q;H_qL1up64lb%X uskN7XN6hNJBldY$*~V!9&{O4~GE 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 HWPtzxg1*PT literal 0 HcmV?d00001 diff --git a/plugins/org.eclipse.dd.doc.dsf/docs/pda/connecting_1.png b/plugins/org.eclipse.dd.doc.dsf/docs/pda/connecting_1.png new file mode 100644 index 0000000000000000000000000000000000000000..b07c13701a92e69b8a1613e18e3afccfb29dda01 GIT binary patch literal 21993 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 MV4w-T|1|vn0N4VR#{d8T literal 0 HcmV?d00001 diff --git a/plugins/org.eclipse.dd.doc.dsf/docs/pda/launch_2.dia b/plugins/org.eclipse.dd.doc.dsf/docs/pda/launch_2.dia new file mode 100644 index 0000000000000000000000000000000000000000..f0d4b4876b243e51858d6f48586591150e611cc3 GIT binary patch literal 771 zcmV+e1N{6SiwFP!000001HD&WZ<{a_eebV8^tCl#A%wO`wLVOmG-(gpo{LZ+?(oAZdUc&h*Y_4Rh5 zKhCZmB7*PKHx@Y2)Eg|@JWchblvAWCwSf$}n&ilr1J%q3_HCot7RJb#V_&sn4ws1i5llndW_+NXbvke}QTC9s|YjF5CKMZY)UDow!Gc7M2x>A^@Z49 zNJc^mO|vIVei;4wW9X}^v#s9y*U#Jy1zT%-h$i5I+rK@;If)=UvCWP#ElkT2W}J$8 z75Co26hoC}y_KMN4Wguf+P7(~T;Q_e97KVKe_$?4dp{*+5f+hlt9?sUBi8rl4t44v z(NzCo9tWsuNztj=SBp@}ciU)$9QS67oT}@3&1mBf!z#T{7BGt`>?D+e?cUoivfLYM zf?Ut@h6w_NB$#u->gR$FGqu&&){nZeU4Jr>=bk~o1QIW0JHKTk+xEtu<2t76O~%$h zFCiBZh~PL!8?w|}Y(B#@B7s*yAyk#<=&pSfo&nMTXQ|p(7gAUd3RUX2BP7K+n=btpTd$hK zq5uoQSM92{eI|84fyG@l(;T`H_7W$m@@a)?Ru<3OHm&}&ANKLt)qmR5nH1{}002EP BbZr0t literal 0 HcmV?d00001 diff --git a/plugins/org.eclipse.dd.doc.dsf/docs/pda/pda.gif b/plugins/org.eclipse.dd.doc.dsf/docs/pda/pda.gif new file mode 100644 index 0000000000000000000000000000000000000000..9a6adbfc87e48e9c48ea6318945d0f7fed0784d9 GIT binary patch literal 182 zcmZ?wbhEHb6krfwc+A591WgP+2};o(9v-Qwskb%H6c-mW+z^>CVZ!|R^VhCj`@j9` zeHow to write a DSF-based debugger -

How to write a DSF-based debugger
-

+

How to write a DSF-based debugger
+

Summary

DSF

  • Customizing, componentization, performance.
  • GDB Reference Implementation
-

Debug Services

+

Push Down Automata (PDA)
+

+The Push Down Automata (PDA) debugger example is used as the basis for +this tutorial.  Before starting the tutorial it is best to +familiarize with the features of the debugger.
+

Running the Example

+Launch the PDA debugger with these twelve "easy" steps:
+
    +
  1. Download and install Eclipse development environment, either the Eclipse Classic 3.4 or Eclipse IDE for C/C++ Developers
    +
  2. +
  3. Install the DSF SDK feature to build against, by performing +either:
    +
  4. +
      +
    1. Using update manager, install the Debugger Services Framework end-user and +extender SDK, found in the Ganymede +Discovery Site under Remote +Access and Device Development.
    2. +
    3. Check out org.eclipse.dd.dsf +and org.eclipse.dd.dsf.ui plugins, found in the /cvsroot/dsdp repository under org.eclipse.dd.dsf/plugins +directory.
    4. +
    +
  5. Check out the org.eclipse.dd.examples.pda +and org.eclipse.dd.examples.pda.ui plugins, +found /cvsroot/dsdp in the org.eclipse.dd.dsf/plugins +directory.
  6. +
  7. Build the PDA plugins.
  8. +
  9. Create an instance of an Eclipse +Application launch configuration and launch it in Debug mode.
    +
  10. +
  11. Switch to the new Eclipse IDE Application
  12. +
  13. Create a new empty project:
    +
  14. +
      +
    1. Select the File->New->Project... +action
    2. +
    3. Select General->Project +in the New Project dialog.
    4. +
    5. Enter a name for the new project (e.g. "PDA")
    6. +
    +
  15. Link in the folder with PDA examples from the org.eclipse.dd.examples.pda plugin.
  16. +
      +
    1. Right-click on the new Project and select New->Folder
      +
    2. +
    3. Click on the Advanced +>> button at the bottom of the New Folder dialog.
    4. +
    5. Select the Link to folder in +the filesystem check box.
    6. +
    7. Type in or browse to the samples +directory found in the org.eclipse.dd.examples.pda +plugin.
    8. +
    +
  17. Open the PDA editor by double-clicking on the PDA file (e.g. fibonacci.pda).  See note +below.
    +
  18. +
  19. Set a breakpoint in the program by double-clicking in the editor +gutter.
  20. +
  21. Launch the PDA debugger
  22. +
      +
    1. Set the dsfPerlDebugger +variable to point to the Perl executable in your system.  +Variables can be set in the Windows->Preferences->Run/Debug->String +Substitution preference page.
    2. +
    3. Create a new launch configuration of type DSF PDA Application
    4. +
    5. In the Main tab, enter the workspace path to the program name +(e.g. /PDA/samples/fibonacci.pda).
    6. +
    7. Select Debug to +launch the PDA debugger.
    8. +
    +
  23. Step, select stack frames, debug...
  24. +
+ + + + + + +
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/).
+
+

Language

+

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:

+
    +
  • Our language has a control stack and thus has call-return +subroutines.
  • +
  • Our language allows data to be stored either on the data stack or +in named variables on the control stack.
  • +
+

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
call Fibonacci function call with one argument on the data stack
output print result to stdout
halt
#
# f(n) = f(n-1) + f(n-2)
# f(0) = 1
# f(1) = 1
#
:fibonacci
var n define variable n on control stack
pop $n get n from data stack
push $n
branch_not_zero gt0
push 1 f(0) = 1

return return with one value on data stack
:gt0
push $n
dec
branch_not_zero gt1
push 1 f(1) = 1
return return with one value on data stack
:gt1
push $n stack: n
dec stack: n-1
call fibonacci stack: f(n-1)

push $n stack: f(n-1) n
dec stack: f(n-1) n-1
dec stack: f(n-1) n-2
call Fibonacci stack: f(n-1) f(n-2)
add stack: f(n-1)+f(n-2)
return return with one value on data stack
+
+
+

Debug Protocol

+

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 socket and sends debug +events to a separate local TCP 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:

+
    +
  • clear N – clear the breakpoint on line N
  • +
  • data – return the contents of the data stack; the +data is returned from oldest to newest as a single string +“value|value|value|…|value|”
  • +
  • exit – end the interpreter
  • +
  • resume – resume full speed execution of the program
  • +
  • set N – set a breakpoint on line N
  • +
  • stack – return the contents of the control stack +(program counters, function and variable names); the stack is returned +from oldest to newest as a single string “frame#frame#frame#…#frame”. +Each frame is a string “filename|pc|function name|variable +name|variable name| …|variable name”
  • +
  • step – single step forward
  • +
  • suspend – end full speed execution and listen for +debug commands
  • +
  • var N M – return the contents of a variable M from +the control stack frame N (stack frames are indexed from 0).
  • +
+

The debug events that are reported asynchronously to the second +socket include:

+
    +
  • started – the interpreter has started (guaranteed to +be the first event sent)
  • +
  • terminated – the interpreter has terminated +(guaranteed to be the last event sent)
  • +
  • suspended X – the interpreter has suspended and +entered debug mode; X is the cause of the suspension, either step or +client or breakpoint N
  • +
  • resumed X – the interpreter has resumed execution in +run mode; X is the cause of the resume, either step or client
  • +
  • unimplemented instruction X – an unimplemented +instruction was encountered
  • +
  • no such label X – a branch or call to an unknown +label was encountered
  • +
+

Debug Services

+

TODO: remove this sesion?

Use of services is intended to allow for maximum level of extendability and customization.  To achieve this, service interfaces should encapsulate functionality that logically belongs together and at the @@ -63,86 +261,1970 @@ for reading stack information.
Service for reading symbol information about the loaded modules.
-


-

+

Step 1 - Launching
+

+The first task in integrating a debugger in Eclipse is creating and +managing the debugger process.  The Eclipse Platform provides an +extensive API for this purpose, which is nicely presented in the We +Have Lift-off: The Launching Framework in Eclipse article.  +This section (as this tutorial) concentrates on the DSF-specific tasks +of launching the PDA debugger.
+

Launch Delegate

+At first glance, there's nothing unusual about the PDA debugger launch +delegate.  Just like the Debug Platform version it:
+
    +
  1. finds the Perl executable,
  2. +
  3. finds free socket ports for debugger communication,
  4. +
  5. finds the PDA program
  6. +
  7. launches Perl to run the interpreter
  8. +
+The major difference is that it does not create an instance of the +standard debug model IDebugTerget +object.  Instead it implements the getLaunch() method in the ILaunchConfigurationDelegate2 +extension interface, in order to create a custom launch object:

+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.launch.PDALaunchDelegate +- getLaunch()

+
+
 51:  public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {

52: // Need to configure the source locator before creating the launch
53: // because once the launch is created and added to launch manager,
54: // the adapters will be created for the whole session, including
55: // the source lookup adapter.
56: ISourceLocator locator = getSourceLocator(configuration);

58: return new PDALaunch(configuration, mode, locator);
59: }
+
+
+
    +
+

PDALaunch

+The PDALaunch object plays two main roles:
+
    +
  1. Serve as the root element of the PDA View Model hierarchy
  2. +
  3. Manage the lifecycle of the DSF session, its services, and the +executor that belongs to the session. 
    +
  4. +
+The first task will be described in the View Model section, the second +task is described here. 

-

Push Down Automata (PDA)
+Even though the PDALaunch constructor is called +long before the debugging services are created, the session and the +executor need to be available to the UI clients that present the launch +object in the Debug view.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.launch.PDALaunch +- <<constructor>>

+
+
 65:     public PDALaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator) {
66: super(launchConfiguration, mode, locator);

68: // Create the dispatch queue to be used by debugger control and services
69: // that belong to this launch
70: final DefaultDsfExecutor dsfExecutor = new DefaultDsfExecutor(PDAPlugin.ID_PDA_DEBUG_MODEL);
71: dsfExecutor.prestartCoreThread();
72: fExecutor = dsfExecutor;
73: fSession = DsfSession.startSession(fExecutor, PDAPlugin.ID_PDA_DEBUG_MODEL);
74: }
+
+
+
    +
  • Lines 70 and 73 create the executor and the session +respectively.
    +
  • +
+As the last step of the launch process, after the Perl process is +started, the launch delegate calls the launch to initialize the DSF +services.  There is an expected race condition between +initializeServices() and shutdownServices() routines in that the PDA +process may run to completion and exit while the initialize services +routine is still running.  Also, the user may terminate the +program while the initialization sequene is still running.  The +use of fInitializationSequence variable and other flags protects deals +with this race condition.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.launch.PDALaunch +- intializeServices()

+
+
 90:     @ConfinedToDsfExecutor("getSession().getExecutor()")
91: public void initializeServices(String program, int requestPort, int eventPort, final RequestMonitor rm)
92: {
93: // Double-check that we're being called in the correct thread.
94: assert fExecutor.isInExecutorThread();

96: // Check if shutdownServices() was called already, which would be
97: // highly unusual, but if so we don't need to do anything except set
98: // the initialized flag.
99: synchronized(this) {
100: if (fShutDown) {
101: fInitialized = true;
102: return;
103: }
104: }

106: // Register the launch as listener for services events.
107: fSession.addServiceEventListener(PDALaunch.this, null);

109: // The initialization sequence is stored in a field to allow it to be
110: // canceled if shutdownServices() is called before the sequence
111: // completes.
112: fInitializationSequence = new PDAServicesInitSequence(
113: getSession(), program, requestPort, eventPort,
114: new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
115: @Override
116: protected void handleCompleted() {
117: // Set the initialized flag and check whether the
118: // shutdown flag is set. Access the flags in a
119: // synchronized section as these flags can be accessed
120: // on any thread.
121: boolean doShutdown = false;
122: synchronized (this) {
123: fInitialized = true;
124: fInitializationSequence = null;
125: if (fShutDown) {
126: doShutdown = true;
127: }
128: }

130: if (doShutdown) {
131: // If shutdownServices() was already called, start the
132: // shutdown sequence now.
133: doShutdown(rm);
134: } else {
135: // If there was an error in the startup sequence,
136: // report the error to the client.
137: if (getStatus().getSeverity() == IStatus.ERROR) {
138: rm.setStatus(getStatus());
139: }
140: rm.done();
141: }
142: fireChanged();
143: }
144: });

146: // Finally, execute the sequence.
147: getSession().getExecutor().execute(fInitializationSequence);
148: }
+
+
+
    +
  • Line 88 declares the initializeServices() to be invoked only +within the session executor thread.  This is to protect access to +the fInitializationSequence variable and to allow the call on line 107 +to be made without use of another runnable.
  • +
+Due to race conditions between debugger events and user commands, the shutdownServices() routine may be +invoked more than once.  The shutdown logic must protect against +these race conditions.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.launch.PDALaunch +- shutdownServices()
+
202:     @ConfinedToDsfExecutor("getSession().getExecutor()")
203: public void shutdownServices(final RequestMonitor rm) {
204: // Check initialize and shutdown flags to determine if the shutdown
205: // sequence can be called yet.
206: boolean doShutdown = false;
207: synchronized (this) {
208: if (!fInitialized && fInitializationSequence != null) {
209: // Launch has not yet initialized, try to cancel the
210: // shutdown sequence.
211: fInitializationSequence.cancel(false);
212: } else {
213: doShutdown = !fShutDown && fInitialized;
214: }
215: fShutDown = true;
216: }

218: if (doShutdown) {
219: doShutdown(rm);
220: } else {
221: rm.done();
222: }
223: }

225: @ConfinedToDsfExecutor("getSession().getExecutor()")
226: private void doShutdown(final RequestMonitor rm) {
227: fExecutor.execute( new PDAServicesShutdownSequence(
228: fExecutor, fSession.getId(),
229: new RequestMonitor(fSession.getExecutor(), rm) {
230: @Override
231: public void handleCompleted() {
232: fSession.removeServiceEventListener(PDALaunch.this);
233: if (!getStatus().isOK()) {
234: PDAPlugin.getDefault().getLog().log(new MultiStatus(
235: PDAPlugin.PLUGIN_ID, -1, new IStatus[]{getStatus()}, "Session shutdown failed", null)); //$NON-NLS-1$
236: }
237: // Last order of business, shutdown the dispatch queue.
238: DsfSession.endSession(fSession);
239: // endSession takes a full dispatch to distribute the
240: // session-ended event, finish step only after the dispatch.
241: fExecutor.shutdown();
242: fireTerminate();

244: rm.setStatus(getStatus());
245: rm.done();
246: }
247: }) );
248: }

+

+
+
+

Launch/Shutdown Sequence

+The actual task of calling the asynchronous IDsfService's initialize() and shutdown() methods is implemented +using the Sequence +object.  The following listing shows part of the declaration of +the +Sequence.Step objects which +perform the service initialization:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.launch.PDAServicesInitSequence +- fSteps

+
+
 38:     Step[] fSteps = new Step[] {
39: new Step()
40: {
41: @Override
42: public void execute(RequestMonitor requestMonitor) {
43: // Create the connection to PDA debugger.
44: fCommandControl = new PDACommandControl(fSession, fProgram, fRequestPort, fEventPort);
45: fCommandControl.initialize(requestMonitor);
46: }
47: },
48: new Step() {
49: @Override
50: public void execute(RequestMonitor requestMonitor) {
51: // Start the run control service.
52: fRunControl = new PDARunControl(fSession);
53: fRunControl.initialize(requestMonitor);
54: }
55: },
56: new Step() {
57: @Override
58: public void execute(RequestMonitor requestMonitor) {
59: // Start the service to manage step actions.
60: new StepQueueManager(fSession).initialize(requestMonitor);
61: }
62: },
...
+
+
+

Step 2 - Connecting 

+With the launch framework in place, the debugger back end is running +and the DSF session and executor are started.  The next step is to +create the first service and to connect to the debugger.  DSF +defines a debug interface: ICommandControl +which abstracts a debugger connection as a facility that processes +commands and generates events.  The ICommandControl method allow +for three major functions:
+
    +
  1. Queue/Remove/Cancel +commands - It is assumed that the command control service uses a +queue to hold commands that are to be sent to the debugger.  As +long as commands are still in the queue, clients can remove the +commands so they are never sent.  Even after the commands are +sent, the clients may request to cancel a running command, although +there is no guarantee that the debugger supports that.
  2. +
  3. Listening to Commands +Queued/Sent/Completed - Clients can listen to all command +traffic in order to implement custom processing.
  4. +
  5. Listening to Events +- Events are messages from the debugger which are not direct responses +to any commands.  Many clients need to listen to events such as +target state change events.
    +
  6. +
+ + + + + + + + + + +

+
Image 1: PDA Command Control Diagram
+
+

Synchronization

+Since there are several threads being used by the PDA Command Control +protecting state data becomes very important.
+
+Most of the state data in the command control service is protected +using the session thread, i.e. they can only be accessed while +executing in the session executor's thread:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDACommandControl +- members declaration
+
 56:     // Parameters that the command control is created with.
57: final private String fProgram;
58: final private int fRequestPort;
59: final private int fEventPort;

61: // Queue of commands waiting to be sent to the debugger. As long as commands
62: // are in this queue, they can still be removed by clients.
63: private final List<CommandHandle> fCommandQueue = new LinkedList<CommandHandle>();
64:
65: // Queue of commands that are being sent to the debugger. This queue is read
66: // by the send job, so as soon as commands are inserted into this queue, they can
67: // be considered as sent.
68: @ThreadSafe
69: private final BlockingQueue<CommandHandle> fTxCommands = new LinkedBlockingQueue<CommandHandle>();
70:
71: // Flag indicating that the PDA debugger started
72: private boolean fStarted = false;
73:
74: // Flag indicating that the PDA debugger has been disconnected
75: @ThreadSafe
76: private boolean fTerminated = false;
77:
78: // Data Model context of this command control.
79: private PDAProgramDMContext fDMContext;

81: // Synchronous listeners for commands and events.
82: private final List<ICommandListener> fCommandListeners = new ArrayList<ICommandListener>();
83: private final List<IEventListener> fEventListeners = new ArrayList<IEventListener>();
84:
85: // Sockets for communicating with PDA debugger
86: @ThreadSafe
87: private Socket fRequestSocket;
88: @ThreadSafe
89: private PrintWriter fRequestWriter;
90: @ThreadSafe
91: private BufferedReader fRequestReader;
92: @ThreadSafe
93: private Socket fEventSocket;
94: @ThreadSafe
95: private BufferedReader fEventReader;

97: // Jobs servicing the sockets.
98: private EventDispatchJob fEventDispatchJob;
99: private CommandSendJob fCommandSendJob;
+

+
+
+
    +
+
    +
  • Line 63 declares the main command queue fCommandQueue.  Commands sit +in this queue until the command channel is free to send.
  • +
  • Line 69 declares a second command queue fTxCommands.  This queue is +used only as a means of synchronization with the send job.
  • +
  • Line 76 declares the fTerminated +flag.  It needs to be thread safe to allow the command and event +processing jobs to access it.
    +
  • +
  • Lines 86-95 declare the commuication sockets.  They are +marked as thread-safe though only used by dedicated threads after being +created.
  • +
+Following is an example of how the access to session-thread protected +variables is implemented.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDACommandControl.EventDispatchJob +- run()

+
+
300:         protected IStatus run(IProgressMonitor monitor) {
301: while (!isTerminated()) {
302: try {
303: // Wait for an event.
304: final String event = fEventReader.readLine();
305: if (event != null) {
306: try {
307: // Process the event in executor thread.
308: getExecutor().execute(new DsfRunnable() {
309: public void run() {
310: processEventReceived(event);
311: }
312: });
313: } catch (RejectedExecutionException e) {}
314: } else {
315: break;
316: }
317: } catch (IOException e) {
318: break;
319: }
320: }
321: if (!isTerminated()) {
322: // Exception from the event socket is an indicator that the PDA debugger
323: // has exited. Call setTerminated() in executor thread.
324: try {
325: getExecutor().execute(new DsfRunnable() {
326: public void run() {
327: setTerminated();
328: }
329: });
330: } catch (RejectedExecutionException e) {}
331: }
332: return Status.OK_STATUS;
333: }
334:
335: }
+
+
    +
  • Line 300 declares the run() +command of the event dispatch job.  It executes this loop reading +the events socket until the socket is closed or the PDA debugger is +terminated
  • +
  • Line 308 submits a runnable to switch to the session executor +thread.
  • +
  • Line 310 calls a method to process the event.
    +
  • +
+
+

Command/Event Listeners

+As mentioned before there are two types of listeners that can be +registered with the comands control: event +listners and command listeners.  The most important +feature of these listeners, is that they are called by the command +control synchronously.  +As a result of this, the command listeners can expect to see the state +of the command queue that is consistent with the event they just +received.  However, if clients need to modify the queue as a +result of the event, they should only do it in a separate runnable, +otherwise other command listeners may encounter the command control in +an inconsistent state.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDACommandControl +- queueCommand()
+
337:     public <V extends ICommandResult> void queueCommand(ICommand<V> command, DataRequestMonitor<V> rm) {
338: if (command instanceof AbstractPDACommand<?>) {
339: // Cast from command with "<V extends ICommandResult>" to a more concrete
340: // type to use internally in the command control.
341: @SuppressWarnings("unchecked")
342: AbstractPDACommand<PDACommandResult> pdaCommand = (AbstractPDACommand<PDACommandResult>)command;
343:
344: // Similarly, cast the request monitor to a more concrete type.
345: @SuppressWarnings("unchecked")
346: DataRequestMonitor<PDACommandResult> pdaRM = (DataRequestMonitor<PDACommandResult>)rm;

348: // Add the command to the queue and notify command listeners.
349: fCommandQueue.add( new CommandHandle(pdaCommand, pdaRM) );
350: for (ICommandListener listener : fCommandListeners) {
351: listener.commandQueued(command);
352: }
353:
354: // In a separate dispatch cycle. This allows command listeners to repond to the
355: // command queued event.
356: getExecutor().execute(new DsfRunnable() {
357: public void run() {
358: processQueues();
359: }
360: });
361:
362: } else {
363: PDAPlugin.failRequest(rm, INTERNAL_ERROR, "Unrecognized command: " + command);
364: }
365: }
+

+
+
+
    +
  • Line 349 adds the new command to the queue.
  • +
  • Lines 350-352 call the command listeners to notify them of the +new command.
  • +
  • Lines 356-360 submit a separate runnable to read the queue and to +send commands to the debugger.  The separate runnable is used to +allow the command listeners to modify the queue as well.
  • +
+

PDAProgramDMContext

+Finally the command control also declares a Data Model context, which +is a parent to all other contexts for a given PDA debugger +session.  Each command used with the command control has to +implement the ICommand.getContext() method, which returns the context +that the command is acting on.  In PDA debugger, this context is +always the PDAProgramDMContext +instance returned by PDACommandControl.getProgramDMContext(). +However in other debuggers this context can have two other functions:
+
    +
  1. To identify the command +control instnace - In debugger sessions that connect to multiple +back ends, the context can be used to identify which command control +should process a given command.
  2. +
  3. To help control +debugger command protocol state - The PDA debug protocol is +stateless, which means that any command acts independently of any +commands that came before it.  For debuggers which do have +protocol state, e.g. GDB/MI, the command control needs to check the +context of each command and set the protocol by preceeding the command +being processed with other commands.
    +
  4. +
+ +

PDA Commands

+To increase type safetly and make the code more readable the plain text +PDA commands are abstracted using specific command objects.  Below +is an example of a command class:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.commands.PDADataCommand +

+
+
 15: /**
16: * Retrieves data stack information
17: *
18: * <pre>
19: * C: data
20: * R: {value 1}|{value 2}|{value 3}|...|
21: * </pre>
22: */
23: @Immutable
24:
public class PDADataCommand extends AbstractPDACommand<PDADataCommandResult> {
25:
26: public PDADataCommand(PDAProgramDMContext context) {
27: super(context, "data");
28: }
29:
30: @Override
31: public PDADataCommandResult createResult(String resultText) {
32: return new PDADataCommandResult(resultText);
33: }
34: }
+
+
+
    +
  • Line 23 declares the class, using the PDADataCommandResult class as the +type for the result which has to be generated by this command.
  • +
  • Line 31 creates and returns the PDADataCommandResult object, +which parses the command result string.
  • +
+Here is the corresponding data result class:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.commands.PDADataCommandResult +

+
+
 20: @Immutable
21:
public class PDADataCommandResult extends PDACommandResult {
22:
23: final public String[] fValues;
24:
25: PDADataCommandResult(String response) {
26: super(response);
27: StringTokenizer st = new StringTokenizer(response, "|");
28: List<String> valuesList = new ArrayList<String>();
29:
30: while (st.hasMoreTokens()) {
31: String token = st.nextToken();
32: if (token.length() != 0) {
33: valuesList.add(st.nextToken());
34: }
35: }
36:
37: fValues = new String[valuesList.size()];
38: for (int i = 0; i < valuesList.size(); i++) {
39: fValues[i] = valuesList.get(i);
40: }
41: }
42: }
+
+
+
    +
  • Line 23 declares the parsed result.  It is declared public +but also final, protecting it from being modified by clients.
    +
  • +
+
+ + + + + + +
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.
+

+

Step 3 - View Model

+

Adapter Glue

+ + + + + + +
The adapter mechanism is something +like the glue of Eclipse APIs, since it allows object to be associated +with each without having any +explicit dependencies.  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.
+
+After connecting to the debugger, the next step is to get something to +display in the debugger views.  Flexible Hierarchy viewers depend +heavily on the adapter mechanism to associate the presentation classes +with the objects being presented.  The first step to connect the +DSF +View Model for the debugger views is to register an adapter factory for +the custom PDALaunch object:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui/plugin.xml +- PDA adapter factory declaration
+
   <extension
point="org.eclipse.core.runtime.adapters">
<factory
class="org.eclipse.dd.examples.pda.ui.PDAAdapterFactory"
adaptableType="org.eclipse.dd.examples.pda.launch.PDALaunch">
<adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider"/>
<adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory"/>
</factory>
</extension>
+

+
+
+
+The adapter factory has two jobs:
+
    +
  1. Return the PDAVMAdapter instance as the content provider for the +PDALaunch element.
  2. +
  3. Register and manage the life-cycle of all other adapters required +for a functioning debugger.
  4. +
+The first job is performed by the IAdapterFactory.getAdapter() method +listed below:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.PDAAdapterFactory +- getAdapter()

+
+
157:     public Object getAdapter(Object adaptableObject, Class adapterType) {
158: if (!(adaptableObject instanceof PDALaunch)) return null;

160: PDALaunch launch = (PDALaunch)adaptableObject;

162: // Find the correct set of adapters based on the launch. If not found
163: // it means that we have a new launch, and we have to create a
164: // new set of adapters.
165: LaunchAdapterSet adapterSet;
166: synchronized(fLaunchAdapterSets) {
167: adapterSet = fLaunchAdapterSets.get(launch);
168: if (adapterSet == null) {
169: adapterSet = new LaunchAdapterSet(launch);
170: fLaunchAdapterSets.put(launch, adapterSet);
171: }
172: }
173:
174: // Returns the adapter type for the launch object.
175: if (adapterType.equals(IElementContentProvider.class)) return adapterSet.fViewModelAdapter;
176: else if (adapterType.equals(IModelProxyFactory.class)) return adapterSet.fViewModelAdapter;
177: else return null;
178: }
+
+
    -
  • Cut and Paste
    +
  • Lines 158-160 verify that the adaptable object is of correct type.
  • +
  • Lines 165-172 check if the given launch has been seen +before.  It if is a new launch, it means that new adapters need to +be created and registered for this debug session.
  • +
  • Lines 175-176 Return the requested adapters for the PDALaunch +object.
-

PDA debugger
+The LaunchAdapterSet constructor is responsible for creating and +registering all other adapters for the new debug session.  +However, instead of using the platform adapter factory mechanism, the +adapters are registered with the DSF session object and are returned as +adapters to the Data Model's IDMContext +object.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.PDAAdapterFactory.LaunchAdapterSet +- <<constructor>>
+
 85:         LaunchAdapterSet(PDALaunch launch) {
86: // Initialize launch and session.
87: fLaunch = launch;
88: DsfSession session = launch.getSession();
89:
90: // Initialize VM
91: fViewModelAdapter = new PDAVMAdapter(session);

93: // Initialize source lookup
94: fSourceDisplayAdapter = new MISourceDisplayAdapter(session, (ISourceLookupDirector)launch.getSourceLocator());
95: session.registerModelAdapter(ISourceDisplay.class, fSourceDisplayAdapter);
96:
97: // Initialize retargetable command handler.
98: fStepIntoCommand = new DsfStepIntoCommand(session);
99: fStepOverCommand = new DsfStepOverCommand(session);
100: fStepReturnCommand = new DsfStepReturnCommand(session);
101: fSuspendCommand = new DsfSuspendCommand(session);
102: fResumeCommand = new DsfResumeCommand(session);
103: fTerminateCommand = new PDATerminateCommand(session);
104: session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand);
105: session.registerModelAdapter(IStepOverHandler.class, fStepOverCommand);
106: session.registerModelAdapter(IStepReturnHandler.class, fStepReturnCommand);
107: session.registerModelAdapter(ISuspendHandler.class, fSuspendCommand);
108: session.registerModelAdapter(IResumeHandler.class, fResumeCommand);
109: session.registerModelAdapter(ITerminateHandler.class, fTerminateCommand);

111: // Initialize debug model provider
112: fDebugModelProvider = new IDebugModelProvider() {
113: public String[] getModelIdentifiers() {
114: return new String[] { PDAPlugin.ID_PDA_DEBUG_MODEL };
115: }
116: };
117: session.registerModelAdapter(IDebugModelProvider.class, fDebugModelProvider);
118:
119: // Register the launch as an adapter This ensures that the launch,
120: // and debug model ID will be associated with all DMContexts from this
121: // session.
122: session.registerModelAdapter(ILaunch.class, fLaunch);
123: }
+

+
+
+
    +
+
    +
  • Line 91 creates the View Model Adapter.  This adapter is +used to populate the content of all the Flexible Hierarchy debugger +views for the given PDA debugger instgance.
  • +
  • Line 94-95 register the source display adapter (the "MI" prefix +is a historical left over).
  • +
  • Lines 98-109 register handlers for common debug commands.
  • +
  • Lines 112 -116 Regiter an adapter to provide debug model +ID.  It is used by Debug Platform to enable custom keybord +shortcuts for the debugger.
  • +
  • Line 122 associates the launch object with the PDA debugger +elements.  This enables some actions in debug view which access +the launch (such as Edit Source +Lookup).
  • +
+Each adapter set is created new for each PDA debug session.  They +also need to be disposed when they are no longer needed.  It could +be expected that the adapters should be disposed when the PDA debugger +is terminated.  However, the terminated debug session still +appears in the Debug view, and this requires the adapters to be +present.  Instead, the adapters are removed when the corresponding +PDA launch is removed:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.PDAAdapterFactory +- launchesRemoved()

+
+
185:     public void launchesRemoved(ILaunch[] launches) {
186: // Dispose the set of adapters for a launch only after the launch is
187: // removed from the view. If the launch is terminated, the adapters
188: // are still needed to populate the contents of the view.
189: for (ILaunch launch : launches) {
190: if (launch instanceof PDALaunch) {
191: PDALaunch pdaLaunch = (PDALaunch)launch;
192: synchronized(fLaunchAdapterSets) {
193: if ( fLaunchAdapterSets.containsKey(pdaLaunch) ) {
194: fLaunchAdapterSets.remove(pdaLaunch).dispose();
195: }
196: }
197: }
198: }
199: }
+
+
+

PDA View Model

+The PDAVMAdapter creates the VM Providers on demand for each debugger +view it supports:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.viewmodel.PDAVMAdapter +- createViewModelProvider()

+
+
 43:     protected AbstractDMVMProvider createViewModelProvider(IPresentationContext context) {
44: if ( IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId()) ) {
45: return new PDALaunchVMProvider(this, context, getSession());
46: } else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(context.getId()) ) {
47: return new VariableVMProvider(this, context, getSession());
48: } else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(context.getId()) ) {
49: return new ExpressionVMProvider(this, context, getSession());
50: }
51: return null;
52: }
+
+
+
    +
  • Line 45 creates a VM Provider for the debug view.  This +provider is created custom for the PDA debugger.
  • +
  • Lines 47 and 49 create VM Providers for the Variables and Expressions views +respectively.  These providers are implemented in the org.eclipse.dd.dsf.debug.ui plugin +and are reused here without modification.
    +
  • +
+

Launch VM Provider

+"Launch" actually refers to the internal name of the Debug view.  +The PDA debugger has a somewhat simpler presentation in Debug view than +most debuggers because it does not support multiple threads so it has +the thread node shown directly below the launch node.
+
+ + + + + + + + + +

+
Image 2: Debug view screen capture
+
+The PDALaunchVMProvider constructor creates the VM Nodes and arranges +them in a hierarchy that mirrors the screen-shot in Image 2.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMProvider +- <<constructor>>

+
+
 50:     public PDALaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) 
51: {
52: super(adapter, presentationContext, session);
53:
54: IRootVMNode launchNode = new LaunchRootVMNode(this);
55: setRootNode(launchNode);

57: // Launch node is a parent to the processes and program nodes.
58: IVMNode pdaProgramNode = new PDAProgramVMNode(this, getSession());
59: IVMNode processesNode = new StandardProcessVMNode(this);
60: addChildNodes(launchNode, new IVMNode[] { pdaProgramNode, processesNode});
61:
62: // Stack frames node is under the PDA program node.
63: IVMNode stackFramesNode = new StackFramesVMNode(this, getSession());
64: addChildNodes(pdaProgramNode, new IVMNode[] { stackFramesNode });

66: // Register the LaunchVM provider as a listener to debug and launch
67: // events. These events are used by the launch and processes nodes.
68: DebugPlugin.getDefault().addDebugEventListener(this);
69: DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
70: }
+
+
+
    +
  • Lines 54,55 create the root node for the PDA hierarchy, which +tracks the single PDA Launch element.
  • +
  • Line 58 creates the PDA program node, which tracks the single PDA +program execution context.
    +
  • +
  • Line 59 creates the processes node.  This node supplies the +elements corresponding to process objects returned by +ILaunch.getProcesses(). 
    +
  • +
  • Line 60 sets the program and processes nodes as children of the +root node so that their elements appear under the launch.
  • +
  • Lines 63,64 add the stack frame node as a child directly under +the program node.
  • +
  • Line 68 adds the Launch VM Provider as a listener to the standard +debug model events.  These events are used by the StandardProcessVMNode to update the +processes' state.
    +
  • +
  • Line 69 add the Launch VM Provider as a listener to the launch +events.  These events are used by the LaunchVMRootNode to update +the state and content of the launch if it has been changed or +terminated.
  • +
+

PDA Program VM Node

+
    +
+

Elements

+The PDA Program Node is the most complex component of the PDA View +Model.  It supplies an element representing the PDA program and it +operates in three modes:
+
    +
  1. Not Initialized +- After the PDALaunch object +has been created, but the services have not yet been initialized.  +In this mode the PDA Program is not shown in Debug view.
    +
  2. +
  3. Running - After +the PDALaunch and PDACommandControl are initialized, the PDAProgramDMContext object is used +as the underlying Data Model element shown in Debug view. 
    +
  4. +
  5. Shut down - +After a program has terminated, it is still shown in the Debug view, as +is consistent with the established workflow.  However, at this +point the PDACommandControl +service is shut down and the PDAProgramDMContext +is not available.  Hence, a separate TerminatedProgramVMContext +wrapper element is used which does not have an underlying Data Model +element.
  6. +
+The following two methods implement the logic of supplying the elements +of the above modes:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode +- update(IChildrenUpdate[])
+
119:     @Override
120: public void update(IChildrenUpdate[] updates) {
121: for (IChildrenUpdate update : updates) {
122: PDALaunch launch = findLaunchInPath(update.getElementPath());
123: if (launch != null && launch.isInitialized() && launch.isShutDown()) {
124: // If the debug session has been shut down, add a dummy
125: // VM context representing the PDA thread.
126: update.setChild(new TerminatedProgramVMContext(getVMProvider().getVMAdapter(), this), 0);
127: update.done();
128: } else {
129: super.update(new IChildrenUpdate[] { update });
130: }
131: }
132: }
133:
134: @Override
135: protected void updateElementsInSessionThread(final IChildrenUpdate update) {
136: // Get the instance of the service. Note that there is no race condition
137: // in getting the service since this method is called only in the
138: // service executor thread.
139: final PDACommandControl commandControl = getServicesTracker().getService(PDACommandControl.class);

141: // Check if the service is available. If it is not, no elements are
142: // updated.
143: if (commandControl == null) {
144: handleFailedUpdate(update);
145: return;
146: }
147:
148: update.setChild(createVMContext(commandControl.getProgramDMContext()), 0);
149: update.done();
150: }
+

+
+
+
+
    +
  • Line 120 overrides the AbstractDMVMNode.update(IChildrenUpdate[]) +update in order to update the terminated element if the PDA program is +already terminated.  The super-class implementation only changes +the execution thread to the DSF session and calls updateElementsInSessionThread(), +which is not needed nor possible after the PDA program is terminated.
  • +
  • Line 126 cretes the dummy View Model context which represents a +terminated PDA program.
  • +
  • Line 135 implements the elements update method which is called in +the DSF session thread. 
    +
  • +
  • Line 139 retrieves the PDACommandControl service and line 143 +confirms that it is still available.  Normally if the DSF session +is still active, then the service should also be available.  +However if the session is in the process of shutting down, this call +may be caught in a race condition, therefore a check if service is +available is necessary.
  • +
+

Label

+Calculating the label for the PDA program element is also split into +two parts depending on whether the program is terminated.  +Similarly as when calculating the element, if the program is +terminated, the label is calculated in the View Model thread, if the +program is running, the execution is switched to the session executor +thread.  This is accomplished in the update(ILabelUpdate[]) +implementation:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode +- update(ILabelUpdate[]) +

+
+
152:     public void update(final ILabelUpdate[] updates) {
153: for (final ILabelUpdate update : updates) {
154: if (update.getElement() instanceof TerminatedProgramVMContext) {
155: // If the element is a terminated program, update the label
156: // in the View Model thread.
157: updateTerminatedThreadLabel(update);
158: } else {
159: // If the element is the PDA Program context, try to switch
160: // to the DSF session thread before updating the label.
161: try {
162: getSession().getExecutor().execute(new DsfRunnable() {
163: public void run() {
164: updateProgramLabelInSessionThread(update);
165: }});
166: } catch (RejectedExecutionException e) {
167: // Acceptable race condition: DSF session terminated.
168: handleFailedUpdate(update);
169: }
170: }
171: }
172: }
+
+
+
    +
  • Line 153 iterates through the udptes. The +IElementLabelProvider.update() method takes an array of updates as an +argument to allow the implementation to process the udpates in bunches, +improving performance. 
    +
  • +
  • Line 157 calls a subroutine to handle the terminated program +label.
  • +
  • Lines 161-169 call a subroutine to update the active program's +session.  The execution thread is first changed to the session +executor thread.
  • +
+The updateProgramLabelInSessionThread() +is rather long, but it is useful to look at it in detail because it is +representative of what all label providers must do.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode +- updateProgramLabelInSessionThread()

+
+
174:     @ConfinedToDsfExecutor("getSession().getExecutor()")
175: private void updateProgramLabelInSessionThread(final ILabelUpdate update) {
176: // Get a reference to the run control service.
177: final IRunControl runControl = getServicesTracker().getService(IRunControl.class);
178: if (runControl == null) {
179: handleFailedUpdate(update);
180: return;
181: }
182:
183: // Find the PDA program context.
184: final PDAProgramDMContext programCtx =
185: findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAProgramDMContext.class);

187: // Call service to get current program state
188: final boolean isSuspended = runControl.isSuspended(programCtx);

190: // Set the program icon based on the running state of the program.
191: String imageKey = null;
192: if (isSuspended) {
193: imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
194: } else {
195: imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
196: }
197: update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);

199: // Retrieve the last state chagne reason
200: runControl.getExecutionData(
201: programCtx,
202: new DataRequestMonitor<IExecutionDMData>(ImmediateExecutor.getInstance(), null)
203: {
204: @Override
205: public void handleCompleted(){
206: // If the request failed, fail the udpate.
207: if (!getStatus().isOK()) {
208: handleFailedUpdate(update);
209: return;
210: }
211:
212: // Compose the thread name string.
213: final StringBuilder builder = new StringBuilder();
214:
215: builder.append("PDA [");
216: builder.append(programCtx.getProgram());
217: builder.append("]");
218:
219: if(isSuspended) {
220: builder.append(" (Suspended");
221: } else {
222: builder.append(" (Running");
223: }
224: // Reason will be null before ContainerSuspendEvent is fired
225: if(getData().getStateChangeReason() != null) {
226: builder.append(" : ");
227: builder.append(getData().getStateChangeReason());
228: }
229: builder.append(")");
230: update.setLabel(builder.toString(), 0);
231: update.done();
232: }
233: });
234: }
+
+
+
    +
  • Line 174 declares the routine as to be called only on the session +thread.  Accessing services on a different thread is a violation +of their API contract.
  • +
  • Lines 177-184 retrieve the IRunControl +service, always checking that the service is actually available.
  • +
  • Lines 184,185 retrieve the PDAProgramDMContext from the +update.  This context can actually be expected to be in the IDMVMConext wrapper returned by IViewerUpdate.getElement().  +However the AbstractDMVMNode.findDmcInPath() +utility method searches the full tree path in the update and is +typically used to extract the Data Model context from the update.
  • +
  • Line 188 retrieves the running state of the program using a +synchronous IRunControl.isSuspended() method.
  • +
  • Lines 191-197 calculate and update the program icon based on the +running state of the program.
  • +
  • Lines 200-233 call an asynchronous IRunControl.getExecutionData() +method to retrieve additional information about the state of the PDA +program.  The label update is completed only after request monitor +of this method is called.
  • +
  • Lines 207-210 perform error handling.
  • +
  • Lines 213-229 finally calcuate the label string for the +program. 
    +
  • +
  • On line 227, The result of the getExecutionData() +call, accessed using DataRequestMonitor.getData(), +is used to fill in the reason for the current state of the program.
  • +
  • Line 230 writes the label to the upate.  This call assumes +that there is no columns in Debug view, so it uses 0 as the column index.
    +
  • +
+

Delta

+Translating the Data Model events into IModelDelta objects that can be +processed by the Flehible Hierarchy views, is the most complicated task +performed by the View Model infrastructure.  The model deltas +require that a path be formed by the IModelDelta objects which matches +the hierarchy elements found in the view, including such details as +indexes of elements and their number at each level.  Normally this +requires that the model event handler should know the full hierarchy of +the elements in a given view.  However, with the DSF View Model, +this logic is split into two parts:
+
    +
  1. The event handler in the VM Provider
  2. +
  3. The build delta methods in the VM Nodes.
  4. +
+The debug model event handler below is an example of the event handler +implementation in the VM Provider.  The event handler for Data +Model events is already implemented in the AbstractDMVMProvider base class:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMProvider +- handleDebugEvents()
+
 73:     public void handleDebugEvents(final DebugEvent[] events) {
74: if (isDisposed()) return;
75:
76: // This method may be called on any thread. Switch to the
77: // view model executor thread before processing.
78: try {
79: getExecutor().execute(new Runnable() {
80: public void run() {
81: if (isDisposed()) return;
82:
83: for (final DebugEvent event : events) {
84: handleEvent(event);
85: }
86: }});
87: } catch (RejectedExecutionException e) {
88: // Ignore. This exception could be thrown if the view model is being
89: // shut down.
90: }
91: }
+

+
+
+
    +
  • Line 84 calls the base class handleEvent() +method which does the hard work care of calling the VM Nodes to build +and send the delta to the views.
  • +
+The PDA program node implements methods to add the delta nodes for its +elements:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode +- buildDelta()

+
+
265:     public int getDeltaFlags(Object e) {
266: if(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) {
267: return IModelDelta.STATE;
268: }
269: if (e instanceof PDAStartedEvent) {
270: return IModelDelta.EXPAND | IModelDelta.SELECT;
271: }
272: return IModelDelta.NO_CHANGE;
273: }
274:
275: public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
276: if(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) {
277: // If a suspended/resumed event is received, just update the
278: // state of the program. StackFramesVMNode will take care of
279: // refreshing the stack frames.
280: parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.STATE);
281: }
282: if (e instanceof PDAStartedEvent) {
283: // When debug session is started expand and select the program.
284: // If the program hits a breakpoint, the top stack frame will then
285: // be selected.
286: parentDelta.addNode(createVMContext(((PDAStartedEvent)e).getDMContext()), IModelDelta.EXPAND | IModelDelta.SELECT);
287: }
288: rm.done();
289: }
290: }
+
+
+
    +
  • Lines 265-273 implement the synchronous +IVMNode.getDeltaFlags().  This method only needs to return what +flags this node may create +for the given event and it is used optimize the logic of building the +model deltas.
  • +
  • Line 270 tells the View Model logic that this node may add the +IModelDelta.EXPAND and IModelDelta.SELECT flags.  These flags are +especially costly in calculating the delta, because they require +calculating of indexes and element counts for all nodes in the path to +this node.
  • +
  • Lines 276-281 handle the run control events.  They tell the +view to refresh the label of the PDA program.  The flags needed to +refresh the stack frames are added to the delta by the +StackFramesVMNode.
  • +
  • Line 280 adds a delta element to the parent delta.  With a +call to AbstractDMVMNode.createVMContext(), +it creates a wrapper element based on the Data Model context contained +in the event. 
    +
  • +
  • Lines 282-287 handle the started event, which is issued when the +PDACommandControl service is initialized.  It causes the PDA +context to be selected.
    +
  • +
  • Line 288 completes the execution of this asynchronous method.
  • +
+ + + + + + +
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 costomized 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.
+

Step 4 - Run Control

+Up to this point most of the work in creating the new PDA debugger has +gone into infrastructure.  Now it is time to start adding +functionality to do some actual debugging.  The work needed to get +run control functionality implemented is all encapsulated in the PDARunControl service.
+

State Tracking

+The primary function of the run control system is to track the current +execution state of the program and to issue the corresponding events to +the run control service clients.  Both of these tasks are +accomplished by the ICommandControl's IEventListner.eventReceived() +implementation in combination with service event handlers for +IRunControl.IResumedDMEvent and IRunControl.ISuspendedDMEvent.  It +may seem odd that the run control service is listening to its own +events in order to change its internal state, but doing so guarantees +that the execution state reported by the service is consistent with the +events it sends out.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDARunControl +- eventReceived()

+
+
181:     public void eventReceived(Object output) {
182: if (!(output instanceof String)) return;
183: String event = (String)output;
184:
185: // Handle PDA debugger suspended/resumed events and issue the
186: // corresponding Data Model events. Do not update the state
187: // information until we start dispatching the service events.
188: if (event.startsWith("suspended")) {
189: IDMEvent<?> dmEvent = new SuspendedEvent(fCommandControl.getProgramDMContext(), event);
190: getSession().dispatchEvent(dmEvent, getProperties());
191: } else if (event.startsWith("resumed")) {
192: IDMEvent<?> dmEvent = new ResumedEvent(fCommandControl.getProgramDMContext(), event);
193: getSession().dispatchEvent(dmEvent, getProperties());
194: }
195: }
196:
197:
198: @DsfServiceEventHandler
199: public void eventDispatched(ResumedEvent e) {
200: // This service should be the first to receive the ResumedEvent,
201: // (before any other listeners are called). Here, update the
202: // service state information based on the the resumed event.
203: fSuspended = false;
204: fResumePending = false;
205: fStateChangeReason = e.getReason();
206: fStepping = e.getReason().equals(StateChangeReason.STEP);
207: }
208:
209:
210: @DsfServiceEventHandler
211: public void eventDispatched(SuspendedEvent e) {
212: // This service should be the first to receive the SuspendedEvent also,
213: // (before any other listeners are called). Here, update the
214: // service state information based on the the suspended event.
215: fStateChangeReason = e.getReason();
216: fResumePending = false;
217: fSuspended = true;
218: fStepping = false;
219: }
+
+
    -
  • Cut and Paste
  • +
  • Lines 181-195 implement the IEventListener.eventReceived() +method.  This method is called any time an out of band record is +received from the PDA debugger. 
    +
  • +
  • Lines 182, 183 cast the opaque output object from PDA debugger to +a String.  The type of this object depends on the specific +debugger connection implementation.  For the PDA debugger, the +events are always a String.
  • +
  • Lines 188-193 generate the suspended/resumed Data Model events.
  • +
  • Lines 199-207 implement the ResumedEvent Data Model event +handler.  This handler is guaranteed to be called first by the DSF +service event framework, before any other listeners are called. It +updates the flags tracking the current state of the debugger.  As +usual, no synchronization is needed because these flags can only be +modified in the session executor thread.
  • +
  • Line 205 retrieves the state change reason from the resumed +event.  This reason is calculated by the ResumedEvent constructor based on +the event string received from the PDA debugger.
  • +
  • Lines 211-219 update the state flags based on the stopped event.
-

Launching
-

+One remarkable aspect of the state tracking logic is the use of the fResumePending flag.  This +flag is set to true when a resume or step command is sent to the PDA +debugger.  It is then used by the canResume() method to disallow +sending another resume command.  This kind of predictive state +logic an improve the efficiency of the IDE commands.
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDARunControl +- canResume()

+
+
222:     public boolean canResume(IExecutionDMContext context) {
223: return isSuspended(context) && !fResumePending;
224: }
+
+
+

Commands

+The command control commands all follow the same patter shown below by +example of the resume() command:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDARunControl +- resume()

+
+
238:     public void resume(IExecutionDMContext context, final RequestMonitor rm) {
239: assert context != null;
240:
241: if (canResume(context)) {
242: fResumePending = true;
243: fCommandControl.queueCommand(
244: new PDAResumeCommand(fCommandControl.getProgramDMContext()),
245: new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
246: @Override
247: protected void handleErrorOrCancel() {
248: // If the resume command failed, we no longer
249: // expect to receive a resumed event.
250: fResumePending = false;
251: super.handleErrorOrCancel();
252: }
253: }
254: );
255: } else {
256: PDAPlugin.failRequest(rm, INVALID_STATE, "Given context: " + context + ", is already running.");
257: }
258: }
+
+
    -
  • Create custom launch object PDALaunch
  • -
-
 51:     public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {

52: // Need to configure the source locator before creating the launch
53: // because once the launch is created and added to launch manager,
54: // the adapters will be created for the whole session, including
55: // the source lookup adapter.
56: ISourceLocator locator = getSourceLocator(configuration);

58: return new PDALaunch(configuration, mode, locator);
59: }
-
    -
  • Creating DSF session and executor
  • -
  • Services Initialize Sequence
  • -
  • Optional diagram showing the relationship between the above
  • -
  • Shutting down (is hard to do)
    +
  • Line 241 checks if the resume command can be called.  If +not, the command fails immediately.
  • +
  • Line 242 updates the fResumePending +state flag.
  • +
  • Lines 244-253 send the resume command to the PDA debugger.
    +
  • +
  • Lines 247-252 adds error handling in case the result command +fails.  It resotres the service state.
  • +
  • Line 251 calls the super class's handleErrorOrCancel() +method.  The super class relays the error status to the parent +request monitor and completes it.
-

Connecting
-

-
    -
  • First service, mechanics of DSF services?
  • -
  • Sockets, queues, synchronization
  • -
  • Diagram showing relationship of different command control -components
    -
  • -
  • Event and command listeners
    -
  • -
-

View Model

-
    -
  • The adapter glue
  • -
  • View Model components
    -
  • -
  • Launch view VM provider
  • -
  • Program VM Node
    -
  • -
-

Run Control

  • Second service, depends on command control
  • Tracking program running state
-

Breakpoints

+

IExecutionDMData

+There is very little data that the run control servie interface returns +for a given execution context.  The intention behind this is to +allow the service to remain very generic and thus applicable to any +debugger.  In specific debuggers, additional data about processes, +threads, cores, etc, should be retrieved from other services or service +extensions.  IExpressionDMData is the only object which is +retrieved asynchronously from the run control service, and it only +contains the state change reason for the last debugger state +change. 
+

Step 5 - Breakpoints

+Managing breakpoints is one of the complicated tasks that need to be +implemented by Eclipse debuggers.  The source of this complexity +is the fact that Eclipse breakpoints (IDE breakpoints) are managed +independently of breakpoints that are installed in the debugger +(target-side breakpoints).  The Eclipse debugger integration has +to keep these two sets of breakpoints synchronized. 
+

IDE Breakpoints

+Eclipse breakpoints are based on markers, which are special tags in the +Eclispe resource system and are associated with files and +folders.  By using markers, breakpoints gain the benefit of the +resource system synchronization mechanism and the automatic +persistence.  Also some other cool features such as adjusting the +breakpoint line number when the source file is edited, are also +automatically gained by using markers. 
+

An eclipse breakpoint declaration comes in three parts:
+

+
    +
  1. org.eclipse.core.resources.markers extension - A debugger must +use this extension to declare a marker type for the new +breakpoint.  Markers are hierarchical and a breakpoint should have +one of the platform breakpoint objects as a super type.
  2. +
  3. org.eclipse.debug.core.breakpoints extension - A breakpoint must +be declared using this extension point, which requires a valid marker +type.
  4. +
  5. org.eclipse.debug.core.model.IBreakpoint implementation - A +breakpoint object must implement this interface.
  6. +
+Finally, in order to have breakpoints to appear in the Breakpoints +view, they need to be registered with the breakpoint manager, which is +represented by the org.eclipse.debug.core.IBreakpointManager +interface.  The breakpoint manager also relays events for +notifying of breakpoint changes and for a debugger it is the central +object used to find the IDE breakpoints that need to be installed on +target.
+
+Code listings are omitted here since implementing Eclipse breakpoints +is described in fine detail the How +to write an Eclipse debugger article.
+

+

Target-Side Breakpoints

+DSF defines the IBreakpoints interface for a service which the fuctions +of managing breakpoints installed on the target.  These functions +include:
+
    +
  • Installing a breakpoint
    +
  • +
  • removing a breakpoint
  • +
  • changing breakpoint attributes (if supported)
  • +
  • listing installed breakpoints
  • +
  • retrieving breakpoint detailed data
  • +
+

Breakpoint Context
+

+It is expected that primary client of this service is going to be +another service which reads IDE Breakpoints, however under certain +circumstances such as launching or testing, this interface could be +used by other clients, therefore it is desirable that the interface +itself should not have any dependencies on the IDE Breakpoint +API.  To remain generic, the attributes for breakpoints to be +created or update are specified using a simple property bag of type: Map<String, Object>.  +After the target-side breakpoint is created, it is represented using an +opaque Data Model context of type IBreakpointDMContext.  +As an example the PDA line breakpoint context implementation is the +following:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDABreakpoints +- BreakpointDMContext

+
+
 50:     private static class BreakpointDMContext extends AbstractDMContext implements IBreakpointDMContext {
51:
52: final Integer fLine;
53:
54: public BreakpointDMContext(String sessionId, PDAProgramDMContext commandControlCtx, Integer line) {
55: super(sessionId, new IDMContext[] { commandControlCtx });
56: fLine = line;
57: }
58:
59: @Override
60: public boolean equals(Object obj) {
61: return baseEquals(obj) && (fLine.equals(((BreakpointDMContext) obj).fLine));
62: }
63:
64: @Override
65: public int hashCode() {
66: return baseHashCode() + fLine.hashCode();
67: }
68:
69: @Override
70: public String toString() {
71: return baseToString() + ".breakpoint(" + fLine + ")"; //$NON-NLS-1$//$NON-NLS-2$*/
72: }
73: }

+
+
+
    +
  • Line 52 declares the fLine variable, which uniquely identifies a +line breakpoint in a PDA debug session.
  • +
+It is also important to note that the IBreakpoints interface is +designed to work with debuggers that can track separate breakpoint sets +for different cores/processes/threads.  Each context which +represents a "breakpoint space" must implement an IBreakpointsTargetDMContext +interface, which is then used as a parent context of the IBreakpointDMContext object +instances.
+

Inserting a Breakpoint

+PDA debugger supports two types of breakpoints.  The +IBreakpoints.insertBreakpoint() implementation performs the task of +what type of breakpoint should be installed and delegates to the proper +subroutine:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDABreakpoints +- insertBreakpoint()

+
+
180:         public void insertBreakpoint(IBreakpointsTargetDMContext context, Map<String, Object> attributes, 
181: DataRequestMonitor<IBreakpointDMContext> rm)
182: {
183: Boolean enabled = (Boolean)attributes.get(IBreakpoint.ENABLED);
184: if (enabled != null && !enabled.booleanValue()) {
185: // If the breakpoint is disabled, just fail the request.
186: PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint is disabled");
187: } else {
188: String type = (String) attributes.get(ATTR_BREAKPOINT_TYPE);
189:
190: if (PDA_LINE_BREAKPOINT.equals(type)) {
191: // Retrieve the PDA program context from the context given in the
192: // argument. This service is typically only called by the
193: // breakpoints mediator, which was called with the program context
194: // in the services initialization sequence. So checking if
195: // programCtx != null is mostly a formality.
196: PDAProgramDMContext programCtx = DMContexts.getAncestorOfType(context, PDAProgramDMContext.class);
197: if (programCtx != null) {
198: doInsertBreakpoint(programCtx, attributes, rm);
199: } else {
200: PDAPlugin.failRequest(rm, INVALID_HANDLE, "Unknown breakpoint type");
201: }
202: }
203: else if (PDA_WATCHPOINT.equals(type)) {
204: doInsertWatchpoint(attributes, rm);
205: }
206: else {
207: PDAPlugin.failRequest(rm, REQUEST_FAILED, "Unknown breakpoint type");
208: }
209: }
210: }
+
+
+
    +
  • Lines 183-186 determine if the breakpoint is enabled.  If it +is not, the insert command fails with an expected error. 
    +
  • +
  • Line 188 retrieves the breakpoint type attribute, shich is used +to determine which breakpoint insert subroutine to call.
  • +
  • Line 196 retrieves the PDAProgramDMContext +from the breakpoint target context.  This context is the only +breakpoints target context in the PDA debugger.
  • +
  • Finally, lines 198 and 207 delegate to the proper subroutine to +create the breakpoint.
  • +
+The doInserBreakpoint() subroutine is listed next:
+
+
+ + + + + + + + + + +
org.eclipse.dd.examples.pda.service.PDABreakpoints +- doInsertBreakpoint()

+
+
212:     private void doInsertBreakpoint(PDAProgramDMContext programCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm) 
213: {
214: // Compare the program path in the breakpoint with the path in the PDA
215: // program context. Only insert the breakpoint if the program matches.
216: String program = (String)attributes.get(ATTR_PROGRAM_PATH);
217: if (!programCtx.getProgram().equals(program)) {
218: PDAPlugin.failRequest(rm, REQUEST_FAILED, "Invalid file name");
219: return;
220: }

222: // Retrieve the line.
223: Integer line = (Integer)attributes.get(IMarker.LINE_NUMBER);
224: if (line == null) {
225: PDAPlugin.failRequest(rm, REQUEST_FAILED, "No breakpoint line specified");
226: return;
227: }

229: // Create a new breakpoint context object and check that it's not
230: // installed already. PDA can only track a single breakpoint at a
231: // given line, attempting to set the second breakpoint should fail.
232: final BreakpointDMContext breakpointCtx =
233: new BreakpointDMContext(getSession().getId(), fCommandControl.getProgramDMContext(), line);
234: if (fBreakpoints.contains(breakpointCtx)) {
235: PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already set");
236: return;
237: }

239: // Add the new breakpoint context to the list of known breakpoints.
240: // Adding it here, before the set command is completed will prevent
241: // a possibility of a second breakpoint being installed in the same
242: // location while this breakpoint is being processed. It will also
243: // allow the breakpoint to be removed or updated even while it is
244: // still being processed here.
245: fBreakpoints.add(breakpointCtx);
246: fCommandControl.queueCommand(
247: new PDASetBreakpointCommand(fCommandControl.getProgramDMContext(), line),
248: new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
249: @Override
250: protected void handleOK() {
251: rm.setData(breakpointCtx);
252: rm.done();
253: }

255: @Override
256: protected void handleErrorOrCancel() {
257: // If inserting of the breakpoint failed, remove it from
258: // the set of installed breakpoints.
259: fBreakpoints.remove(breakpointCtx);
260: super.handleErrorOrCancel();
261: }
262: });
263: }

+
+
+

Removing a Breakpoint

+The PDABreakpoints.removeBreakpoint() command takes the +IBreakpointDMContext as an argument, but otherwise follows the same +general logic as the insertBreakpoint() implementation.
+

Updating a Breakpoint

+Updating a breakpoint involves motifying some of the attributes of an +existing breakpoint.  Not all debuggers may support this +functionality and for debuggers that do, not all types of breakpoints +and not all attributes may be updated.  The IBreakpoints interface +does not provide a way for the clients to discover what breakpoints and +what attributes may be updated.  It is up to the client to know +this information in advance. 
+

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) {
368: if (!fBreakpoints.contains(bpCtx)) {
369: PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint not installed");
370: return;
371: }

373: if (bpCtx instanceof BreakpointDMContext) {
374: PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Modifying PDA breakpoints is not supported");
375: } else if (bpCtx instanceof WatchpointDMContext) {
376: WatchpointDMContext wpCtx = (WatchpointDMContext)bpCtx;
377: if (!wpCtx.fFunction.equals(attributes.get(PDAWatchpoint.FUNCTION_NAME)) ||
378: !wpCtx.fVariable.equals(attributes.get(PDAWatchpoint.VAR_NAME)) )
379: {
380: PDAPlugin.failRequest(rm, REQUEST_FAILED, "Cannot modify watchpoint function or variable");
381: return;
382: }
383:
384: // PDA debugger can only track one watchpoint in the same location,
385: // so we can simply remove the existing context from the set and
386: // call insert again.
387: fBreakpoints.remove(bpCtx);
388: doInsertWatchpoint(
389: attributes,
390: new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), rm) {
391: @Override
392: protected void handleOK() {
393: // The inserted watchpoint context will equal the
394: // current context.
395: assert bpCtx.equals(getData());
396: rm.done();
397: }
398: });
399: } else {
400: PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoint");
401: }
402: }

+
+
+
    +
  • Lines 368-371 verify that the given breakpoint exists.  If +it does not exist the update request fails. 
    +
  • +
  • Lines 377-382 verify that only the data access attributes of the +watchpoint were modified.
  • +
  • Lines 387 -398 re-insert the watchpoint which effectively updates +the watchpoint attributes.
    +
  • +
  • Target Side Breakpoints
  • Mediator
  • Diagram showing Mediator's role
-

Stack

+

Step 6 - Stack

  • Command Cache at work
-

Source Display

+

Step 7 - Source Display

  • Source lookup director
-

Variables

+

Step 8 - Variables

  • Reading and writing variables
  • @@ -150,5 +2232,23 @@ components
  • Expressions view
+
+ + + + + + + + + + +
org.eclipse.dd.examples.dsf.timers.TimersVMNode +

+

+
+