Skip to content

Latest commit

 

History

History
1785 lines (1400 loc) · 48.1 KB

slides.md

File metadata and controls

1785 lines (1400 loc) · 48.1 KB

% 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?










##

Plug-in development


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
--- title: SWT

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!

But the button does not belong in view itself, it would be nicer in the toolbar.

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!

If you enable logging and close/reopen the view, what happens?

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!

What happens?

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()









##

Getting to know DSF


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.

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

  • 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 on IDsfService)

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()

  • DataRequestMonitor to "return" a value
    • getData() 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 and MultiRequestMonitor
    • For multiple asynchronous request in parallel

  • ImmediateRequestMonitor and similar
    • handleSuccess() 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 and DataRequestMonitor 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

    • To test, make sure you launch a C/C++ Debug session first

    • Use the Tasks view to see what needs to be done

    • Go!

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

  • 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?

  • 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?

  • Wrap first call to DSF service in Executor
    • Call submit() of the Executor
    • Pass a DsfRunnable() whose run() does the work
    • Go!

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 an IDMContext
    • 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

  • 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!

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 only

  • IContainerSuspendedDMEvent 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)







##

Why?


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!

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

  • 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] vs GDB[service] (historical)
    • GDB[service][version]
    • GDB[service]_HEAD

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

    • Go!

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

    • initialize() and shutdown() should be enhanced

    • Some method providing the service functionality is needed

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!

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() and dispose() called by Activator

    • Instantiate and initialize() a FrameSpyService for each new DSF session

    • When done FrameSpyView should show: [time] method:line

    • Go!

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

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!

title: Exercise Review







##

Modifying DSF-GDB's behaviour


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

title: Modifying DSF-GDB

  • To change an existing debugging feature

    • Override View Model code

    • Override Data 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 whose getFunction() returns "entry" instead of "main"

    • Go!

title: New Service Instantiation build_lists: true

  • Like before we now have a new class we must instantiate

  • Can we use FrameSpyServiceManager?
    • FrameSpyStackService extends existing GDBStack_HEAD service
    • GDBStack_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

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

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

    • Go!

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

  • 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()

    • Go!

    • You should be able to see "entry" instead of "main"

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
  • 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!

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 platform
    • FrameSpyLaunchDelegate#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

  • 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

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

    • Getting notified of asynchronous GDB events.
      • =breakpoint-created/deleted/modified
      • =memory-changed
      • *stopped/*running
      • etc

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!

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

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 extend FinalLaunchSequence

  • Add a new stepSetVerbose() to this initialization sequence

    • Reset to DSF9.2_START or DSF9.2_ADVANCED

    • Go!

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!

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