{"__v":319,"_id":"54d5635632d98b0d00384b03","category":{"__v":5,"_id":"54fa1d3fe7a0ba2f00306309","pages":["54fa1d54e7a0ba2f0030630c","54fa1d5de7a0ba2f0030630e","54fa1d65961fea210092064f","54fa1dcff63cf9210041c4c0","551f404b6886f8230055f02f"],"project":"54d53c7b23010a0d001aca0c","version":"54d5635532d98b0d00384afb","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-03-06T21:33:51.375Z","from_sync":false,"order":6,"slug":"runners-debuggers","title":"Runners & Debuggers"},"parentDoc":null,"project":"54d53c7b23010a0d001aca0c","user":"54cfa8e1a8a4fd0d00b7fd1d","version":{"__v":10,"_id":"54d5635532d98b0d00384afb","forked_from":"54d53c7c23010a0d001aca0f","project":"54d53c7b23010a0d001aca0c","createdAt":"2015-02-07T00:59:01.934Z","releaseDate":"2015-02-07T00:59:01.934Z","categories":["54d5635632d98b0d00384afc","54d5635632d98b0d00384afd","54d5635632d98b0d00384afe","54d5635632d98b0d00384aff","54d5635632d98b0d00384b00","54d5635632d98b0d00384b01","54d5635632d98b0d00384b02","54d652097e05890d006f153e","54dd1315ca1e5219007e9daa","54e21e2b22de1c230094b147","54e68e62a43fe13500db3879","54fa1d3fe7a0ba2f00306309","551c453a23a1ee190034d19a","551df586e52a0b23000c62b6","551f39be6886f8230055f02a","55a6720751457325000e4d97"],"is_deprecated":false,"is_hidden":false,"is_beta":true,"is_stable":true,"codename":"","version_clean":"0.1.0","version":"0.1"},"updates":["54ff5c34422a14190073fb93"],"next":{"pages":[],"description":""},"createdAt":"2015-02-06T23:57:23.991Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":3,"body":"The `c9.ide.run.debug` package offers a set of plugins that provide a generic, configurable and extendable user interface for step-through debuggers. The plugin structure is optimized to easily support additional debugger protocols. Each debugger protocol can be implemented in a so called \"Debugger Implementation\" plugin. This article outlines how to create a debugger implementation. Cloud9 comes with an implementation for the `v8` debug protocol and a recent community addition supports `gdb`, the GNU Project Debugger. An `xdebug` implementation is forthcoming.\n\n# UI\n\nThe debugger user interface consists of a panel with a button toolbar and several debug panels. By default there are 4 debug panels:\n\n- Watch Expressions\n- Call Stack\n- Scope Variables\n- Breakpoints\n\nOther plugins can introduce new debug panels - this is outside of the scope of this article and will be addressed in a future article. \n\nThe debugger integrates with the Ace editor and allows users to set (conditional) breakpoints and highlights the current line while stepping through the code or looking through the call stack. In addition, while execution is paused, the user can hover over a variable in the editor to evaluate that variable in the current context or frame.\n[block:image]\n{\n  \"images\": [\n    {}\n  ]\n}\n[/block]\n# Approach\n\nThe debugger implementation is a plugin that provides a specific API which is used by the UI as described above. This means that in most cases you won't have to add any UI to implement a step-through debugger for a certain runtime or platform. \n\nThe interface for the debugger implementation is straightforward and can be implemented mostly stateless. The implementer (you) has the choice to add any state you want. We just made sure that this is not a requirement for the plugin.\n\nIt is common practice to keep the plugin stateless and move state information, such as the connection and management of any processes that assist with debugging, to the implementation of a so-called \"proxy.\" This proxy is server-side code that sits between the running process and the debugger implementation and is described in more detail below.\n\nThe diagram below visualizes the structure of the debugger. It consists of the following parts:\n[block:html]\n{\n  \"html\": \"<table>\\n<tr><th>Running Process</th><td>The process that was started by the Cloud9 runner.</td></tr>\\n<tr><th>[Debug Server]</th><td>Optional. Some platforms may support or require a separate process for debugging (e.g., GDB Server).</td></tr>\\n<tr><th>Proxy Process</th><td>A process that holds the connection to the debugger (and will survive browser reloads)</td></tr>\\n<tr><th>Debug Socket</th><td>The debug socket plugin provides the connection between the proxy process and the debugger implementation. This plugin is also responsible for starting the proxy process.</td></tr>\\n<tr><th>Your Debugger Implementation</th><td>This implementation mediates communication between the APIs of running debugger (or debug server) and the Debugger UI.</td></tr>\\n<tr><th>Debugger UI</th><td>The UI for the debugger that the user interacts with.</td></tr>\\n</table>\"\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/IHZvzpmQRmm8KSvtsEzA_debugger%20architecture%20(1).png\",\n        \"debugger architecture (1).png\",\n        \"818\",\n        \"256\",\n        \"#7c6454\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou should strongly consider using a Debug Server if the debugger process supports it and if typical running processes for your debugger will use console access (e.g., command-line programs). Using such an implementation allows easy separation between the standard streams (i.e., `stdin`, `stdout`, and `stderr`) from the running process and the command interface for the debugger itself. In other words, the Cloud9 runner will start the corresponding client process and allow the standard streams to be visible in the Console window of the UI. Without using such an implementation, you may need to write additional code in the proxy process that parses and separates the debugger's output from the process' output, properly passes user input along to the running process, and prevents the user from intentionally or accidentally writing commands to the debugger.\n\nThe focus of this article includes both the orange (debugger implementation) and green (proxy) blocks. \n\n# Basic Debugger Implementation Plugin\n\n*Scroll to the bottom the article to find a copy and paste-able snippet to get started.*\n\nLets start with the outline of the plugin by consuming the `Plugin` factory and `debugger` plugin and give our plugin a name.\n\n```\ndefine(function(require, exports, module) {\n    main.consumes = [\"Plugin\", \"debugger\"];\n    main.provides = [\"mydebugger\"];\n    return main;\n    \n    function main(options, imports, register) {\n        var Plugin = imports.Plugin;\n        var debug = imports[\"debugger\"];\n```\n\nGet local references to the [data objects](#data-objects) the we'll use later.\n\n```\n        var Frame = debug.Frame;\n        var Source = debug.Source;\n        var Breakpoint = debug.Breakpoint;\n        var Variable = debug.Variable;\n        var Scope = debug.Scope;\n```\n\nDefine the type of the plugin to be used throughout the plugin. This string is used in the runner to reference this debugger. As examples, for the v8 debugger the string is \"v8\" and for GDB the string is \"gdb\".\n```\n        var TYPE = \"yourtype\";\n```\n\nInitialize the plugin and emitters. Make sure to set the maximum number of listeners as there might be many.\n\n```        \n        var plugin = new Plugin(\"Your Name\", main.consumes);\n        var emit = plugin.getEmitter();\n        emit.setMaxListeners(1000);\n```\n\nDuring load and unload register and unregister the implementation with the `debug` plugin.\n```\n        plugin.on(\"load\", function(){\n            debug.registerDebugger(TYPE, plugin);\n        });\n        plugin.on(\"unload\", function(){\n            debug.unregisterDebugger(TYPE, plugin);\n        });\n```\n\nFinally define the public API and register your plugin. There will be much more API as is described further down in this article.        \n```\n        plugin.freezePublicAPI({\n            type: TYPE\n        });\n        \n        register(null, {\n            \"mydebugger\" : plugin\n        });\n    }\n});\n```\n\n# API\n\nThis part of the article will go into the interface that your debugger implementation should support. Implementing support for a debugger protocol is essentially implementing this set of APIs. \n\nThese properties and functions *should* all be defined in the public API.\n\n```\nplugin.freezePublicAPI({\n    // The API is defined here\n});\n```\n\nAll properties, methods and events that *must* be implemented by your debugger implementation plugin are listed in the [reference guide](https://docs.c9.io/api/#!/api/debugger.implementation). We'll highlight some of the ones that require more in-depth explanation below. Keep the reference guide as the authoritative source for all members that *must* be implemented.\n\n## Debugger Features\n\nThe debugger implementation can hint which features are supported and which are not. Setting (some of) these features to false will disable the corresponding UI and will prevent related functions from being called.\n\n```\nfeatures: {\n                                    // Able to:\n    scripts: true,                  // download code (if false: disable the scripts button)\n    conditionalBreakpoints: true,   // have conditional breakpoints (if false: disable menu item)\n    liveUpdate: true,               // update code live (if false: don't do anything when saving)\n    updateWatchedVariables: true,   // edit vars in watches (if false: don't show editor)\n    updateScopeVariables: true,     // edit vars in variables panel (if false: don't show editor)\n    setBreakBehavior: true,         // configure break behavior (if false: disables button)\n    executeCode: true               // execute code (if false: disable REPL)\n},\n```\n[block:callout]\n{\n  \"type\": \"success\",\n  \"title\": \"Need more control?\",\n  \"body\": \"The ability to turn off features like this is a recent addition and we appreciate any feedback on this via the mailinglist or in a github issue.\"\n}\n[/block]\n## Properties\n\nBesides [features](https://docs.c9.io/api/#!/api/debugger.implementation-property-features) and [type](https://docs.c9.io/api/#!/api/debugger.implementation-property-type), there are only four properties for which you *should* define property getters. These are [state](https://docs.c9.io/api/#!/api/debugger.implementation-property-state), [attached](https://docs.c9.io/api/#!/api/debugger.implementation-property-attached), [breakOnExceptions](https://docs.c9.io/api/#!/api/debugger.implementation-property-breakOnExceptions) and [breakOnUncaughtExceptions](https://docs.c9.io/api/#!/api/debugger.implementation-property-breakOnUncaughtExceptions).\n\nIf you are unfamiliar with adding getter properties in javascript, the following example shows how to do this.\n\n```\nplugin.freezePublicAPI({\n    get attached(){ return attached; }\n});\n```\n\nIn that example, the `attached` variable is a local variable which value is returned when another plugin calls `plugin.attached`.\n\n### Attached\n\nThe `attached` property *must* be set to `true` immediately before firing the `attach` event and set to `false` immediately before firing the `detach` event. This property is used throughout the debugger UI plugins to determine whether to interact with the debugger implementation or not.\n\n### State\n\nThe `state` property indicates the process' execution state; it might be \"stopped\" on a breakpoint, \"running\", or `null` if it doesn't exist. The `stateChange` event *must* be fired immediately after changing the `state` property.\n[block:html]\n{\n  \"html\": \"<table style=\\\"width:300px\\\">\\n<tr><th>Value</th><th>      Description</th></tr>\\n<tr><td>null</td><td>       process doesn't exist</td></tr>\\n<tr><td>\\\"stopped\\\"</td><td>  paused on breakpoint</td></tr>\\n<tr><td>\\\"running\\\"</td><td>  process is running</td></tr>\\n</table>\"\n}\n[/block]\n## Events\n\nThere are 14 events that can be implemented by your plugin. These events *must* be emitted by the event emitter of your plugin.\n\n```\nemit(\"attach\", { breakpoints: breakpoints });\n```\n\nThe following table lists all the events. Several events are required no matter how basic your implementation is, but others are dependent on the features you support. We'll discuss them below.\n[block:html]\n{\n  \"html\": \"<table>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-attach\\\" target=\\\"_blank\\\">attach</a></th><td>Required. Fires when the debugger is attached.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-detach\\\" target=\\\"_blank\\\">detach</a></th><td>Required. Fires when the debugger is detached.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-error\\\" target=\\\"_blank\\\">error</a></th><td>Required. Fires when the socket experiences an error</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-break\\\" target=\\\"_blank\\\">break</a></th><td>Required. Fires when the debugger hits a breakpoint.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-exception\\\" target=\\\"_blank\\\">exception</a></th><td>Fires when the debugger hits an exception.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-sourcesCompile\\\" target=\\\"_blank\\\">sourcesCompile</a></th><td>Fires when a source file is (re-)compiled. </td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-frameActivate\\\" target=\\\"_blank\\\">frameActivate</a></th><td>Required. Fires when a frame becomes active.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-setScriptSource\\\" target=\\\"_blank\\\">setScriptSource</a></th><td>Fires when the source of a file is updated</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-getFrames\\\" target=\\\"_blank\\\">getFrames</a></th><td>Required. Fires when the result of the getFrames call comes in.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-sources\\\" target=\\\"_blank\\\">sources</a></th><td>Fires when the result of the getSources call comes in.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-suspend\\\" target=\\\"_blank\\\">suspend</a></th><td>Required. Fires when execution is suspended (paused)</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-getBreakpoints\\\" target=\\\"_blank\\\">getBreakpoints</a></th><td>Fires when the current list of breakpoints is needed</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-breakpointUpdate\\\" target=\\\"_blank\\\">breakpointUpdate</a></th><td>Fires when a breakpoint is updated.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-event-stateChange\\\" target=\\\"_blank\\\">stateChange</a></th><td>Fires when the state property changes</td></tr>\\n</table>\"\n}\n[/block]\n### attach, detach, error\n\nThese events *must* fire during the different state transitions of the connection. The `attach` event *should* be fired after the debugger is ready to receive commands. In practice this means that the `attach` event is fired after connecting to the debugger, getting a list of source filenames, setting the breakpoints and detecting whether the debugger is already on a breakpoint. \n\nThe `detach` event *must* be fired when the debugger gets detached. This is usually in the `detach` method.\n\nLastly the `error` event is fired when the socket object that is passed to the `attach` method has an error:\n```\nsocket.on(\"error\", function(err) {\n    emit(\"error\", err);\n}, plugin);\n```\n\n### break, exception, sourcesCompile\n\nThese events *must* fire when the debugger either; hits a breakpoint (`break`), exceptions or segfaults (`exception`) or finishes compiling a source file (`sourcesCompile` - only if applicable).\n\n### frameActivate\n\nThe `frameActivate` event *must* fire when a different frame becomes active (or no frame). Make sure to also call this after `attach` and `detach` and during a `break` event.\n\n### setScriptSource, getFrames, sources, suspend\n\nThese events *must* fire in the callback of their related methods.\n\n```\nfunction getSources(callback) {\n    fetchSources(function(sources) {\n        callback(null, sources);\n        emit(\"sources\", { sources: sources })\n    });\n}\n```\n\n### getBreakpoints\n\nUnlike other events the `getBreakpoints` event *should* fire when you need a list of current breakpoints from the UI.\n\n```\nfunction attach(socket, reconnect, callback){\n   var breakpoints = emit(\"getBreakpoints\");\n   connect(breakpoints, callback);\n}\n```\n\n### breakpointUpdate\n\nThis event *must* fire when a breakpoint is moved to a new line. This can happen when it is set at a location which is not an expression. Certain debuggers (such as v8) will move the breakpoint location to the first expression that's next in source order.\n\n```\nfunction setBreakpoint(breakpoint, callback) {\n    setbreakpoint(breakpoint, function(info) {\n        if (isDifferentLocation(info, breakpoint)) {\n            updateBreakpoint(breakpoint, info);\n            emit(\"breakpointUpdate\", { breakpoint: breakpoint });\n        }\n        callback(null, breakpoint, info);\n    });\n    return true;\n}\n```\n\n## Methods\n\nThere are 23 methods that *must* be implemented by your plugin. These methods *must* be defined on the public API of your plugin.\n\n```\nfunction attach(){}\n\nplugin.freezePublicAPI({\n    attach: attach\n});\n```\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Unsupported methods\",\n  \"body\": \"Some debuggers don't support all the operations needed to implement a function. In that case simply keep the function empty and [call the callback with an error](#unimplemented-methods).\"\n}\n[/block]\nThe following table lists all the methods. We'll discuss them below.\n[block:html]\n{\n  \"html\": \"<table>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-attach\\\" target=\\\"_blank\\\">attach</a></th><td>Attaches the debugger to the started process.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-detach\\\" target=\\\"_blank\\\">detach</a></th><td>Detaches the debugger from the started process.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getSources\\\" target=\\\"_blank\\\">getSources</a></th><td>Loads all the active sources from the process</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getSource\\\" target=\\\"_blank\\\">getSource</a></th><td>Retrieves the contents of a source file</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getFrames\\\" target=\\\"_blank\\\">getFrames</a></th><td>Retrieves the current stack of frames (aka \\\"the call stack\\\") </td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getScope\\\" target=\\\"_blank\\\">getScope</a></th><td>Retrieves the variables from a scope.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getProperties\\\" target=\\\"_blank\\\">getProperties</a></th><td>Retrieves and sets the properties of a variable.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-stepInto\\\" target=\\\"_blank\\\">stepInto</a></th><td>Step into the next statement.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-stepOver\\\" target=\\\"_blank\\\">stepOver</a></th><td>Step over the next statement.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-stepOut\\\" target=\\\"_blank\\\">stepOut</a></th><td>Step out of the current statement.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-resume\\\" target=\\\"_blank\\\">resume</a></th><td>Continues execution of a process after it has hit a breakpoint.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-suspend\\\" target=\\\"_blank\\\">suspend</a></th><td>Pauses the execution of a process at the next statement.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-evaluate\\\" target=\\\"_blank\\\">evaluate</a></th><td>Evaluates an expression in a frame or in global space.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-setScriptSource\\\" target=\\\"_blank\\\">setScriptSource</a></th><td>Change a live running source to the latest code state.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-setBreakpoint\\\" target=\\\"_blank\\\">setBreakpoint</a></th><td>Adds a breakpoint to a line in a source file.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-changeBreakpoint\\\" target=\\\"_blank\\\">changeBreakpoint</a></th><td>Updates properties of a breakpoint.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-clearBreakpoint\\\" target=\\\"_blank\\\">clearBreakpoint</a></th><td>Removes a breakpoint from a line in a source file.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-listBreakpoints\\\" target=\\\"_blank\\\">listBreakpoints</a></th><td>Retrieves a list of all the breakpoints that are set in the debugger.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-setVariable\\\" target=\\\"_blank\\\">setVariable</a></th><td>Sets the value of a variable.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-restartFrame\\\" target=\\\"_blank\\\">restartFrame</a></th><td>Starts a frame (usually a function) from the first expression in that frame. </td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-serializeVariable\\\" target=\\\"_blank\\\">serializeVariable</a></th><td>Retrieve the value of a variable.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-setBreakBehavior\\\" target=\\\"_blank\\\">setBreakBehavior</a></th><td>Defines how the debugger deals with exceptions.</td></tr>\\n<tr><th><a href=\\\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getProxySource\\\" target=\\\"_blank\\\">getProxySource</a></th><td>Returns the source of the proxy process.</td></tr>\\n</table>\"\n}\n[/block]\n### attach\n\nThe `attach` method implements the flow for connecting to the debugger through a proxy connection which is setup by the socket. This is arguably the most involved function to implement and the exact implementation will be highly unique for each debugger. After the `attach()` function has set up the initial connection with the debugger, the other functions will be responsible for sending commands and parsing the response.\n\n```\nvar socket;\nfunction attach(_socket, reconnect, callback) {\n    socket = _socket;\n\n    // The back event is fired when the socket reconnects\n    socket.on(\"back\", function(err) {\n        // Get a list of breakpoints\n        var breakpoints = emit(\"getBreakpoints\");\n        // Redo the state sync\n        sync(breakpoints, true);\n    }, plugin);\n    \n    // The error event is fired when the socket fails to connect\n    socket.on(\"error\", function(err) {\n        emit(\"error\", err);\n    }, plugin);\n    \n    // Attach to the debugger in your own way\n    attachToDebugger(socket, function(err) {\n        if (err) return callback(err);\n    \n        // Reset the active frame\n        emit(\"frameActivate\", { frame: null });\n\n        // Initialize the connected debugger\n        sync(emit(\"getBreakpoints\"), reconnect, callback);\n    });\n}\n```\n\nThe example above portrays the basic flow your implementation of the attach method *should* follow. The UI depends on the `error` and `frameActivate` events to present the correct state to the user. For more information on the `socket` object [click here](#socket).\n\nThe `sync` function is a placeholder for a function that fetches the state from the debugger. Check out an example implementation below.\n\n```\nfunction sync(breakpoints, reconnect, callback){\n    // TODO: Fetch sources\n    // TODO: Fetch frames (if on a break)\n    // TODO: Sync breakpoints\n    \n    attached = true;\n    emit(\"attach\", { breakpoints: breakpoints });\n    \n    if (frames.length) {\n        emit(\"frameActivate\", { frame: frames[0] });\n        emit(\"break\", {\n            frame: frames[0],\n            frames: frames\n        });\n        emit(\"stateChange\", { state: \"stopped\" });\n    }\n    else {\n        emit(\"stateChange\", { state: \"running\" });\n    }\n}\n```\n\nThe `sync()` (or similar function) should fetch the current state from the debugger. This includes the sources, frames and breakpoints - after setting the list of breakpoints that are known to the UI. The `attach`, `frameActivate`, `stateChange` and `break` events direct the UI to render the state.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"The 'v8' example debugger\",\n  \"body\": \"The very first Cloud9 debugger is the `v8` debugger and it still serves as an example to anyone implementing their own debugger. If you check out the [v8 source code](https://github.com/c9/c9.ide.run.debug/blob/master/debuggers/v8/v8debugger.js) you'll find that the `attach` function calls out to its `sync` function which implements the init flow for v8.\"\n}\n[/block]\n### detach\n\nThe `detach()` function gracefully disconnects from the debugger. You *must* emit the `frameActivate`, `stateChange` and `detach` events in order for the UI to update correctly.\n\n```\nfunction detach() {\n    // Clean up the debugger connection\n    detachFromDebugger();\n    \n    emit(\"frameActivate\", { frame: null });\n    emit(\"stateChange\", { state: null });\n    \n    attached = false;\n    emit(\"detach\");\n}\n```\n\n### getSources\n\nThe `getSources()` function retrieves all the source files (paths) known to the debugger and returns them as an array of `Source` objects.\n\n```\nfunction getSources(callback) {\n    getSourcesFromDebugger(function(err, scripts) {\n        if (err) return callback(err);\n    \n        var sources = scripts.map(function(options){\n            return createSource(options);\n        });\n\n        callback(null, sources);\n        emit(\"sources\", { sources: sources });\n    });\n}\n```\n\nThe `createSource()` helper function used above returns a `Source` object.\n\n```\nfunction createSource(options) {\n    return new Source({\n        // etc\n    });\n}\n```\n\n### getSource\n\nThe `getSource()` method fetches the source code of a source file. If your debugger doesn't support this feature it should simply [call the callback with an error](#unimplemented-methods).\n\n```\nfunction getSource(source, callback) {\n    getSourceFromDebugger(source, function(err, code) {\n        callback(err, code);\n    });\n}\n```\n\n### getFrames\n\nThe `getFrames()` function retrieves all the frames on the callstack from the debugger and returns them as an array of `Frame` objects.\n\n```\nfunction getFrames(callback, silent) {\n    getFramesFromDebugger(function(err, items) {\n        frames = items.map(function(options, index) {\n            return createFrame(frame, index);\n        });\n\n        emit(\"getFrames\", { frames: frames });\n        callback(null, frames);\n    });\n}\n```\n\nThe `createFrame()` helper function used above returns a `Frame` object.\n\n```\nfunction createFrame(options, index) {\n    var frame = new Frame({\n        istop: index == 0\n        // etc\n    });\n}\n```\n\n### getScope\n\nThe `getScope()` function retrieves all the variables in a frame from the debugger and returns them as an array of `Variable` objects.\n\n```\nfunction getScope(frame, scope, callback) {\n    getScopeFromDebugger(scope.index, frame.index, function(err, properties) {\n        if (err) return callback(err);\n        \n        var variables = properties.map(function(options) {\n            return createVariable(options);\n        });\n        \n        scope.variables = variables;\n        callback(null, variables, scope, frame);\n    });\n}\n```\n\nThe `createVariable()` helper function used above returns a `Frame` object.\n\n```\nfunction createVariable(options) {\n    return new Variable({\n        // etc\n    });\n}\n```\n\n### getProperties\n\nThe `getProperties()` function retrieves all the properties of a variable from the debugger and returns them as an array of `Variable` objects. For each property that is of a basic data type, you *must* set the value (i.e. string, int, etc.). The UI will call this function recursively as a user clicks through the datagrid.\n\n```\nfunction getProperties(variable, callback) {\n    getPropertiesFromDebugger(variable.ref, function(err, props) {\n        if (err) return callback(err);\n        \n        if (props.length > 5000) {\n            props = [new Variable({\n                name: \"Too many properties\",\n                type: \"error\", \n                value: \"Found more than 5000 properties\",\n                children: false\n            })];\n            \n            variable.properties = props;\n            callback(null, props, variable);\n            return;\n        }\n        \n        var properties = props.map(function(prop) { \n            return createVariable(prop);\n        });\n        \n        variable.properties = properties;\n        callback(null, properties, variable);\n    });\n}\n```\n\nIn the example above we only return 5000 or fewer properties. This is generally a good practice if there are multiple calls to the debugger needed to fetch the requested data - for instance the v8 debugger requires one call for each property to fetch its value.\n\n### stepInto\n\nThe `stepInto()` function steps into the current expression.\n\n```\nfunction stepInto(callback) {\n    stepIntoDebugger(function(err){ callback(err); });\n}\n```\n\n### stepOver\n\nThe `stepOver()` function steps over the current expression.\n\n```\nfunction stepOver(callback) {\n    stepOverDebugger(function(err){ callback(err); });\n}\n```\n\n### stepOut\n\nThe `stepOut()` function steps out of the current frame.\n\n```\nfunction stepOut(callback) {\n    stepOutDebugger(function(err){ callback(err); });\n}\n```\n\n### resume\n\nThe `resume()` function continues execution.\n\n```\nfunction resume(callback) {\n    resumeDebugger(function(err){ callback(err); });\n}\n```\n\n### suspend\n\nThe `suspend()` function pauses expression at the next possible expression.\n\n```\nfunction suspend(callback) {\n    suspendDebugger(function(err){\n        if (err) return callback(err);\n        \n        emit(\"suspend\");\n        callback();\n    });\n}\n```\n\n### evaluate\n\nThe `evaluate()` function takes an expression and executes it in the global context or the context of a frame. If your debugger doesn't support evaluation of expressions simply return an error in the callback. This function is used amongst others by the immediate window.\n\n```\nfunction evaluate(expression, frame, global, disableBreak, callback) {\n    var frameIndex = frame && typeof frame == \"object\" ? frame.index : frame;\n    \n    evaluateInDebugger(expression, frameIndex, global, disableBreak, \n      function(error, value, properties) {\n        var name = expression.trim();\n        if (error) {\n            var err = new Error(error.message);\n            err.name = name;\n            err.stack = error.stack;\n            return callback(err);\n        }\n        \n        var variable = createVariable({\n            name: name,\n            value: value\n        });\n        if (properties)\n            variable.properties = properties;\n        \n        callback(null, variable);\n    });\n}\n```\n\n### setScriptSource\n\nThe `setScriptSource()` function updates the source of a file that is active in the running process. If your debugger doesn't support this simply [call the callback with an error](#unimplemented-methods). \n\n```\nfunction setScriptSource(script, newSource, previewOnly, callback) {\n    setScriptSourceInDebugger(script.id, newSource, previewOnly, function(err, data) {\n        if (err)\n            callback(new Error(\"Could not update source\"));\n        \n        emit(\"setScriptSource\", data);\n        callback(null, data);\n    });\n};\n```\n\n### setBreakpoint\n\nThe `setBreakpoint()` function adds a breakpoint to a line and column in a source file. \n\n```\nfunction setBreakpoint(bp, callback) {\n    setBreakpointAtDebugger(bp, function(info) {\n        if (isDifferentLocation(info, bp)) {\n            updateBreakpoint(bp, info);\n            emit(\"breakpointUpdate\", { breakpoint: bp });\n        }\n        callback(null, bp, info);\n    });\n    return true;\n}\n```\n\n### changeBreakpoint\n\nThe `changeBreakpoint()` function updates a breakpoint such as toggling the enabled state, condition or ignoreCount. If your debugger implementation doesn't support updating a breakpoint simply remove the existing one and add a new one.\n\n```\nfunction changeBreakpoint(bp, callback) {\n    changeBreakpointAtDebugger(function(err, data) {\n        callback(err, bp, data);\n    });\n}\n```\n\n### clearBreakpoint\n\nThe `clearBreakpoint()` function remove a breakpoint from a certain line and column in a source file.\n\n```\nfunction clearBreakpoint(bp, callback) {\n    clearBreakpointAtDebugger(bp, function(err) {\n        callback(err);\n    });\n}\n```\n\n### listBreakpoints\n\nThe `listBreakpoints()` function fetches an array of breakpoints known by the debugger.\n\n```\nfunction listBreakpoints(callback) {\n    listBreakpointsAtDebugger(function(err, breakpoints) {\n        if (err) return callback(err);\n        \n        callback(null, breakpoints.map(function(bp) {\n            return createBreakpoint(bp);\n        }));\n    });\n}\n```\n\n### setVariable\n\nThe `setVariable()` function sets the value of a variable in a certain frame. This is used by the watch expression and the variables debug panel. The `parents` argument is an array of variables that are the objects on which this variable is a property. For a local variable to the frame this array is empty, otherwise the 0th element will contain the reference to the object the variable is a property of.\n\n```\nfunction setVariable(variable, parents, value, frame, callback) {\n    setVariableAtDebugger(variable, parents, value, frame, function(err, options){\n        if (err) return callback(err)\n        callback(null, createVariable(options));\n    });\n}\n```\n\n### restartFrame\n\nThe `restartFrame()` function starts the frame at the first expression in that frame. If your debugger doesn't support this feature simply return an error in the callback.\n\n```\nfunction restartFrame(frame, callback) {\n    var frameIndex = frame && typeof frame == \"object\" ? frame.index : frame;\n    \n    restartFrameAtDebugger(frameIndex, function(err, data) {\n        callback(err, data);\n    });\n}\n```\n\n### serializeVariable\n\nThe `serializeVariable()` function returns a serialized version of the variable. For a string this would be `\"value\"` for a regexp this might be `/\\w/` and for a function this might be the source of that function or `function`. You have total freedom in determining the serialized state of a variable. It is wise to choose a format that can be used to set the variable when using `setVariable()` if your debugger supports that.\n\n```\nfunction serializeVariable(variable, callback) {\n    serializeVariableAtDebugger(variable, function(err, value) {\n        callback(err, value);\n    });\n}\n```\n\n### setBreakBehavior\n\nThe `setBreakBehavior()` function tells the debugger on which type of exceptions to break. The `type` argument can be set to `all` or `uncaught`.\n\n```\nfunction setBreakBehavior(type, enabled, callback) {\n    breakOnExceptions = enabled ? type == \"all\" : false;\n    breakOnUncaughtExceptions = enabled ? type == \"uncaught\" : false;\n    \n    setBreakBehavior(type, enabled, callback);\n}\n```\n\n### getProxySource\n\nThe `getProxySource()` function is used to fetch the source code of the proxy for your debugger implementation. You can fetch the default proxy source from `debug.proxySource`. You can find more information about the proxy below.\n\n```\nfunction getProxySource(process){\n    return debug.proxySource\n        .replace(/\\/\\/.*/g, \"\")\n        .replace(/[\\n\\r]/g, \"\")\n        .replace(/\\{PORT\\}/, process.runner[0].debugport);\n}\n```\n\n### Unimplemented methods\n\nIf your implementation doesn't support a feature of the public API, you must still implement the method but you can supply an error to the provided callback, as shown in an example below.\n\n```\nfunction getSource(source, callback) {\n   callback(new Error(\"Debugger cannot return source code\"));\n}\n```","excerpt":"","slug":"debugger-plugin","type":"basic","title":"Debugger Plugin"}
The `c9.ide.run.debug` package offers a set of plugins that provide a generic, configurable and extendable user interface for step-through debuggers. The plugin structure is optimized to easily support additional debugger protocols. Each debugger protocol can be implemented in a so called "Debugger Implementation" plugin. This article outlines how to create a debugger implementation. Cloud9 comes with an implementation for the `v8` debug protocol and a recent community addition supports `gdb`, the GNU Project Debugger. An `xdebug` implementation is forthcoming. # UI The debugger user interface consists of a panel with a button toolbar and several debug panels. By default there are 4 debug panels: - Watch Expressions - Call Stack - Scope Variables - Breakpoints Other plugins can introduce new debug panels - this is outside of the scope of this article and will be addressed in a future article. The debugger integrates with the Ace editor and allows users to set (conditional) breakpoints and highlights the current line while stepping through the code or looking through the call stack. In addition, while execution is paused, the user can hover over a variable in the editor to evaluate that variable in the current context or frame. [block:image] { "images": [ {} ] } [/block] # Approach The debugger implementation is a plugin that provides a specific API which is used by the UI as described above. This means that in most cases you won't have to add any UI to implement a step-through debugger for a certain runtime or platform. The interface for the debugger implementation is straightforward and can be implemented mostly stateless. The implementer (you) has the choice to add any state you want. We just made sure that this is not a requirement for the plugin. It is common practice to keep the plugin stateless and move state information, such as the connection and management of any processes that assist with debugging, to the implementation of a so-called "proxy." This proxy is server-side code that sits between the running process and the debugger implementation and is described in more detail below. The diagram below visualizes the structure of the debugger. It consists of the following parts: [block:html] { "html": "<table>\n<tr><th>Running Process</th><td>The process that was started by the Cloud9 runner.</td></tr>\n<tr><th>[Debug Server]</th><td>Optional. Some platforms may support or require a separate process for debugging (e.g., GDB Server).</td></tr>\n<tr><th>Proxy Process</th><td>A process that holds the connection to the debugger (and will survive browser reloads)</td></tr>\n<tr><th>Debug Socket</th><td>The debug socket plugin provides the connection between the proxy process and the debugger implementation. This plugin is also responsible for starting the proxy process.</td></tr>\n<tr><th>Your Debugger Implementation</th><td>This implementation mediates communication between the APIs of running debugger (or debug server) and the Debugger UI.</td></tr>\n<tr><th>Debugger UI</th><td>The UI for the debugger that the user interacts with.</td></tr>\n</table>" } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/IHZvzpmQRmm8KSvtsEzA_debugger%20architecture%20(1).png", "debugger architecture (1).png", "818", "256", "#7c6454", "" ] } ] } [/block] You should strongly consider using a Debug Server if the debugger process supports it and if typical running processes for your debugger will use console access (e.g., command-line programs). Using such an implementation allows easy separation between the standard streams (i.e., `stdin`, `stdout`, and `stderr`) from the running process and the command interface for the debugger itself. In other words, the Cloud9 runner will start the corresponding client process and allow the standard streams to be visible in the Console window of the UI. Without using such an implementation, you may need to write additional code in the proxy process that parses and separates the debugger's output from the process' output, properly passes user input along to the running process, and prevents the user from intentionally or accidentally writing commands to the debugger. The focus of this article includes both the orange (debugger implementation) and green (proxy) blocks. # Basic Debugger Implementation Plugin *Scroll to the bottom the article to find a copy and paste-able snippet to get started.* Lets start with the outline of the plugin by consuming the `Plugin` factory and `debugger` plugin and give our plugin a name. ``` define(function(require, exports, module) { main.consumes = ["Plugin", "debugger"]; main.provides = ["mydebugger"]; return main; function main(options, imports, register) { var Plugin = imports.Plugin; var debug = imports["debugger"]; ``` Get local references to the [data objects](#data-objects) the we'll use later. ``` var Frame = debug.Frame; var Source = debug.Source; var Breakpoint = debug.Breakpoint; var Variable = debug.Variable; var Scope = debug.Scope; ``` Define the type of the plugin to be used throughout the plugin. This string is used in the runner to reference this debugger. As examples, for the v8 debugger the string is "v8" and for GDB the string is "gdb". ``` var TYPE = "yourtype"; ``` Initialize the plugin and emitters. Make sure to set the maximum number of listeners as there might be many. ``` var plugin = new Plugin("Your Name", main.consumes); var emit = plugin.getEmitter(); emit.setMaxListeners(1000); ``` During load and unload register and unregister the implementation with the `debug` plugin. ``` plugin.on("load", function(){ debug.registerDebugger(TYPE, plugin); }); plugin.on("unload", function(){ debug.unregisterDebugger(TYPE, plugin); }); ``` Finally define the public API and register your plugin. There will be much more API as is described further down in this article. ``` plugin.freezePublicAPI({ type: TYPE }); register(null, { "mydebugger" : plugin }); } }); ``` # API This part of the article will go into the interface that your debugger implementation should support. Implementing support for a debugger protocol is essentially implementing this set of APIs. These properties and functions *should* all be defined in the public API. ``` plugin.freezePublicAPI({ // The API is defined here }); ``` All properties, methods and events that *must* be implemented by your debugger implementation plugin are listed in the [reference guide](https://docs.c9.io/api/#!/api/debugger.implementation). We'll highlight some of the ones that require more in-depth explanation below. Keep the reference guide as the authoritative source for all members that *must* be implemented. ## Debugger Features The debugger implementation can hint which features are supported and which are not. Setting (some of) these features to false will disable the corresponding UI and will prevent related functions from being called. ``` features: { // Able to: scripts: true, // download code (if false: disable the scripts button) conditionalBreakpoints: true, // have conditional breakpoints (if false: disable menu item) liveUpdate: true, // update code live (if false: don't do anything when saving) updateWatchedVariables: true, // edit vars in watches (if false: don't show editor) updateScopeVariables: true, // edit vars in variables panel (if false: don't show editor) setBreakBehavior: true, // configure break behavior (if false: disables button) executeCode: true // execute code (if false: disable REPL) }, ``` [block:callout] { "type": "success", "title": "Need more control?", "body": "The ability to turn off features like this is a recent addition and we appreciate any feedback on this via the mailinglist or in a github issue." } [/block] ## Properties Besides [features](https://docs.c9.io/api/#!/api/debugger.implementation-property-features) and [type](https://docs.c9.io/api/#!/api/debugger.implementation-property-type), there are only four properties for which you *should* define property getters. These are [state](https://docs.c9.io/api/#!/api/debugger.implementation-property-state), [attached](https://docs.c9.io/api/#!/api/debugger.implementation-property-attached), [breakOnExceptions](https://docs.c9.io/api/#!/api/debugger.implementation-property-breakOnExceptions) and [breakOnUncaughtExceptions](https://docs.c9.io/api/#!/api/debugger.implementation-property-breakOnUncaughtExceptions). If you are unfamiliar with adding getter properties in javascript, the following example shows how to do this. ``` plugin.freezePublicAPI({ get attached(){ return attached; } }); ``` In that example, the `attached` variable is a local variable which value is returned when another plugin calls `plugin.attached`. ### Attached The `attached` property *must* be set to `true` immediately before firing the `attach` event and set to `false` immediately before firing the `detach` event. This property is used throughout the debugger UI plugins to determine whether to interact with the debugger implementation or not. ### State The `state` property indicates the process' execution state; it might be "stopped" on a breakpoint, "running", or `null` if it doesn't exist. The `stateChange` event *must* be fired immediately after changing the `state` property. [block:html] { "html": "<table style=\"width:300px\">\n<tr><th>Value</th><th> Description</th></tr>\n<tr><td>null</td><td> process doesn't exist</td></tr>\n<tr><td>\"stopped\"</td><td> paused on breakpoint</td></tr>\n<tr><td>\"running\"</td><td> process is running</td></tr>\n</table>" } [/block] ## Events There are 14 events that can be implemented by your plugin. These events *must* be emitted by the event emitter of your plugin. ``` emit("attach", { breakpoints: breakpoints }); ``` The following table lists all the events. Several events are required no matter how basic your implementation is, but others are dependent on the features you support. We'll discuss them below. [block:html] { "html": "<table>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-attach\" target=\"_blank\">attach</a></th><td>Required. Fires when the debugger is attached.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-detach\" target=\"_blank\">detach</a></th><td>Required. Fires when the debugger is detached.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-error\" target=\"_blank\">error</a></th><td>Required. Fires when the socket experiences an error</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-break\" target=\"_blank\">break</a></th><td>Required. Fires when the debugger hits a breakpoint.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-exception\" target=\"_blank\">exception</a></th><td>Fires when the debugger hits an exception.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-sourcesCompile\" target=\"_blank\">sourcesCompile</a></th><td>Fires when a source file is (re-)compiled. </td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-frameActivate\" target=\"_blank\">frameActivate</a></th><td>Required. Fires when a frame becomes active.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-setScriptSource\" target=\"_blank\">setScriptSource</a></th><td>Fires when the source of a file is updated</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-getFrames\" target=\"_blank\">getFrames</a></th><td>Required. Fires when the result of the getFrames call comes in.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-sources\" target=\"_blank\">sources</a></th><td>Fires when the result of the getSources call comes in.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-suspend\" target=\"_blank\">suspend</a></th><td>Required. Fires when execution is suspended (paused)</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-getBreakpoints\" target=\"_blank\">getBreakpoints</a></th><td>Fires when the current list of breakpoints is needed</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-breakpointUpdate\" target=\"_blank\">breakpointUpdate</a></th><td>Fires when a breakpoint is updated.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-event-stateChange\" target=\"_blank\">stateChange</a></th><td>Fires when the state property changes</td></tr>\n</table>" } [/block] ### attach, detach, error These events *must* fire during the different state transitions of the connection. The `attach` event *should* be fired after the debugger is ready to receive commands. In practice this means that the `attach` event is fired after connecting to the debugger, getting a list of source filenames, setting the breakpoints and detecting whether the debugger is already on a breakpoint. The `detach` event *must* be fired when the debugger gets detached. This is usually in the `detach` method. Lastly the `error` event is fired when the socket object that is passed to the `attach` method has an error: ``` socket.on("error", function(err) { emit("error", err); }, plugin); ``` ### break, exception, sourcesCompile These events *must* fire when the debugger either; hits a breakpoint (`break`), exceptions or segfaults (`exception`) or finishes compiling a source file (`sourcesCompile` - only if applicable). ### frameActivate The `frameActivate` event *must* fire when a different frame becomes active (or no frame). Make sure to also call this after `attach` and `detach` and during a `break` event. ### setScriptSource, getFrames, sources, suspend These events *must* fire in the callback of their related methods. ``` function getSources(callback) { fetchSources(function(sources) { callback(null, sources); emit("sources", { sources: sources }) }); } ``` ### getBreakpoints Unlike other events the `getBreakpoints` event *should* fire when you need a list of current breakpoints from the UI. ``` function attach(socket, reconnect, callback){ var breakpoints = emit("getBreakpoints"); connect(breakpoints, callback); } ``` ### breakpointUpdate This event *must* fire when a breakpoint is moved to a new line. This can happen when it is set at a location which is not an expression. Certain debuggers (such as v8) will move the breakpoint location to the first expression that's next in source order. ``` function setBreakpoint(breakpoint, callback) { setbreakpoint(breakpoint, function(info) { if (isDifferentLocation(info, breakpoint)) { updateBreakpoint(breakpoint, info); emit("breakpointUpdate", { breakpoint: breakpoint }); } callback(null, breakpoint, info); }); return true; } ``` ## Methods There are 23 methods that *must* be implemented by your plugin. These methods *must* be defined on the public API of your plugin. ``` function attach(){} plugin.freezePublicAPI({ attach: attach }); ``` [block:callout] { "type": "warning", "title": "Unsupported methods", "body": "Some debuggers don't support all the operations needed to implement a function. In that case simply keep the function empty and [call the callback with an error](#unimplemented-methods)." } [/block] The following table lists all the methods. We'll discuss them below. [block:html] { "html": "<table>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-attach\" target=\"_blank\">attach</a></th><td>Attaches the debugger to the started process.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-detach\" target=\"_blank\">detach</a></th><td>Detaches the debugger from the started process.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getSources\" target=\"_blank\">getSources</a></th><td>Loads all the active sources from the process</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getSource\" target=\"_blank\">getSource</a></th><td>Retrieves the contents of a source file</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getFrames\" target=\"_blank\">getFrames</a></th><td>Retrieves the current stack of frames (aka \"the call stack\") </td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getScope\" target=\"_blank\">getScope</a></th><td>Retrieves the variables from a scope.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getProperties\" target=\"_blank\">getProperties</a></th><td>Retrieves and sets the properties of a variable.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-stepInto\" target=\"_blank\">stepInto</a></th><td>Step into the next statement.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-stepOver\" target=\"_blank\">stepOver</a></th><td>Step over the next statement.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-stepOut\" target=\"_blank\">stepOut</a></th><td>Step out of the current statement.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-resume\" target=\"_blank\">resume</a></th><td>Continues execution of a process after it has hit a breakpoint.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-suspend\" target=\"_blank\">suspend</a></th><td>Pauses the execution of a process at the next statement.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-evaluate\" target=\"_blank\">evaluate</a></th><td>Evaluates an expression in a frame or in global space.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-setScriptSource\" target=\"_blank\">setScriptSource</a></th><td>Change a live running source to the latest code state.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-setBreakpoint\" target=\"_blank\">setBreakpoint</a></th><td>Adds a breakpoint to a line in a source file.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-changeBreakpoint\" target=\"_blank\">changeBreakpoint</a></th><td>Updates properties of a breakpoint.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-clearBreakpoint\" target=\"_blank\">clearBreakpoint</a></th><td>Removes a breakpoint from a line in a source file.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-listBreakpoints\" target=\"_blank\">listBreakpoints</a></th><td>Retrieves a list of all the breakpoints that are set in the debugger.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-setVariable\" target=\"_blank\">setVariable</a></th><td>Sets the value of a variable.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-restartFrame\" target=\"_blank\">restartFrame</a></th><td>Starts a frame (usually a function) from the first expression in that frame. </td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-serializeVariable\" target=\"_blank\">serializeVariable</a></th><td>Retrieve the value of a variable.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-setBreakBehavior\" target=\"_blank\">setBreakBehavior</a></th><td>Defines how the debugger deals with exceptions.</td></tr>\n<tr><th><a href=\"https://docs.c9.io/api/#!/api/debugger.implementation-method-getProxySource\" target=\"_blank\">getProxySource</a></th><td>Returns the source of the proxy process.</td></tr>\n</table>" } [/block] ### attach The `attach` method implements the flow for connecting to the debugger through a proxy connection which is setup by the socket. This is arguably the most involved function to implement and the exact implementation will be highly unique for each debugger. After the `attach()` function has set up the initial connection with the debugger, the other functions will be responsible for sending commands and parsing the response. ``` var socket; function attach(_socket, reconnect, callback) { socket = _socket; // The back event is fired when the socket reconnects socket.on("back", function(err) { // Get a list of breakpoints var breakpoints = emit("getBreakpoints"); // Redo the state sync sync(breakpoints, true); }, plugin); // The error event is fired when the socket fails to connect socket.on("error", function(err) { emit("error", err); }, plugin); // Attach to the debugger in your own way attachToDebugger(socket, function(err) { if (err) return callback(err); // Reset the active frame emit("frameActivate", { frame: null }); // Initialize the connected debugger sync(emit("getBreakpoints"), reconnect, callback); }); } ``` The example above portrays the basic flow your implementation of the attach method *should* follow. The UI depends on the `error` and `frameActivate` events to present the correct state to the user. For more information on the `socket` object [click here](#socket). The `sync` function is a placeholder for a function that fetches the state from the debugger. Check out an example implementation below. ``` function sync(breakpoints, reconnect, callback){ // TODO: Fetch sources // TODO: Fetch frames (if on a break) // TODO: Sync breakpoints attached = true; emit("attach", { breakpoints: breakpoints }); if (frames.length) { emit("frameActivate", { frame: frames[0] }); emit("break", { frame: frames[0], frames: frames }); emit("stateChange", { state: "stopped" }); } else { emit("stateChange", { state: "running" }); } } ``` The `sync()` (or similar function) should fetch the current state from the debugger. This includes the sources, frames and breakpoints - after setting the list of breakpoints that are known to the UI. The `attach`, `frameActivate`, `stateChange` and `break` events direct the UI to render the state. [block:callout] { "type": "warning", "title": "The 'v8' example debugger", "body": "The very first Cloud9 debugger is the `v8` debugger and it still serves as an example to anyone implementing their own debugger. If you check out the [v8 source code](https://github.com/c9/c9.ide.run.debug/blob/master/debuggers/v8/v8debugger.js) you'll find that the `attach` function calls out to its `sync` function which implements the init flow for v8." } [/block] ### detach The `detach()` function gracefully disconnects from the debugger. You *must* emit the `frameActivate`, `stateChange` and `detach` events in order for the UI to update correctly. ``` function detach() { // Clean up the debugger connection detachFromDebugger(); emit("frameActivate", { frame: null }); emit("stateChange", { state: null }); attached = false; emit("detach"); } ``` ### getSources The `getSources()` function retrieves all the source files (paths) known to the debugger and returns them as an array of `Source` objects. ``` function getSources(callback) { getSourcesFromDebugger(function(err, scripts) { if (err) return callback(err); var sources = scripts.map(function(options){ return createSource(options); }); callback(null, sources); emit("sources", { sources: sources }); }); } ``` The `createSource()` helper function used above returns a `Source` object. ``` function createSource(options) { return new Source({ // etc }); } ``` ### getSource The `getSource()` method fetches the source code of a source file. If your debugger doesn't support this feature it should simply [call the callback with an error](#unimplemented-methods). ``` function getSource(source, callback) { getSourceFromDebugger(source, function(err, code) { callback(err, code); }); } ``` ### getFrames The `getFrames()` function retrieves all the frames on the callstack from the debugger and returns them as an array of `Frame` objects. ``` function getFrames(callback, silent) { getFramesFromDebugger(function(err, items) { frames = items.map(function(options, index) { return createFrame(frame, index); }); emit("getFrames", { frames: frames }); callback(null, frames); }); } ``` The `createFrame()` helper function used above returns a `Frame` object. ``` function createFrame(options, index) { var frame = new Frame({ istop: index == 0 // etc }); } ``` ### getScope The `getScope()` function retrieves all the variables in a frame from the debugger and returns them as an array of `Variable` objects. ``` function getScope(frame, scope, callback) { getScopeFromDebugger(scope.index, frame.index, function(err, properties) { if (err) return callback(err); var variables = properties.map(function(options) { return createVariable(options); }); scope.variables = variables; callback(null, variables, scope, frame); }); } ``` The `createVariable()` helper function used above returns a `Frame` object. ``` function createVariable(options) { return new Variable({ // etc }); } ``` ### getProperties The `getProperties()` function retrieves all the properties of a variable from the debugger and returns them as an array of `Variable` objects. For each property that is of a basic data type, you *must* set the value (i.e. string, int, etc.). The UI will call this function recursively as a user clicks through the datagrid. ``` function getProperties(variable, callback) { getPropertiesFromDebugger(variable.ref, function(err, props) { if (err) return callback(err); if (props.length > 5000) { props = [new Variable({ name: "Too many properties", type: "error", value: "Found more than 5000 properties", children: false })]; variable.properties = props; callback(null, props, variable); return; } var properties = props.map(function(prop) { return createVariable(prop); }); variable.properties = properties; callback(null, properties, variable); }); } ``` In the example above we only return 5000 or fewer properties. This is generally a good practice if there are multiple calls to the debugger needed to fetch the requested data - for instance the v8 debugger requires one call for each property to fetch its value. ### stepInto The `stepInto()` function steps into the current expression. ``` function stepInto(callback) { stepIntoDebugger(function(err){ callback(err); }); } ``` ### stepOver The `stepOver()` function steps over the current expression. ``` function stepOver(callback) { stepOverDebugger(function(err){ callback(err); }); } ``` ### stepOut The `stepOut()` function steps out of the current frame. ``` function stepOut(callback) { stepOutDebugger(function(err){ callback(err); }); } ``` ### resume The `resume()` function continues execution. ``` function resume(callback) { resumeDebugger(function(err){ callback(err); }); } ``` ### suspend The `suspend()` function pauses expression at the next possible expression. ``` function suspend(callback) { suspendDebugger(function(err){ if (err) return callback(err); emit("suspend"); callback(); }); } ``` ### evaluate The `evaluate()` function takes an expression and executes it in the global context or the context of a frame. If your debugger doesn't support evaluation of expressions simply return an error in the callback. This function is used amongst others by the immediate window. ``` function evaluate(expression, frame, global, disableBreak, callback) { var frameIndex = frame && typeof frame == "object" ? frame.index : frame; evaluateInDebugger(expression, frameIndex, global, disableBreak, function(error, value, properties) { var name = expression.trim(); if (error) { var err = new Error(error.message); err.name = name; err.stack = error.stack; return callback(err); } var variable = createVariable({ name: name, value: value }); if (properties) variable.properties = properties; callback(null, variable); }); } ``` ### setScriptSource The `setScriptSource()` function updates the source of a file that is active in the running process. If your debugger doesn't support this simply [call the callback with an error](#unimplemented-methods). ``` function setScriptSource(script, newSource, previewOnly, callback) { setScriptSourceInDebugger(script.id, newSource, previewOnly, function(err, data) { if (err) callback(new Error("Could not update source")); emit("setScriptSource", data); callback(null, data); }); }; ``` ### setBreakpoint The `setBreakpoint()` function adds a breakpoint to a line and column in a source file. ``` function setBreakpoint(bp, callback) { setBreakpointAtDebugger(bp, function(info) { if (isDifferentLocation(info, bp)) { updateBreakpoint(bp, info); emit("breakpointUpdate", { breakpoint: bp }); } callback(null, bp, info); }); return true; } ``` ### changeBreakpoint The `changeBreakpoint()` function updates a breakpoint such as toggling the enabled state, condition or ignoreCount. If your debugger implementation doesn't support updating a breakpoint simply remove the existing one and add a new one. ``` function changeBreakpoint(bp, callback) { changeBreakpointAtDebugger(function(err, data) { callback(err, bp, data); }); } ``` ### clearBreakpoint The `clearBreakpoint()` function remove a breakpoint from a certain line and column in a source file. ``` function clearBreakpoint(bp, callback) { clearBreakpointAtDebugger(bp, function(err) { callback(err); }); } ``` ### listBreakpoints The `listBreakpoints()` function fetches an array of breakpoints known by the debugger. ``` function listBreakpoints(callback) { listBreakpointsAtDebugger(function(err, breakpoints) { if (err) return callback(err); callback(null, breakpoints.map(function(bp) { return createBreakpoint(bp); })); }); } ``` ### setVariable The `setVariable()` function sets the value of a variable in a certain frame. This is used by the watch expression and the variables debug panel. The `parents` argument is an array of variables that are the objects on which this variable is a property. For a local variable to the frame this array is empty, otherwise the 0th element will contain the reference to the object the variable is a property of. ``` function setVariable(variable, parents, value, frame, callback) { setVariableAtDebugger(variable, parents, value, frame, function(err, options){ if (err) return callback(err) callback(null, createVariable(options)); }); } ``` ### restartFrame The `restartFrame()` function starts the frame at the first expression in that frame. If your debugger doesn't support this feature simply return an error in the callback. ``` function restartFrame(frame, callback) { var frameIndex = frame && typeof frame == "object" ? frame.index : frame; restartFrameAtDebugger(frameIndex, function(err, data) { callback(err, data); }); } ``` ### serializeVariable The `serializeVariable()` function returns a serialized version of the variable. For a string this would be `"value"` for a regexp this might be `/\w/` and for a function this might be the source of that function or `function`. You have total freedom in determining the serialized state of a variable. It is wise to choose a format that can be used to set the variable when using `setVariable()` if your debugger supports that. ``` function serializeVariable(variable, callback) { serializeVariableAtDebugger(variable, function(err, value) { callback(err, value); }); } ``` ### setBreakBehavior The `setBreakBehavior()` function tells the debugger on which type of exceptions to break. The `type` argument can be set to `all` or `uncaught`. ``` function setBreakBehavior(type, enabled, callback) { breakOnExceptions = enabled ? type == "all" : false; breakOnUncaughtExceptions = enabled ? type == "uncaught" : false; setBreakBehavior(type, enabled, callback); } ``` ### getProxySource The `getProxySource()` function is used to fetch the source code of the proxy for your debugger implementation. You can fetch the default proxy source from `debug.proxySource`. You can find more information about the proxy below. ``` function getProxySource(process){ return debug.proxySource .replace(/\/\/.*/g, "") .replace(/[\n\r]/g, "") .replace(/\{PORT\}/, process.runner[0].debugport); } ``` ### Unimplemented methods If your implementation doesn't support a feature of the public API, you must still implement the method but you can supply an error to the provided callback, as shown in an example below. ``` function getSource(source, callback) { callback(new Error("Debugger cannot return source code")); } ```