mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
3025 lines
176 KiB
HTML
3025 lines
176 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<html>
|
|
<head>
|
|
<title>How to write a DSF-based debugger</title>
|
|
</head>
|
|
<body>
|
|
<h1 style="text-align: center;">How to write a DSF-based debugger <br>
|
|
</h1>
|
|
<h4><a class="mozTocH4" name="mozTocId986718"></a>Summary</h4>
|
|
This tutorial describes the process of integrating a debugger with
|
|
Eclipse using the Debugger Services Framework (DSF) developed by the <a
|
|
href="http://www.eclipse.org/dsdp/dd/">DSDP Device Debugging </a>project.<br>
|
|
<h4><a class="mozTocH4" name="mozTocId443083"></a>Table of Contents</h4>
|
|
<ul class="readonly" id="mozToc">
|
|
<!--mozToc h2 1 h3 2-->
|
|
<li><a href="#mozTocId733947"> 1 Push Down Automata
|
|
(PDA) </a>
|
|
<ul>
|
|
<li><a href="#mozTocId421423">1.1 Running the
|
|
Example</a></li>
|
|
<li><a href="#mozTocId60418">1.2 Language</a></li>
|
|
<li><a href="#mozTocId662812">1.3 Debug Protocol</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mozTocId351550">2 Step 1 - Launching </a>
|
|
<ul>
|
|
<li><a href="#mozTocId265932">2.1 Launch Delegate</a></li>
|
|
<li><a href="#mozTocId33333">2.2 PDALaunch</a></li>
|
|
<li><a href="#mozTocId247519">2.3 Launch/Shutdown
|
|
Sequence</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mozTocId17855">3 Step 2 -
|
|
Connecting </a>
|
|
<ul>
|
|
<li><a href="#mozTocId197410">3.1 Synchronization</a></li>
|
|
<li><a href="#mozTocId109235">3.2 Command/Event
|
|
Listeners</a></li>
|
|
<li><a href="#mozTocId233698">3.3 PDAProgramDMContext</a></li>
|
|
<li><a href="#mozTocId223991">3.4 PDA Commands</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mozTocId989042">4 Step
|
|
3 - View Model</a>
|
|
<ul>
|
|
<li><a href="#mozTocId558380">4.1 Adapter Glue</a></li>
|
|
<li><a href="#mozTocId59724">4.2 PDA View Model</a></li>
|
|
<li><a href="#mozTocId222824">4.3 Launch VM Provider</a></li>
|
|
<li><a href="#mozTocId22521">4.4 PDA Program VM Node</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mozTocId819534">5 Step 4 - Run Control</a>
|
|
<ul>
|
|
<li><a href="#mozTocId333707">5.1 State Tracking</a></li>
|
|
<li><a href="#mozTocId120075">5.2 Commands</a></li>
|
|
<li><a href="#mozTocId976358">5.3 IExecutionDMData</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mozTocId325852">6 Step 5 - Breakpoints</a>
|
|
<ul>
|
|
<li><a href="#mozTocId19247">6.1 IDE Breakpoints</a></li>
|
|
<li><a href="#mozTocId991346">6.2 Target-Side
|
|
Breakpoints</a></li>
|
|
<li><a href="#mozTocId389907">6.4 Breakpoints Mediator</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mozTocId380385">7 Step 6 - Stack</a>
|
|
<ul>
|
|
<li><a href="#mozTocId378363">7.1 Command Cache</a></li>
|
|
<li><a href="#mozTocId923476">7.2 Frame Context</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mozTocId156503">8 Step 7 - Source
|
|
Display</a></li>
|
|
<li><a href="#mozTocId343062">9 Step 8 - Variables</a>
|
|
<ul>
|
|
<li><a href="#mozTocId837286">9.1 Variable Contexts</a></li>
|
|
<li><a href="#mozTocId327572">9.2 Expression Contexts</a></li>
|
|
<li><a href="#mozTocId668928">9.3 Expression Data
|
|
</a></li>
|
|
<li><a href="#mozTocId233056">9.4 Formatted Value
|
|
Context
|
|
</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mozTocId840787">10 Additional Resources
|
|
</a>
|
|
<ul>
|
|
<li><a href="#mozTocId824835">10.1 Debug Platform</a></li>
|
|
<li><a href="#mozTocId512801">10.2 GDB</a></li>
|
|
<li><a href="#mozTocId126766">10.3 TCF</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h4>Copyright</h4>
|
|
Copyright (c) 2005, 2008 IBM Corporation and others. All rights
|
|
reserved. This program and the accompanying materials are made
|
|
available under the terms of the Eclipse Public License v1.0 which
|
|
accompanies this distribution, and is available at
|
|
http://www.eclipse.org/legal/epl-v10.html<br>
|
|
<br>
|
|
Contributors:<br>
|
|
<ul>
|
|
<li>IBM Corporation - initial content</li>
|
|
<li>Wind River Systems - adapted article to use with DSF<br>
|
|
</li>
|
|
</ul>
|
|
<hr style="width: 100%; height: 2px;">
|
|
<h2><a class="mozTocH2" name="mozTocId733947"></a> 1 Push Down Automata
|
|
(PDA) <br>
|
|
</h2>
|
|
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.<br>
|
|
<h3><a class="mozTocH3" name="mozTocId421423"></a>1.1 Running the
|
|
Example</h3>
|
|
Launch the PDA debugger with these twelve "easy" steps:<br>
|
|
<ol>
|
|
<li>Download and install Eclipse development environment, either the <span
|
|
style="font-style: italic;">Eclipse Classic 3.4 </span>or <span
|
|
style="font-style: italic;">Eclipse IDE for C/C++ Developers</span><br>
|
|
</li>
|
|
<li>Install the DSF SDK feature to build against, by performing
|
|
either:<br>
|
|
</li>
|
|
<ol style="list-style-type: lower-alpha;">
|
|
<li>Using update manager, install the <span
|
|
style="font-style: italic;">Debugger Services Framework end-user and
|
|
extender SDK</span>, found in the <span style="font-style: italic;">Ganymede
|
|
Discovery Site</span> under <span style="font-style: italic;">Remote
|
|
Access and Device Development</span>.</li>
|
|
<li>Check out <span style="font-style: italic;">org.eclipse.dd.dsf
|
|
and org.eclipse.dd.dsf.ui</span> plugins, found in the <span
|
|
style="font-style: italic;">/cvsroot/dsdp</span> repository under <span
|
|
style="font-style: italic;">org.eclipse.dd.dsf/plugins</span>
|
|
directory.</li>
|
|
</ol>
|
|
<li>Check out the <span style="font-style: italic;">org.eclipse.dd.examples.pda</span>
|
|
and <span style="font-style: italic;">org.eclipse.dd.examples.pda.ui </span>plugins,
|
|
found <span style="font-style: italic;">/cvsroot/dsdp</span> in the <span
|
|
style="font-style: italic;">org.eclipse.dd.dsf/plugins</span>
|
|
directory.</li>
|
|
<li>Build the PDA plugins.</li>
|
|
<li>Create an instance of an <span style="font-style: italic;">Eclipse
|
|
Application</span> launch configuration and launch it in Debug mode.<br>
|
|
</li>
|
|
<li>Switch to the new Eclipse IDE Application</li>
|
|
<li>Create a new empty project: <br>
|
|
</li>
|
|
<ol style="list-style-type: lower-alpha;">
|
|
<li>Select the <span style="font-style: italic;">File->New->Project...</span>
|
|
action</li>
|
|
<li>Select <span style="font-style: italic;">General->Project</span>
|
|
in the <span style="font-style: italic;">New Project</span> dialog.</li>
|
|
<li>Enter a name for the new project (e.g. "PDA")</li>
|
|
</ol>
|
|
<li>Link in the folder with PDA examples from the <span
|
|
style="font-style: italic;">org.eclipse.dd.examples.pda</span> plugin.</li>
|
|
<ol style="list-style-type: lower-alpha;">
|
|
<li>Right-click on the new Project and select <span
|
|
style="font-style: italic;">New->Folder</span><br>
|
|
</li>
|
|
<li>Click on the <span style="font-style: italic;">Advanced
|
|
>></span> button at the bottom of the <span
|
|
style="font-style: italic;">New Folder</span> dialog.</li>
|
|
<li>Select the <span style="font-style: italic;">Link to folder in
|
|
the filesystem</span> check box.</li>
|
|
<li>Type in or browse to the <span style="font-style: italic;">samples</span>
|
|
directory found in the <span style="font-style: italic;">org.eclipse.dd.examples.pda</span>
|
|
plugin.</li>
|
|
</ol>
|
|
<li>Open the PDA editor by double-clicking on the PDA file (e.g. <span
|
|
style="font-style: italic;">fibonacci.pda)</span>. See note
|
|
below.<br>
|
|
</li>
|
|
<li>Set a breakpoint in the program by double-clicking in the editor
|
|
gutter.</li>
|
|
<li>Launch the PDA debugger</li>
|
|
<ol style="list-style-type: lower-alpha;">
|
|
<li>Set the <span style="font-style: italic;">dsfPerlDebugger</span>
|
|
variable to point to the Perl executable in your system.
|
|
Variables can be set in the <span style="font-style: italic;">Windows->Preferences->Run/Debug->String
|
|
Substitution</span> preference page.</li>
|
|
<li>Create a new launch configuration of type <span
|
|
style="font-style: italic;">DSF PDA Application</span></li>
|
|
<li>In the Main tab, enter the workspace path to the program name
|
|
(e.g. <span style="font-style: italic;">/PDA/samples/fibonacci.pda</span>).</li>
|
|
<li>Select <span style="font-style: italic;">Debug</span> to
|
|
launch the PDA debugger.</li>
|
|
</ol>
|
|
<li>Step, select stack frames, debug...</li>
|
|
</ol>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">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: <img
|
|
style="width: 16px; height: 16px;" alt="" title="PDA debugger icon."
|
|
src="pda.gif"> </td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<br>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">Note: A Perl
|
|
interpreter is required for PDA. Linux®™ comes with Perl. For
|
|
Microsoft®
|
|
Windows®, we use either ActivePerl (<a
|
|
href="http://www.activeperl.com/">http://www.activeperl.com/</a>) or
|
|
Indigo Perl (<a href="http://www.indigostar.com/">http://www.indigostar.com/</a>).<br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h3><a class="mozTocH3" name="mozTocId60418"></a>1.2 Language</h3>
|
|
<p>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:</p>
|
|
<ul>
|
|
<li>Our language has a control stack and thus has call-return
|
|
subroutines.</li>
|
|
<li>Our language allows data to be stored either on the data stack or
|
|
in named variables on the control stack.</li>
|
|
</ul>
|
|
<p>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):</p>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">samples/fibonacci.pda</span><br>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre>push 6<br>call Fibonacci <i>function call with one argument on the data stack</i><br>output <i>print result to stdout</i><br>halt<br>#<br># f(n) = f(n-1) + f(n-2)<br># f(0) = 1<br># f(1) = 1<br>#<br>:fibonacci<br>var n <i>define variable n on control stack</i><br>pop $n <i>get n from data stack</i><br>push $n<br>branch_not_zero gt0<br>push 1 <i>f(0) = 1</i><br><br>return <i>return with one value on data stack</i><br>:gt0 <br>push $n<br>dec<br>branch_not_zero gt1<br>push 1 <i>f(1) = 1</i><br>return <i>return with one value on data stack</i><br>:gt1<br>push $n <i>stack: n</i><br>dec <i>stack: n-1</i><br>call fibonacci <i>stack: f(n-1)</i><br><br>push $n <i>stack: f(n-1) n</i><br>dec <i>stack: f(n-1) n-1</i><br>dec <i>stack: f(n-1) n-2</i><br>call Fibonacci <i>stack: f(n-1) f(n-2)</i><br>add <i>stack: f(n-1)+f(n-2)</i><br>return <i>return with one value on data stack</i></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h3><a class="mozTocH3" name="mozTocId662812"></a>1.3 Debug Protocol</h3>
|
|
<p>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 <span style="font-style: italic;">org.eclipse.dd.examples.pda/pdavm/docs/protocol.html</span>,
|
|
but the lists below show a quick overview.<br>
|
|
</p>
|
|
<p>The commands include:</p>
|
|
<ul>
|
|
<li><samp>clear N</samp> – clear the breakpoint on line N</li>
|
|
<li><samp>data</samp> – return the contents of the data stack; the
|
|
data is returned from oldest to newest as a single string
|
|
“value|value|value|…|value|”</li>
|
|
<li><samp>exit</samp> – end the interpreter</li>
|
|
<li><samp>resume</samp> – resume full speed execution of the program</li>
|
|
<li><samp>set N</samp> – set a breakpoint on line N</li>
|
|
<li><samp>stack</samp> – 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”</li>
|
|
<li><samp>step</samp> – single step forward</li>
|
|
<li><samp>suspend</samp> – end full speed execution and listen for
|
|
debug commands</li>
|
|
<li><samp>var N M</samp> – return the contents of a variable M from
|
|
the control stack frame N (stack frames are indexed from 0).</li>
|
|
</ul>
|
|
<p>The debug events that are reported asynchronously to the second
|
|
socket include:</p>
|
|
<ul>
|
|
<li><samp>started</samp> – the interpreter has started (guaranteed to
|
|
be the first event sent)</li>
|
|
<li><samp>terminated</samp> – the interpreter has terminated
|
|
(guaranteed to be the last event sent)</li>
|
|
<li><samp>suspended X</samp> – the interpreter has suspended and
|
|
entered debug mode; X is the cause of the suspension, either step or
|
|
client or breakpoint N</li>
|
|
<li><samp>resumed X</samp> – the interpreter has resumed execution in
|
|
run mode; X is the cause of the resume, either step or client</li>
|
|
<li><samp>unimplemented instruction X</samp> – an unimplemented
|
|
instruction was encountered</li>
|
|
<li><samp>no such label X</samp> – a branch or call to an unknown
|
|
label was encountered</li>
|
|
</ul>
|
|
<h2><a class="mozTocH2" name="mozTocId351550"></a>2 Step 1 - Launching <br>
|
|
</h2>
|
|
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 <i><a
|
|
href="http://www.eclipse.org/articles/Article-Launch-Framework/launch.html">We
|
|
Have Lift-off: The Launching Framework in Eclipse</a> </i>article.
|
|
This section (as this tutorial) concentrates on the DSF-specific tasks
|
|
of launching the PDA debugger.<br>
|
|
<h3><a class="mozTocH3" name="mozTocId265932"></a>2.1 Launch Delegate</h3>
|
|
At first glance, there's nothing unusual about the PDA debugger launch
|
|
delegate. Just like the Debug Platform version it:<br>
|
|
<ol>
|
|
<li>finds the Perl executable,</li>
|
|
<li>finds free socket ports for debugger communication,</li>
|
|
<li>finds the PDA program</li>
|
|
<li>launches Perl to run the interpreter</li>
|
|
</ol>
|
|
The major difference is that it does not create an instance of the
|
|
standard debug model <span style="font-style: italic;">IDebugTerget</span>
|
|
object. Instead it implements the <span
|
|
style="font-style: italic;">getLaunch()</span> method in the <span
|
|
style="font-style: italic;">ILaunchConfigurationDelegate2</span>
|
|
extension interface, in order to create a custom launch object:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.launch.PDALaunchDelegate
|
|
- getLaunch()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre width="200"><a name="line51"> 51: </a><strong><font
|
|
color="#4169e1"> public ILaunch getLaunch(ILaunchConfiguration configuration, String mode)</font></strong> <font
|
|
color="#4169e1">throws</font> CoreException {<br><br><a name="line52"> 52: </a> <font
|
|
color="#b22222"> // Need to configure the source locator before creating the launch</font><br><a
|
|
name="line53"> 53: </a> <font color="#b22222"> // because once the launch is created and added to launch manager,</font><br><a
|
|
name="line54"> 54: </a> <font color="#b22222"> // the adapters will be created for the whole session, including </font><br><a
|
|
name="line55"> 55: </a> <font color="#b22222"> // the source lookup adapter.</font><br><a
|
|
name="line56"> 56: </a> ISourceLocator locator = getSourceLocator(configuration);<br><br><a
|
|
name="line58"> 58: </a> <font color="#4169e1"> return</font> new PDALaunch(configuration, mode, locator);<br><a
|
|
name="line59"> 59: </a> }<i><br></i></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
</ul>
|
|
<h3><a class="mozTocH3" name="mozTocId33333"></a>2.2 PDALaunch</h3>
|
|
The PDALaunch object plays two main roles:<br>
|
|
<ol>
|
|
<li>Serve as the root element of the PDA View Model hierarchy</li>
|
|
<li>Manage the lifecycle of the DSF session, its services, and the
|
|
executor that belongs to the session. <br>
|
|
</li>
|
|
</ol>
|
|
The first task will be described in the View Model section, the second
|
|
task is described here. <br>
|
|
<br>
|
|
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.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"> <span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.launch.PDALaunch
|
|
- <<constructor>></span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line65"> 65: </a><strong><font color="#4169e1"> public PDALaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator)</font></strong> {<br><a
|
|
name="line66"> 66: </a> super(launchConfiguration, mode, locator);<br><br><a
|
|
name="line68"> 68: </a> <font color="#b22222">// Create the dispatch queue to be used by debugger control and services </font><br><a
|
|
name="line69"> 69: </a> <font color="#b22222">// that belong to this launch</font><br><a
|
|
name="line70"> 70: </a> final DefaultDsfExecutor dsfExecutor = new DefaultDsfExecutor(PDAPlugin.ID_PDA_DEBUG_MODEL);<br><a
|
|
name="line71"> 71: </a> dsfExecutor.prestartCoreThread();<br><a
|
|
name="line72"> 72: </a> fExecutor = dsfExecutor;<br><a
|
|
name="line73"> 73: </a> fSession = DsfSession.startSession(fExecutor, PDAPlugin.ID_PDA_DEBUG_MODEL);<br><a
|
|
name="line74"> 74: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Lines 70 and 73 create the executor and the session
|
|
respectively. <br>
|
|
</li>
|
|
</ul>
|
|
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.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"> <span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.launch.PDALaunch
|
|
- intializeServices()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line90"> 90: </a> @ConfinedToDsfExecutor(<font
|
|
color="#666666">"getSession().getExecutor()"</font>)<br><a
|
|
name="line91"> 91: </a><strong><font color="#4169e1"> public void initializeServices(String program, int requestPort, int eventPort, final RequestMonitor rm)</font></strong><br><a
|
|
name="line92"> 92: </a> {<br><a name="line93"> 93: </a> <font
|
|
color="#b22222">// Double-check that we're being called in the correct thread.</font><br><a
|
|
name="line94"> 94: </a> assert fExecutor.isInExecutorThread();<br><br><a
|
|
name="line96"> 96: </a> <font color="#b22222">// Check if shutdownServices() was called already, which would be </font><br><a
|
|
name="line97"> 97: </a> <font color="#b22222">// highly unusual, but if so we don't need to do anything except set </font><br><a
|
|
name="line98"> 98: </a> <font color="#b22222">// the initialized flag.</font><br><a
|
|
name="line99"> 99: </a> synchronized(this) {<br><a
|
|
name="line100">100: </a> <font color="#4169e1">if</font> (fShutDown) {<br><a
|
|
name="line101">101: </a> fInitialized = true;<br><a
|
|
name="line102">102: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line103">103: </a> }<br><a name="line104">104: </a> }<br><br><a
|
|
name="line106">106: </a> <font color="#b22222">// Register the launch as listener for services events.</font><br><a
|
|
name="line107">107: </a> fSession.addServiceEventListener(PDALaunch.this, null);<br><br><a
|
|
name="line109">109: </a> <font color="#b22222">// The initialization sequence is stored in a field to allow it to be </font><br><a
|
|
name="line110">110: </a> <font color="#b22222">// canceled if shutdownServices() is called before the sequence </font><br><a
|
|
name="line111">111: </a> <font color="#b22222">// completes.</font><br><a
|
|
name="line112">112: </a> fInitializationSequence = new PDAServicesInitSequence(<br><a
|
|
name="line113">113: </a> getSession(), program, requestPort, eventPort, <br><a
|
|
name="line114">114: </a> new RequestMonitor(ImmediateExecutor.getInstance(), rm) {<br><a
|
|
name="line115">115: </a> @Override<br><a name="line116">116: </a><strong><font
|
|
color="#4169e1"> protected void handleCompleted()</font></strong> {<br><a
|
|
name="line117">117: </a> <font color="#b22222">// Set the initialized flag and check whether the </font><br><a
|
|
name="line118">118: </a> <font color="#b22222">// shutdown flag is set. Access the flags in a </font><br><a
|
|
name="line119">119: </a> <font color="#b22222">// synchronized section as these flags can be accessed</font><br><a
|
|
name="line120">120: </a> <font color="#b22222">// on any thread.</font><br><a
|
|
name="line121">121: </a> boolean doShutdown = false;<br><a
|
|
name="line122">122: </a> synchronized (this) { <br><a
|
|
name="line123">123: </a> fInitialized = true;<br><a
|
|
name="line124">124: </a> fInitializationSequence = null;<br><a
|
|
name="line125">125: </a> <font color="#4169e1">if</font> (fShutDown) {<br><a
|
|
name="line126">126: </a> doShutdown = true;<br><a
|
|
name="line127">127: </a> }<br><a name="line128">128: </a> }<br><br><a
|
|
name="line130">130: </a> <font color="#4169e1">if</font> (doShutdown) {<br><a
|
|
name="line131">131: </a> <font color="#b22222">// If shutdownServices() was already called, start the </font><br><a
|
|
name="line132">132: </a> <font color="#b22222">// shutdown sequence now.</font><br><a
|
|
name="line133">133: </a> doShutdown(rm);<br><a
|
|
name="line134">134: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line135">135: </a> <font color="#b22222">// If there was an error in the startup sequence, </font><br><a
|
|
name="line136">136: </a> <font color="#b22222">// report the error to the client.</font><br><a
|
|
name="line137">137: </a> <font color="#4169e1">if</font> (getStatus().getSeverity() == IStatus.ERROR) {<br><a
|
|
name="line138">138: </a> rm.setStatus(getStatus());<br><a
|
|
name="line139">139: </a> }<br><a name="line140">140: </a> rm.done();<br><a
|
|
name="line141">141: </a> }<br><a name="line142">142: </a> fireChanged();<br><a
|
|
name="line143">143: </a> }<br><a name="line144">144: </a> });<br><br><a
|
|
name="line146">146: </a> <font color="#b22222">// Finally, execute the sequence. </font><br><a
|
|
name="line147">147: </a> getSession().getExecutor().execute(fInitializationSequence);<br><a
|
|
name="line148">148: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 90 declares the <span style="font-style: italic;">initializeServices()</span>
|
|
to be invoked only
|
|
within the session executor thread. This is to protect access to
|
|
the <span style="font-style: italic;">fInitializationSequence</span>
|
|
variable and to allow the call on line 112
|
|
to be made without use of another runnable.</li>
|
|
</ul>
|
|
Due to race conditions between debugger events and user commands, the <span
|
|
style="font-style: italic;">shutdownServices()</span> routine may be
|
|
invoked more than once. The shutdown logic must protect against
|
|
these race conditions.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"> <span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.launch.PDALaunch
|
|
- shutdownServices()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;">
|
|
<pre><a name="line202"></a><br></pre>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line202">202: </a> @ConfinedToDsfExecutor(<font
|
|
color="#666666">"getSession().getExecutor()"</font>)<br><a
|
|
name="line203">203: </a><strong><font color="#4169e1"> public void shutdownServices(final RequestMonitor rm)</font></strong> {<br><a
|
|
name="line204">204: </a> <font color="#b22222">// Check initialize and shutdown flags to determine if the shutdown</font><br><a
|
|
name="line205">205: </a> <font color="#b22222">// sequence can be called yet.</font><br><a
|
|
name="line206">206: </a> boolean doShutdown = false;<br><a
|
|
name="line207">207: </a> synchronized (this) {<br><a
|
|
name="line208">208: </a> <font color="#4169e1">if</font> (!fInitialized && fInitializationSequence != null) {<br><a
|
|
name="line209">209: </a> <font color="#b22222">// Launch has not yet initialized, try to cancel the </font><br><a
|
|
name="line210">210: </a> <font color="#b22222">// shutdown sequence.</font><br><a
|
|
name="line211">211: </a> fInitializationSequence.cancel(false);<br><a
|
|
name="line212">212: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line213">213: </a> doShutdown = !fShutDown && fInitialized;<br><a
|
|
name="line214">214: </a> }<br><a name="line215">215: </a> fShutDown = true;<br><a
|
|
name="line216">216: </a> }<br><br><a name="line218">218: </a> <font
|
|
color="#4169e1">if</font> (doShutdown) {<br><a name="line219">219: </a> doShutdown(rm);<br><a
|
|
name="line220">220: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line221">221: </a> rm.done();<br><a name="line222">222: </a> }<br><a
|
|
name="line223">223: </a> }<br><br><a name="line225">225: </a> @ConfinedToDsfExecutor(<font
|
|
color="#666666">"getSession().getExecutor()"</font>)<br><a
|
|
name="line226">226: </a><strong><font color="#4169e1"> private void doShutdown(final RequestMonitor rm)</font></strong> {<br><a
|
|
name="line227">227: </a> fExecutor.execute( new PDAServicesShutdownSequence(<br><a
|
|
name="line228">228: </a> fExecutor, fSession.getId(),<br><a
|
|
name="line229">229: </a> new RequestMonitor(fSession.getExecutor(), rm) { <br><a
|
|
name="line230">230: </a> @Override<br><a name="line231">231: </a><strong><font
|
|
color="#4169e1"> public void handleCompleted()</font></strong> {<br><a
|
|
name="line232">232: </a> fSession.removeServiceEventListener(PDALaunch.this);<br><a
|
|
name="line233">233: </a> <font color="#4169e1">if</font> (!getStatus().isOK()) {<br><a
|
|
name="line234">234: </a> PDAPlugin.getDefault().getLog().log(new MultiStatus(<br><a
|
|
name="line235">235: </a> PDAPlugin.PLUGIN_ID, -1, new IStatus[]{getStatus()}, <font
|
|
color="#666666">"Session shutdown failed"</font>, null)); <font
|
|
color="#b22222">//$NON-NLS-1$</font><br><a name="line236">236: </a> }<br><a
|
|
name="line237">237: </a> <font color="#b22222">// Last order of business, shutdown the dispatch queue.</font><br><a
|
|
name="line238">238: </a> DsfSession.endSession(fSession);<br><a
|
|
name="line239">239: </a> <font color="#b22222">// endSession takes a full dispatch to distribute the </font><br><a
|
|
name="line240">240: </a> <font color="#b22222">// session-ended event, finish step only after the dispatch.</font><br><a
|
|
name="line241">241: </a> fExecutor.shutdown();<br><a
|
|
name="line242">242: </a> fireTerminate();<br><br><a
|
|
name="line244">244: </a> rm.setStatus(getStatus());<br><a
|
|
name="line245">245: </a> rm.done();<br><a
|
|
name="line246">246: </a> }<br><a name="line247">247: </a> }) );<br><a
|
|
name="line248">248: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h3><a class="mozTocH3" name="mozTocId247519"></a>2.3 Launch/Shutdown
|
|
Sequence</h3>
|
|
The actual task of calling the asynchronous <span
|
|
style="font-style: italic;">IDsfService</span>'s <span
|
|
style="font-style: italic;">initialize()</span> and <span
|
|
style="font-style: italic;">shutdown()</span> methods is implemented
|
|
using the <span style="font-style: italic;">Sequence</span>
|
|
object. The following listing shows part of the declaration of
|
|
the
|
|
<span style="font-style: italic;">Sequence.Step</span> objects which
|
|
perform the service initialization:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.launch.PDAServicesInitSequence
|
|
- fSteps</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line38"> 38: </a> Step[] fSteps = new Step[] {<br><a
|
|
name="line39"> 39: </a> new Step() <br><a name="line40"> 40: </a> { <br><a
|
|
name="line41"> 41: </a> @Override<br><a name="line42"> 42: </a><strong><font
|
|
color="#4169e1"> public void execute(RequestMonitor requestMonitor)</font></strong> {<br><a
|
|
name="line43"> 43: </a> <font color="#b22222">// Create the connection to PDA debugger.</font><br><a
|
|
name="line44"> 44: </a> fCommandControl = new PDACommandControl(fSession, fProgram, fRequestPort, fEventPort);<br><a
|
|
name="line45"> 45: </a> fCommandControl.initialize(requestMonitor);<br><a
|
|
name="line46"> 46: </a> }<br><a name="line47"> 47: </a> },<br><a
|
|
name="line48"> 48: </a> new Step() { <br><a name="line49"> 49: </a> @Override<br><a
|
|
name="line50"> 50: </a><strong><font color="#4169e1"> public void execute(RequestMonitor requestMonitor)</font></strong> {<br><a
|
|
name="line51"> 51: </a> <font color="#b22222">// Start the run control service.</font><br><a
|
|
name="line52"> 52: </a> fRunControl = new PDARunControl(fSession);<br><a
|
|
name="line53"> 53: </a> fRunControl.initialize(requestMonitor);<br><a
|
|
name="line54"> 54: </a> }<br><a name="line55"> 55: </a> },<br><a
|
|
name="line56"> 56: </a> new Step() { <br><a name="line57"> 57: </a> @Override<br><a
|
|
name="line58"> 58: </a><strong><font color="#4169e1"> public void execute(RequestMonitor requestMonitor)</font></strong> {<br><a
|
|
name="line59"> 59: </a> <font color="#b22222">// Start the service to manage step actions.</font><br><a
|
|
name="line60"> 60: </a> new StepQueueManager(fSession).initialize(requestMonitor);<br><a
|
|
name="line61"> 61: </a> }<br><a name="line62"> 62: </a> },<br> ...<a
|
|
name="line63"></a><br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h2><a class="mozTocH2" name="mozTocId17855"></a>3 <a class="mozTocH2"
|
|
name="mozTocId867240"></a>Step 2 -
|
|
Connecting </h2>
|
|
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: <span style="font-style: italic;">ICommandControl</span>
|
|
which abstracts a debugger connection as a facility that processes
|
|
commands and generates events. The ICommandControl method allow
|
|
for three major functions:<br>
|
|
<ol>
|
|
<li><span style="text-decoration: underline;">Queue/Remove/Cancel
|
|
commands</span> - 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.</li>
|
|
<li><span style="text-decoration: underline;">Listening to Commands
|
|
Queued/Sent/Completed</span> - Clients can listen to all command
|
|
traffic in order to implement custom processing.</li>
|
|
<li><span style="text-decoration: underline;">Listening to Events</span>
|
|
- 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.<br>
|
|
</li>
|
|
</ol>
|
|
<span style="font-style: italic;"></span>
|
|
<table style="text-align: left; margin-left: auto; margin-right: auto;"
|
|
border="0" cellpadding="5" cellspacing="30">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: center; vertical-align: middle;"><img
|
|
style="width: 400px; height: 655px;"
|
|
title="PDA Command Control Diagram" alt="" src="connecting_1.png"><br>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top;"><small><span
|
|
style="font-weight: bold;">Image 1: PDA Command Control Diagram</span></small><br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h3><a class="mozTocH3" name="mozTocId197410"></a>3.1 <a
|
|
class="mozTocH3" name="mozTocId239705"></a>Synchronization</h3>
|
|
Since there are several threads being used by the PDA Command Control
|
|
protecting state data becomes very important. <br>
|
|
<br>
|
|
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:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDACommandControl
|
|
- members declaration</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;">
|
|
<pre><a name="line56"></a><br></pre>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line56"> 56: </a> <font color="#b22222">// Parameters that the command control is created with.</font><br><a
|
|
name="line57"> 57: </a> final private String fProgram;<br><a
|
|
name="line58"> 58: </a> final private int fRequestPort;<br><a
|
|
name="line59"> 59: </a> final private int fEventPort;<br><br><a
|
|
name="line61"> 61: </a> <font color="#b22222">// Queue of commands waiting to be sent to the debugger. As long as commands</font><br><a
|
|
name="line62"> 62: </a> <font color="#b22222">// are in this queue, they can still be removed by clients. </font><br><a
|
|
name="line63"> 63: </a> private final List<CommandHandle> fCommandQueue = new LinkedList<CommandHandle>();<br><a
|
|
name="line64"> 64: </a> <br><a name="line65"> 65: </a> <font
|
|
color="#b22222">// Queue of commands that are being sent to the debugger. This queue is read</font><br><a
|
|
name="line66"> 66: </a> <font color="#b22222">// by the send job, so as soon as commands are inserted into this queue, they can</font><br><a
|
|
name="line67"> 67: </a> <font color="#b22222">// be considered as sent.</font><br><a
|
|
name="line68"> 68: </a> @ThreadSafe<br><a name="line69"> 69: </a> private final BlockingQueue<CommandHandle> fTxCommands = new LinkedBlockingQueue<CommandHandle>();<br><a
|
|
name="line70"> 70: </a> <br><a name="line71"> 71: </a> <font
|
|
color="#b22222">// Flag indicating that the PDA debugger started</font><br><a
|
|
name="line72"> 72: </a> private boolean fStarted = false;<br><a
|
|
name="line73"> 73: </a> <br><a name="line74"> 74: </a> <font
|
|
color="#b22222">// Flag indicating that the PDA debugger has been disconnected </font><br><a
|
|
name="line75"> 75: </a> @ThreadSafe<br><a name="line76"> 76: </a> private boolean fTerminated = false;<br><a
|
|
name="line77"> 77: </a> <br><a name="line78"> 78: </a> <font
|
|
color="#b22222">// Data Model context of this command control. </font><br><a
|
|
name="line79"> 79: </a> private PDAProgramDMContext fDMContext;<br><br><a
|
|
name="line81"> 81: </a> <font color="#b22222">// Synchronous listeners for commands and events.</font><br><a
|
|
name="line82"> 82: </a> private final List<ICommandListener> fCommandListeners = new ArrayList<ICommandListener>();<br><a
|
|
name="line83"> 83: </a> private final List<IEventListener> fEventListeners = new ArrayList<IEventListener>();<br><a
|
|
name="line84"> 84: </a> <br><a name="line85"> 85: </a> <font
|
|
color="#b22222">// Sockets for communicating with PDA debugger </font><br><a
|
|
name="line86"> 86: </a> @ThreadSafe<br><a name="line87"> 87: </a> private Socket fRequestSocket;<br><a
|
|
name="line88"> 88: </a> @ThreadSafe<br><a name="line89"> 89: </a> private PrintWriter fRequestWriter;<br><a
|
|
name="line90"> 90: </a> @ThreadSafe<br><a name="line91"> 91: </a> private BufferedReader fRequestReader;<br><a
|
|
name="line92"> 92: </a> @ThreadSafe<br><a name="line93"> 93: </a> private Socket fEventSocket;<br><a
|
|
name="line94"> 94: </a> @ThreadSafe<br><a name="line95"> 95: </a> private BufferedReader fEventReader;<br><br><a
|
|
name="line97"> 97: </a> <font color="#b22222">// Jobs servicing the sockets.</font><br><a
|
|
name="line98"> 98: </a> private EventDispatchJob fEventDispatchJob;<br><a
|
|
name="line99"> 99: </a> private CommandSendJob fCommandSendJob;</pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ol>
|
|
</ol>
|
|
<ul>
|
|
<li>Line 63 declares the main command queue <span
|
|
style="font-style: italic;">fCommandQueue</span>. Commands sit
|
|
in this queue until the command channel is free to send.</li>
|
|
<li>Line 69 declares a second command queue <span
|
|
style="font-style: italic;">fTxCommands</span>. This queue is
|
|
used only as a means of synchronization with the send job.</li>
|
|
<li>Line 76 declares the <span style="font-style: italic;">fTerminated</span>
|
|
flag. It needs to be thread safe to allow the command and event
|
|
processing jobs to access it.<br>
|
|
</li>
|
|
<li>Lines 86-95 declare the communication sockets. They are
|
|
marked as thread-safe though only used by dedicated threads after being
|
|
created.</li>
|
|
</ul>
|
|
Following is an example of how the access to session-thread protected
|
|
variables is implemented.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDACommandControl.EventDispatchJob
|
|
- run()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line300">300: </a><strong><font color="#4169e1"> protected IStatus run(IProgressMonitor monitor)</font></strong> {<br><a
|
|
name="line301">301: </a> <font color="#4169e1">while</font> (!isTerminated()) {<br><a
|
|
name="line302">302: </a> <font color="#4169e1">try</font> {<br><a
|
|
name="line303">303: </a> <font color="#b22222">// Wait for an event.</font><br><a
|
|
name="line304">304: </a> final String event = fEventReader.readLine();<br><a
|
|
name="line305">305: </a> <font color="#4169e1">if</font> (event != null) {<br><a
|
|
name="line306">306: </a> <font color="#4169e1">try</font> {<br><a
|
|
name="line307">307: </a> <font
|
|
color="#b22222">// Process the event in executor thread.</font><br><a
|
|
name="line308">308: </a> getExecutor().execute(new DsfRunnable() {<br><a
|
|
name="line309">309: </a><strong><font color="#4169e1"> public void run()</font></strong> {<br><a
|
|
name="line310">310: </a> processEventReceived(event);<br><a
|
|
name="line311">311: </a> }<br><a
|
|
name="line312">312: </a> });<br><a
|
|
name="line313">313: </a> } <font color="#4169e1">catch</font> (RejectedExecutionException e) {} <br><a
|
|
name="line314">314: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line315">315: </a> <font color="#4169e1">break</font>;<br><a
|
|
name="line316">316: </a> }<br><a name="line317">317: </a> } <font
|
|
color="#4169e1">catch</font> (IOException e) {<br><a name="line318">318: </a> <font
|
|
color="#4169e1">break</font>;<br><a name="line319">319: </a> }<br><a
|
|
name="line320">320: </a> }<br><a name="line321">321: </a> <font
|
|
color="#4169e1">if</font> (!isTerminated()) {<br><a name="line322">322: </a> <font
|
|
color="#b22222">// Exception from the event socket is an indicator that the PDA debugger</font><br><a
|
|
name="line323">323: </a> <font color="#b22222">// has exited. Call setTerminated() in executor thread.</font><br><a
|
|
name="line324">324: </a> <font color="#4169e1">try</font> {<br><a
|
|
name="line325">325: </a> getExecutor().execute(new DsfRunnable() {<br><a
|
|
name="line326">326: </a><strong><font color="#4169e1"> public void run()</font></strong> {<br><a
|
|
name="line327">327: </a> setTerminated();<br><a
|
|
name="line328">328: </a> }<br><a name="line329">329: </a> });<br><a
|
|
name="line330">330: </a> } <font color="#4169e1">catch</font> (RejectedExecutionException e) {} <br><a
|
|
name="line331">331: </a> }<br><a name="line332">332: </a> <font
|
|
color="#4169e1">return</font> Status.OK_STATUS;<br><a name="line333">333: </a> }<br><a
|
|
name="line334">334: </a> <br><a name="line335">335: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<ul>
|
|
<li>Line 300 declares the <span style="font-style: italic;">run()</span>
|
|
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</li>
|
|
<li>Line 308 submits a runnable to switch to the session executor
|
|
thread.</li>
|
|
<li>Line 310 calls a method to process the event.<br>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<h3><a class="mozTocH3" name="mozTocId109235"></a>3.2 <a
|
|
class="mozTocH3" name="mozTocId244961"></a>Command/Event
|
|
Listeners</h3>
|
|
As mentioned before there are two types of listeners that can be
|
|
registered with the commands control: <span style="font-style: italic;">event
|
|
listeners </span>and command listeners. The most important
|
|
feature of these listeners, is that they are called by the command
|
|
control <span style="font-style: italic;">synchronously</span>.
|
|
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.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDACommandControl
|
|
- queueCommand()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<table
|
|
style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;">
|
|
<pre><a name="line337">337: </a> public <V extends ICommandResult> void queueCommand(ICommand<V> command, DataRequestMonitor<V> rm) {<br><a
|
|
name="line338">338: </a> <font color="#4169e1">if</font> (command instanceof AbstractPDACommand<?>) {<br><a
|
|
name="line339">339: </a> <font color="#b22222">// Cast from command with "<V extends ICommandResult>" to a more concrete</font><br><a
|
|
name="line340">340: </a> <font color="#b22222">// type to use internally in the command control.</font><br><a
|
|
name="line341">341: </a> @SuppressWarnings(<font
|
|
color="#666666">"unchecked"</font>)<br><a name="line342">342: </a> AbstractPDACommand<PDACommandResult> pdaCommand = (AbstractPDACommand<PDACommandResult>)command;<br><a
|
|
name="line343">343: </a> <br><a name="line344">344: </a> <font
|
|
color="#b22222">// Similarly, cast the request monitor to a more concrete type.</font><br><a
|
|
name="line345">345: </a> @SuppressWarnings(<font
|
|
color="#666666">"unchecked"</font>)<br><a name="line346">346: </a> DataRequestMonitor<PDACommandResult> pdaRM = (DataRequestMonitor<PDACommandResult>)rm;<br><br><a
|
|
name="line348">348: </a> <font color="#b22222">// Add the command to the queue and notify command listeners.</font><br><a
|
|
name="line349">349: </a> fCommandQueue.add( new CommandHandle(pdaCommand, pdaRM) );<br><a
|
|
name="line350">350: </a> <font color="#4169e1">for</font> (ICommandListener listener : fCommandListeners) {<br><a
|
|
name="line351">351: </a> listener.commandQueued(command);<br><a
|
|
name="line352">352: </a> }<br><a name="line353">353: </a> <br><a
|
|
name="line354">354: </a> <font color="#b22222">// In a separate dispatch cycle. This allows command listeners to repond to the </font><br><a
|
|
name="line355">355: </a> <font color="#b22222">// command queued event. </font><br><a
|
|
name="line356">356: </a> getExecutor().execute(new DsfRunnable() {<br><a
|
|
name="line357">357: </a><strong><font color="#4169e1"> public void run()</font></strong> {<br><a
|
|
name="line358">358: </a> processQueues();<br><a
|
|
name="line359">359: </a> }<br><a name="line360">360: </a> });<br><a
|
|
name="line361">361: </a> <br><a name="line362">362: </a> } <font
|
|
color="#4169e1">else</font> {<br><a name="line363">363: </a> PDAPlugin.failRequest(rm, INTERNAL_ERROR, <font
|
|
color="#666666">"Unrecognized command: "</font> + command);<br><a
|
|
name="line364">364: </a> }<br><a name="line365">365: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 349 adds the new command to the queue.</li>
|
|
<li>Lines 350-352 call the command listeners to notify them of the
|
|
new command.</li>
|
|
<li>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.</li>
|
|
</ul>
|
|
<h3><a class="mozTocH3" name="mozTocId233698"></a>3.3 <a
|
|
class="mozTocH3" name="mozTocId231356"></a>PDAProgramDMContext</h3>
|
|
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 <span style="font-style: italic;">PDAProgramDMContext</span>
|
|
instance returned by <span style="font-style: italic;">PDACommandControl.getProgramDMContext()</span>.
|
|
However in other debuggers this context can have two other functions:<br>
|
|
<ol>
|
|
<li><span style="text-decoration: underline;">To identify the command
|
|
control instance</span> - In debugger sessions that connect to multiple
|
|
back ends, the context can be used to identify which command control
|
|
should process a given command.</li>
|
|
<li><span style="text-decoration: underline;">To help control
|
|
debugger command protocol state</span> - 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 preceding the command
|
|
being processed with other commands (such as <span
|
|
style="font-style: italic;">-thread-select</span> in GDB/MI).<br>
|
|
</li>
|
|
</ol>
|
|
<span style="font-weight: bold;"></span>
|
|
<h3><a class="mozTocH3" name="mozTocId223991"></a>3.4 <a
|
|
class="mozTocH3" name="mozTocId218300"></a>PDA Commands</h3>
|
|
To increase type safety 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:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.commands.PDADataCommand</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line15"> 15: </a><font color="#b22222">/**</font><br><a
|
|
name="line16"> 16: </a><font color="#b22222"> * Retrieves data stack information </font><br><a
|
|
name="line17"> 17: </a><font color="#b22222"> * </font><br><a
|
|
name="line18"> 18: </a><font color="#b22222"> * <pre></font><br><a
|
|
name="line19"> 19: </a><font color="#b22222"> * C: data</font><br><a
|
|
name="line20"> 20: </a><font color="#b22222"> * R: {value 1}|{value 2}|{value 3}|...|</font><br><a
|
|
name="line21"> 21: </a><font color="#b22222"> * </pre></font><br><a
|
|
name="line22"> 22: </a><font color="#b22222"> */</font><br><a
|
|
name="line23"> 23: @Immutable<br> 24: </a><strong><font color="#4169e1"><a
|
|
name="PDADataCommand"></a>public class PDADataCommand extends AbstractPDACommand</font></strong><PDADataCommandResult> {<br> 25:<br><a
|
|
name="line25"> 26: </a><strong><font color="#4169e1"> public PDADataCommand(PDAProgramDMContext context)</font></strong> {<br><a
|
|
name="line26"> 27: </a> super(context, <font color="#666666">"data"</font>);<br><a
|
|
name="line27"> 28: </a> }<br><a name="line28"> 29: </a> <br><a
|
|
name="line29"> 30: </a> @Override<br><a name="line30"> 31: </a><strong><font
|
|
color="#4169e1"> public PDADataCommandResult createResult(String resultText)</font></strong> {<br><a
|
|
name="line31"> 32: </a> <font color="#4169e1">return</font> new PDADataCommandResult(resultText);<br><a
|
|
name="line32"> 33: </a> }<br><a name="line33"> 34: </a>}<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 24 declares the class, using the <span
|
|
style="font-style: italic;">PDADataCommandResult</span> class as the
|
|
type for the result which has to be generated by this command.</li>
|
|
<li>Line 32 creates and returns the PDADataCommandResult object,
|
|
which parses the command result string.</li>
|
|
</ul>
|
|
Here is the corresponding data result class:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.commands.PDADataCommandResult</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line21"> 20: @Immutable<br> 21: </a><strong><font
|
|
color="#4169e1"><a name="PDADataCommandResult"></a>public class PDADataCommandResult extends PDACommandResult </font></strong>{<br><a
|
|
name="line22"> 22: </a> <br><a name="line23"> 23: </a> final public String[] fValues;<br><a
|
|
name="line24"> 24: </a> <br><a name="line25"> 25: </a> PDADataCommandResult(String response) {<br><a
|
|
name="line26"> 26: </a> super(response);<br><a name="line27"> 27: </a> StringTokenizer st = new StringTokenizer(response, <font
|
|
color="#666666">"|"</font>);<br><a name="line28"> 28: </a> List<String> valuesList = new ArrayList<String>();<br><a
|
|
name="line29"> 29: </a> <br><a name="line30"> 30: </a> <font
|
|
color="#4169e1">while</font> (st.hasMoreTokens()) {<br><a name="line31"> 31: </a> String token = st.nextToken();<br><a
|
|
name="line32"> 32: </a> <font color="#4169e1">if</font> (token.length() != 0) {<br><a
|
|
name="line33"> 33: </a> valuesList.add(st.nextToken());<br><a
|
|
name="line34"> 34: </a> }<br><a name="line35"> 35: </a> }<br><a
|
|
name="line36"> 36: </a> <br><a name="line37"> 37: </a> fValues = new String[valuesList.size()];<br><a
|
|
name="line38"> 38: </a> <font color="#4169e1">for</font> (int i = 0; i < valuesList.size(); i++) {<br><a
|
|
name="line39"> 39: </a> fValues[i] = valuesList.get(i);<br><a
|
|
name="line40"> 40: </a> }<br><a name="line41"> 41: </a> }<br><a
|
|
name="line42"> 42: </a>}</pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 23 declares the parsed result. It is declared public
|
|
but also final, protecting it from being modified by clients.<br>
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">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. </td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h2><a class="mozTocH2" name="mozTocId989042"></a>4 <a class="mozTocH2"
|
|
name="mozTocId660065"></a><a name="Step_3_-_View_Model"></a><span
|
|
style="font-weight: bold;">Step
|
|
3 - View Model</span></h2>
|
|
<h3><a class="mozTocH3" name="mozTocId558380"></a>4.1 <a
|
|
class="mozTocH3" name="mozTocId202968"></a>Adapter Glue</h3>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">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.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<br>
|
|
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 <span style="font-style: italic;">PDALaunch</span> object:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui/plugin.xml
|
|
- PDA adapter factory declaration</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;">
|
|
<pre><br></pre>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre> <extension<br> point="org.eclipse.core.runtime.adapters"><br> <factory<br> class="org.eclipse.dd.examples.pda.ui.PDAAdapterFactory"<br> adaptableType="org.eclipse.dd.examples.pda.launch.PDALaunch"><br> <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider"/><br> <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory"/><br> </factory><br> </extension></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<br>
|
|
The adapter factory has two jobs:<br>
|
|
<ol>
|
|
<li>Return the PDAVMAdapter instance as the content provider for the
|
|
PDALaunch element.</li>
|
|
<li>Register and manage the life-cycle of all other adapters required
|
|
for a functioning debugger.</li>
|
|
</ol>
|
|
The first job is performed by the IAdapterFactory.getAdapter() method
|
|
listed below:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.PDAAdapterFactory
|
|
- getAdapter()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line157">157: </a><strong><font color="#4169e1"> public Object getAdapter(Object adaptableObject, Class adapterType)</font></strong> {<br><a
|
|
name="line158">158: </a> <font color="#4169e1">if</font> (!(adaptableObject instanceof PDALaunch)) <font
|
|
color="#4169e1">return</font> null; <br><br><a name="line160">160: </a> PDALaunch launch = (PDALaunch)adaptableObject;<br><br><a
|
|
name="line162">162: </a> <font color="#b22222">// Find the correct set of adapters based on the launch. If not found</font><br><a
|
|
name="line163">163: </a> <font color="#b22222">// it means that we have a new launch, and we have to create a </font><br><a
|
|
name="line164">164: </a> <font color="#b22222">// new set of adapters. </font><br><a
|
|
name="line165">165: </a> LaunchAdapterSet adapterSet;<br><a
|
|
name="line166">166: </a> synchronized(fLaunchAdapterSets) {<br><a
|
|
name="line167">167: </a> adapterSet = fLaunchAdapterSets.get(launch);<br><a
|
|
name="line168">168: </a> <font color="#4169e1">if</font> (adapterSet == null) {<br><a
|
|
name="line169">169: </a> adapterSet = new LaunchAdapterSet(launch);<br><a
|
|
name="line170">170: </a> fLaunchAdapterSets.put(launch, adapterSet);<br><a
|
|
name="line171">171: </a> }<br><a name="line172">172: </a> }<br><a
|
|
name="line173">173: </a> <br><a name="line174">174: </a> <font
|
|
color="#b22222">// Returns the adapter type for the launch object.</font><br><a
|
|
name="line175">175: </a> <font color="#4169e1">if</font> (adapterType.equals(IElementContentProvider.class)) <font
|
|
color="#4169e1">return</font> adapterSet.fViewModelAdapter;<br><a
|
|
name="line176">176: </a> <font color="#4169e1">else</font> <font
|
|
color="#4169e1">if</font> (adapterType.equals(IModelProxyFactory.class)) <font
|
|
color="#4169e1">return</font> adapterSet.fViewModelAdapter;<br><a
|
|
name="line177">177: </a> <font color="#4169e1">else</font> <font
|
|
color="#4169e1">return</font> null;<br><a name="line178">178: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Lines 158-160 verify that the adaptable object is of correct type.</li>
|
|
<li>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.</li>
|
|
<li>Lines 175-176 Return the requested adapters for the PDALaunch
|
|
object.<br>
|
|
</li>
|
|
</ul>
|
|
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 <span style="font-style: italic;">IDMContext</span>
|
|
object.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.PDAAdapterFactory.LaunchAdapterSet
|
|
- <<constructor>></span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;">
|
|
<pre><a name="line85"></a><br></pre>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line85"> 85: </a> LaunchAdapterSet(PDALaunch launch) {<br><a
|
|
name="line86"> 86: </a> <font color="#b22222">// Initialize launch and session.</font><br><a
|
|
name="line87"> 87: </a> fLaunch = launch;<br><a
|
|
name="line88"> 88: </a> DsfSession session = launch.getSession();<br><a
|
|
name="line89"> 89: </a> <br><a name="line90"> 90: </a> <font
|
|
color="#b22222">// Initialize VM</font><br><a name="line91"> 91: </a> fViewModelAdapter = new PDAVMAdapter(session);<br><br><a
|
|
name="line93"> 93: </a> <font color="#b22222">// Initialize source lookup</font><br><a
|
|
name="line94"> 94: </a> fSourceDisplayAdapter = new MISourceDisplayAdapter(session, (ISourceLookupDirector)launch.getSourceLocator());<br><a
|
|
name="line95"> 95: </a> session.registerModelAdapter(ISourceDisplay.class, fSourceDisplayAdapter);<br><a
|
|
name="line96"> 96: </a> <br><a name="line97"> 97: </a> <font
|
|
color="#b22222">// Initialize retargetable command handler.</font><br><a
|
|
name="line98"> 98: </a> fStepIntoCommand = new DsfStepIntoCommand(session);<br><a
|
|
name="line99"> 99: </a> fStepOverCommand = new DsfStepOverCommand(session);<br><a
|
|
name="line100">100: </a> fStepReturnCommand = new DsfStepReturnCommand(session);<br><a
|
|
name="line101">101: </a> fSuspendCommand = new DsfSuspendCommand(session);<br><a
|
|
name="line102">102: </a> fResumeCommand = new DsfResumeCommand(session);<br><a
|
|
name="line103">103: </a> fTerminateCommand = new PDATerminateCommand(session);<br><a
|
|
name="line104">104: </a> session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand);<br><a
|
|
name="line105">105: </a> session.registerModelAdapter(IStepOverHandler.class, fStepOverCommand);<br><a
|
|
name="line106">106: </a> session.registerModelAdapter(IStepReturnHandler.class, fStepReturnCommand);<br><a
|
|
name="line107">107: </a> session.registerModelAdapter(ISuspendHandler.class, fSuspendCommand);<br><a
|
|
name="line108">108: </a> session.registerModelAdapter(IResumeHandler.class, fResumeCommand);<br><a
|
|
name="line109">109: </a> session.registerModelAdapter(ITerminateHandler.class, fTerminateCommand);<br><br><a
|
|
name="line111">111: </a> <font color="#b22222">// Initialize debug model provider</font><br><a
|
|
name="line112">112: </a> fDebugModelProvider = new IDebugModelProvider() {<br><a
|
|
name="line113">113: </a> public String[] getModelIdentifiers() {<br><a
|
|
name="line114">114: </a> <font color="#4169e1">return</font> new String[] { PDAPlugin.ID_PDA_DEBUG_MODEL };<br><a
|
|
name="line115">115: </a> }<br><a name="line116">116: </a> };<br><a
|
|
name="line117">117: </a> session.registerModelAdapter(IDebugModelProvider.class, fDebugModelProvider);<br><a
|
|
name="line118">118: </a> <br><a name="line119">119: </a> <font
|
|
color="#b22222">// Register the launch as an adapter This ensures that the launch, </font><br><a
|
|
name="line120">120: </a> <font color="#b22222">// and debug model ID will be associated with all DMContexts from this </font><br><a
|
|
name="line121">121: </a> <font color="#b22222">// session. </font><br><a
|
|
name="line122">122: </a> session.registerModelAdapter(ILaunch.class, fLaunch);<br><a
|
|
name="line123">123: </a> }</pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
</ul>
|
|
<ul>
|
|
<li>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 instance.</li>
|
|
<li><a name="Source_Display_Adapter_Registration"></a>Line 94-95
|
|
register the source display adapter (the "MI" prefix
|
|
is a historical left over).</li>
|
|
<li>Lines 98-109 register handlers for common debug commands.
|
|
(See note below)<span style="color: rgb(255, 0, 0);"></span><br>
|
|
</li>
|
|
<li>Lines 112 -116 Register an adapter to provide debug model
|
|
ID. It is used by Debug Platform to enable custom keyboard
|
|
shortcuts for the debugger.</li>
|
|
<li>Line 122 associates the launch object with the PDA debugger
|
|
elements. This enables some actions in debug view which access
|
|
the launch (such as <span style="font-style: italic;">Edit Source
|
|
Lookup</span>).</li>
|
|
</ul>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">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.<br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<br>
|
|
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:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.PDAAdapterFactory
|
|
- launchesRemoved()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line185">185: </a><strong><font color="#4169e1"> public void launchesRemoved(ILaunch[] launches)</font></strong> {<br><a
|
|
name="line186">186: </a> <font color="#b22222">// Dispose the set of adapters for a launch only after the launch is </font><br><a
|
|
name="line187">187: </a> <font color="#b22222">// removed from the view. If the launch is terminated, the adapters</font><br><a
|
|
name="line188">188: </a> <font color="#b22222">// are still needed to populate the contents of the view.</font><br><a
|
|
name="line189">189: </a> <font color="#4169e1">for</font> (ILaunch launch : launches) {<br><a
|
|
name="line190">190: </a> <font color="#4169e1">if</font> (launch instanceof PDALaunch) {<br><a
|
|
name="line191">191: </a> PDALaunch pdaLaunch = (PDALaunch)launch;<br><a
|
|
name="line192">192: </a> synchronized(fLaunchAdapterSets) {<br><a
|
|
name="line193">193: </a> <font color="#4169e1">if</font> ( fLaunchAdapterSets.containsKey(pdaLaunch) ) {<br><a
|
|
name="line194">194: </a> fLaunchAdapterSets.remove(pdaLaunch).dispose();<br><a
|
|
name="line195">195: </a> }<br><a name="line196">196: </a> }<br><a
|
|
name="line197">197: </a> } <br><a
|
|
name="line198">198: </a> }<br><a name="line199">199: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h3><a class="mozTocH3" name="mozTocId59724"></a>4.2 <a
|
|
class="mozTocH3" name="mozTocId531112"></a>PDA View Model</h3>
|
|
The <span style="font-style: italic;">PDAVMAdapter</span> creates the
|
|
VM Providers on demand for each debugger
|
|
view it supports:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.viewmodel.PDAVMAdapter
|
|
- createViewModelProvider()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line43"> 43: </a><strong><font color="#4169e1"> protected AbstractDMVMProvider createViewModelProvider(IPresentationContext context)</font></strong> {<br><a
|
|
name="line44"> 44: </a> <font color="#4169e1">if</font> ( IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId()) ) {<br><a
|
|
name="line45"> 45: </a> <font color="#4169e1">return</font> new PDALaunchVMProvider(this, context, getSession()); <br><a
|
|
name="line46"> 46: </a> } <font color="#4169e1">else</font> <font
|
|
color="#4169e1">if</font> (IDebugUIConstants.ID_VARIABLE_VIEW.equals(context.getId()) ) {<br><a
|
|
name="line47"> 47: </a> <font color="#4169e1">return</font> new VariableVMProvider(this, context, getSession());<br><a
|
|
name="line48"> 48: </a> } <font color="#4169e1">else</font> <font
|
|
color="#4169e1">if</font> (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(context.getId()) ) {<br><a
|
|
name="line49"> 49: </a> <font color="#4169e1">return</font> new ExpressionVMProvider(this, context, getSession());<br><a
|
|
name="line50"> 50: </a> } <br><a name="line51"> 51: </a> <font
|
|
color="#4169e1">return</font> null;<br><a name="line52"> 52: </a> } <br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 45 creates a VM Provider for the debug view. This
|
|
provider is created custom for the PDA debugger.</li>
|
|
<li>Lines 47 and 49 create VM Providers for the <span
|
|
style="font-style: italic;">Variables</span> and <span
|
|
style="font-style: italic;">Expressions</span> views
|
|
respectively. These providers are implemented in the <span
|
|
style="font-style: italic;">org.eclipse.dd.dsf.debug.ui</span> plugin
|
|
and are reused here without modification.</li>
|
|
</ul>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">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. </td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<br>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">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.<br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h3><a class="mozTocH3" name="mozTocId222824"></a>4.3 <a
|
|
class="mozTocH3" name="mozTocId395362"></a>Launch VM Provider</h3>
|
|
"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.<br>
|
|
<br>
|
|
<table style="text-align: left; margin-left: auto; margin-right: auto;"
|
|
border="0" cellpadding="5" cellspacing="30">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: center; vertical-align: middle;"><img
|
|
style="width: 392px; height: 231px;" title="Debug view screen capture"
|
|
alt="" src="launch_1.png"><br>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top;"><small><span
|
|
style="font-weight: bold;">Image 2: Debug view screen capture</span></small><br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
The <span style="font-style: italic;">PDALaunchVMProvider</span>
|
|
constructor creates the VM Nodes and arranges
|
|
them in a hierarchy that mirrors the screen-shot in <span
|
|
style="font-style: italic;">Image 2</span>.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMProvider
|
|
- <<constructor>></span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line50"> 50: </a><strong><font color="#4169e1"> public PDALaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session)</font></strong> <br><a
|
|
name="line51"> 51: </a> {<br><a name="line52"> 52: </a> super(adapter, presentationContext, session);<br><a
|
|
name="line53"> 53: </a> <br><a name="line54"> 54: </a> IRootVMNode launchNode = new LaunchRootVMNode(this);<br><a
|
|
name="line55"> 55: </a> setRootNode(launchNode);<br><br><a
|
|
name="line57"> 57: </a> <font color="#b22222">// Launch node is a parent to the processes and program nodes.</font><br><a
|
|
name="line58"> 58: </a> IVMNode pdaProgramNode = new PDAProgramVMNode(this, getSession());<br><a
|
|
name="line59"> 59: </a> IVMNode processesNode = new StandardProcessVMNode(this);<br><a
|
|
name="line60"> 60: </a> addChildNodes(launchNode, new IVMNode[] { pdaProgramNode, processesNode});<br><a
|
|
name="line61"> 61: </a> <br><a name="line62"> 62: </a> <font
|
|
color="#b22222">// Stack frames node is under the PDA program node.</font><br><a
|
|
name="line63"> 63: </a> IVMNode stackFramesNode = new StackFramesVMNode(this, getSession());<br><a
|
|
name="line64"> 64: </a> addChildNodes(pdaProgramNode, new IVMNode[] { stackFramesNode });<br><br><a
|
|
name="line66"> 66: </a> <font color="#b22222">// Register the LaunchVM provider as a listener to debug and launch </font><br><a
|
|
name="line67"> 67: </a> <font color="#b22222">// events. These events are used by the launch and processes nodes.</font><br><a
|
|
name="line68"> 68: </a> DebugPlugin.getDefault().addDebugEventListener(this);<br><a
|
|
name="line69"> 69: </a> DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);<br><a
|
|
name="line70"> 70: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Lines 54,55 create the root node for the PDA hierarchy, which
|
|
tracks the single PDA Launch element.</li>
|
|
<li>Line 58 creates the PDA program node, which tracks the single PDA
|
|
program execution context. <br>
|
|
</li>
|
|
<li>Line 59 creates the processes node. This node supplies the
|
|
elements corresponding to process objects returned by
|
|
ILaunch.getProcesses(). <br>
|
|
</li>
|
|
<li>Line 60 sets the program and processes nodes as children of the
|
|
root node so that their elements appear under the launch.</li>
|
|
<li>Lines 63,64 add the stack frame node as a child directly under
|
|
the program node.</li>
|
|
<li>Line 68 adds the Launch VM Provider as a listener to the standard
|
|
debug model events. These events are used by the <span
|
|
style="font-style: italic;">StandardProcessVMNode</span> to update the
|
|
processes' state.<br>
|
|
</li>
|
|
<li>Line 69 adds 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.</li>
|
|
</ul>
|
|
<h3><a class="mozTocH3" name="mozTocId22521"></a>4.4 <a
|
|
class="mozTocH3" name="mozTocId104193"></a>PDA Program VM Node</h3>
|
|
<ul>
|
|
</ul>
|
|
<h4><a class="mozTocH4" name="mozTocId832094"></a>Elements</h4>
|
|
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:<br>
|
|
<ol>
|
|
<li><span style="text-decoration: underline;">Not Initialized</span>
|
|
- After the <span style="font-style: italic;">PDALaunch</span> object
|
|
has been created, but the services have not yet been initialized.
|
|
In this mode the PDA Program is not shown in Debug view.<br>
|
|
</li>
|
|
<li><span style="text-decoration: underline;">Running</span> - After
|
|
the PDALaunch and PDACommandControl are initialized, the <span
|
|
style="font-style: italic;">PDAProgramDMContext</span> object is used
|
|
as the underlying Data Model element shown in Debug view. <br>
|
|
</li>
|
|
<li><span style="text-decoration: underline;">Shut down</span> -
|
|
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 <span style="font-style: italic;">PDACommandControl</span>
|
|
service is shut down and the <span style="font-style: italic;">PDAProgramDMContext</span>
|
|
is not available. Hence, a separate TerminatedProgramVMContext
|
|
wrapper element is used which does not have an underlying Data Model
|
|
element.</li>
|
|
</ol>
|
|
The following two methods implement the logic of supplying the elements
|
|
for the above modes:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode
|
|
- update(IChildrenUpdate[])</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;">
|
|
<pre><a name="line119"></a><br></pre>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line119">119: </a> @Override<br><a name="line120">120: </a><strong><font
|
|
color="#4169e1"> public void update(IChildrenUpdate[] updates)</font></strong> {<br><a
|
|
name="line121">121: </a> <font color="#4169e1">for</font> (IChildrenUpdate update : updates) {<br><a
|
|
name="line122">122: </a> PDALaunch launch = findLaunchInPath(update.getElementPath());<br><a
|
|
name="line123">123: </a> <font color="#4169e1">if</font> (launch != null && launch.isInitialized() && launch.isShutDown()) {<br><a
|
|
name="line124">124: </a> <font color="#b22222">// If the debug session has been shut down, add a dummy </font><br><a
|
|
name="line125">125: </a> <font color="#b22222">// VM context representing the PDA thread.</font><br><a
|
|
name="line126">126: </a> update.setChild(new TerminatedProgramVMContext(getVMProvider().getVMAdapter(), this), 0);<br><a
|
|
name="line127">127: </a> update.done();<br><a
|
|
name="line128">128: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line129">129: </a> super.update(new IChildrenUpdate[] { update });<br><a
|
|
name="line130">130: </a> }<br><a name="line131">131: </a> }<br><a
|
|
name="line132">132: </a> }<br><a name="line133">133: </a> <br><a
|
|
name="line134">134: </a> @Override<br><a name="line135">135: </a><strong><font
|
|
color="#4169e1"> protected void updateElementsInSessionThread(final IChildrenUpdate update)</font></strong> {<br><a
|
|
name="line136">136: </a> <font color="#b22222">// Get the instance of the service. Note that there is no race condition</font><br><a
|
|
name="line137">137: </a> <font color="#b22222">// in getting the service since this method is called only in the </font><br><a
|
|
name="line138">138: </a> <font color="#b22222">// service executor thread.</font><br><a
|
|
name="line139">139: </a> final PDACommandControl commandControl = getServicesTracker().getService(PDACommandControl.class);<br><br><a
|
|
name="line141">141: </a> <font color="#b22222">// Check if the service is available. If it is not, no elements are </font><br><a
|
|
name="line142">142: </a> <font color="#b22222">// updated.</font><br><a
|
|
name="line143">143: </a> <font color="#4169e1">if</font> (commandControl == null) {<br><a
|
|
name="line144">144: </a> handleFailedUpdate(update);<br><a
|
|
name="line145">145: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line146">146: </a> }<br><a name="line147">147: </a> <br><a
|
|
name="line148">148: </a> update.setChild(createVMContext(commandControl.getProgramDMContext()), 0);<br><a
|
|
name="line149">149: </a> update.done();<br><a name="line150">150: </a> }</pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<br>
|
|
<ul>
|
|
<li>Line 120 overrides the <span style="font-style: italic;">AbstractDMVMNode.update(IChildrenUpdate[])</span>
|
|
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 <span
|
|
style="font-style: italic;">updateElementsInSessionThread()</span>,
|
|
which is not needed nor possible after the PDA program is terminated.</li>
|
|
<li>Line 126 creates the dummy View Model context which represents a
|
|
terminated PDA program.</li>
|
|
<li>Line 135 implements the elements update method which is called in
|
|
the DSF session thread. <br>
|
|
</li>
|
|
<li>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.</li>
|
|
</ul>
|
|
<h4><a class="mozTocH4" name="mozTocId960575"></a>Label</h4>
|
|
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 <span
|
|
style="font-style: italic;">update(ILabelUpdate[])</span>
|
|
implementation:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode
|
|
- </span><span style="font-family: monospace; font-weight: bold;">update(ILabelUpdate[])</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line152">152: </a><strong><font color="#4169e1"> public void update(final ILabelUpdate[] updates)</font></strong> {<br><a
|
|
name="line153">153: </a> <font color="#4169e1">for</font> (final ILabelUpdate update : updates) {<br><a
|
|
name="line154">154: </a> <font color="#4169e1">if</font> (update.getElement() instanceof TerminatedProgramVMContext) {<br><a
|
|
name="line155">155: </a> <font color="#b22222">// If the element is a terminated program, update the label </font><br><a
|
|
name="line156">156: </a> <font color="#b22222">// in the View Model thread.</font><br><a
|
|
name="line157">157: </a> updateTerminatedThreadLabel(update);<br><a
|
|
name="line158">158: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line159">159: </a> <font color="#b22222">// If the element is the PDA Program context, try to switch</font><br><a
|
|
name="line160">160: </a> <font color="#b22222">// to the DSF session thread before updating the label.</font><br><a
|
|
name="line161">161: </a> <font color="#4169e1">try</font> {<br><a
|
|
name="line162">162: </a> getSession().getExecutor().execute(new DsfRunnable() {<br><a
|
|
name="line163">163: </a><strong><font color="#4169e1"> public void run()</font></strong> {<br><a
|
|
name="line164">164: </a> updateProgramLabelInSessionThread(update);<br><a
|
|
name="line165">165: </a> }});<br><a
|
|
name="line166">166: </a> } <font color="#4169e1">catch</font> (RejectedExecutionException e) {<br><a
|
|
name="line167">167: </a> <font color="#b22222">// Acceptable race condition: DSF session terminated.</font><br><a
|
|
name="line168">168: </a> handleFailedUpdate(update);<br><a
|
|
name="line169">169: </a> }<br><a name="line170">170: </a> }<br><a
|
|
name="line171">171: </a> }<br><a name="line172">172: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 153 iterates through the updates. The
|
|
IElementLabelProvider.update() method takes an array of updates as an
|
|
argument to allow the implementation to process the updates in bunches,
|
|
improving performance. <br>
|
|
</li>
|
|
<li>Line 157 calls a subroutine to handle the terminated program
|
|
label.</li>
|
|
<li>Lines 161-169 call a subroutine to update the active program's
|
|
session. The execution thread is first changed to the session
|
|
executor thread.</li>
|
|
</ul>
|
|
The <span style="font-style: italic;">updateProgramLabelInSessionThread()</span>
|
|
is rather long, but it is useful to look at it in detail because it is
|
|
representative of what all label providers must do.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMNode
|
|
- updateProgramLabelInSessionThread()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line174">174: </a> @ConfinedToDsfExecutor(<font
|
|
color="#666666">"getSession().getExecutor()"</font>)<br><a
|
|
name="line175">175: </a><strong><font color="#4169e1"> private void updateProgramLabelInSessionThread(final ILabelUpdate update)</font></strong> {<br><a
|
|
name="line176">176: </a> <font color="#b22222">// Get a reference to the run control service.</font><br><a
|
|
name="line177">177: </a> final IRunControl runControl = getServicesTracker().getService(IRunControl.class);<br><a
|
|
name="line178">178: </a> <font color="#4169e1">if</font> (runControl == null) {<br><a
|
|
name="line179">179: </a> handleFailedUpdate(update);<br><a
|
|
name="line180">180: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line181">181: </a> }<br><a name="line182">182: </a> <br><a
|
|
name="line183">183: </a> <font color="#b22222">// Find the PDA program context.</font><br><a
|
|
name="line184">184: </a> final PDAProgramDMContext programCtx = <br><a
|
|
name="line185">185: </a> findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAProgramDMContext.class);<br><br><a
|
|
name="line187">187: </a> <font color="#b22222">// Call service to get current program state</font><br><a
|
|
name="line188">188: </a> final boolean isSuspended = runControl.isSuspended(programCtx);<br><br><a
|
|
name="line190">190: </a> <font color="#b22222">// Set the program icon based on the running state of the program.</font><br><a
|
|
name="line191">191: </a> String imageKey = null;<br><a
|
|
name="line192">192: </a> <font color="#4169e1">if</font> (isSuspended) {<br><a
|
|
name="line193">193: </a> imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;<br><a
|
|
name="line194">194: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line195">195: </a> imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;<br><a
|
|
name="line196">196: </a> }<br><a name="line197">197: </a> update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);<br><br><a
|
|
name="line199">199: </a> <font color="#b22222">// Retrieve the last state change reason </font><br><a
|
|
name="line200">200: </a> runControl.getExecutionData(<br><a
|
|
name="line201">201: </a> programCtx, <br><a name="line202">202: </a> new DataRequestMonitor<IExecutionDMData>(ImmediateExecutor.getInstance(), null) <br><a
|
|
name="line203">203: </a> { <br><a name="line204">204: </a> @Override<br><a
|
|
name="line205">205: </a><strong><font color="#4169e1"> public void handleCompleted()</font></strong>{<br><a
|
|
name="line206">206: </a> <font color="#b22222">// If the request failed, fail the udpate. </font><br><a
|
|
name="line207">207: </a> <font color="#4169e1">if</font> (!getStatus().isOK()) {<br><a
|
|
name="line208">208: </a> handleFailedUpdate(update);<br><a
|
|
name="line209">209: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line210">210: </a> }<br><a name="line211">211: </a> <br><a
|
|
name="line212">212: </a> <font color="#b22222">// Compose the thread name string.</font><br><a
|
|
name="line213">213: </a> final StringBuilder builder = new StringBuilder(); <br><a
|
|
name="line214">214: </a> <br><a name="line215">215: </a> builder.append(<font
|
|
color="#666666">"PDA ["</font>);<br><a name="line216">216: </a> builder.append(programCtx.getProgram());<br><a
|
|
name="line217">217: </a> builder.append(<font
|
|
color="#666666">"]"</font>);<br><a name="line218">218: </a> <br><a
|
|
name="line219">219: </a> <font color="#4169e1">if</font>(isSuspended) {<br><a
|
|
name="line220">220: </a> builder.append(<font
|
|
color="#666666">" (Suspended"</font>); <br><a name="line221">221: </a> } <font
|
|
color="#4169e1">else</font> {<br><a name="line222">222: </a> builder.append(<font
|
|
color="#666666">" (Running"</font>); <br><a name="line223">223: </a> }<br><a
|
|
name="line224">224: </a> <font color="#b22222">// Reason will be null before ContainerSuspendEvent is fired</font><br><a
|
|
name="line225">225: </a> <font color="#4169e1">if</font>(getData().getStateChangeReason() != null) {<br><a
|
|
name="line226">226: </a> builder.append(<font
|
|
color="#666666">" : "</font>); <br><a name="line227">227: </a> builder.append(getData().getStateChangeReason());<br><a
|
|
name="line228">228: </a> }<br><a name="line229">229: </a> builder.append(<font
|
|
color="#666666">")"</font>); <br><a name="line230">230: </a> update.setLabel(builder.toString(), 0);<br><a
|
|
name="line231">231: </a> update.done();<br><a
|
|
name="line232">232: </a> }<br><a name="line233">233: </a> }); <br><a
|
|
name="line234">234: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>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.</li>
|
|
<li>Lines 177-181 retrieve the <span style="font-style: italic;">IRunControl</span>
|
|
service, always checking that the service is actually available.</li>
|
|
<li>Lines 184,185 retrieve the PDAProgramDMContext from the
|
|
update. This context can actually be expected to be in the <span
|
|
style="font-style: italic;">IDMVMConext</span> wrapper returned by <span
|
|
style="font-style: italic;">IViewerUpdate.getElement()</span>.
|
|
However the <span style="font-style: italic;">AbstractDMVMNode.findDmcInPath()</span>
|
|
utility method searches the full tree path in the update and is
|
|
typically used to extract the Data Model context from the update.</li>
|
|
<li>Line 188 retrieves the running state of the program using a
|
|
synchronous IRunControl.isSuspended() method.</li>
|
|
<li>Lines 191-197 calculate and update the program icon based on the
|
|
running state of the program.</li>
|
|
<li>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.</li>
|
|
<li>Lines 207-210 perform error handling.</li>
|
|
<li>Lines 213-229 finally calculate the label string for the
|
|
program. <br>
|
|
</li>
|
|
<li>On line 227, The result of the <span style="font-style: italic;">getExecutionData()</span>
|
|
call, accessed using <span style="font-style: italic;">DataRequestMonitor.getData()</span>,
|
|
is used to fill in the reason for the current state of the program.</li>
|
|
<li>Line 230 writes the label to the update. This call assumes
|
|
that there is no columns in Debug view, so it uses <span
|
|
style="font-style: italic;">0</span> as the column index.<br>
|
|
</li>
|
|
</ul>
|
|
<h4><a class="mozTocH4" name="mozTocId416458"></a>Delta</h4>
|
|
Translating the Data Model events into <span
|
|
style="font-style: italic;">IModelDelta</span> objects that can be
|
|
processed by the Flexible 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:<br>
|
|
<ol>
|
|
<li>The event handler in the VM Provider</li>
|
|
<li>The build delta methods in the VM Nodes.</li>
|
|
</ol>
|
|
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 <span
|
|
style="font-style: italic;">AbstractDMVMProvider</span> base class:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDALaunchVMProvider
|
|
- handleDebugEvents()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;">
|
|
<pre><a name="line73"></a><br></pre>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line73"> 73: </a><strong><font color="#4169e1"> public void handleDebugEvents(final DebugEvent[] events)</font></strong> {<br><a
|
|
name="line74"> 74: </a> <font color="#4169e1">if</font> (isDisposed()) <font
|
|
color="#4169e1">return</font>;<br><a name="line75"> 75: </a> <br><a
|
|
name="line76"> 76: </a> <font color="#b22222">// This method may be called on any thread. Switch to the </font><br><a
|
|
name="line77"> 77: </a> <font color="#b22222">// view model executor thread before processing.</font><br><a
|
|
name="line78"> 78: </a> <font color="#4169e1">try</font> {<br><a
|
|
name="line79"> 79: </a> getExecutor().execute(new Runnable() {<br><a
|
|
name="line80"> 80: </a><strong><font color="#4169e1"> public void run()</font></strong> {<br><a
|
|
name="line81"> 81: </a> <font color="#4169e1">if</font> (isDisposed()) <font
|
|
color="#4169e1">return</font>;<br><a name="line82"> 82: </a> <br><a
|
|
name="line83"> 83: </a> <font color="#4169e1">for</font> (final DebugEvent event : events) {<br><a
|
|
name="line84"> 84: </a> handleEvent(event);<br><a
|
|
name="line85"> 85: </a> }<br><a name="line86"> 86: </a> }});<br><a
|
|
name="line87"> 87: </a> } <font color="#4169e1">catch</font> (RejectedExecutionException e) {<br><a
|
|
name="line88"> 88: </a> <font color="#b22222">// Ignore. This exception could be thrown if the view model is being </font><br><a
|
|
name="line89"> 89: </a> <font color="#b22222">// shut down. </font><br><a
|
|
name="line90"> 90: </a> }<br><a name="line91"> 91: </a> }</pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 84 calls the base class <span style="font-style: italic;">handleEvent()</span>
|
|
method which does the hard work of calling the VM Nodes to build
|
|
and send the delta to the views.</li>
|
|
</ul>
|
|
The PDA program node implements methods to add the delta nodes for its
|
|
elements:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.ui.viewmodel.launch.PDAProgramVMNode
|
|
- buildDelta()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line265">265: </a><strong><font color="#4169e1"> public int getDeltaFlags(Object e)</font></strong> {<br><a
|
|
name="line266">266: </a> <font color="#4169e1">if</font>(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) {<br><a
|
|
name="line267">267: </a> <font color="#4169e1">return</font> IModelDelta.STATE;<br><a
|
|
name="line268">268: </a> } <br><a name="line269">269: </a> <font
|
|
color="#4169e1">if</font> (e instanceof PDAStartedEvent) {<br><a
|
|
name="line270">270: </a> <font color="#4169e1">return</font> IModelDelta.EXPAND | IModelDelta.SELECT;<br><a
|
|
name="line271">271: </a> }<br><a name="line272">272: </a> <font
|
|
color="#4169e1">return</font> IModelDelta.NO_CHANGE;<br><a
|
|
name="line273">273: </a> }<br>274:<br><a name="line275">275: </a><strong><font
|
|
color="#4169e1"> public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm)</font></strong> {<br><a
|
|
name="line276">276: </a> <font color="#4169e1">if</font>(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) {<br><a
|
|
name="line277">277: </a> <font color="#b22222">// If a suspended/resumed event is received, just update the </font><br><a
|
|
name="line278">278: </a> <font color="#b22222">// state of the program. StackFramesVMNode will take care of </font><br><a
|
|
name="line279">279: </a> <font color="#b22222">// refreshing the stack frames.</font><br><a
|
|
name="line280">280: </a> parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.STATE);<br><a
|
|
name="line281">281: </a> } <br><a name="line282">282: </a> <font
|
|
color="#4169e1">if</font> (e instanceof PDAStartedEvent) {<br><a
|
|
name="line283">283: </a> <font color="#b22222">// When debug session is started expand and select the program.</font><br><a
|
|
name="line284">284: </a> <font color="#b22222">// If the program hits a breakpoint, the top stack frame will then</font><br><a
|
|
name="line285">285: </a> <font color="#b22222">// be selected.</font><br><a
|
|
name="line286">286: </a> parentDelta.addNode(createVMContext(((PDAStartedEvent)e).getDMContext()), IModelDelta.EXPAND | IModelDelta.SELECT); <br><a
|
|
name="line287">287: </a> }<br><a name="line288">288: </a> rm.done();<br><a
|
|
name="line289">289: </a> }<br><a name="line290">290: </a>}<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Lines 265-273 implement the synchronous <span
|
|
style="font-style: italic;">IVMNode.getDeltaFlags()</span>.
|
|
This method only needs to return what
|
|
flags this node <span style="font-style: italic;">may</span> create
|
|
for the given event and it is used to optimize the logic of building
|
|
the
|
|
model deltas.</li>
|
|
<li>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.</li>
|
|
<li>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.</li>
|
|
<li>Line 280 adds a delta element to the parent delta. With a
|
|
call to <span style="font-style: italic;">AbstractDMVMNode.createVMContext()</span>,
|
|
it creates a wrapper element based on the Data Model context contained
|
|
in the event. <br>
|
|
</li>
|
|
<li>Lines 282-287 handle the started event, which is issued when the
|
|
PDACommandControl service is initialized. It causes the PDA
|
|
context to be selected.<br>
|
|
</li>
|
|
<li>Line 288 completes the execution of this asynchronous method.</li>
|
|
</ul>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">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. </td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h2><a class="mozTocH2" name="mozTocId819534"></a>5 <a class="mozTocH2"
|
|
name="mozTocId797186"></a>Step 4 - Run Control</h2>
|
|
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 <span
|
|
style="font-style: italic;">PDARunControl</span> service.<br>
|
|
<h3><a class="mozTocH3" name="mozTocId333707"></a>5.1 State Tracking</h3>
|
|
<span style="color: rgb(255, 0, 0);"></span>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 <span style="font-style: italic;">IEventListner.eventReceived()</span>
|
|
implementation in combination with service event handlers for
|
|
<span style="font-style: italic;">IRunControl.IResumedDMEvent</span>
|
|
and <span style="font-style: italic;">IRunControl.ISuspendedDMEvent</span>.
|
|
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.<span style="color: rgb(255, 0, 0);"></span><br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDARunControl
|
|
- eventReceived()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line181">181: </a><strong><font color="#4169e1"> public void eventReceived(Object output)</font></strong> {<br><a
|
|
name="line182">182: </a> <font color="#4169e1">if</font> (!(output instanceof String)) <font
|
|
color="#4169e1">return</font>;<br><a name="line183">183: </a> String event = (String)output;<br><a
|
|
name="line184">184: </a> <br><a name="line185">185: </a> <font
|
|
color="#b22222">// Handle PDA debugger suspended/resumed events and issue the </font><br><a
|
|
name="line186">186: </a> <font color="#b22222">// corresponding Data Model events. Do not update the state</font><br><a
|
|
name="line187">187: </a> <font color="#b22222">// information until we start dispatching the service events.</font><br><a
|
|
name="line188">188: </a> <font color="#4169e1">if</font> (event.startsWith(<font
|
|
color="#666666">"suspended"</font>)) {<br><a name="line189">189: </a> IDMEvent<?> dmEvent = new SuspendedEvent(fCommandControl.getProgramDMContext(), event);<br><a
|
|
name="line190">190: </a> getSession().dispatchEvent(dmEvent, getProperties());<br><a
|
|
name="line191">191: </a> } <font color="#4169e1">else</font> <font
|
|
color="#4169e1">if</font> (event.startsWith(<font color="#666666">"resumed"</font>)) {<br><a
|
|
name="line192">192: </a> IDMEvent<?> dmEvent = new ResumedEvent(fCommandControl.getProgramDMContext(), event);<br><a
|
|
name="line193">193: </a> getSession().dispatchEvent(dmEvent, getProperties());<br><a
|
|
name="line194">194: </a> }<br><a name="line195">195: </a> }<br><a
|
|
name="line196">196: </a> <br><a name="line197">197: </a> <br><a
|
|
name="line198">198: </a> @DsfServiceEventHandler <br><a
|
|
name="line199">199: </a><strong><font color="#4169e1"> public void eventDispatched(ResumedEvent e)</font></strong> {<br><a
|
|
name="line200">200: </a> <font color="#b22222">// This service should be the first to receive the ResumedEvent, </font><br><a
|
|
name="line201">201: </a> <font color="#b22222">// (before any other listeners are called). Here, update the</font><br><a
|
|
name="line202">202: </a> <font color="#b22222">// service state information based on the the resumed event.</font><br><a
|
|
name="line203">203: </a> fSuspended = false;<br><a
|
|
name="line204">204: </a> fResumePending = false;<br><a
|
|
name="line205">205: </a> fStateChangeReason = e.getReason();<br><a
|
|
name="line206">206: </a> fStepping = e.getReason().equals(StateChangeReason.STEP);<br><a
|
|
name="line207">207: </a> } <br>208:<br>209:<br><a name="line210">210: </a> @DsfServiceEventHandler <br><a
|
|
name="line211">211: </a><strong><font color="#4169e1"> public void eventDispatched(SuspendedEvent e)</font></strong> {<br><a
|
|
name="line212">212: </a> <font color="#b22222">// This service should be the first to receive the SuspendedEvent also, </font><br><a
|
|
name="line213">213: </a> <font color="#b22222">// (before any other listeners are called). Here, update the</font><br><a
|
|
name="line214">214: </a> <font color="#b22222">// service state information based on the the suspended event.</font><br><a
|
|
name="line215">215: </a> fStateChangeReason = e.getReason();<br><a
|
|
name="line216">216: </a> fResumePending = false;<br><a
|
|
name="line217">217: </a> fSuspended = true;<br><a name="line218">218: </a> fStepping = false;<br><a
|
|
name="line219">219: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>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. <br>
|
|
</li>
|
|
<li>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.</li>
|
|
<li>Lines 188-193 generate the suspended/resumed Data Model events.</li>
|
|
<li>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.</li>
|
|
<li>Line 205 retrieves the state change reason from the resumed
|
|
event. This reason is calculated by the <span
|
|
style="font-style: italic;">ResumedEvent</span> constructor based on
|
|
the event string received from the PDA debugger.</li>
|
|
<li>Lines 211-219 update the state flags based on the stopped event.</li>
|
|
</ul>
|
|
<table
|
|
style="width: 95%; text-align: left; margin-left: auto; margin-right: auto; background-color: rgb(255, 255, 204); font-style: italic;"
|
|
border="0" cellpadding="10" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: left;">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. <br>
|
|
<br>
|
|
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.<br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<br>
|
|
One remarkable aspect of the state tracking logic is the use of the <span
|
|
style="font-style: italic;">fResumePending</span> 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 can improve the efficiency of the IDE commands.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDARunControl
|
|
- canResume()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line222">222: </a><strong><font color="#4169e1"> public boolean canResume(IExecutionDMContext context)</font></strong> {<br><a
|
|
name="line223">223: </a> <font color="#4169e1">return</font> isSuspended(context) && !fResumePending;<br><a
|
|
name="line224">224: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h3><a class="mozTocH3" name="mozTocId120075"></a>5.2 Commands</h3>
|
|
|
|
All run control commands follow the same pattern shown below, by
|
|
example of the resume() command:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDARunControl
|
|
- resume()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line238">238: </a><strong><font color="#4169e1"> public void resume(IExecutionDMContext context, final RequestMonitor rm)</font></strong> {<br><a
|
|
name="line239">239: </a> assert context != null;<br>240:<br><a
|
|
name="line241">241: </a> <font color="#4169e1">if</font> (canResume(context)) { <br><a
|
|
name="line242">242: </a> fResumePending = true;<br><a
|
|
name="line243">243: </a> fCommandControl.queueCommand(<br><a
|
|
name="line244">244: </a> new PDAResumeCommand(fCommandControl.getProgramDMContext()),<br><a
|
|
name="line245">245: </a> new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { <br><a
|
|
name="line246">246: </a> @Override<br><a
|
|
name="line247">247: </a><strong><font color="#4169e1"> protected void handleErrorOrCancel()</font></strong> {<br><a
|
|
name="line248">248: </a> <font color="#b22222">// If the resume command failed, we no longer</font><br><a
|
|
name="line249">249: </a> <font color="#b22222">// expect to receive a resumed event.</font><br><a
|
|
name="line250">250: </a> fResumePending = false;<br>251: super.handleErrorOrCancel();<br><a
|
|
name="line251">252: </a> }<br><a name="line252">253: </a> }<br><a
|
|
name="line253">254: </a> );<br><a name="line254">255: </a> }<font
|
|
color="#4169e1"> else</font> {<br><a name="line255">256: </a> PDAPlugin.failRequest(rm, INVALID_STATE, <font
|
|
color="#666666">"Given context: "</font> + context + <font
|
|
color="#666666">", is already running."</font>);<br><a name="line256">257: </a> }<br><a
|
|
name="line257">258: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 241 checks if the resume command can be called. If
|
|
not, the command fails immediately.</li>
|
|
<li>Line 242 updates the <span style="font-style: italic;">fResumePending</span>
|
|
state flag.</li>
|
|
<li>Lines 243-253 send the resume command to the PDA debugger. <br>
|
|
</li>
|
|
<li>Lines 247-252 adds error handling in case the result command
|
|
fails. It restores the service state.</li>
|
|
<li>Line 251 calls the super class's handleErrorOrCancel()
|
|
method. The super class relays the error status to the parent
|
|
request monitor and completes it.<br>
|
|
</li>
|
|
</ul>
|
|
<ul>
|
|
<li>Second service, depends on command control</li>
|
|
<li>Tracking program running state <br>
|
|
</li>
|
|
</ul>
|
|
<h3><a class="mozTocH3" name="mozTocId976358"></a>5.3 IExecutionDMData</h3>
|
|
There is very little data that the run control service 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. <br>
|
|
<h2><a class="mozTocH2" name="mozTocId325852"></a>6 Step 5 - Breakpoints</h2>
|
|
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. <br>
|
|
<h3><a class="mozTocH3" name="mozTocId19247"></a>6.1 IDE Breakpoints</h3>
|
|
Eclipse breakpoints are based on markers, which are special tags in the
|
|
Eclipse 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. <br>
|
|
<p>An Eclipse breakpoint declaration comes in three parts:<br>
|
|
</p>
|
|
<ol>
|
|
<li><span style="text-decoration: underline;">org.eclipse.core.resources.markers
|
|
extension</span> - 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.</li>
|
|
<li><span style="text-decoration: underline;">org.eclipse.debug.core.breakpoints
|
|
extension</span> - A breakpoint must
|
|
be declared using this extension point, which requires a valid marker
|
|
type.</li>
|
|
<li><span style="text-decoration: underline;">org.eclipse.debug.core.model.IBreakpoint
|
|
implementation</span> - A
|
|
breakpoint object must implement this interface.</li>
|
|
</ol>
|
|
Finally, in order to have breakpoints appear in the Breakpoints
|
|
view, they need to be registered with the breakpoint manager, which is
|
|
represented by the <span style="font-style: italic;">org.eclipse.debug.core.IBreakpointManager</span>
|
|
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.<br>
|
|
<br>
|
|
Code listings are omitted here since implementing Eclipse breakpoints
|
|
is described in fine detail the <a style="font-style: italic;"
|
|
href="http://www.eclipse.org/articles/Article-Debugger/how-to.html">How
|
|
to write an Eclipse debugger</a> article.<br>
|
|
<p> </p>
|
|
<h3><a class="mozTocH3" name="mozTocId991346"></a>6.2 Target-Side
|
|
Breakpoints</h3>
|
|
DSF defines the IBreakpoints interface for a service which the
|
|
functions
|
|
of managing breakpoints installed on the target. These functions
|
|
include:<br>
|
|
<ul>
|
|
<li>Installing a breakpoint<br>
|
|
</li>
|
|
<li>removing a breakpoint</li>
|
|
<li>changing breakpoint attributes (if supported)</li>
|
|
<li>listing installed breakpoints</li>
|
|
<li>retrieving breakpoint detailed data</li>
|
|
</ul>
|
|
<h4><a class="mozTocH4" name="mozTocId892077"></a>Breakpoint Context<br>
|
|
</h4>
|
|
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: <span
|
|
style="font-style: italic;">Map<String, Object></span>.
|
|
After the target-side breakpoint is created, it is represented using an
|
|
opaque Data Model context of type <span style="font-style: italic;">IBreakpointDMContext</span>.
|
|
As an example the PDA line breakpoint context implementation is the
|
|
following:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDABreakpoints
|
|
- BreakpointDMContext</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line50"> 50: </a> private static class BreakpointDMContext extends AbstractDMContext implements IBreakpointDMContext {<br> 51:<br><a
|
|
name="line52"> 52: </a> final Integer fLine;<br> 53:<br><a
|
|
name="line54"> 54: </a><strong><font color="#4169e1"> public BreakpointDMContext(String sessionId, PDAProgramDMContext commandControlCtx, Integer line)</font></strong> {<br><a
|
|
name="line55"> 55: </a> super(sessionId, new IDMContext[] { commandControlCtx });<br><a
|
|
name="line56"> 56: </a> fLine = line;<br><a name="line57"> 57: </a> }<br> 58:<br><a
|
|
name="line59"> 59: </a> @Override<br><a name="line60"> 60: </a><strong><font
|
|
color="#4169e1"> public boolean equals(Object obj)</font></strong> {<br><a
|
|
name="line61"> 61: </a> <font color="#4169e1">return</font> baseEquals(obj) && (fLine.equals(((BreakpointDMContext) obj).fLine));<br><a
|
|
name="line62"> 62: </a> }<br> 63:<br><a name="line64"> 64: </a> @Override<br><a
|
|
name="line65"> 65: </a><strong><font color="#4169e1"> public int hashCode()</font></strong> {<br><a
|
|
name="line66"> 66: </a> <font color="#4169e1">return</font> baseHashCode() + fLine.hashCode();<br><a
|
|
name="line67"> 67: </a> }<br> 68:<br><a name="line69"> 69: </a> @Override<br><a
|
|
name="line70"> 70: </a><strong><font color="#4169e1"> public String toString()</font></strong> {<br><a
|
|
name="line71"> 71: </a> <font color="#4169e1">return</font> baseToString() + <font
|
|
color="#666666">".breakpoint("</font> + fLine + <font color="#666666">")"</font>; <font
|
|
color="#b22222">//$NON-NLS-1$//$NON-NLS-2$*/</font><br><a name="line72"> 72: </a> }<br><a
|
|
name="line73"> 73: </a> }<br><br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 52 declares the fLine variable, which uniquely identifies a
|
|
line breakpoint in a PDA debug session.</li>
|
|
</ul>
|
|
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 <span
|
|
style="font-style: italic;">IBreakpointsTargetDMContext</span>
|
|
interface, which is then used as a parent context of the <span
|
|
style="font-style: italic;">IBreakpointDMContext</span> object
|
|
instances.<br>
|
|
<h4><a class="mozTocH4" name="mozTocId237357"></a>Inserting a Breakpoint</h4>
|
|
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:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDABreakpoints
|
|
- insertBreakpoint()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line180">180: </a> public void insertBreakpoint(IBreakpointsTargetDMContext context, Map<String, Object> attributes, <br><a
|
|
name="line181">181: </a> DataRequestMonitor<IBreakpointDMContext> rm) <br><a
|
|
name="line182">182: </a> {<br><a name="line183">183: </a> Boolean enabled = (Boolean)attributes.get(IBreakpoint.ENABLED);<br><a
|
|
name="line184">184: </a> <font color="#4169e1">if</font> (enabled != null && !enabled.booleanValue()) {<br><a
|
|
name="line185">185: </a> <font color="#b22222">// If the breakpoint is disabled, just fail the request. </font><br><a
|
|
name="line186">186: </a> PDAPlugin.failRequest(rm, REQUEST_FAILED, <font
|
|
color="#666666">"Breakpoint is disabled"</font>);<br><a name="line187">187: </a> } <font
|
|
color="#4169e1">else</font> {<br><a name="line188">188: </a> String type = (String) attributes.get(ATTR_BREAKPOINT_TYPE);<br><a
|
|
name="line189">189: </a> <br><a name="line190">190: </a> <font
|
|
color="#4169e1">if</font> (PDA_LINE_BREAKPOINT.equals(type)) {<br><a
|
|
name="line191">191: </a> <font color="#b22222">// Retrieve the PDA program context from the context given in the </font><br><a
|
|
name="line192">192: </a> <font color="#b22222">// argument. This service is typically only called by the </font><br><a
|
|
name="line193">193: </a> <font color="#b22222">// breakpoints mediator, which was called with the program context</font><br><a
|
|
name="line194">194: </a> <font color="#b22222">// in the services initialization sequence. So checking if </font><br><a
|
|
name="line195">195: </a> <font color="#b22222">// programCtx != null is mostly a formality.</font><br><a
|
|
name="line196">196: </a> PDAProgramDMContext programCtx = DMContexts.getAncestorOfType(context, PDAProgramDMContext.class);<br><a
|
|
name="line197">197: </a> <font color="#4169e1">if</font> (programCtx != null) {<br><a
|
|
name="line198">198: </a> doInsertBreakpoint(programCtx, attributes, rm);<br><a
|
|
name="line199">199: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line200">200: </a> PDAPlugin.failRequest(rm, INVALID_HANDLE, <font
|
|
color="#666666">"Unknown breakpoint type"</font>);<br><a name="line201">201: </a> }<br><a
|
|
name="line202">202: </a> }<br><a name="line203">203: </a> <font
|
|
color="#4169e1">else</font> <font color="#4169e1">if</font> (PDA_WATCHPOINT.equals(type)) {<br><a
|
|
name="line204">204: </a> doInsertWatchpoint(attributes, rm);<br><a
|
|
name="line205">205: </a> }<br><a name="line206">206: </a> <font
|
|
color="#4169e1">else</font> {<br><a name="line207">207: </a> PDAPlugin.failRequest(rm, REQUEST_FAILED, <font
|
|
color="#666666">"Unknown breakpoint type"</font>);<br><a name="line208">208: </a> }<br><a
|
|
name="line209">209: </a> }<br><a name="line210">210: </a> }</pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Lines 183-186 determine if the breakpoint is enabled. If it
|
|
is not, the insert command fails with an expected error. <br>
|
|
</li>
|
|
<li>Line 188 retrieves the breakpoint type attribute, which is used
|
|
to determine which breakpoint insert subroutine to call.</li>
|
|
<li>Line 196 retrieves the <span style="font-style: italic;">PDAProgramDMContext</span>
|
|
from the breakpoint target context. This context is the only
|
|
breakpoints target context in the PDA debugger.</li>
|
|
<li>Finally, lines 198 and 207 delegate to the proper subroutine to
|
|
create the breakpoint.</li>
|
|
</ul>
|
|
The doInserBreakpoint() subroutine is listed next:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDABreakpoints
|
|
- doInsertBreakpoint()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line212">212: </a> private void doInsertBreakpoint(PDAProgramDMContext programCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm) <br><a
|
|
name="line213">213: </a> {<br><a name="line214">214: </a> <font
|
|
color="#b22222">// Compare the program path in the breakpoint with the path in the PDA </font><br><a
|
|
name="line215">215: </a> <font color="#b22222">// program context. Only insert the breakpoint if the program matches. </font><br><a
|
|
name="line216">216: </a> String program = (String)attributes.get(ATTR_PROGRAM_PATH);<br><a
|
|
name="line217">217: </a> <font color="#4169e1">if</font> (!programCtx.getProgram().equals(program)) {<br><a
|
|
name="line218">218: </a> PDAPlugin.failRequest(rm, REQUEST_FAILED, <font
|
|
color="#666666">"Invalid file name"</font>);<br><a name="line219">219: </a> <font
|
|
color="#4169e1">return</font>;<br><a name="line220">220: </a> }<br><br><a
|
|
name="line222">222: </a> <font color="#b22222">// Retrieve the line.</font><br><a
|
|
name="line223">223: </a> Integer line = (Integer)attributes.get(IMarker.LINE_NUMBER);<br><a
|
|
name="line224">224: </a> <font color="#4169e1">if</font> (line == null) {<br><a
|
|
name="line225">225: </a> PDAPlugin.failRequest(rm, REQUEST_FAILED, <font
|
|
color="#666666">"No breakpoint line specified"</font>);<br><a
|
|
name="line226">226: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line227">227: </a> }<br><br><a name="line229">229: </a> <font
|
|
color="#b22222">// Create a new breakpoint context object and check that it's not </font><br><a
|
|
name="line230">230: </a> <font color="#b22222">// installed already. PDA can only track a single breakpoint at a </font><br><a
|
|
name="line231">231: </a> <font color="#b22222">// given line, attempting to set the second breakpoint should fail.</font><br><a
|
|
name="line232">232: </a> final BreakpointDMContext breakpointCtx = <br><a
|
|
name="line233">233: </a> new BreakpointDMContext(getSession().getId(), fCommandControl.getProgramDMContext(), line);<br><a
|
|
name="line234">234: </a> <font color="#4169e1">if</font> (fBreakpoints.contains(breakpointCtx)) {<br><a
|
|
name="line235">235: </a> PDAPlugin.failRequest(rm, REQUEST_FAILED, <font
|
|
color="#666666">"Breakpoint already set"</font>);<br><a name="line236">236: </a> <font
|
|
color="#4169e1">return</font>;<br><a name="line237">237: </a> }<br><br><a
|
|
name="line239">239: </a> <font color="#b22222">// Add the new breakpoint context to the list of known breakpoints. </font><br><a
|
|
name="line240">240: </a> <font color="#b22222">// Adding it here, before the set command is completed will prevent </font><br><a
|
|
name="line241">241: </a> <font color="#b22222">// a possibility of a second breakpoint being installed in the same </font><br><a
|
|
name="line242">242: </a> <font color="#b22222">// location while this breakpoint is being processed. It will also</font><br><a
|
|
name="line243">243: </a> <font color="#b22222">// allow the breakpoint to be removed or updated even while it is </font><br><a
|
|
name="line244">244: </a> <font color="#b22222">// still being processed here.</font><br><a
|
|
name="line245">245: </a> fBreakpoints.add(breakpointCtx);<br><a
|
|
name="line246">246: </a> fCommandControl.queueCommand(<br><a
|
|
name="line247">247: </a> new PDASetBreakpointCommand(fCommandControl.getProgramDMContext(), line), <br><a
|
|
name="line248">248: </a> new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {<br><a
|
|
name="line249">249: </a> @Override<br><a name="line250">250: </a><strong><font
|
|
color="#4169e1"> protected void handleOK()</font></strong> {<br><a
|
|
name="line251">251: </a> rm.setData(breakpointCtx);<br><a
|
|
name="line252">252: </a> rm.done();<br><a
|
|
name="line253">253: </a> }<br><br><a name="line255">255: </a> @Override<br><a
|
|
name="line256">256: </a><strong><font color="#4169e1"> protected void handleErrorOrCancel()</font></strong> {<br><a
|
|
name="line257">257: </a> <font color="#b22222">// If inserting of the breakpoint failed, remove it from</font><br><a
|
|
name="line258">258: </a> <font color="#b22222">// the set of installed breakpoints.</font><br><a
|
|
name="line259">259: </a> fBreakpoints.remove(breakpointCtx);<br><a
|
|
name="line260">260: </a> super.handleErrorOrCancel();<br><a
|
|
name="line261">261: </a> }<br><a name="line262">262: </a> });<br><a
|
|
name="line263">263: </a> }<br><br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h4><a class="mozTocH4" name="mozTocId923537"></a>Removing a Breakpoint</h4>
|
|
The PDABreakpoints.removeBreakpoint() command takes the
|
|
IBreakpointDMContext as an argument, but otherwise follows the same
|
|
general logic as the insertBreakpoint() implementation.<br>
|
|
<h4><a class="mozTocH4" name="mozTocId963766"></a>Updating a Breakpoint</h4>
|
|
Updating a breakpoint involves modifying 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. <br>
|
|
<p>The PDA debugger allows watchpoints to be updated, but only with
|
|
respect to what operations may trigger the watchpoint:<br>
|
|
</p>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDABreakpoints
|
|
- updateBreakpoint()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line367">367: </a> public void updateBreakpoint(final IBreakpointDMContext bpCtx, Map<String, Object> attributes, final RequestMonitor rm) {<br><a
|
|
name="line368">368: </a> <font color="#4169e1">if</font> (!fBreakpoints.contains(bpCtx)) {<br><a
|
|
name="line369">369: </a> PDAPlugin.failRequest(rm, REQUEST_FAILED, <font
|
|
color="#666666">"Breakpoint not installed"</font>);<br><a
|
|
name="line370">370: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line371">371: </a> }<br><br><a name="line373">373: </a> <font
|
|
color="#4169e1">if</font> (bpCtx instanceof BreakpointDMContext) {<br><a
|
|
name="line374">374: </a> PDAPlugin.failRequest(rm, NOT_SUPPORTED, <font
|
|
color="#666666">"Modifying PDA breakpoints is not supported"</font>);<br><a
|
|
name="line375">375: </a> } <font color="#4169e1">else</font> <font
|
|
color="#4169e1">if</font> (bpCtx instanceof WatchpointDMContext) {<br><a
|
|
name="line376">376: </a> WatchpointDMContext wpCtx = (WatchpointDMContext)bpCtx;<br><a
|
|
name="line377">377: </a> <font color="#4169e1">if</font> (!wpCtx.fFunction.equals(attributes.get(PDAWatchpoint.FUNCTION_NAME)) || <br><a
|
|
name="line378">378: </a> !wpCtx.fVariable.equals(attributes.get(PDAWatchpoint.VAR_NAME)) )<br><a
|
|
name="line379">379: </a> {<br><a name="line380">380: </a> PDAPlugin.failRequest(rm, REQUEST_FAILED, <font
|
|
color="#666666">"Cannot modify watchpoint function or variable"</font>);<br><a
|
|
name="line381">381: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line382">382: </a> }<br><a name="line383">383: </a> <br><a
|
|
name="line384">384: </a> <font color="#b22222">// PDA debugger can only track one watchpoint in the same location, </font><br><a
|
|
name="line385">385: </a> <font color="#b22222">// so we can simply remove the existing context from the set and </font><br><a
|
|
name="line386">386: </a> <font color="#b22222">// call insert again. </font><br><a
|
|
name="line387">387: </a> fBreakpoints.remove(bpCtx);<br><a
|
|
name="line388">388: </a> doInsertWatchpoint(<br><a
|
|
name="line389">389: </a> attributes, <br><a
|
|
name="line390">390: </a> new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), rm) {<br><a
|
|
name="line391">391: </a> @Override<br><a
|
|
name="line392">392: </a><strong><font color="#4169e1"> protected void handleOK()</font></strong> {<br><a
|
|
name="line393">393: </a> <font color="#b22222">// The inserted watchpoint context will equal the </font><br><a
|
|
name="line394">394: </a> <font color="#b22222">// current context.</font><br><a
|
|
name="line395">395: </a> assert bpCtx.equals(getData());<br><a
|
|
name="line396">396: </a> rm.done();<br><a
|
|
name="line397">397: </a> }<br><a name="line398">398: </a> });<br><a
|
|
name="line399">399: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line400">400: </a> PDAPlugin.failRequest(rm, INVALID_HANDLE, <font
|
|
color="#666666">"Invalid breakpoint"</font>);<br><a name="line401">401: </a> }<br><a
|
|
name="line402">402: </a> }<br><br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Lines 368-371 verify that the given breakpoint exists. If
|
|
it does not exist the update request fails. <br>
|
|
</li>
|
|
<li>Lines 377-382 verify that only the data access attributes of the
|
|
watchpoint were modified.</li>
|
|
<li>Lines 387 -398 re-insert the watchpoint which effectively updates
|
|
the watchpoint attributes.</li>
|
|
</ul>
|
|
<h4><a class="mozTocH4" name="mozTocId206093"></a>Listing Breakpoints</h4>
|
|
The PDA Breakpoints service tracks the inserted breakpoints using the <span
|
|
style="font-style: italic;">fBreakpoints</span> field. Returning
|
|
the list of breakpoints only requires returning the current state of
|
|
this field.<br>
|
|
<h4><a class="mozTocH4" name="mozTocId621678"></a>Retrieving Breakpoint
|
|
Detailed Data</h4>
|
|
The simple PDA debugger does not track detailed breakpoint data, such
|
|
has hit counts, addresses etc. So this function simply returns an
|
|
error.<br>
|
|
<h3><a class="mozTocH3" name="mozTocId389907"></a>6.4 Breakpoints
|
|
Mediator</h3>
|
|
With the APIs for managing IDE and Target-Side breakpoints clearly
|
|
defined, there is a need for a component which will keep the two sets
|
|
of breakpoint objects synchronized. DSF provides a standard <span
|
|
style="font-style: italic;">BreakpointsMediator</span> service to
|
|
accomplish this task.
|
|
<table style="text-align: left; margin-left: auto; margin-right: auto;"
|
|
border="0" cellpadding="5" cellspacing="30">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: center; vertical-align: middle;"><img
|
|
style="width: 788px; height: 289px;"
|
|
title="Mediating IDE and Target-Side breakpoints" alt=""
|
|
src="breakpoints_1.png"><br>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top;"><small><span
|
|
style="font-weight: bold;">Image 3: Mediating IDE and Target-Side
|
|
breakpoints</span></small><br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
The <span style="font-style: italic;">BreakpointsMediator</span>
|
|
service is not meant to be sub-classed by specific debugger
|
|
integrations, however the specific IDE Breakpoint objects as well as
|
|
Target-Side Breakpoint attributes differ from debugger to
|
|
debugger.
|
|
Therefore, the Breakpoints Mediator requires a helper object, which
|
|
implements IBreakpointAttributeTranslator which encapsulates the
|
|
debugger-specific functionality. The most important function of
|
|
the attribute translator is to translate IDE Breakpoint attributes into
|
|
Target-Side breakpoint attributes. The following listing shows
|
|
how the PDA debugger implements this function:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDABreakpointAttributeTranslator
|
|
- getBreakpointAttributes()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line65"> 65: </a> public List<Map<String, Object>> getBreakpointAttributes(IBreakpoint bp, boolean bpManagerEnabled) <br><a
|
|
name="line66"> 66: </a> <font color="#4169e1"> throws</font> CoreException <br><a
|
|
name="line67"> 67: </a> {<br><a name="line68"> 68: </a> Map<String, Object> attrs = new HashMap<String, Object>(); <br><br><a
|
|
name="line70"> 70: </a> <font color="#b22222">// Check that the marker exists and retrieve its attributes. </font><br><a
|
|
name="line71"> 71: </a> <font color="#b22222">// Due to accepted race conditions, the breakpiont marker may become null </font><br><a
|
|
name="line72"> 72: </a> <font color="#b22222">// while this method is being invoked. In this case throw an exception</font><br><a
|
|
name="line73"> 73: </a> <font color="#b22222">// and let the caller handle it.</font><br><a
|
|
name="line74"> 74: </a> IMarker marker = bp.getMarker();<br><a
|
|
name="line75"> 75: </a> <font color="#4169e1">if</font> (marker == null || !marker.exists()) {<br><a
|
|
name="line76"> 76: </a> <font color="#4169e1">throw</font> new DebugException(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, <font
|
|
color="#666666">"Breakpoint marker does not exist"</font>, null)); <br><a
|
|
name="line77"> 77: </a> }<br><a name="line78"> 78: </a> <font
|
|
color="#b22222">// Suppress cast warning: platform is still on Java 1.3</font><br><a
|
|
name="line79"> 79: </a> @SuppressWarnings(<font color="#666666">"unchecked"</font>)<br><a
|
|
name="line80"> 80: </a> Map<String, Object> platformBpAttrs = marker.getAttributes();<br><br><a
|
|
name="line82"> 82: </a> <font color="#b22222">// Copy breakpoint attributes.</font><br><a
|
|
name="line83"> 83: </a> <font color="#4169e1">if</font> (bp instanceof PDAWatchpoint) {<br><a
|
|
name="line84"> 84: </a> attrs.put(PDABreakpoints.ATTR_BREAKPOINT_TYPE, PDABreakpoints.PDA_WATCHPOINT);<br><br><a
|
|
name="line86"> 86: </a> copyAttributes(platformBpAttrs, attrs, fgPDAWatchpointAttributes);<br><a
|
|
name="line87"> 87: </a> } <font color="#4169e1">else</font> <font
|
|
color="#4169e1">if</font> (bp instanceof PDALineBreakpoint) {<br><a
|
|
name="line88"> 88: </a> attrs.put(PDABreakpoints.ATTR_BREAKPOINT_TYPE, PDABreakpoints.PDA_LINE_BREAKPOINT);<br><a
|
|
name="line89"> 89: </a> attrs.put(PDABreakpoints.ATTR_PROGRAM_PATH, marker.getResource().getFullPath().toString()); <br><br><a
|
|
name="line91"> 91: </a> copyAttributes(platformBpAttrs, attrs, fgPDALineBreakpointAttributes);<br><a
|
|
name="line92"> 92: </a> }<br><br><a name="line94"> 94: </a> <font
|
|
color="#b22222">// If the breakpoint manager is disabled, override the enabled attribute.</font><br><a
|
|
name="line95"> 95: </a> <font color="#4169e1">if</font> (!bpManagerEnabled) {<br><a
|
|
name="line96"> 96: </a> attrs.put(IBreakpoint.ENABLED, false);<br><a
|
|
name="line97"> 97: </a> }<br><br><a name="line99"> 99: </a> <font
|
|
color="#b22222">// The breakpoint mediator allows for multiple target-side breakpoints </font><br><a
|
|
name="line100">100: </a> <font color="#b22222">// to be created for each IDE breakpoint. Although in case of PDA this </font><br><a
|
|
name="line101">101: </a> <font color="#b22222">// feature is never used, we still have to return a list of attributes.</font><br><a
|
|
name="line102">102: </a> List<Map<String, Object>> retVal = new ArrayList<Map<String, Object>>(1);<br><a
|
|
name="line103">103: </a> retVal.add(attrs);<br><a name="line104">104: </a> <font
|
|
color="#4169e1">return</font> retVal;<br><a name="line105">105: </a> }<br><br><a
|
|
name="line107">107: </a> private void copyAttributes(Map<String, Object> srcMap, Map<String, Object> destMap, String[] attrs) {<br><a
|
|
name="line108">108: </a> <font color="#4169e1">for</font> (String attr : attrs) {<br><a
|
|
name="line109">109: </a> <font color="#4169e1">if</font> (srcMap.containsKey(attr)) {<br><a
|
|
name="line110">110: </a> destMap.put(attr, srcMap.get(attr));<br><a
|
|
name="line111">111: </a> }<br><a name="line112">112: </a> }<br><a
|
|
name="line113">113: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h2><a class="mozTocH2" name="mozTocId380385"></a>7 Step 6 - Stack</h2>
|
|
<h3><a class="mozTocH3" name="mozTocId378363"></a>7.1 Command Cache</h3>
|
|
A new feature introduced in this service is the command cache.
|
|
The command cache is a surprisingly simple mechanism for caching
|
|
service data which otherwise would need to be retrieved repeatedly from
|
|
the debugger back end. The command cache performs two functions:<br>
|
|
<ol>
|
|
<li>Map Command objects to corresponding Command Result objects.</li>
|
|
<li>While waiting for a Command to be processed, queue incoming
|
|
Commands for the same data and complete them when the first Command is
|
|
completed.</li>
|
|
</ol>
|
|
Using the command cache greatly simplifies the logic in implementing
|
|
data retrieval commands. As an example, the following is the
|
|
listing of the PDAStack.getFrames() method:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDAStack
|
|
- getFrames()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line244">244: </a> public void getFrames(IDMContext context, final DataRequestMonitor<IFrameDMContext[]> rm) {<br><a
|
|
name="line245">245: </a> <font color="#b22222">// Can only create stack frames for an execution context as a parent, </font><br><a
|
|
name="line246">246: </a> <font color="#b22222">// however the argument context is a generic context type, so it could </font><br><a
|
|
name="line247">247: </a> <font color="#b22222">// be an execution context, a frame, a variable, etc. Search the </font><br><a
|
|
name="line248">248: </a> <font color="#b22222">// hierarchy of the argument context to find the execution one.</font><br><a
|
|
name="line249">249: </a> final IExecutionDMContext execCtx = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);<br><a
|
|
name="line250">250: </a> <font color="#4169e1">if</font> (execCtx == null) {<br><a
|
|
name="line251">251: </a> PDAPlugin.failRequest(rm, IDsfService.INVALID_HANDLE, <font
|
|
color="#666666">"Invalid context "</font> + context);<br><a
|
|
name="line252">252: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line253">253: </a> }<br><br><a name="line255">255: </a> <font
|
|
color="#b22222">// Execute the stack command and create the corresponding frame contexts.</font><br><a
|
|
name="line256">256: </a> fCommandCache.execute(<br><a
|
|
name="line257">257: </a> new PDAStackCommand(fCommandControl.getProgramDMContext()),<br><a
|
|
name="line258">258: </a> new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {<br><a
|
|
name="line259">259: </a> @Override<br><a name="line260">260: </a><strong><font
|
|
color="#4169e1"> protected void handleOK()</font></strong> {<br><a
|
|
name="line261">261: </a> IFrameDMContext[] frameCtxs = new IFrameDMContext[getData().fFrames.length];<br><a
|
|
name="line262">262: </a> <font color="#4169e1">for</font> (int i = 0; i < getData().fFrames.length; i++) {<br><a
|
|
name="line263">263: </a> frameCtxs[i] = new FrameDMContext(getSession().getId(), execCtx, i);<br><a
|
|
name="line264">264: </a> }<br><a name="line265">265: </a> rm.setData(frameCtxs);<br><a
|
|
name="line266">266: </a> rm.done();<br><a
|
|
name="line267">267: </a> }<br><a name="line268">268: </a> });<br><a
|
|
name="line269">269: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Lines 256-268 create a new PDAStackCommand, and execute it using
|
|
the command cache. <br>
|
|
</li>
|
|
<ul>
|
|
<li>If the <span style="font-style: italic;">PDAStackCommand</span>
|
|
was previously executed, the <span style="font-style: italic;">PDAStackCommandResult</span>
|
|
object will be returned from the cached data. <br>
|
|
</li>
|
|
<li>If the <span style="font-style: italic;">PDAStackCommand</span>
|
|
was just sent to the debugger, and the cache is waiting for the result,
|
|
this request monitor will be put in a queue to wait for the
|
|
result. <br>
|
|
</li>
|
|
<li>If the cache does not contain an entry for the <span
|
|
style="font-style: italic;">PDAStackCommand</span>, it will create one
|
|
and send it to the debugger.<br>
|
|
</li>
|
|
</ul>
|
|
<li>Lines 261-266 implement the handler which processes the <span
|
|
style="font-style: italic;">PDAStackCommandResult</span>. It
|
|
creates an array of FrameDMContext objects and returns it to the client.<br>
|
|
</li>
|
|
</ul>
|
|
<h3><a class="mozTocH3" name="mozTocId923476"></a>7.2 Frame Context</h3>
|
|
The primary object type managed by the stack service a stack
|
|
frame. It is implemented by the FrameDMContext object listed
|
|
below:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDAStack
|
|
- FrameDMContext</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line54"> 54: </a> private static class FrameDMContext extends AbstractDMContext implements IFrameDMContext {<br><br><a
|
|
name="line56"> 56: </a> final private int fLevel;<br><br><a
|
|
name="line58"> 58: </a> FrameDMContext(String sessionId, IExecutionDMContext execDmc, int level) {<br><a
|
|
name="line59"> 59: </a> super(sessionId, new IDMContext[] { execDmc });<br><a
|
|
name="line60"> 60: </a> fLevel = level;<br><a name="line61"> 61: </a> }<br><br><a
|
|
name="line63"> 63: </a><strong><font color="#4169e1"> public int getLevel()</font></strong> { <font
|
|
color="#4169e1">return</font> fLevel; }<br><br><a name="line65"> 65: </a> @Override<br><a
|
|
name="line66"> 66: </a><strong><font color="#4169e1"> public boolean equals(Object other)</font></strong> {<br><a
|
|
name="line67"> 67: </a> <font color="#4169e1">return</font> super.baseEquals(other) && ((FrameDMContext)other).fLevel == fLevel;<br><a
|
|
name="line68"> 68: </a> }<br><br><a name="line70"> 70: </a> @Override<br><a
|
|
name="line71"> 71: </a><strong><font color="#4169e1"> public int hashCode()</font></strong> {<br><a
|
|
name="line72"> 72: </a> <font color="#4169e1">return</font> super.baseHashCode() ^ fLevel;<br><a
|
|
name="line73"> 73: </a> }<br><br><a name="line75"> 75: </a> @Override<br><a
|
|
name="line76"> 76: </a><strong><font color="#4169e1"> public String toString()</font></strong> { <br><a
|
|
name="line77"> 77: </a> <font color="#4169e1">return</font> baseToString() + <font
|
|
color="#666666">".frame["</font> + fLevel + <font color="#666666">"]"</font>; <font
|
|
color="#b22222">//$NON-NLS-1$ //$NON-NLS-2$</font><br><a name="line78"> 78: </a> }<br><a
|
|
name="line79"> 79: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 56 declares the only field in the frame object, which is the
|
|
frame level. <br>
|
|
</li>
|
|
</ul>
|
|
The frame context, which in itself does not provide access to much
|
|
frame information, can be used to retrieve more complete frame data
|
|
implemented using the FrameDMData object. The frame data object
|
|
is based on information parsed from the result of the PDA debugger
|
|
"stack" command, which is written into the <span
|
|
style="font-style: italic;">PDAFrame</span> object by the <span
|
|
style="font-style: italic;">PDAStackCommandResult</span><br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDAStack
|
|
- FrameDMData</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line85"> 85: </a> private static class FrameDMData implements IFrameDMData {<br><br><a
|
|
name="line87"> 87: </a> final private PDAFrame fFrame;<br><br><a
|
|
name="line89"> 89: </a> FrameDMData(PDAFrame frame) {<br><a
|
|
name="line90"> 90: </a> fFrame = frame;<br><a name="line91"> 91: </a> }<br><br><a
|
|
name="line93"> 93: </a><strong><font color="#4169e1"> public String getFile()</font></strong> {<br><a
|
|
name="line94"> 94: </a> <font color="#4169e1">return</font> fFrame.fFilePath.lastSegment();<br><a
|
|
name="line95"> 95: </a> }<br><br><a name="line97"> 97: </a><strong><font
|
|
color="#4169e1"> public String getFunction()</font></strong> {<br><a
|
|
name="line98"> 98: </a> <font color="#4169e1">return</font> fFrame.fFunction;<br><a
|
|
name="line99"> 99: </a> }<br><br><a name="line101">101: </a><strong><font
|
|
color="#4169e1"> public int getLine()</font></strong> {<br><a
|
|
name="line102">102: </a> <font color="#4169e1">return</font> fFrame.fLine + 1;<br><a
|
|
name="line103">103: </a> }<br><br><a name="line105">105: </a><strong><font
|
|
color="#4169e1"> public int getColumn()</font></strong> {<br><a
|
|
name="line106">106: </a> <font color="#4169e1">return</font> 0;<br><a
|
|
name="line107">107: </a> }<br><br><a name="line109">109: </a><strong><font
|
|
color="#4169e1"> public IAddress getAddress()</font></strong> {<br><a
|
|
name="line110">110: </a> <font color="#4169e1">return</font> null;<br><a
|
|
name="line111">111: </a> }<br><a name="line112">112: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<h2><a class="mozTocH2" name="mozTocId156503"></a>8 Step 7 - Source
|
|
Display</h2>
|
|
Integrating source display is relatively simple task, even though the
|
|
Eclipse APIs for looking up and displaying source are rather
|
|
convoluted. Fortunately Eclipse Platform and DSF provide most of
|
|
the components needed to implement this functionality.<br>
|
|
<table style="text-align: left; margin-left: auto; margin-right: auto;"
|
|
border="0" cellpadding="5" cellspacing="30">
|
|
<tbody>
|
|
<tr>
|
|
<td style="text-align: center; vertical-align: middle;"><img
|
|
style="width: 628px; height: 458px;"
|
|
title="Components involved in Source Display" alt=""
|
|
src="source_display_1.png"><br>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top;"><small><span
|
|
style="font-weight: bold;">Image 3: Components involved in Source
|
|
Display</span></small><br>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
The first step in integrating source lookup, is to create a source
|
|
lookup director and the source container. This is explained in
|
|
detail in the <a style="font-style: italic;"
|
|
href="http://www.eclipse.org/articles/Article-Debugger/how-to.html">How
|
|
to write an Eclipse debugger</a> article referenced earlier.
|
|
There is one difference in this process for a DSF-based debugger.
|
|
The source lookup director does not need to initialize a source lookup
|
|
participant list. <br>
|
|
<p>The second step is to register a DSF source display adapter.
|
|
This has actually <a href="#Source_Display_Adapter_Registration">already
|
|
been accomplished</a> in <a href="#Step_3_-_View_Model">Step 3 - View
|
|
Model</a>, when registering the View Model adapters.<br>
|
|
</p>
|
|
<h2><a class="mozTocH2" name="mozTocId343062"></a>9 Step 8 - Variables</h2>
|
|
At this point we almost have a fully functional PDA debugger. The
|
|
only thing that is left is to populate the Variables and Expressions
|
|
views. <br>
|
|
Displaying variable data in DSF requires use of two services:<br>
|
|
<ol>
|
|
<li><span style="text-decoration: underline;">IStack service</span> -
|
|
This service is used to get the list of local variables' names in a
|
|
given stack frame.<br>
|
|
</li>
|
|
<li><span style="text-decoration: underline;">IExpressions service</span>
|
|
- This service is used to evaluate the variable names as expressions in
|
|
order to retrieve full type and value information for the given
|
|
variables.<br>
|
|
</li>
|
|
</ol>
|
|
<h3><a class="mozTocH3" name="mozTocId837286"></a>9.1 Variable Contexts</h3>
|
|
The stack service allows clients to retrieve two types of variables
|
|
through two methods<br>
|
|
<ul>
|
|
<li>getLocals() - local variables</li>
|
|
<li>getArguments() - function arguments (not implemented by the PDA
|
|
debugger)<br>
|
|
</li>
|
|
</ul>
|
|
Both of these methods return a context that implements the <span
|
|
style="font-style: italic;">IStack.IVariableDMContext</span>
|
|
interface. The implementation of this context is very simple in
|
|
PDA<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDAStack
|
|
- VariableDMContext</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line117">117: </a> @Immutable<br><a
|
|
name="line118">118: </a> private static class VariableDMContext extends AbstractDMContext implements IVariableDMContext {<br><br><a
|
|
name="line120">120: </a> final private String fVariable;<br><br><a
|
|
name="line122">122: </a> VariableDMContext(String sessionId, IFrameDMContext frameCtx, String variable) {<br><a
|
|
name="line123">123: </a> super(sessionId, new IDMContext[] { frameCtx });<br><a
|
|
name="line124">124: </a> fVariable = variable;<br><a
|
|
name="line125">125: </a> }<br><br><a name="line127">127: </a> String getVariable() { <font
|
|
color="#4169e1">return</font> fVariable; }<br><br><a name="line129">129: </a> @Override<br><a
|
|
name="line130">130: </a><strong><font color="#4169e1"> public boolean equals(Object other)</font></strong> {<br><a
|
|
name="line131">131: </a> <font color="#4169e1">return</font> super.baseEquals(other) && ((VariableDMContext)other).fVariable.equals(fVariable);<br><a
|
|
name="line132">132: </a> }<br><br><a name="line134">134: </a> @Override<br><a
|
|
name="line135">135: </a><strong><font color="#4169e1"> public int hashCode()</font></strong> {<br><a
|
|
name="line136">136: </a> <font color="#4169e1">return</font> super.baseHashCode() + fVariable.hashCode();<br><a
|
|
name="line137">137: </a> }<br><br><a name="line139">139: </a> @Override<br><a
|
|
name="line140">140: </a><strong><font color="#4169e1"> public String toString()</font></strong> { <br><a
|
|
name="line141">141: </a> <font color="#4169e1">return</font> baseToString() + <font
|
|
color="#666666">".variable("</font> + fVariable + <font color="#666666">")"</font>; <font
|
|
color="#b22222">//$NON-NLS-1$ //$NON-NLS-2$</font><br><a name="line142">142: </a> }<br><a
|
|
name="line143">143: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 127 declares the <span style="font-style: italic;">fVariable</span>
|
|
(name) field which along with the parent context uniquely identifies a
|
|
PDA variable.<br>
|
|
</li>
|
|
</ul>
|
|
The getLocals() implementation is also very simple as it only uses the
|
|
familiar <span style="font-style: italic;">stack</span> PDA debugger
|
|
command:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDAStack
|
|
- getLocals()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line271">271: </a> public void getLocals(final IFrameDMContext frameCtx, final DataRequestMonitor<IVariableDMContext[]> rm) {<br><a
|
|
name="line272">272: </a> <font color="#b22222">// Execute the stack command again.</font><br><a
|
|
name="line273">273: </a> fCommandCache.execute(<br><a
|
|
name="line274">274: </a> new PDAStackCommand(fCommandControl.getProgramDMContext()),<br><a
|
|
name="line275">275: </a> new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {<br><a
|
|
name="line276">276: </a> @Override<br><a name="line277">277: </a><strong><font
|
|
color="#4169e1"> protected void handleOK()</font></strong> {<br><a
|
|
name="line278">278: </a> <font color="#b22222">// Find the correct PDAFrame</font><br><a
|
|
name="line279">279: </a> int frameId = getData().fFrames.length - frameCtx.getLevel() - 1;<br><a
|
|
name="line280">280: </a> <font color="#4169e1">if</font> (frameId < 0) {<br><a
|
|
name="line281">281: </a> PDAPlugin.failRequest(rm, IDsfService.INVALID_HANDLE, <font
|
|
color="#666666">"Invalid frame level "</font> + frameCtx);<br><a
|
|
name="line282">282: </a> <font color="#4169e1">return</font>;<br><a
|
|
name="line283">283: </a> }<br><a name="line284">284: </a> PDAFrame pdaFrame = getData().fFrames[frameId];<br><br><a
|
|
name="line286">286: </a> <font color="#b22222">// Create variable contexts for all variables in frame.</font><br><a
|
|
name="line287">287: </a> IVariableDMContext[] variableCtxs = new IVariableDMContext[pdaFrame.fVariables.length];<br><a
|
|
name="line288">288: </a> <font color="#4169e1">for</font> (int i = 0; i < pdaFrame.fVariables.length; i++) {<br><a
|
|
name="line289">289: </a> variableCtxs[i] = new VariableDMContext(getSession().getId(), frameCtx, pdaFrame.fVariables[i]);<br><a
|
|
name="line290">290: </a> }<br><a name="line291">291: </a> rm.setData(variableCtxs);<br><a
|
|
name="line292">292: </a> rm.done();<br><a
|
|
name="line293">293: </a> }<br><a name="line294">294: </a> });<br><br><a
|
|
name="line296">296: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Lines 273-294 send the <span style="font-style: italic;">stack</span>
|
|
command to the PDA debugger through the command cache.</li>
|
|
<li>Lines 279-284 verify the stack frame number and retrieve the
|
|
corresponding <span style="font-style: italic;">PDAFrame</span> object
|
|
from the stack result.</li>
|
|
<li>Lines 287-290 create the variable Data Model contexts and return
|
|
then to the caller.</li>
|
|
</ul>
|
|
The IStack interface also defines an IVariableDMData interface which
|
|
returns information about the variable. However, the only method
|
|
from this interface used by the Variables view is the getName() method
|
|
and it is the only method implemented by the PDA debugger integration:<br>
|
|
<h3><a class="mozTocH3" name="mozTocId327572"></a>9.2 Expression
|
|
Contexts</h3>
|
|
The IExpressions interface
|
|
uses a somewhat unusual way of managing contexts. A client can
|
|
create an <span style="font-style: italic;">IExpressionDMContext</span>
|
|
context instance for any expression and
|
|
parent context by calling the <span style="font-style: italic;">IExpressions.createExpressions()
|
|
</span>method. However, when the returned expression context is
|
|
evaluated, if its expression is not valid or if it uses an invalid
|
|
parent context, it is guaranteed to fail. The
|
|
PDAExpressions.createExpression() implementation reflects this:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDAExpressions
|
|
- createExpression()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line213">213: </a><strong><font color="#4169e1"> public IExpressionDMContext createExpression(IDMContext ctx, String expression)</font></strong> {<br><a
|
|
name="line214">214: </a> <font color="#b22222">// Create an expression based on the given context and string expression. </font><br><a
|
|
name="line215">215: </a> <font color="#b22222">// The PDA debugger can only evaluate variables as expressions and only</font><br><a
|
|
name="line216">216: </a> <font color="#b22222">// in context of a frame. </font><br><a
|
|
name="line217">217: </a> IFrameDMContext frameCtx = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class);<br><a
|
|
name="line218">218: </a> <font color="#4169e1">if</font> (frameCtx != null) {<br><a
|
|
name="line219">219: </a> <font color="#4169e1">return</font> new ExpressionDMContext(getSession().getId(), frameCtx, expression);<br><a
|
|
name="line220">220: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line221">221: </a> <font color="#b22222">// If a frame cannot be found in context, return an "invalid" </font><br><a
|
|
name="line222">222: </a> <font color="#b22222">// expression context, because a null return value is not allowed.</font><br><a
|
|
name="line223">223: </a> <font color="#b22222">// Evaluating an invalid expression context will always yield an </font><br><a
|
|
name="line224">224: </a> <font color="#b22222">// error.</font><br><a
|
|
name="line225">225: </a> <font color="#4169e1">return</font> new InvalidExpressionDMContext(getSession().getId(), ctx, expression);<br><a
|
|
name="line226">226: </a> }<br><a name="line227">227: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<br>
|
|
<h3><a class="mozTocH3" name="mozTocId668928"></a>9.3 Expression Data<br>
|
|
</h3>
|
|
The IExpressions interface allows for retrieving data in two stages:<br>
|
|
<ol>
|
|
<li>Variable type and other data.</li>
|
|
<li>Variable value.</li>
|
|
</ol>
|
|
The implementation of the IExpressions.IExpressionDMData interface is
|
|
required by the Variables views, however for the PDA debugger the
|
|
IExpressionDMData does not carry any additional information beyond the
|
|
expression string.<br>
|
|
<h3><a class="mozTocH3" name="mozTocId233056"></a>9.4 Formatted Value
|
|
Context<br>
|
|
</h3>
|
|
The IExpressions service allows expression values to be retrieved in
|
|
different, client-selectable formats. For the PDA debugger, only
|
|
one formatting is available, which is reflected in the implementation
|
|
of
|
|
<span style="font-style: italic;">IFormattedValues.getAvailableFormats()</span>
|
|
method. Also, the implementation of the <span
|
|
style="font-style: italic;">IFormattedValues.getFormattedValueContext()</span>
|
|
method is just a formality.<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDAExpressions
|
|
- getAvailableFormats()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line262">262: </a> public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm) {<br><a
|
|
name="line263">263: </a> <font color="#b22222">// PDA debugger doesn't support formatting the expression. Natural </font><br><a
|
|
name="line264">264: </a> <font color="#b22222">// formatting is the only available option.</font><br><a
|
|
name="line265">265: </a> rm.setData(new String[] { NATURAL_FORMAT });<br><a
|
|
name="line266">266: </a> rm.done();<br><a name="line267">267: </a> }<br><br><a
|
|
name="line269">269: </a>public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext exprCtx, String formatId) {<br><a
|
|
name="line270">270: </a> <font color="#b22222">// Creates a context that can be used to retrieve a formatted value.</font><br><a
|
|
name="line271">271: </a> <font color="#4169e1">return</font> new FormattedValueDMContext(this, exprCtx, formatId);<br><a
|
|
name="line272">272: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<br>
|
|
Only when the formatted value context is evaluated, the <span
|
|
style="font-style: italic;">var</span> command is sent to the PDA
|
|
debugger:<br>
|
|
<br>
|
|
<div style="margin-left: 20px;">
|
|
<table style="text-align: left; background-color: rgb(238, 238, 238);"
|
|
border="0" cellpadding="5" cellspacing="0">
|
|
<tbody>
|
|
<tr>
|
|
<td colspan="2" rowspan="1" style="vertical-align: top;"><span
|
|
style="font-family: monospace; font-weight: bold;">org.eclipse.dd.examples.pda.service.PDAExpressions
|
|
- getFormattedExpressionValue()</span> </td>
|
|
</tr>
|
|
<tr>
|
|
<td style="vertical-align: top; width: 10px;"><br>
|
|
</td>
|
|
<td style="vertical-align: top;">
|
|
<pre><a name="line274">274: </a> public void getFormattedExpressionValue(FormattedValueDMContext formattedCtx, <br><a
|
|
name="line275">275: </a> final DataRequestMonitor<FormattedValueDMData> rm) <br><a
|
|
name="line276">276: </a> {<br><a name="line277">277: </a> final ExpressionDMContext exprCtx = DMContexts.getAncestorOfType(formattedCtx, ExpressionDMContext.class);<br><a
|
|
name="line278">278: </a> <font color="#4169e1">if</font> (exprCtx != null) {<br><a
|
|
name="line279">279: </a> final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);<br><a
|
|
name="line280">280: </a> <br><a name="line281">281: </a> <font
|
|
color="#b22222">// First retrieve the stack depth, needed to properly calculate</font><br><a
|
|
name="line282">282: </a> <font color="#b22222">// the frame index that is used by the PDAVarCommand. </font><br><a
|
|
name="line283">283: </a> fStack.getStackDepth(<br><a
|
|
name="line284">284: </a> frameCtx, 0,<br><a
|
|
name="line285">285: </a> new DataRequestMonitor<Integer>(getExecutor(), rm) {<br><a
|
|
name="line286">286: </a> @Override<br><a
|
|
name="line287">287: </a><strong><font color="#4169e1"> protected void handleOK()</font></strong> {<br><a
|
|
name="line288">288: </a> <font color="#b22222">// Calculate the frame index.</font><br><a
|
|
name="line289">289: </a> int frameId = getData() - frameCtx.getLevel() - 1;<br><a
|
|
name="line290">290: </a> <br><a name="line291">291: </a> <font
|
|
color="#b22222">// Send the command to evaluate the variable.</font><br><a
|
|
name="line292">292: </a> fCommandCache.execute(<br><a
|
|
name="line293">293: </a> new PDAVarCommand(fCommandControl.getProgramDMContext(), frameId, exprCtx.getExpression()), <br><a
|
|
name="line294">294: </a> new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {<br><a
|
|
name="line295">295: </a> @Override<br><a
|
|
name="line296">296: </a><strong><font color="#4169e1"> protected void handleOK()</font></strong> {<br><a
|
|
name="line297">297: </a> rm.setData(new FormattedValueDMData(getData().fResponseText));<br><a
|
|
name="line298">298: </a> rm.done();<br><a
|
|
name="line299">299: </a> }<br><a
|
|
name="line300">300: </a> }); <br><a
|
|
name="line301">301: </a> }<br><a name="line302">302: </a> });<br><a
|
|
name="line303">303: </a> } <font color="#4169e1">else</font> {<br><a
|
|
name="line304">304: </a> PDAPlugin.failRequest(rm, INVALID_HANDLE, <font
|
|
color="#666666">"Invalid expression context "</font> + formattedCtx);<br><a
|
|
name="line305">305: </a> rm.done();<br><a name="line306">306: </a> }<br><a
|
|
name="line307">307: </a> }<br></pre>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<ul>
|
|
<li>Line 277 extracts the expression context out of the <span
|
|
style="font-style: italic;">formattedCtx</span> argument. If the
|
|
expression context is not found, the evaluation is failed.</li>
|
|
<li>Line 283 calls the stack service to retrieve the stack
|
|
depth. This step is required because the PDA debugger <span
|
|
style="font-style: italic;">var</span> command requires a stack frame
|
|
number which is counted from the bottom. Where as the stack frame
|
|
level returned in the <span style="font-style: italic;">IFrameDMCotnext.getLevel()</span>
|
|
is counted at the top of the stack.</li>
|
|
<li>Line 289 calculates the frame number that can be used with the <span
|
|
style="font-style: italic;">var</span> command.</li>
|
|
<li>Lines 292-300 call the var command to evaluate the given
|
|
expression and return the result to the client.<br>
|
|
</li>
|
|
</ul>
|
|
<h2><a class="mozTocH2" name="mozTocId840787"></a>10 Additional
|
|
Resources<br>
|
|
</h2>
|
|
<h3><a class="mozTocH3" name="mozTocId824835"></a>10.1 Debug Platform</h3>
|
|
The platform team has evolved and improved the debug APIs over many
|
|
releases. Before starting a debugger integration using DSF, it
|
|
would be very helpful to familiarize yourself with materials in these
|
|
documents:<br>
|
|
<ul>
|
|
<li><i><a
|
|
href="http://www.eclipse.org/articles/Article-Launch-Framework/launch.html">We
|
|
Have Lift-off: The Launching Framework in Eclipse</a> </i>article<i><br>
|
|
</i></li>
|
|
<li><a style="font-style: italic;"
|
|
href="http://www.eclipse.org/articles/Article-Debugger/how-to.html">How
|
|
to write an Eclipse debugger</a> article.</li>
|
|
<li><a href="http://www.eclipsecon.org/2008/?page=sub/&id=40">Debug
|
|
Platform: The Basics</a> EclipseCon tutorial.</li>
|
|
<li><a href="http://www.eclipsecon.org/2008/?page=sub/&id=41">Debug
|
|
Platform: Custom Integration</a> EclipseCon tutorial.<br>
|
|
</li>
|
|
</ul>
|
|
<h3><a class="mozTocH3" name="mozTocId512801"></a>10.2 GDB</h3>
|
|
The <a href="http://www.eclipse.org/dsdp/dd/">DSDP Device Debugging
|
|
project</a> is developing a DSF-based debugger integration with GDB as
|
|
the main reference implementation of the DSF APIs. In comparison
|
|
with PDA, GDB is a much more complex and feature rich debugger
|
|
integration. The GDB debugger integration is also being
|
|
continually developed and improve features and performance.<br>
|
|
<h3><a class="mozTocH3" name="mozTocId126766"></a>10.3 TCF</h3>
|
|
The Target Communication Framework which is being developed as part of
|
|
the <a href="http://www.eclipse.org/dsdp/tm/">DSDP Target Management
|
|
project</a> includes a reference debugger agent implementation. This
|
|
reference debugger agent is integrated with Eclipse using DSF.
|
|
The
|
|
TCF debugger is more limited in features than the GDB debugger, however
|
|
the TCF debugger API is considerably different than the GDB/MI protocol
|
|
and is an interesting example integration.<br>
|
|
<br>
|
|
</body>
|
|
</html>
|