% title: Eclipse Plug-in Development % title_class: #empty, largeblend[123] or fullblend % subtitle: Extending the CDT Debugger % author: Marc Khouzam % author: Marc-André Laperle % thankyou: Thank you % thankyou_details:
title: Agenda class: nobackground build_lists: false content_class:
- Day 1: Plug-in development
- Module 1: Eclipse Platform and plug-in development
- Module 2: Implementing a first plug-in
- Day 2: Getting to know DSF
- Module 3: DSF concepts and exercises
- Module 4: DSF events and exercises
title: Other content available but not covered build_lists: false
- Getting to know DSF-GDB
- Module 5: DSF-GDB concepts and exercises
- Modifying DSF-GDB's behaviour
- Module 6: Changing the Debug View
- Module 7: Changing GDB's initialization
##Let's get started! [//]: (This is a comment)
title: Approach to course
- A mix of theory and hands-on exercises
- Teams of 2
- Ask questions often and give feeback
- 9h30 to 16h30 schedule
- One hour lunch
- 15 minute break, morning and afternoon
- Please tell us if you are confused during the course
title: Start your Eclipse
-
Execute the start script ~/workspace-training/start.tcsh
-
All good?
##
title: Module 1 subtitle: Eclipse Platform and Plug-in Development
- Intro to Eclipse Platform
- Plug-in development
title: The Eclipse Platform
Frameworks and Common services for:
- Rich Client Platform (RCP)
- Tool integration
Examples of rich client applications:
- Eclipse for Java Developpers, Eclipse SDK, Stand-alone C/C++ Debugger, Trace Compass, etc.
Examples of tool integrations:
- CDT, EGit, Trace Compass plugins
title: The Eclipse Platform
title: Eclipse Runtime
Mainly composed of the Eclipse Equinox project.
Eclipse Equinox:
- Implements the OSGI specification (modules, services, etc)
- P2: Provisioning framework. Installs new plug-ins, resolves dependencies, etc.
- Miscellaneous Core functionallity like the extension registry (plug-ins), Jobs, Preferences, etc.
- Eclipse launcher (native)
title: Workspace
- The workspace is a view of the user's data files: the resources.
- Types of resources: projects, folders, and files
- Only one workspace per running platform
- Structure: Workspace root > Projects > IFolders or IFiles
- Common classes:
- IResource
- IWorkspace
- IFile
- IFolder
- IProject
- Resource names and their paths in the workspace to not have to match the location on the filesystem
title: Workspace
Other features than navigation/listing:
- Markers: to display problems like compilation errors
- Properties: per-file storage. Think flags like "read-only" but more customizable.
- Virtual folders: for greater flexibility when organizing projects
- Project natures: to differentiate between different kind of projects (Java, C/C++)
- Resource deltas: Listen to file modification, creation, deletion, etc.
title: EFS
Eclipse File System (EFS).
- An abstract file system API
- The Workspace resources sit on top of EFS
- The default implementations is for Local file systems
- Other implementations: SSH, FTP, dstore, ZIP, etc.
title: Eclipse Team
Framework to integrate SCMs.
- Repository configuration
- Resource management: Hooks for delete, move, add. Decorators in the UI.
- Synchronization: tracks whether or not resources are in sync. Local history.
- Logical Model Integration: Operate at the model level instead of per-file.
- Views: Synchronize, History, etc.
EGit, CVS, Subversion, Perforce use this.
title: Eclipse Help
- Table of content, Search, indexed
- Context sensitive (F1). Plug-ins can set context "ids"
- Runs on a local server, either in internal browser (SWT wiget) or external
Other "User Assistance" features
- Cheat cheets
- Welcome page
- Tutorials
Standard Widget Toolkit (org.eclipse.swt.*)
A Java library of widgets aimed at providing efficient, portable access to the user-interface facilities of the operating systems on which it is implemented.
This is typically the lowest level of UI programming done in Eclipse development.
title: SWT subtitle: Features
- Native look
- Quite fast!
- Button, Text, Browser, Group, Table, Tree, etc.
- Parent is specified in constructor (versus add child to parent container explicitly)
- Can be used as a stand-alone Java library (without anything else Eclipse)
title: SWT subtitle: Implementation
- Single UI thread
- Implemented using JNI calling the OS native library (which means SWT has some native glue code)
- Windows: Win32
- Mac: Cocoa
- Linux: GTK2 and GTK3
- Browser widget is integrated with different libraries: Webkit, Internet Explorer, XULRunner (Firefox)
- Most crashes (i.e. segmentation fault) in Eclipse due to native libraries called by SWT
- GTK, WebKitGTK+, Ubuntu-specific libraries (Unity)
- A bit hard (but fun) to debug. Java + Native C
title: JFace
JFace is a UI toolkit with classes for handling many common UI programming tasks. It is designed to work with SWT without hiding it.
org.eclipse.jface.*
Common uses:
- Viewers: TreeViewer, TableViewer, etc.
- Dialogs: Message dialog, error dialog, etc.
- Wizards: Wizard dialog, pages
title: Workbench
org.eclipse.ui.*
This is where classes more related to the common IDE UI fonctionality reside.
title: Workbench
-
A Workbench has one or more workbench windows.
-
Each Workbench Window has workbench pages.
-
Each Workbench Page has workbench parts, of which there are two kinds: views and editors.
-
Each Workbench Part is either a View or an Editor.
title: Workbench
Common uses:
- Views: IViewPart and the extension point org.eclipse.ui.views
- Commands and Handlers: org.eclipse.ui.commands, org.eclipse.ui.handlers extension points.
- Preference pages: org.eclipse.ui.preferencePages extension point
- Editors: org.eclipse.ui.editors extension point. IEditorPart and useful classes like TextEditor
title: The Eclipse SDK
To be able to work with the Eclipse Platform, you need tools.
The Eclipse SDK = Platform (including source) + JDT + PDE
title: JDT: Eclipse Java development tools
Those are the tools suitable for any Java-based programming
title: PDE: Plug-in Development Environment
Provides tools to create, develop, test, debug, build and deploy Eclipse plug-ins.
title: Module 2 subtitle: Implementing a First Plug-in
title: Project for exercices
We will create a new view that will display a log. Every time the debugger stops, print function:linenumber.
--- title: What IS an Eclipse plug-in?It's an OSGI bundle, a java module. But with an Eclipse flavor. Among other things:
- Specifies dependencies to other plug-ins
- Uses extensions to plug into existing extension points
- Can define new extension points for others to extend
- Specifies what to package in the (Jar)
- Specifies the execution environment (Java 7, 8, etc).
Difference between extension and extension point?
Extension = plug
Extension point = socket
A lot of things are done through extension points. For that, we need a plug-in.
title: Exercise: Create a plug-in
- Go to Plug-in Development perspective
- File > New > Plug-in project
- Name your plug-in (org.eclipse.cdt.example.framespy)
- Press Next then Finish
- Go!
What are all the tabs for?
title: Step to prepare
- Since we want to use the Git repo, delete the project and import existing one.
- Right-click on your project and press Delete then press OK
title: Step to prepare (2)
-
Go to Plug-in Development perspective:
- File->Import...->General->Existing Projects into Workspace
- Press Next
- Press Browse...
- Choose ~/workspace-training/EclipseTraining/org.eclipse.cdt.example.framespy
- Make sure a single project is showing and is selected
- Press Finish
-
Right-click on project and choose Team->Fetch from Upstream
title: Exercise: Create a view
- Reset to PLUG1
- Add a new view by adding an extension (plugin.xml)
- Create the view class (tip: click the hyperlink to bring up the New Class wizard)
- Make sure the view has an id, name
- To test your progress
- Go!
title: SWT Basic widget creation
Text textBox = new Text(parentComposite, SWT.SOMESTYLE | SWT.OTHERSTYLE); textBox.set*Somesetter* textBox.add*Somelistener*
Composite are containers of widgets that can be layed out.
Composites can be in composites!
title: Exercise: Add button to view
Let's add a Button. Let's make it a checkbox button.
- Reset to PLUG2
- In view class, in createPartControl() add new Button with a "checkbox style"
- Add selection listener to detect when it's pressed
- Output something to the console
- Go!
title: Eclipse commands and handlers
The Commands framework is a way to add user actions to the user interface. A command has:
- An id that declares a semantic behavior
- One or more handlers
For example, the Copy command has the id org.eclipse.ui.edit.copy. But it has many handlers that behave differently depending on the context (selection, view)
title: Exercise: Create the command and handler
- Reset to PLUG3
- Add a command extension to toggle log on/off
- Create a defaultHandler class (tip: use hyperlink to create class). Make it extend AbstractHandler (the one in 'core')
- Implement the execute method to make it print something to the console
- Go!
title: The menus extension point
The org.eclipse.ui.menus extension point can add commands to:
- Main menu (menu)
- Main toolbars (toolbar)
- View context menus (popup)
- View toolbars (toolbar)
- View menus (menu)
It has an odd locationURI field: [Scheme]:[ID]?[placement]
For example:
menu:org.eclipse.ui.main.menu?after=additions
title: Exercise: Add toolbar button
Let's add the command to the view toolbar.
- Reset to PLUG4
- Create the menus extension (Extension tab, org.eclipse.ui.menus extension)
- Add a menuContribution, set the locationURI so that it gets displayed in the view toolbar, after additions
- locationUri: toolbar:my.view.id?after=additions
- Right-click on menuContribution, Add a command. Set the id, icon and style
- id: the id of your command
- icon: enablespy.gif
- style: push
- Go!
It would be nice in the context menu as well.
title: Exercise: Context menu
Let's add the same command in the context menu.
- Reset to PLUG5
- Add a new menuContribution (right-click on org.eclipse.ui.menus). Because it needs different locationURI.
- locationUri= popup:my.view.id
- Add the command (right-click on menuContribution). Set the id, icon and style (push)
- Create a context menu in the view, to be populated:
// put in createPartControl fMenuManager = new MenuManager(); Menu menu = fMenuManager.createContextMenu(composite); composite.setMenu(menu); getViewSite().registerContextMenu(fMenuManager, null); ... // put in dispose (override the method) fMenuManager.dispose();
- Go!
title: Exercise: Show the toggle state
The user needs to see whether logging is enabled or not.
Let's add a label that displays that.
-
Reset to PLUG6
-
Add a Label (a SWT widget) at the view creation.
- Label label = new Label(c, SWT.NONE)
- label.setText(Boolean.FALSE.toString());
-
When the command executes:
- Set the toggle state (you can add a method to the view)
- In the handler, get the view with FrameSpyView part = (FrameSpyView) HandlerUtil.getActivePartChecked(event);
- Update the label text
- label.setText
-
Go!
title: The Preference Store
We should make sure that the toggle state is remembered when the view is closed (or Eclipse is restarted). There are multiple ways to do this. A useful one is the Preference Store.
- Works like a key/value map
- Can be applied to different scopes:
- DefaultScope: When the user presses "restore defaults" it restores to this.
- InstanceScope: Saved at the workspace level. Overrides Default.
- ProjectScope: Saved at the project level. Overrides Instance.
- Custom!
- Organized in nodes (think namespaces). Typically the plug-in id.
title: Exercise: Persist the toggle state
- Reset to PLUG7
- When the toggle state is set:
- Get the InstanceScope
- Get the node
- Set the key/value
Saving the preferences in our FrameSpyView.togleState method
IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID); preferences.put(TOGGLE_STATE_PREF_KEY, Boolean.toString(fToggledState));
title: Exercise: Persist the toggle state
- When the view is created:
- Get the InstanceScope
- Get the node
- Get value using key, set the label text
IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID); preferences.get(TOGGLE_STATE_PREF_KEY, Boolean.toString(false)); // set to false in case it was never set
- Go!
title: Eclipse Jobs
Jobs are similar to Java Thread but have Eclipse flavor.
Some differences:
- Scheduling rules: determine which jobs can run concurrently
- Deadlock detection: and recovery (ILock)
- Shown in the Progress View to the user (or not) with progress (IProgressMonitor)
- Can be made cancellable by the user
- Returns a status (IStatus)
In Eclipse code, Jobs and Threads are both commonly used, depending on the situation.
For the first implementation of our logging feature, we will poll every one second using a job.
title: Eclipse Jobs
job = new Job("Frame Spy Polling Job") { @Override protected IStatus run(IProgressMonitor monitor) { return Status.OK_STATUS; } }; job.schedule();
title: Exercise: Creating a polling job
- Reset to PLUG8
- When toggle state is on, create and schedule a job. Store it in a field (fJob).
- Give the job a nice name to be shown in the Progress View
- In the job run() method, sleep for 1 sec. Use Thread.sleep
- After the 1 sec, reschedule the job (only if the toggle state is still on!). Use schedule()
- Print something to the console every tick "polling..."
- If the toggle state becomes 'off' cancel the job. Use fJob.cancel().
- Go!
title: Exercise: Print to view
Every tick, we would like to show the elapsed time in the view. It can just be an incrementing counter.
- Reset to PLUG9
- Create a counter (a simple int) that is incremented each tick.
- Set the text label with the value of the counter
- Go!
title: SWT Display and the UI thread
Changes to the UI (widgets) should always be done on the UI thread.
The Display implements the event loop. There is only one instance in a running Eclipse.
Display.getDefault().asyncExec // Execute code at the next reasonable opportunity. Caller continues in parallel. Display.getDefault().syncExec // Blocks calling thread until executed on UI thread
With this knowledge we can fix the Invalid Thread Access. We can use asyncExec in this case. (PLUG10)
title: Exercise: Handle cancel
An IProgressMonitor is passed to the job.
We can use it to know if the user canceled the logging.
- Reset to PLUG10
- Use monitor.isCanceled() to know when user canceled
- Set the toggle state to off when canceled
- Go!
What happens? Do you have a problem with the job starting again? If you need results from UI thread right away -> syncExec
title: Exercise Review subtitle: What we accomplished
- Create a plug-in
- File > New > Plug-in project
title: Exercise Review (2) subtitle: What we accomplished build_lists: false
-
Creating a view
- extension point="org.eclipse.ui.views"
- Extending ViewPart and filling createPartControl()
-
Using SWT widgets
- Using Button, Label
- Using the UI Thread for such things
- Display.getDefault().syncExec()/asyncExec()
title: Exercise Review (3) subtitle: What we accomplished build_lists: false
- Using commands, handlers and menus
- extension point="org.eclipse.ui.commands"
- Extending AbstractHandler#execute() to do the work of the command
- extension point="org.eclipse.ui.menus"
- toolbar:org.eclipse.cdt.example.framespy.view?after=additions
- popup:org.eclipse.cdt.example.framespy.view
- Initializing a context-menu using MenuManager
title: Exercise Review (4) subtitle: What we accomplished build_lists: false
- Using the preference store
- InstanceScope.INSTANCE.getNode(PLUGIN_ID)
- Using Jobs and Progress Monitors
- Job#schedule()
- monitor.isCanceled()
##
title: Module 3 subtitle: DSF Concepts and Exercises
- Eclipse Debug Platform
- What is DSF?
- DSF concepts applied
- DSF Exercise 1
title: Building on our new view
- Debug Frame Spy
- New view logging each
method:line
at which the debugger stopped.
- New view logging each
title: Debug Frame Spy Details
- Show list of
method:line
of each location the program was interrupted - Show time of interrupt for each entry
- Show the number of arguments of the function for each entry
title: Eclipse Debug Platform
- Eclipse provides a foundation for Debugging
- Debug perspective
- Debug views
- Debug Actions, Toolbar, Menus
- Debug Launching
title: What is DSF?
- Overview
- View Model and Data Model
- Services
- Data Model contexts
- DSF Executor thread
- DSF Session
- Asynchronous (callback) programming
title: DSF Overview
- API for integrating debuggers in Eclipse
- Also designed for efficiency (slow or remote targets)
- Figure shows typical debugger integration using DSF
title: View Model
- View Model provides layer of abstraction for views
- User-presentable structure of the data
- User-presentable structure of the data
- View Model allows to easily modify presentation e.g.,
- Hide running threads
- Limit number of stack frames
- Only show processes if there is more than one
title: Using the CDT Debugger
- Start your test Eclipse
- Use the debug icon to debug a C program
- Step, look at variables, set breakpoints, resume
title: Data Model
- Data Model deals directly with the backend debugger
- Natural or backend structure of the data
- Independent of presentation to user
- Provides building blocks for the view model
- Uses common debugger concepts
- Execution elements (e.g., processes, threads)
- Formatted values (e.g., variables, registers)
- etc
title: DSF Services
- DSF provides a service API to access the Data Model
- Built on top of OSGi (as Eclipse is)
- Services are entities managing logical subsets of the data model
- Services are used to request information or to perform actions
title: DSF Services (2)
- For example, the IRunControl service:
- Provides list of execution elements (e.g., threads, processes)
- Provides details about such elements (e.g., name, state)
- Supports step, resume, interrupt, etc
- Other services: IMemory, IRegisters, IExpressions, IDisassembly...
- All services extend
IDsfService
(press F4 onIDsfService
)
title: Data Model Contexts
- IDMContext class is a 'pointer' to any type of backend data
- IExecutionDMContext - thread, process, group
- IFrameDMContext - stack frames
- IBreakpointDMContext - breakpoint, tracepoint, dprintf
- All contexts extend
IDMContext
(use F4)
- Contexts are hierachical
- process -> thread -> frame -> expression
DMContexts.getAncestorOfType()
- Contexts are used to retrieve data from services
title: DSF Executor thread
- Accessing data from different threads requires synchronization
- DSF uses a single-threaded executor to avoid synchronization
title: DSF Session
- Instances of DSF services are grouped into a DSF session
- There can be multiple sessions running at the same time
- The session provides the DSF Executor (
DsfSession#getExecutor()
) - A session handles sending events to registered listeners
title: Asynchronous (callback) programming
- Most DSF APIs return void but indicate completion in a callback
RequestMonitor
is the main callback class- Remember to call
done()
when real work is finished - This calls:
handleCompleted()
,handleSuccess()
,handleError()
- Remember to call
DataRequestMonitor
to "return" a valuegetData()
to get that value
title: RequestMonitor example
- To call an asynchronous method, such as:
void asyncCall(IDMContext dmc, RequestMonitor rm);
- there are two main coding styles:
Declarative:
RequestMonitor myRm = new RequestMonitor(getExecutor(), parentRm); asyncCall(dmc, myRm);
In-line:
asyncCall(dmc, new RequestMonitor(getExecutor(), parentRm));
title: Declarative Style
- First declare the RequestMonitor and what it should do
- Then call the asynchronous method, passing the RM
RequestMonitor myRm = new RequestMonitor(getExecutor(), parentRm) { @Override void handleSuccess() { System.out.println("Async call succeeded"); parentRm.done(); } }; asyncCall(dmc, myRm);
title: In-line Style
- Directly call the asynchronous method
- Declare and define the RM in-line
asyncCall(dmc, new RequestMonitor(getExecutor(), parentRm) { @Override void handleSuccess() { System.out.println("Async call succeeded"); parentRm.done(); } });
- In-line has the benefit of showing the execution flow
title: DataRequestMonitor
- Extention of
RequestMonitor
which "returns" data
DataRequestMonitor parentRm = new DataRequestMonitor(getExecutor, null); asyncCallWithData( dmc, new DataRequestMonitor(getExecutor(), parentRm) { @Override void handleSuccess() { String resultString = "Success with result " + getData(); parentRm.done(resultString); } });
title: Other RequestMonitors
CountingRequestMonitor
andMultiRequestMonitor
- For multiple asynchronous request in parallel
- For multiple asynchronous request in parallel
ImmediateRequestMonitor
and similarhandleSuccess()
and others are called on the thread where the ImmediateRM was created.
title: DSF concepts review build_lists: false
- APIs to integrate a debugger 'more easily' e.g., GDB
- View Model for presentation layer
- Data Model to communicate with backend (GDB)
- Services API to access Data
- No synchronization: DSF Executor must be used to access Data
- Services for one backend are grouped in a Session
- Heavy use of asynchronous programming for responsiveness
title: DSF practical review build_lists: false
- Services extend
IDsfService
- Contexts extend
IDMContext
- Context hierarchy searched with
DMContexts
- Executor can be found with
DsfSession#getExecutor()
RequestMonitor
andDataRequestMonitor
for callbacks
title: DSF Exercise build_lists: false
- FrameSpy to periodically print "method:line" for current frame
- Reset branch to commit starting with
- DSF1_START or DSF1_ADVANCED
- DSF1_START or DSF1_ADVANCED
- To test, make sure you launch a C/C++ Debug session first
- Use the Tasks view to see what needs to be done
- Go!
- Reset branch to commit starting with
title: Exercise review build_lists: false
- Finding the DSF session using debug context
- Debug View and Debug Context
- Adapter pattern
- Calling an existing DSF service
- Using a DsfServicesTracker for the DSF session
- Using a DsfServicesTracker for the DSF session
- Call the asynchronous IStack.getTopFrame()
- Using a new DataRequestMonitor
- Calling getData() in handledSuccess()
title: Exercise review (2)
- IDMContext vs IDMData
- call IStack.getFrameData()
- Using a new DataRequestMonitor
- Calling getData() in handledSuccess()
- Then finally display "method:line"
title: Exercise follow-up part 1 build_lists: false
- What if you select the process element?
- The top frame of which thread should we use?
- The top frame of which thread should we use?
- For now, just handle the error (as seen on console)
- Reset to DSF1_ANSWERS if you need
- Override
handleError()
- Go!
title: Follow-up part 1 review
title: Exercise follow-up part 2
- Assertions are a great way to notice unexpected situations
- Enable assertions in development eclipse for test eclipse
- In launch configuration, Arguments tab, VM arguments
- Add -ea
- Make sure you have a breakpoint for AssertionError
- Re-launch and try
- Go!
title: Exercise follow-up part 2
- Did you use the DSF Executor?
- Which code runs on the Executor, which not?
- Which code runs on the Executor, which not?
- Wrap first call to DSF service in Executor
- Call
submit()
of the Executor - Pass a
DsfRunnable()
whoserun()
does the work - Go!
- Call
title: Follow-up part 2 review
title: Module 4 subtitle: DSF Events and Exercises
- What are DSF events
- Sending and receving DSF events
- DSF Exercises 2 and 3
title: DSF Events
- DSF uses events to notify listeners of different things e.g.,
- Thread/Process started/exited
- Thread/Process suspend/resumed
- Breakpoint added/updated/removed
- etc
title: DSF Events (2) build_lists: false
- Events are how the Data Model tells the View Model of changes
- e.g., Thread stops => Update Debug View
- View Model is an advanced topic not covered in this course
- Events also notify services of other services' changes
- e.g., Clearing caches when execution resumes
title: DSF Events details
- Most events implement
IDMEvent
which provides anIDMContext
- e.g., When thread suspends, event specifies which thread
- e.g., When thread suspends, event specifies which thread
- Event types usually found in the different service interfaces e.g.,
IRunControl
:ISuspendedDMEvent
,IContainerSuspendedDMEvent
IResumedDMEvent
,IContainerResumedDMEvent
- Not all services trigger events
IStack
has not events
title: Sending DSF Events
- To send an event a service calls
DsfSession#dispatchEvent()
title: Receiving DSF Events
- To receive a DSF events a client must:
- Declare a public method of any name
- Method takes the event of interest as a parameter
- Annotate method with
@DsfServiceEventHandler
- Register with the DSF Session using
DsfSession#addServiceEventListener()
- Registration must be done on the Executor
- The method is called on the DSF Executor
title: Receiving event example
- The following method from SomeClass will be called for every suspended event
@DsfServiceEventHandler public void anyName(ISuspendedDMEvent e) { System.out.println("Received " + e.toString()); }
- as long as we register the class with the session
getSession().addServiceEventListener(SomeClass.this, null);
- Remember that registration must be done on Executor
title: Help with the Executor build_lists: false
- DSF provides Java Annotations to guide with Executor use
@ThreadSafe
- Safe for any thread (synchronization used)
@ConfinedToDsfExecutor(executor)
- Must use specified executor
@ThreadSafeAndProhibitedFromDsfExecutor(executor)
- Safe for any thread except the specified executor
- Safe for any thread except the specified executor
- They are hierarchical, so apply to children (e.g., methods of class)
- Unfortunetly, there is no compiler support so they are effectively just comments (that are sometimes missing)
title: DSF Event Exercise
- Show "method:line" each time a thread stops instead of polling
- Reset branch to commit starting with
- DSF2_START or DSF2_ADVANCED
- Polling job has been removed for you
- "method:line" only shown when FrameSpy first enabled
- To test:
- make sure your debug session is in Non-Stop mode
- step program and check new "method:line" each step
- Go!
- Reset branch to commit starting with
title: Event Exercise Review
- Registering for DSF events
- addServiceEventListener() using the Executor
- Must pass
FrameSpyView.this
(or another listener class)
- Unregister for DSF events when FrameSpy disabled
- removeServiceEventListener() using the Executor
- Must pass
FrameSpyView.this
(or listener used)
title: Event Exercise Review (2)
- Receiving the event
@DsfServiceEventHandler public void anyName(ISuspendedDMEvent event) { // Fetch frame info and print it }
title: Event Exercise for All-Stop
ISuspendedDMEvent
is used for Non-stop onlyIContainerSuspendedDMEvent
for All-stop- Represents the process stopping
- The top frame of which thread should we use?
- This event specifies which thread caused the stop
- Use that triggerring thread (context)
- (Look at declaration of
IContainerSuspendedDMEvent
) - Reset to DSF2_ANSWERS
- Go!
title: All-Stop Exercise Review
title: Handling a new session
- FrameSpy has an important limitation now
- enable FrameSpy
- stop the session and start a new one
- step the new session
- FrameSpy no longer prints
title: Handling a new session (2)
##
title: Handling a new session (3) build_lists: false
- When new session starts, we are not registered for its events
- How to know when new session starts so we can register?
title: DsfSession to the rescue
- DsfSession notifies registered listeners of start/end of all sessions
addSessionStartedListener()
,removeSessionStartedListener()
addSessionEndedListener()
,removeSessionEndedListener()
- DsfSession provides access to all running sessions:
getActiveSessions()
,getSession(id)
title: Multiple Session Exercise
- Register for event for each new DSF session
- Reset to DSF3_START or DSF3_ADVANCED
- Listen for new session and register with them
- Unregister when FrameSpy gets disabled
- Go!
- Reset to DSF3_START or DSF3_ADVANCED
title: Sessions Exercise Review
title: Final Recap
- We've created a new view that used existing services
- We've created a new service that the new view can use
- We've created a replacement service for our own delegate
title: Module 5
- What is DSF-GDB
- A little history
- DSF-GDB's service structure
- DSF Exercises 4, 5 and 6
title: What is DSF-GDB
- Integration of GDB using DSF
- Cannot use run DSF by itself
- Cannot use run DSF by itself
- Extra features on top of base DSF
- Tracepoints
- Visualizer
- OS Resources
title: History of DSF-GDB
- How it started
- Ericsson's involvement
- GDB's evolution
- Default CDT Debugger integration
- Where we stand today
title: DSF-GDB's services
- DSF provides API for services
IStack
,IBreakpoints
,IExpressions
, etc
- DSF-GDB provides an implementation
- Hierarchy of DSF-GDB services
- Press F4 on
IDsfService
MI[service]
vsGDB[service]
(historical)GDB[service][version]
GDB[service]_HEAD
- Press F4 on
title: New Service Exercise build_lists: false
- Write a new service providing the current time
- Reset to DSF4_START or DSF4_ADVANCED
- FrameSpyService.java already created for you
- Make it into a DSF service that can be found by name
- Provide methods:
- Synchronous
getLocalTimeOfDayString
method - Asynchronous
getTargetTimeOfDayString
method
- Synchronous
- Go!
- Reset to DSF4_START or DSF4_ADVANCED
title: New Service Review build_lists: false
AbstractDsfService
can be used as a base class for services
- Need to implement
getBundleContext()
- Need to advertise a service using
register()
- Any name can be used but class or interface name is good
- Any name can be used but class or interface name is good
initialize()
andshutdown()
should be enhanced- Some method providing the service functionality is needed
- Need to implement
title: Asynchronous vs Synchronous API
- Slowest part of the CDT debugger is communication with GDB
- DSF provides infrastructure for async communication
- New async API can use that infrastructure
- New sync API cannot
- Async API can be used synchronously but not other way around
title: Using new service
- Prepend every printout in FrameSpyView with the time of day
- Reset to DSF4_UPDATE_START
- FrameSpyView to show: [time] method:line
- If you test it, it will not work (yet)
- Go!
- Reset to DSF4_UPDATE_START
title: Instantiating new service build_lists: false
- We can't find the service because we didn't instantiate it
- We need one instance for each DSF session
- A DSF-GDB session instantiates its services
- We haven't hooked into a DSF-GDB session (yet)
- We need to manage our new service ourselves
- Remember
addSessionStartedListener()
and friends?
title: Instantiation Exercise
- Implement a managing class to create/dispose of the new service
- Reset to DSF5_START or DSF5_ADVANCED
- Done for you:
- Singleton FrameSpyServiceManager.java
initialize()
anddispose()
called byActivator
- Instantiate and
initialize()
a FrameSpyService for each new DSF session - When done FrameSpyView should show: [time] method:line
- Go!
- Reset to DSF5_START or DSF5_ADVANCED
title: Service Shutdown
- We instantiate a service for each new DSF session
- What about shutting down those instances?
- Each time a DSF session ends
- DSF-GDB automatically shutsdown all DSF services
- Anything registered and implementing
IDsfService
- We don't need to take care of it ourselves
- Refer to DSF-GDB's ShutdownSequence.java
- Anything registered and implementing
title: Frame Argument count build_lists: false
- Provide the number of arguments when printing "method:line"
- Reset to DSF6_START or DSF6_ADVANCED
- Provide API (method) in your service for arguments count
- Async or Sync?
- Is the info needed in GDB?
- Are you going to call any async APIs?
- Use
IStack
service to get list of frame arguments - Update FrameSpyView to show: [time] method:line (# args)
- Go!
- Reset to DSF6_START or DSF6_ADVANCED
##
title: Module 6 subtitle: Changing the Debug View
- Extending an existing service
- Launch Delegates and Launch Configuration Types
- Service Factories
- DSF Exercises 7 and 8
title: Building on DSF-GDB
- For a new debugging feature
- Use existing DSF-GDB services
- Re-work obtained information
- Provide new information to view
- Use existing DSF-GDB services
title: Modifying DSF-GDB
- To change an existing debugging feature
- Override View Model code
- Override Data Model code
- Override View Model code
- We will focus on overriding a service (i.e., the data model)
title: Extending a service build_lists: false
- For stack frames, replace method name "main" with "entry"
- Reset to DSF7.1_START or DSF7.1_ADVANCED
- FrameSpyStackService.java extends existing Stack service
- Override
getFrameData()
- "Return" an
IFrameDMData
whosegetFunction()
returns "entry" instead of "main" - Go!
- Reset to DSF7.1_START or DSF7.1_ADVANCED
title: New Service Instantiation build_lists: true
- Like before we now have a new class we must instantiate
- Can we use
FrameSpyServiceManager?
FrameSpyStackService
extends existingGDBStack_HEAD
serviceGDBStack_HEAD
is already being instantiated by DSF-GDB- Instantiating ours would create two IStack services
- We need to instantiate our service instead of the original one
title: Two approaches to extend DSF-GDB
- Creating a new view and a new service
- Does not affect the rest of the debugging views
- We can do this to any DSF-GDB session
- This was our first set of exercises
- Replacing a service and changing an existing view
- Does affect normal debugger behaviour
- Should be chosen by user explicitly
- Aimed at specific scenarios
- This is what we need now
So, how do we replace a service?
title: First solution
- New Launch Configuration Type
- Current ones
i. C/C++ Application
i. C/C++ Attach to Application
i. C/C++ Postmortem Debugger
i. C/C++ Remote Application
- Add a new one such as "IMA2l-Chip Debugger"
- Launch Config Types need a Launch Delegate
- When chosen by user, we know to replace IStack service
- Current ones
i. C/C++ Application
i. C/C++ Attach to Application
i. C/C++ Postmortem Debugger
i. C/C++ Remote Application
title: Second solution
- New Launch Delegate to existing Launch Configuration Type
- Current ones for C/C++ Application
i. GDB (DSF) Debug Process Launcher
i. Legacy Create Process Launcher (will be removed)
- Add a new one such as "IMA2l-Chip Local Launcher"
- When chosen by user, we know to replace IStack service
- Current ones for C/C++ Application
i. GDB (DSF) Debug Process Launcher
i. Legacy Create Process Launcher (will be removed)
title: Differences
- Both solutions are almost the same
- Both need a new launch delegate
- The first also provides a new launch config type
- The second re-uses existing launch config types
- Base choice on the UI presented to the user
- Code differences are minor
title: Launch Delegate exercise build_lists: false
- Create a new Launch Delegate for C/C++ Application
- Reset to DSF7.2_START
- FrameSpyLaunchDelegate.java extends
GdbLaunchDelegate
- Update Extensions tab of plugin.xml
- Fill-in
org.eclipse.debug.core.launchDelegates
- "Main" Launch tab has been provided for you
- Fill-in
- Go!
- Reset to DSF7.2_START
title: Launch Delegate Review
- When creating a "C/C++ Application" launch, we can now select our delegate
- But the new delegate does exactly what DSF-GDB does
- It still does not instantiate
FrameSpyStackService
title: New Services Factory
- Now that we have a new delegate, we can create a new Services Factory
- A DSF Service Factory is used to create the different services
- Let's have a look at
GdbDebugServicesFactory
- Let's have a look at
- When user chooses new delegate, they will get new IStack service
title: Services Factory Exercise build_lists: false
- Create a new Services Factory for our Launch Delegate
- Reset to DSF7.3_START
- FrameSpyServicesFactory.java extends
GdbDebugServicesFactory
- This new service factory instantiates
FrameSpyStackService
- Our delegate uses
FrameSpyServicesFactory
- by overridding
newServiceFactory()
- by overridding
- Go!
- You should be able to see "entry" instead of "main"
- Reset to DSF7.3_START
title: Current status
- We have a new delegate
FrameSpyLaunchDelegate
- We have a new service factory
FrameSpyServicesFactory
- We have a new service
FrameSpyStackService
- New delegate uses new service which replaces "main" with "entry"
title: Service_HEAD pattern
- Why did our new service extend
GDBStack_HEAD
? - Recent improvement allows extenders to stay on newest GDB version
- Let's look at an example
- F4 on
GDBControl_HEAD
- F4 on
GDBService_HEAD
always points at newest service version- Favors stability of latest GDB version at the detriment of older ones
title: Launch Config Type exercise
- Create a new Launch Configuration Type for our delegate
- Reset to DSF8_START
- Use extension points in plugin.xml
o.e.debug.core.launchConfigurationTypes
o.e.debug.ui.launchConfigurationTypeImages
o.e.debug.ui.launchConfigurationTabGroups
- Assign our launch delegate to new launch config type
- Assign our launch tab to new launch tab group
- Go!
- Reset to DSF8_START
title: What we've seen
- We've created a new view that used existing services
- We've created a new service that the new view can use
- We've created a replacement service for our own delegate
title: Module 7 subtitle: Changing GDB's Initialization
- DSF-GDB Launch steps
- Communicating directly with GDB
- FinalLaunchSequence
- Extending the FinalLaunchSequence
- DSF Exercise 9
title: Modifying GDB initialization
- DSF-GDB initializes GDB based on parameters of the launch config, e.g.,
- Enable non-stop mode
- Connect to a remote target
- Open a core file
- In some situations, we may want to modify how GDB is initialized, e.g.,
- Remove step that connects to remote target
- Modify which .gdbinit file is read
- Send a new command before connecting to target
title: DSF-GDB launch steps
GdbLaunchDelegate#launch()
called by platformFrameSpyLaunchDelegate#launch()
for our extension
ServicesLaunchSequence
triggered to start services- This uses the Services Factory we saw earlier
FinalLaunchSequence
triggered to initialize GDB
title: Adding a step at initialization
- Goal: Turn on GDB verbosity (debug printouts) from the beginning
- Need to send GDB the MI command:
-gdb-set verbose on
- Need to send it before other commands sent to GDB
- Need to send GDB the MI command:
- Exercises:
- Provide API in
FrameSpyService
to send new command - Extend DSF-GDB's initialization class: (
FinalLaunchSequence
) - Use extended initialization class instead of DSF-GDB's one
- Provide API in
title: Communicating with GDB
ICommandControl#queueCommand()
used to send a command to GDB
ICommandControl#queueCommand( new MIExecContinue(threadContext), new DataRequestMonitor(getExecutor(), parentRm));
ICommandControl#queueCommand( new MIStackInfoDepth(threadContext), new DataRequestMonitor(getExecutor(), parentRm) { @Override protected void handleSuccess() { parentRm.setData(getData().getDepth()); parentRm.done(); } });
title: ICommandControl service
ICommandControl
also provides APIs for:- Getting notified of GDB commands status changes
- Queued, Sent, Removed, Done
- Queued, Sent, Removed, Done
- Getting notified of asynchronous GDB events.
=breakpoint-created/deleted/modified
=memory-changed
*stopped/*running
- etc
- Getting notified of GDB commands status changes
title: Sending a command to GDB exercise
- Add a method to FrameSpyService that will send the command "-gdb-set verbose on"
- Reset to DSF9.1_START or DSF9.1_ADVANCED
- Go!
- Reset to DSF9.1_START or DSF9.1_ADVANCED
title: When to trigger this new command
- We want to enable debug logs
- We should send the command as early as possible
title: The ReflectionSequence class
-
Used by
FinalLaunchSequence
to be extendable -
Born out of necessity
-
Support grouping of steps.
- In practice, only
GROUP_TOP_LEVEL
is used
- In practice, only
title: The ReflectionSequence class (2)
getExecutionOrder()
returns array of steps using method names
return new String[] { "stepGDBVersion", "stepSetEnvironmentDirectory", "stepSetBreakpointPending", ...
getExecutionOrder()
can be overridden to add/remove steps- Steps are implemented by methods with specific name and tagged with
@Execute
title: Extending GDB Initialization Sequence
- Have
FrameSpyFinalLaunchSequence
extendFinalLaunchSequence
- Add a new
stepSetVerbose()
to this initialization sequence
- Reset to DSF9.2_START or DSF9.2_ADVANCED
- Go!
- Reset to DSF9.2_START or DSF9.2_ADVANCED
title: Instantiating the new sequence
- As for previous steps, we need to instantiate our new sequence
title: Using new initialization Sequence
- Have
FrameSpyControlService
extend the existing ICommandControl service - Override
getCompleteInitializationSequence()
to choose new launch sequence
- Reset to DSF9.3_ADVANCED
- Go!
- Reset to DSF9.3_ADVANCED
title: Final Recap
- We've created a new view that used existing services
- We've created a new service that the new view can use
- We've created a replacement service for our own delegate
- We've modified GDB's initialization sequence