mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-04-19 12:57:17 +00:00
Removed the arduino-debugger-extension
extension
We use the `cortex-debug` VSX. Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
48c6c53b9b
commit
96f0722d56
@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "arduino-debugger-extension",
|
||||
"version": "2.0.0-beta.1",
|
||||
"description": "An extension for debugging Arduino programs",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@theia/debug": "next",
|
||||
"arduino-ide-extension": "2.0.0-beta.1",
|
||||
"cdt-gdb-adapter": "^0.0.14",
|
||||
"vscode-debugadapter": "^1.26.0",
|
||||
"vscode-debugprotocol": "^1.26.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "yarn run clean && yarn run build",
|
||||
"clean": "rimraf lib",
|
||||
"lint": "tslint -c ./tslint.json --project ./tsconfig.json",
|
||||
"build": "tsc && yarn lint",
|
||||
"watch": "tsc -w"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"theiaExtensions": [
|
||||
{
|
||||
"backend": "lib/node/arduino-debug-backend-module",
|
||||
"frontend": "lib/browser/arduino-debug-frontend-module"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import { DebugConfigurationManager } from "@theia/debug/lib/browser/debug-configuration-manager";
|
||||
import { injectable } from "inversify";
|
||||
|
||||
@injectable()
|
||||
export class ArduinoDebugConfigurationManager extends DebugConfigurationManager {
|
||||
|
||||
get defaultDebugger(): Promise<string | undefined> {
|
||||
return this.debug.getDebuggersForLanguage('ino').then(debuggers => {
|
||||
if (debuggers.length === 0)
|
||||
return undefined;
|
||||
return debuggers[0].type;
|
||||
});
|
||||
}
|
||||
|
||||
protected async selectDebugType(): Promise<string | undefined> {
|
||||
const widget = this.editorManager.currentEditor;
|
||||
if (!widget) {
|
||||
return this.defaultDebugger;
|
||||
}
|
||||
const { languageId } = widget.editor.document;
|
||||
const debuggers = await this.debug.getDebuggersForLanguage(languageId);
|
||||
if (debuggers.length === 0) {
|
||||
return this.defaultDebugger;
|
||||
}
|
||||
return this.quickPick.show(debuggers.map(
|
||||
({ label, type }) => ({ label, value: type }),
|
||||
{ placeholder: 'Select Environment' })
|
||||
);
|
||||
}
|
||||
|
||||
async createDefaultConfiguration(): Promise<void> {
|
||||
const { model } = this;
|
||||
if (model) {
|
||||
await this.doCreate(model);
|
||||
await this.updateModels();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { MenuModelRegistry, MessageService, Command, CommandRegistry } from '@theia/core';
|
||||
import { KeybindingRegistry } from '@theia/core/lib/browser';
|
||||
import { TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
||||
import { DebugFrontendApplicationContribution, DebugCommands } from '@theia/debug/lib/browser/debug-frontend-application-contribution';
|
||||
import { DebugSessionOptions } from "@theia/debug/lib/browser/debug-session-options";
|
||||
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { FileSystem } from '@theia/filesystem/lib/common';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { EditorManager } from '@theia/editor/lib/browser';
|
||||
import { EditorMode } from "arduino-ide-extension/lib/browser/editor-mode";
|
||||
import { SketchesService } from 'arduino-ide-extension/lib/common/protocol/sketches-service';
|
||||
import { ArduinoToolbar } from 'arduino-ide-extension/lib/browser/toolbar/arduino-toolbar';
|
||||
import { ArduinoDebugConfigurationManager } from './arduino-debug-configuration-manager';
|
||||
|
||||
export namespace ArduinoDebugCommands {
|
||||
export const START_DEBUG: Command = {
|
||||
id: 'arduino-start-debug',
|
||||
label: 'Start Debugging'
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class ArduinoDebugFrontendApplicationContribution extends DebugFrontendApplicationContribution {
|
||||
|
||||
@inject(EditorMode)
|
||||
protected readonly editorMode: EditorMode;
|
||||
|
||||
@inject(WorkspaceService)
|
||||
protected readonly workspaceService: WorkspaceService;
|
||||
|
||||
@inject(SketchesService)
|
||||
protected readonly sketchesService: SketchesService;
|
||||
|
||||
@inject(FileSystem)
|
||||
protected readonly fileSystem: FileSystem;
|
||||
|
||||
@inject(EditorManager)
|
||||
protected readonly editorManager: EditorManager;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
|
||||
async start(noDebug?: boolean, debugSessionOptions?: DebugSessionOptions): Promise<void> {
|
||||
const configurations = this.configurations as ArduinoDebugConfigurationManager;
|
||||
let current = debugSessionOptions ? debugSessionOptions : configurations.current;
|
||||
// If no configurations are currently present, create them
|
||||
if (!current) {
|
||||
await configurations.createDefaultConfiguration();
|
||||
current = configurations.current;
|
||||
}
|
||||
if (current) {
|
||||
if (noDebug !== undefined) {
|
||||
current = {
|
||||
...current,
|
||||
configuration: {
|
||||
...current.configuration,
|
||||
noDebug
|
||||
}
|
||||
};
|
||||
}
|
||||
if (current.configuration.type === 'arduino') {
|
||||
const wsStat = this.workspaceService.workspace;
|
||||
let sketchFileURI: URI | undefined;
|
||||
if (wsStat && await this.sketchesService.isSketchFolder(wsStat.resource.toString())) {
|
||||
const wsPath = wsStat.resource.path;
|
||||
const sketchFilePath = wsPath.join(wsPath.name + '.ino').toString();
|
||||
sketchFileURI = new URI(sketchFilePath);
|
||||
} else if (this.editorManager.currentEditor) {
|
||||
const editorURI = this.editorManager.currentEditor.getResourceUri();
|
||||
if (editorURI && editorURI.path && editorURI.path.ext === '.ino') {
|
||||
sketchFileURI = editorURI;
|
||||
}
|
||||
}
|
||||
if (sketchFileURI) {
|
||||
await this.editorManager.open(sketchFileURI);
|
||||
await this.manager.start(current);
|
||||
} else {
|
||||
this.messageService.error('Please open a sketch file to start debugging.')
|
||||
}
|
||||
} else {
|
||||
await this.manager.start(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initializeLayout(): Promise<void> {
|
||||
if (this.editorMode.proMode) {
|
||||
return super.initializeLayout();
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
registerMenus(menus: MenuModelRegistry): void {
|
||||
if (this.editorMode.proMode) {
|
||||
super.registerMenus(menus);
|
||||
menus.unregisterMenuAction(DebugCommands.START_NO_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
registerKeybindings(keybindings: KeybindingRegistry): void {
|
||||
if (this.editorMode.proMode) {
|
||||
super.registerKeybindings(keybindings);
|
||||
keybindings.unregisterKeybinding({
|
||||
command: DebugCommands.START_NO_DEBUG.id,
|
||||
keybinding: 'ctrl+f5'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
registerToolbarItems(toolbar: TabBarToolbarRegistry): void {
|
||||
super.registerToolbarItems(toolbar);
|
||||
toolbar.registerItem({
|
||||
id: ArduinoDebugCommands.START_DEBUG.id,
|
||||
command: ArduinoDebugCommands.START_DEBUG.id,
|
||||
tooltip: 'Start Debugging',
|
||||
priority: 3
|
||||
});
|
||||
}
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
super.registerCommands(registry);
|
||||
registry.registerCommand(ArduinoDebugCommands.START_DEBUG, {
|
||||
isVisible: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
|
||||
isEnabled: widget => ArduinoToolbar.is(widget) && widget.side === 'left',
|
||||
execute: () => {
|
||||
registry.executeCommand(DebugCommands.START.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
import { ContainerModule } from 'inversify';
|
||||
import { VariableContribution } from '@theia/variable-resolver/lib/browser';
|
||||
import { ArduinoVariableResolver } from './arduino-variable-resolver';
|
||||
import { DebugSessionManager } from '@theia/debug/lib/browser/debug-session-manager';
|
||||
import { DebugFrontendApplicationContribution } from '@theia/debug/lib/browser/debug-frontend-application-contribution';
|
||||
import { DebugConfigurationManager } from '@theia/debug/lib/browser/debug-configuration-manager';
|
||||
import { ArduinoDebugConfigurationManager } from './arduino-debug-configuration-manager';
|
||||
import { ArduinoDebugFrontendApplicationContribution } from './arduino-debug-frontend-application-contribution';
|
||||
import { ArduinoDebugSessionManager } from './arduino-debug-session-manager';
|
||||
|
||||
import '../../src/browser/style/index.css';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ArduinoVariableResolver).toSelf().inSingletonScope();
|
||||
bind(VariableContribution).toService(ArduinoVariableResolver);
|
||||
rebind(DebugSessionManager).to(ArduinoDebugSessionManager).inSingletonScope();
|
||||
rebind(DebugConfigurationManager).to(ArduinoDebugConfigurationManager).inSingletonScope();
|
||||
rebind(DebugFrontendApplicationContribution).to(ArduinoDebugFrontendApplicationContribution);
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
import { DebugSessionManager } from "@theia/debug/lib/browser/debug-session-manager";
|
||||
import { DebugSessionOptions } from "@theia/debug/lib/browser/debug-session-options";
|
||||
|
||||
export class ArduinoDebugSessionManager extends DebugSessionManager {
|
||||
|
||||
start(options: DebugSessionOptions) {
|
||||
if (options.configuration.type === 'arduino' && this.sessions.find(s => s.configuration.type === 'arduino')) {
|
||||
this.messageService.info('A debug session is already running. You must stop the running session before starting a new one.')
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
return super.start(options);
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
|
||||
import { VariableContribution, VariableRegistry, Variable } from '@theia/variable-resolver/lib/browser';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { BoardsServiceProvider } from 'arduino-ide-extension/lib/browser/boards/boards-service-provider';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoVariableResolver implements VariableContribution {
|
||||
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceProvider: BoardsServiceProvider;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService
|
||||
|
||||
registerVariables(variables: VariableRegistry): void {
|
||||
variables.registerVariable(<Variable>{
|
||||
name: 'fqbn',
|
||||
description: 'Qualified name of the selected board',
|
||||
resolve: this.resolveFqbn.bind(this),
|
||||
});
|
||||
variables.registerVariable({
|
||||
name: 'port',
|
||||
description: 'Selected upload port',
|
||||
resolve: this.resolvePort.bind(this)
|
||||
});
|
||||
}
|
||||
|
||||
protected async resolveFqbn(): Promise<string | undefined> {
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
if (!boardsConfig || !boardsConfig.selectedBoard) {
|
||||
this.messageService.error('No board selected. Please select a board for debugging.');
|
||||
return undefined;
|
||||
}
|
||||
return boardsConfig.selectedBoard.fqbn;
|
||||
}
|
||||
|
||||
protected async resolvePort(): Promise<string | undefined> {
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
if (!boardsConfig || !boardsConfig.selectedPort) {
|
||||
return undefined;
|
||||
}
|
||||
return boardsConfig.selectedPort.address;
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
.arduino-start-debug-icon {
|
||||
-webkit-mask: url('debug-dark.svg') 50%;
|
||||
mask: url('debug-dark.svg') 50%;
|
||||
-webkit-mask-size: 100%;
|
||||
mask-size: 100%;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-repeat: no-repeat;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--theia-ui-button-font-color);
|
||||
}
|
||||
|
||||
.arduino-start-debug {
|
||||
border-radius: 12px;
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
import * as path from 'path';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { DebugAdapterContribution, DebugAdapterExecutable } from '@theia/debug/lib/common/debug-model';
|
||||
import { DebugConfiguration } from '@theia/debug/lib/common/debug-configuration';
|
||||
import { IJSONSchema } from '@theia/core/lib/common/json-schema';
|
||||
import { ArduinoDaemonImpl } from 'arduino-ide-extension/lib/node/arduino-daemon-impl';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoDebugAdapterContribution implements DebugAdapterContribution {
|
||||
|
||||
readonly type = 'arduino';
|
||||
readonly label = 'Arduino';
|
||||
readonly languages = ['c', 'cpp', 'ino'];
|
||||
|
||||
@inject(ArduinoDaemonImpl) daemon: ArduinoDaemonImpl;
|
||||
|
||||
getSchemaAttributes(): IJSONSchema[] {
|
||||
return [
|
||||
{
|
||||
'properties': {
|
||||
'sketch': {
|
||||
'type': 'string',
|
||||
'description': 'path to the sketch root ino file',
|
||||
'default': '${file}',
|
||||
},
|
||||
'pauseAtMain': {
|
||||
'description': 'If enabled the debugger will pause at the start of the main function.',
|
||||
'type': 'boolean',
|
||||
'default': false
|
||||
},
|
||||
'debugDebugAdapter': {
|
||||
'type': 'boolean',
|
||||
'description': 'Start the debug adapter in debug mode (with --inspect-brk)',
|
||||
'default': false
|
||||
},
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
provideDebugAdapterExecutable(config: DebugConfiguration): DebugAdapterExecutable {
|
||||
const debugAdapterMain = path.join(__dirname, 'debug-adapter', 'main');
|
||||
if (config.debugDebugAdapter) {
|
||||
return {
|
||||
command: process.execPath,
|
||||
args: ['--inspect-brk', debugAdapterMain],
|
||||
}
|
||||
}
|
||||
return {
|
||||
modulePath: debugAdapterMain,
|
||||
args: [],
|
||||
}
|
||||
}
|
||||
|
||||
provideDebugConfigurations(): DebugConfiguration[] {
|
||||
return [
|
||||
<DebugConfiguration>{
|
||||
name: this.label,
|
||||
type: this.type,
|
||||
request: 'launch'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
async resolveDebugConfiguration(config: DebugConfiguration): Promise<DebugConfiguration> {
|
||||
const startFunction = config.pauseAtMain ? 'main' : 'setup';
|
||||
const res: ActualDebugConfig = {
|
||||
...config,
|
||||
arduinoCli: await this.daemon.getExecPath(),
|
||||
fqbn: '${fqbn}',
|
||||
uploadPort: '${port}',
|
||||
initCommands: [
|
||||
`-break-insert -t --function ${startFunction}`
|
||||
]
|
||||
}
|
||||
if (!res.sketch) {
|
||||
res.sketch = '${file}';
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface ActualDebugConfig extends DebugConfiguration {
|
||||
arduinoCli?: string;
|
||||
sketch?: string;
|
||||
fqbn?: string;
|
||||
uploadPort?: string;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
import { ContainerModule } from 'inversify';
|
||||
import { DebugAdapterContribution } from '@theia/debug/lib/common/debug-model';
|
||||
import { ArduinoDebugAdapterContribution } from './arduino-debug-adapter-contribution';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(DebugAdapterContribution).to(ArduinoDebugAdapterContribution).inSingletonScope();
|
||||
});
|
@ -1,140 +0,0 @@
|
||||
import { DebugProtocol } from 'vscode-debugprotocol';
|
||||
import { GDBDebugSession, FrameVariableReference } from 'cdt-gdb-adapter/dist/GDBDebugSession';
|
||||
import { GDBBackend } from 'cdt-gdb-adapter/dist/GDBBackend';
|
||||
import * as mi from 'cdt-gdb-adapter/dist/mi';
|
||||
import { ArduinoGDBBackend } from './arduino-gdb-backend';
|
||||
import { ArduinoVariableHandler } from './arduino-variable-handler';
|
||||
import { Scope, OutputEvent } from 'vscode-debugadapter';
|
||||
|
||||
export interface ArduinoLaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
|
||||
arduinoCli?: string;
|
||||
sketch?: string;
|
||||
fqbn?: string;
|
||||
uploadPort?: string;
|
||||
}
|
||||
|
||||
const GLOBAL_HANDLE_ID = 0xFE;
|
||||
const STATIC_HANDLES_START = 0x010000;
|
||||
const STATIC_HANDLES_FINISH = 0x01FFFF;
|
||||
|
||||
export class ArduinoDebugSession extends GDBDebugSession {
|
||||
|
||||
private _variableHandler: ArduinoVariableHandler;
|
||||
|
||||
get arduinoBackend(): ArduinoGDBBackend {
|
||||
return this.gdb as ArduinoGDBBackend;
|
||||
}
|
||||
|
||||
protected get variableHandler() {
|
||||
if (this._variableHandler) {
|
||||
return this._variableHandler;
|
||||
}
|
||||
if (!this.gdb) {
|
||||
throw new Error("GDB backend is not ready.");
|
||||
}
|
||||
const handler = new ArduinoVariableHandler(this, this.frameHandles, this.variableHandles);
|
||||
this._variableHandler = handler;
|
||||
return handler;
|
||||
}
|
||||
|
||||
protected createBackend(): GDBBackend {
|
||||
return new ArduinoGDBBackend();
|
||||
}
|
||||
|
||||
protected async configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse): Promise<void> {
|
||||
try {
|
||||
await this.gdb.sendCommand('-interpreter-exec console "monitor reset halt"')
|
||||
await mi.sendExecContinue(this.gdb);
|
||||
this.sendResponse(response);
|
||||
} catch (err) {
|
||||
this.sendErrorResponse(response, 100, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
protected pauseRequest(response: DebugProtocol.PauseResponse, args: DebugProtocol.PauseArguments): Promise<void> {
|
||||
if (process.platform === 'win32') {
|
||||
const message = 'Pause is not supported on Windows. Please stop the debug session and set a breakpoint instead.';
|
||||
this.sendEvent(new OutputEvent(message));
|
||||
this.sendErrorResponse(response, 1, message);
|
||||
return Promise.resolve();
|
||||
}
|
||||
return super.pauseRequest(response, args);
|
||||
}
|
||||
|
||||
protected async disconnectRequest(response: DebugProtocol.DisconnectResponse): Promise<void> {
|
||||
try {
|
||||
if (this.isRunning) {
|
||||
if (process.platform === 'win32') {
|
||||
// We cannot pause on Windows
|
||||
this.arduinoBackend.kill();
|
||||
this.sendResponse(response);
|
||||
return;
|
||||
}
|
||||
// Need to pause first
|
||||
const waitPromise = new Promise(resolve => this.waitPaused = resolve);
|
||||
this.gdb.pause();
|
||||
await waitPromise;
|
||||
}
|
||||
await this.gdb.sendGDBExit();
|
||||
this.sendResponse(response);
|
||||
} catch (err) {
|
||||
this.sendErrorResponse(response, 1, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
|
||||
try {
|
||||
const frame: FrameVariableReference = {
|
||||
type: 'frame',
|
||||
frameHandle: args.frameId,
|
||||
};
|
||||
// const pins: ObjectVariableReference = {
|
||||
// type: "object",
|
||||
// varobjName: "__pins",
|
||||
// frameHandle: 42000,
|
||||
// }
|
||||
|
||||
response.body = {
|
||||
scopes: [
|
||||
// new Scope('Pins', this.variableHandles.create(pins), false),
|
||||
new Scope('Local', this.variableHandles.create(frame), false),
|
||||
new Scope('Global', GLOBAL_HANDLE_ID, false),
|
||||
// new Scope('Static', STATIC_HANDLES_START + parseInt(args.frameId as any, 10), false)
|
||||
],
|
||||
};
|
||||
|
||||
this.sendResponse(response);
|
||||
} catch (err) {
|
||||
this.sendErrorResponse(response, 1, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): Promise<void> {
|
||||
try {
|
||||
response.body = {
|
||||
variables: [] as DebugProtocol.Variable[]
|
||||
};
|
||||
const ref = this.variableHandles.get(args.variablesReference);
|
||||
if (args.variablesReference === GLOBAL_HANDLE_ID) {
|
||||
// Use hardcoded global handle to load and store global variables
|
||||
response.body.variables = await this.variableHandler.getGlobalVariables();
|
||||
} else if (args.variablesReference >= STATIC_HANDLES_START && args.variablesReference <= STATIC_HANDLES_FINISH) {
|
||||
// Use STATIC_HANDLES_START to shift the framehandles back
|
||||
const frameHandle = args.variablesReference - STATIC_HANDLES_START;
|
||||
response.body.variables = await this.variableHandler.getStaticVariables(frameHandle);
|
||||
} else if (ref && ref.type === 'frame') {
|
||||
// List variables for current frame
|
||||
response.body.variables = await this.handleVariableRequestFrame(ref);
|
||||
} else if (ref && ref.varobjName === '__pins') {
|
||||
response.body.variables = await this.variableHandler.handlePinStatusRequest();
|
||||
} else if (ref && ref.type === 'object') {
|
||||
// List data under any variable
|
||||
response.body.variables = await this.handleVariableRequestObject(ref);
|
||||
}
|
||||
this.sendResponse(response);
|
||||
} catch (err) {
|
||||
this.sendErrorResponse(response, 1, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import * as path from 'path';
|
||||
import * as fs from 'arduino-ide-extension/lib/node/fs-extra'
|
||||
import { spawn } from 'child_process';
|
||||
import { GDBBackend } from 'cdt-gdb-adapter/dist/GDBBackend';
|
||||
import { MIFrameInfo } from 'cdt-gdb-adapter/dist/mi';
|
||||
import { ArduinoLaunchRequestArguments } from './arduino-debug-session';
|
||||
import { ArduinoParser } from './arduino-parser';
|
||||
|
||||
export class ArduinoGDBBackend extends GDBBackend {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.parser = new ArduinoParser(this);
|
||||
}
|
||||
|
||||
spawn(requestArgs: ArduinoLaunchRequestArguments): Promise<void> {
|
||||
if (!requestArgs.sketch) {
|
||||
throw new Error('Missing argument: sketch');
|
||||
}
|
||||
if (!requestArgs.fqbn) {
|
||||
throw new Error('Missing argument: fqbn')
|
||||
}
|
||||
const sketchFS = fs.statSync(requestArgs.sketch);
|
||||
const sketchDir = sketchFS.isFile() ? path.dirname(requestArgs.sketch) : requestArgs.sketch;
|
||||
const command = requestArgs.arduinoCli || 'arduino-cli';
|
||||
const args = [
|
||||
'debug',
|
||||
'-p', requestArgs.uploadPort || 'none',
|
||||
'-b', requestArgs.fqbn,
|
||||
'--interpreter', 'mi2',
|
||||
sketchDir
|
||||
];
|
||||
console.log('Starting debugger:', command, JSON.stringify(args));
|
||||
const proc = spawn(command, args);
|
||||
this.proc = proc;
|
||||
this.out = proc.stdin;
|
||||
return (this.parser as ArduinoParser).parseFull(proc);
|
||||
}
|
||||
|
||||
sendFileExecAndSymbols(): Promise<void> {
|
||||
// The program file is already sent by `arduino-cli`
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
sendExecInterrupt(threadId?: number) {
|
||||
let command = '-exec-interrupt';
|
||||
if (threadId) {
|
||||
command += ` --thread ${threadId}`;
|
||||
}
|
||||
return this.sendCommand(command);
|
||||
}
|
||||
|
||||
sendStackInfoFrame(threadId: number, frameId: number): Promise<{ frame: MIFrameInfo }> {
|
||||
const command = `-stack-info-frame --thread ${threadId} --frame ${frameId}`;
|
||||
return this.sendCommand(command);
|
||||
}
|
||||
|
||||
sendTargetDetach(): Promise<void> {
|
||||
return this.sendCommand('-target-detach');
|
||||
}
|
||||
|
||||
kill(): void {
|
||||
if (!this.proc) {
|
||||
return;
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
spawn('taskkill', ['/pid', this.proc.pid.toString(), '/f', '/t']);
|
||||
} else {
|
||||
this.proc.kill('SIGKILL');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
import { ChildProcessWithoutNullStreams } from 'child_process';
|
||||
import { Readable } from 'stream';
|
||||
import { MIParser } from "cdt-gdb-adapter/dist/MIParser";
|
||||
|
||||
const LINE_REGEX = /(.*)(\r?\n)/;
|
||||
|
||||
export class ArduinoParser extends MIParser {
|
||||
|
||||
protected rejectReady?: (error: Error) => void;
|
||||
|
||||
parseFull(proc: ChildProcessWithoutNullStreams): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Detect errors when the child process could not be spawned
|
||||
proc.on('error', reject);
|
||||
|
||||
this.waitReady = () => {
|
||||
this.rejectReady = undefined;
|
||||
resolve();
|
||||
}
|
||||
this.rejectReady = (error: Error) => {
|
||||
this.waitReady = undefined;
|
||||
reject(error);
|
||||
}
|
||||
// Detect unexpected termination
|
||||
proc.on('exit', () => {
|
||||
if (this.rejectReady) {
|
||||
this.rejectReady(new Error('The gdb debugger terminated unexpectedly.'));
|
||||
}
|
||||
});
|
||||
this.readInputStream(proc.stdout);
|
||||
this.readErrorStream(proc.stderr);
|
||||
});
|
||||
}
|
||||
|
||||
private readInputStream(stream: Readable) {
|
||||
let buff = '';
|
||||
stream.on('data', chunk => {
|
||||
buff += chunk.toString();
|
||||
let regexArray = LINE_REGEX.exec(buff);
|
||||
while (regexArray) {
|
||||
const line = regexArray[1];
|
||||
this.line = line;
|
||||
this.pos = 0;
|
||||
this.handleLine();
|
||||
// Detect error emitted as log message
|
||||
if (this.rejectReady && line.toLowerCase().startsWith('&"error')) {
|
||||
this.pos = 1;
|
||||
this.rejectReady(new Error(this.handleCString() || regexArray[1]));
|
||||
this.rejectReady = undefined;
|
||||
}
|
||||
buff = buff.substring(regexArray[1].length + regexArray[2].length);
|
||||
regexArray = LINE_REGEX.exec(buff);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private readErrorStream(stream: Readable) {
|
||||
let buff = '';
|
||||
stream.on('data', chunk => {
|
||||
buff += chunk.toString();
|
||||
let regexArray = LINE_REGEX.exec(buff);
|
||||
while (regexArray) {
|
||||
const line = regexArray[1];
|
||||
this.gdb.emit('consoleStreamOutput', line + '\n', 'stderr');
|
||||
// Detect error emitted on the stderr stream
|
||||
if (this.rejectReady && line.toLowerCase().startsWith('error')) {
|
||||
this.rejectReady(new Error(line));
|
||||
this.rejectReady = undefined;
|
||||
}
|
||||
buff = buff.substring(regexArray[1].length + regexArray[2].length);
|
||||
regexArray = LINE_REGEX.exec(buff);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
import * as path from 'path';
|
||||
import { DebugProtocol } from "vscode-debugprotocol";
|
||||
import { Handles } from 'vscode-debugadapter/lib/handles';
|
||||
import { FrameReference, VariableReference } from "cdt-gdb-adapter/dist/GDBDebugSession";
|
||||
import { VarManager } from 'cdt-gdb-adapter/dist/varManager';
|
||||
import * as mi from 'cdt-gdb-adapter/dist/mi';
|
||||
import { ArduinoDebugSession } from "./arduino-debug-session";
|
||||
import { ArduinoGDBBackend } from './arduino-gdb-backend';
|
||||
|
||||
export class ArduinoVariableHandler {
|
||||
|
||||
protected readonly gdb: ArduinoGDBBackend;
|
||||
protected readonly varMgr: VarManager;
|
||||
|
||||
protected globalHandle: number;
|
||||
|
||||
constructor(protected readonly session: ArduinoDebugSession,
|
||||
protected frameHandles: Handles<FrameReference>,
|
||||
protected variableHandles: Handles<VariableReference>) {
|
||||
this.gdb = session.arduinoBackend;
|
||||
this.varMgr = new VarManager(this.gdb);
|
||||
}
|
||||
|
||||
createGlobalHandle() {
|
||||
this.globalHandle = this.frameHandles.create({
|
||||
threadId: -1,
|
||||
frameId: -1
|
||||
});
|
||||
}
|
||||
|
||||
/** TODO */
|
||||
async getGlobalVariables(): Promise<DebugProtocol.Variable[]> {
|
||||
throw new Error('Global variables are not supported yet.');
|
||||
const frame = this.frameHandles.get(this.globalHandle);
|
||||
const symbolInfo: any[] = [] // this.symbolTable.getGlobalVariables();
|
||||
const variables: DebugProtocol.Variable[] = [];
|
||||
|
||||
for (const symbol of symbolInfo) {
|
||||
const name = `global_var_${symbol.name}`;
|
||||
const variable = await this.getVariables(frame, name, symbol.name, -1);
|
||||
variables.push(variable);
|
||||
}
|
||||
|
||||
return variables;
|
||||
}
|
||||
|
||||
/** TODO */
|
||||
async getStaticVariables(frameHandle: number): Promise<DebugProtocol.Variable[]> {
|
||||
throw new Error('Static variables are not supported yet.');
|
||||
const frame = this.frameHandles.get(frameHandle);
|
||||
const result = await this.gdb.sendStackInfoFrame(frame.threadId, frame.frameId);
|
||||
const file = path.normalize(result.frame.file || '');
|
||||
const symbolInfo: any[] = [] // this.symbolTable.getStaticVariables(file);
|
||||
const variables: DebugProtocol.Variable[] = [];
|
||||
|
||||
// Fetch stack depth to obtain frameId/threadId/depth tuple
|
||||
const stackDepth = await mi.sendStackInfoDepth(this.gdb, { maxDepth: 100 });
|
||||
const depth = parseInt(stackDepth.depth, 10);
|
||||
|
||||
for (const symbol of symbolInfo) {
|
||||
const name = `${file}_static_var_${symbol.name}`;
|
||||
const variable = await this.getVariables(frame, name, symbol.name, depth);
|
||||
variables.push(variable);
|
||||
}
|
||||
|
||||
return variables;
|
||||
}
|
||||
|
||||
private async getVariables(frame: FrameReference, name: string, expression: string, depth: number): Promise<DebugProtocol.Variable> {
|
||||
let global = this.varMgr.getVar(frame.frameId, frame.threadId, depth, name);
|
||||
|
||||
if (global) {
|
||||
// Update value if it is already loaded
|
||||
const vup = await mi.sendVarUpdate(this.gdb, { name });
|
||||
const update = vup.changelist[0];
|
||||
if (update && update.in_scope === 'true' && update.name === global.varname) {
|
||||
global.value = update.value;
|
||||
}
|
||||
} else {
|
||||
// create var in GDB and store it in the varMgr
|
||||
const varCreateResponse = await mi.sendVarCreate(this.gdb, {
|
||||
name,
|
||||
frame: 'current',
|
||||
expression,
|
||||
});
|
||||
|
||||
global = this.varMgr.addVar(frame.frameId, frame.threadId, depth, name, true, false, varCreateResponse);
|
||||
}
|
||||
|
||||
return {
|
||||
name: expression,
|
||||
value: (global.value === void 0) ? '<unknown>' : global.value,
|
||||
type: global.type,
|
||||
variablesReference: parseInt(global.numchild, 10) > 0
|
||||
? this.variableHandles.create({
|
||||
frameHandle: this.globalHandle,
|
||||
type: 'object',
|
||||
varobjName: global.varname,
|
||||
})
|
||||
: 0,
|
||||
};
|
||||
}
|
||||
|
||||
async handlePinStatusRequest(): Promise<DebugProtocol.Variable[]> {
|
||||
const variables: DebugProtocol.Variable[] = [];
|
||||
variables.push({
|
||||
name: "D2",
|
||||
type: "gpio",
|
||||
value: "0x00",
|
||||
variablesReference: 0
|
||||
})
|
||||
return variables;
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import * as process from 'process';
|
||||
import { logger } from 'vscode-debugadapter/lib/logger';
|
||||
import { ArduinoDebugSession } from './arduino-debug-session';
|
||||
import { DebugSession } from 'vscode-debugadapter';
|
||||
|
||||
process.on('uncaughtException', (err: any) => {
|
||||
logger.error(JSON.stringify(err));
|
||||
});
|
||||
|
||||
DebugSession.run(ArduinoDebugSession);
|
@ -1,31 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noImplicitAny": true,
|
||||
"noEmitOnError": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"strictNullChecks": true,
|
||||
"experimentalDecorators": true,
|
||||
"downlevelIteration": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"outDir": "lib",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"jsx": "react",
|
||||
"sourceMap": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"files": [
|
||||
"../node_modules/@theia/monaco/src/typings/monaco/index.d.ts"
|
||||
]
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"class-name": true,
|
||||
"comment-format": [true, "check-space"],
|
||||
"curly": false,
|
||||
"forin": false,
|
||||
"indent": [true, "spaces"],
|
||||
"max-line-length": [true, 180],
|
||||
"no-trailing-whitespace": false,
|
||||
"no-unused-expression": true,
|
||||
"no-var-keyword": true,
|
||||
"one-line": [true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"radix": true,
|
||||
"trailing-comma": [false],
|
||||
"triple-equals": [true, "allow-null-check"],
|
||||
"typedef-whitespace": [true, {
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}],
|
||||
"variable-name": false,
|
||||
"whitespace": [true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
@ -28,8 +28,7 @@ for (const toUpdate of [
|
||||
path.join(repoRootPath, 'package.json'),
|
||||
path.join(repoRootPath, 'electron-app', 'package.json'),
|
||||
path.join(repoRootPath, 'browser-app', 'package.json'),
|
||||
path.join(repoRootPath, 'arduino-ide-extension', 'package.json'),
|
||||
path.join(repoRootPath, 'arduino-debugger-extension', 'package.json') // Currently unused. The debugger functionality comes from the `cortex.debug` VS Code extension.
|
||||
path.join(repoRootPath, 'arduino-ide-extension', 'package.json')
|
||||
]) {
|
||||
process.stdout.write(` Updating ${toUpdate}'...`);
|
||||
const pkg = require(toUpdate);
|
||||
|
Loading…
x
Reference in New Issue
Block a user