Introduction

Multiple external debuggers

The scope module provides facilities for interaction with external or semi-external content debuggers. Examples are javascript debuggers, document inspectors, logging services, and playback services.

...

Debugger architecture

A module that wishes to provide debugging services will implement this service in two parts, a "back end" close to the module code (and usually located with the module in the CVS) and a "front end" that serializes and deserializes data and communicates with the debugger (usually located in the scope module). The back end and front end will normally communicate by a simple API using data structures defined in the back end. Thus the scope module contains code pertaining to the debugging needs of many modules.

The two-layer architecture for the debugging support makes it simple to implement custom or multiple communication protocols or to move parts of the debugger into Opera for performance or other reasons.

For debuggers that are in fact external to Opera, there is a third transport layer below the front end that is responsible for sending and receiving data over a network connection.

Typical control flow

The back end is structured in part as an event listener. An event in the debugged module will be signalled as a call to the back end. It will extract the necessary data pertaining to the event from the module state, package these data somehow, and call the front end to have them delivered to the debugger. For an external debugger, the front end transforms the data to XML and delivers them to the network layer for delivery. The network layer returns to the front end, which returns to the back end, which can either block (when it has just sent an event that the debugger wants it to stop at) or just continue.

If there is a debugger that wants to control Opera in some way, then the transport layer will receive data from the debugger. It delivers these data to the front end, which deserializes them into data structures understood by the back end and finally delivers them to the back end. The back end then implements the necessary operations on its module.

External representation

XML

The preferred representation for messages to and from external debugging agents is ASCII-encoded XML, and the scope module provides numerous utilities to ease the use of this representation.

Though an XML representation will typically be larger and slower than a well-designed binary representation, it is human-readable and therefore more easily debuggable. XML libraries exist for many programming languages and therefore places few restrictions on the technology chosen for a particular debugger.

The following style guidelines apply to all the XML protocols.

Encoding

Attribute values never contain characters outside ASCII. They are escaped if necessary, using the normal "%xx" scheme.

Element text data can contain characters from the entire Unicode character set. These data are always base-64 encoded.

Following the preceding two translations, the message is representable in ASCII and therefore also UTF-8.

Examples

The file js-protocol.txt contains the protocol specification for the Javascript debugger.

Implementation matters

XML serialization

This is currently done by ad-hoc methods in a utility class, "ScopeDebugMessage". For the moment this seems to be adequate.

XML deserialization

This is done by a wrapper class around the XML parser, "XMLFragmentParser". This wrapper class also functions as an interator over the generated parse tree, allowing the conversion from XML to an internal data structure to be implemented by ad-hoc code. This too seems to be adequate.

Transport layer

Previously the Javascript debugger used custom code for transport.

For the scope module, I am planning to instead use the probetools "shell" functionality as the transport layer, since it was designed to provide this type of service anyway.