add doc strings
This commit is contained in:
@@ -20,6 +20,7 @@ jobs:
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- run: npm install -g npm@latest
|
||||
- run: npm ci
|
||||
- run: npm install
|
||||
- run: rm -rf dist
|
||||
- run: npm run build
|
||||
- run: npm publish --provenance --access public
|
||||
|
||||
@@ -23,6 +23,7 @@ import { MI2 } from './mi2/mi2';
|
||||
import { MINode } from './mi_parse';
|
||||
import { SymbolTable } from './symbols';
|
||||
|
||||
/** Wraps a variable reference with options. */
|
||||
class ExtendedVariable {
|
||||
constructor(
|
||||
public name: string,
|
||||
@@ -45,6 +46,7 @@ class CustomContinuedEvent extends Event {
|
||||
}
|
||||
}
|
||||
|
||||
/** DAP implementation on top of GDB/MI2. */
|
||||
export class GDBDebugSession extends DebugSession {
|
||||
private variableHandles = new Handles<string | VariableObject | ExtendedVariable>(131072);
|
||||
private variableHandlesReverse: { [name: string]: number } = {};
|
||||
@@ -68,6 +70,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
super(debuggerLinesStartAt1, isServer);
|
||||
}
|
||||
|
||||
/** Attaches MI2 listeners and sends InitializedEvent. */
|
||||
initDebugger(): void {
|
||||
this.miDebugger.on('launcherror', this.launchError.bind(this));
|
||||
this.miDebugger.on('quit', this.quitEvent.bind(this));
|
||||
@@ -85,6 +88,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
this.sendEvent(new InitializedEvent());
|
||||
}
|
||||
|
||||
/** Responds to DAP initialize with capabilities. */
|
||||
protected initializeRequest(response: any, args: any): void {
|
||||
response.body.supportsConditionalBreakpoints = true;
|
||||
response.body.supportsConfigurationDoneRequest = true;
|
||||
@@ -98,16 +102,19 @@ export class GDBDebugSession extends DebugSession {
|
||||
this.sendResponse(response);
|
||||
}
|
||||
|
||||
/** Handles DAP launch request. */
|
||||
protected launchRequest(response: any, args: any): void {
|
||||
this.args = args;
|
||||
this.processLaunchAttachRequest(response, false);
|
||||
}
|
||||
|
||||
/** Handles DAP attach request. */
|
||||
protected attachRequest(response: any, args: any): void {
|
||||
this.args = args;
|
||||
this.processLaunchAttachRequest(response, true);
|
||||
}
|
||||
|
||||
/** Core launch/attach handler. */
|
||||
private processLaunchAttachRequest(response: any, isAttach: boolean): void {
|
||||
this.quit = false;
|
||||
this.attached = false;
|
||||
@@ -168,6 +175,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
);
|
||||
}
|
||||
|
||||
/** Handles custom DAP requests. */
|
||||
protected customRequest(command: string, response: any, args: any): void {
|
||||
switch (command) {
|
||||
case 'set-force-disassembly':
|
||||
@@ -238,6 +246,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles disassemble custom request. */
|
||||
protected async disassembleRequest(response: any, args: any): Promise<void> {
|
||||
if (args.function) {
|
||||
try {
|
||||
@@ -282,6 +291,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets/caches function disassembly. */
|
||||
private async getDisassemblyForFunction(functionName: string, file: string): Promise<any> {
|
||||
const func = this.symbolTable.getFunctionByName(functionName, file);
|
||||
if (!func) {
|
||||
@@ -309,6 +319,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
return func;
|
||||
}
|
||||
|
||||
/** Gets disassembly for address range. */
|
||||
private async getDisassemblyForAddresses(startAddress: number, length: number): Promise<any[]> {
|
||||
const endAddress = startAddress + length;
|
||||
const result = await this.miDebugger.sendCommand(
|
||||
@@ -324,6 +335,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
}));
|
||||
}
|
||||
|
||||
/** Reads memory via MI. */
|
||||
private customReadMemoryRequest(response: any, address: number, length: number): void {
|
||||
this.miDebugger.examineMemory(address, length).then(
|
||||
(data) => {
|
||||
@@ -342,6 +354,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
);
|
||||
}
|
||||
|
||||
/** Writes memory via MI. */
|
||||
private customWriteMemoryRequest(response: any, address: number, data: string): void {
|
||||
const hexAddr = hexFormat(address, 8);
|
||||
this.miDebugger.sendCommand(`data-write-memory-bytes ${hexAddr} ${data}`).then(
|
||||
@@ -355,6 +368,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
);
|
||||
}
|
||||
|
||||
/** Reads CPU registers via MI. */
|
||||
private customReadRegistersRequest(response: any): void {
|
||||
this.miDebugger.sendCommand('data-list-register-values x').then(
|
||||
(result) => {
|
||||
@@ -379,6 +393,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
);
|
||||
}
|
||||
|
||||
/** Reads register names via MI. */
|
||||
private customReadRegisterListRequest(response: any): void {
|
||||
this.miDebugger.sendCommand('data-list-register-names').then(
|
||||
(result) => {
|
||||
@@ -402,6 +417,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
);
|
||||
}
|
||||
|
||||
/** Handles DAP disconnect. */
|
||||
protected disconnectRequest(response: any, args: any): void {
|
||||
if (this.miDebugger) {
|
||||
if (this.attached) {
|
||||
@@ -413,6 +429,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
this.sendResponse(response);
|
||||
}
|
||||
|
||||
/** Handles DAP terminate. */
|
||||
protected terminateRequest(response: any, args: any): void {
|
||||
if (this.miDebugger) {
|
||||
this.miDebugger.stop();
|
||||
@@ -420,6 +437,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
this.sendResponse(response);
|
||||
}
|
||||
|
||||
/** Handles DAP restart. */
|
||||
protected restartRequest(response: any, args: any): void {
|
||||
const doRestart = () => {
|
||||
this.miDebugger
|
||||
@@ -448,10 +466,12 @@ export class GDBDebugSession extends DebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
/** Emits adapter output event. */
|
||||
private handleAdapterOutput(text: string): void {
|
||||
this.sendEvent(new AdapterOutputEvent(text, 'out'));
|
||||
}
|
||||
|
||||
/** Forwards GDB console/log messages. */
|
||||
private handleMsg(type: string, message: string): void {
|
||||
if (type === 'target') {
|
||||
type = 'stdout';
|
||||
@@ -462,12 +482,14 @@ export class GDBDebugSession extends DebugSession {
|
||||
this.sendEvent(new OutputEvent(message, type));
|
||||
}
|
||||
|
||||
/** Emits continued events. */
|
||||
private handleRunning(info: any): void {
|
||||
this.stopped = false;
|
||||
this.sendEvent(new ContinuedEvent(this.currentThreadId, true));
|
||||
this.sendEvent(new CustomContinuedEvent(this.currentThreadId, true));
|
||||
}
|
||||
|
||||
/** Emits stopped events for breakpoints. */
|
||||
private handleBreakpoint(info: any): void {
|
||||
const threadId = parseInt(info.record('thread-id') || this.currentThreadId);
|
||||
this.stopped = true;
|
||||
@@ -476,6 +498,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
this.sendEvent(new CustomStopEvent('breakpoint', threadId));
|
||||
}
|
||||
|
||||
/** Emits stopped events for step end. */
|
||||
private handleBreak(info: any): void {
|
||||
this.stopped = true;
|
||||
this.stoppedReason = 'step';
|
||||
@@ -483,6 +506,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
this.sendEvent(new CustomStopEvent('step', this.currentThreadId));
|
||||
}
|
||||
|
||||
/** Emits stopped events for user pause. */
|
||||
private handlePause(info: any): void {
|
||||
this.stopped = true;
|
||||
this.stoppedReason = 'user request';
|
||||
@@ -490,19 +514,23 @@ export class GDBDebugSession extends DebugSession {
|
||||
this.sendEvent(new CustomStopEvent('user request', this.currentThreadId));
|
||||
}
|
||||
|
||||
/** Emits thread started. */
|
||||
private handleThreadCreated(info: any): void {
|
||||
this.sendEvent(new ThreadEvent('started', info.threadId));
|
||||
}
|
||||
|
||||
/** Emits thread exited. */
|
||||
private handleThreadExited(info: any): void {
|
||||
this.sendEvent(new ThreadEvent('exited', info.threadId));
|
||||
}
|
||||
|
||||
/** Emits thread selected. */
|
||||
private handleThreadSelected(info: any): void {
|
||||
this.currentThreadId = info.threadId;
|
||||
this.sendEvent(new ThreadEvent('selected', info.threadId));
|
||||
}
|
||||
|
||||
/** Handles unexpected stop. */
|
||||
private stopEvent(info: any): void {
|
||||
if (!this.started) {
|
||||
this.crashed = true;
|
||||
@@ -515,16 +543,19 @@ export class GDBDebugSession extends DebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles GDB quit. */
|
||||
private quitEvent(): void {
|
||||
this.quit = true;
|
||||
this.sendEvent(new TerminatedEvent());
|
||||
}
|
||||
|
||||
/** Handles launch error. */
|
||||
private launchError(err: any): void {
|
||||
this.handleMsg('stderr', `Could not start debugger process > ${err.toString()}\n`);
|
||||
this.quitEvent();
|
||||
}
|
||||
|
||||
/** Handles function breakpoints. */
|
||||
protected setFunctionBreakPointsRequest(response: any, args: any): void {
|
||||
if (!args.breakpoints || !args.breakpoints.length) {
|
||||
return;
|
||||
@@ -579,6 +610,7 @@ export class GDBDebugSession extends DebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles source/disassembly breakpoints. */
|
||||
protected setBreakPointsRequest(response: any, args: any): void {
|
||||
const setBreakpoints = async (shouldContinue: boolean) => {
|
||||
this.debugReady = true;
|
||||
|
||||
@@ -16,6 +16,7 @@ export function isExpandable(value: string): number {
|
||||
return 0;
|
||||
}
|
||||
if (value.startsWith('{...}')) {
|
||||
/** Determines if a value string is expandable. */
|
||||
return 2;
|
||||
}
|
||||
if (value[0] === '{') {
|
||||
@@ -39,6 +40,7 @@ export function expandValue(
|
||||
root: string = '',
|
||||
extra?: any
|
||||
): any {
|
||||
/** Parses a GDB value string into a DAP variable tree. */
|
||||
const parseQuotedString = (): string => {
|
||||
value = value.trim();
|
||||
if (value[0] !== '"' && value[0] !== "'") {
|
||||
|
||||
@@ -33,6 +33,7 @@ export class MI2 extends EventEmitter {
|
||||
super();
|
||||
}
|
||||
|
||||
/** Spawns GDB and sends startup MI commands. */
|
||||
connect(cwd: string, commands: string[]): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const args = [...this.args];
|
||||
@@ -67,6 +68,7 @@ export class MI2 extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/** Buffers and dispatches stdout lines. */
|
||||
stdout(data: any): void {
|
||||
this.buffer += typeof data === 'string' ? data : data.toString('utf8');
|
||||
const newlineIndex = this.buffer.lastIndexOf('\n');
|
||||
@@ -81,6 +83,7 @@ export class MI2 extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/** Buffers and logs stderr lines. */
|
||||
stderr(data: any): void {
|
||||
this.errbuf += typeof data === 'string' ? data : data.toString('utf8');
|
||||
const newlineIndex = this.errbuf.lastIndexOf('\n');
|
||||
@@ -94,6 +97,7 @@ export class MI2 extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/** Splits and logs multi-line stderr. */
|
||||
onOutputStderr(output: string): void {
|
||||
const lines = output.split('\n');
|
||||
lines.forEach((line) => {
|
||||
@@ -101,6 +105,7 @@ export class MI2 extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/** Handles partial line; logs non-MI output. */
|
||||
onOutputPartial(line: string): boolean {
|
||||
if (isPlainOutput(line)) {
|
||||
this.logNoNewLine('stdout', line);
|
||||
@@ -109,6 +114,7 @@ export class MI2 extends EventEmitter {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Parses and routes MI output lines. */
|
||||
onOutput(output: string): void {
|
||||
const lines = output.split('\n');
|
||||
lines.forEach((line) => {
|
||||
@@ -208,6 +214,7 @@ export class MI2 extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/** Sends -gdb-exit; optional force-kill after 1s. */
|
||||
stop(forceKill: boolean = false): void {
|
||||
if (forceKill) {
|
||||
const proc = this.process;
|
||||
@@ -221,6 +228,7 @@ export class MI2 extends EventEmitter {
|
||||
this.sendRaw('-gdb-exit');
|
||||
}
|
||||
|
||||
/** Sends -target-detach with fallback kill. */
|
||||
detach(): void {
|
||||
const proc = this.process;
|
||||
const killTimeout = setTimeout(() => {
|
||||
@@ -232,6 +240,7 @@ export class MI2 extends EventEmitter {
|
||||
this.sendRaw('-target-detach');
|
||||
}
|
||||
|
||||
/** Interrupts a thread. */
|
||||
interrupt(threadId: number): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.sendCommand(`exec-interrupt --thread ${threadId}`).then(
|
||||
@@ -243,6 +252,7 @@ export class MI2 extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/** Continues a thread. */
|
||||
continue(threadId: number): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.sendCommand(`exec-continue --thread ${threadId}`).then(
|
||||
@@ -254,6 +264,7 @@ export class MI2 extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/** Steps to next line/instruction. */
|
||||
next(threadId: number, instruction: boolean): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const command = instruction ? 'exec-next-instruction' : 'exec-next';
|
||||
@@ -266,6 +277,7 @@ export class MI2 extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/** Steps into next line/instruction. */
|
||||
step(threadId: number, instruction: boolean): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const command = instruction ? 'exec-step-instruction' : 'exec-step';
|
||||
@@ -278,6 +290,7 @@ export class MI2 extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/** Steps out of current function. */
|
||||
stepOut(threadId: number): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.sendCommand(`exec-finish --thread ${threadId}`).then(
|
||||
@@ -289,6 +302,7 @@ export class MI2 extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/** Restarts by sending MI commands. */
|
||||
restart(commands: string[]): Promise<boolean> {
|
||||
return this._sendCommandSequence(commands);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ export class VariableObject {
|
||||
applyChanges(node: any): void {
|
||||
this.value = MINode.valueOf(node, 'value');
|
||||
if (MINode.valueOf(node, 'type_changed')) {
|
||||
/** Applies a -var-update changelist entry. */
|
||||
this.type = MINode.valueOf(node, 'new_type');
|
||||
}
|
||||
this.dynamic = !!MINode.valueOf(node, 'dynamic');
|
||||
@@ -42,6 +43,7 @@ export class VariableObject {
|
||||
isCompound(): boolean {
|
||||
return (
|
||||
this.numchild > 0 ||
|
||||
/** True if this variable has children. */
|
||||
this.value === '{...}' ||
|
||||
(this.dynamic && (this.displayhint === 'array' || this.displayhint === 'map'))
|
||||
);
|
||||
@@ -51,6 +53,7 @@ export class VariableObject {
|
||||
toProtocolVariable(): any {
|
||||
return {
|
||||
name: this.exp,
|
||||
/** Converts to DAP Variable. */
|
||||
evaluateName: this.fullExp || this.exp,
|
||||
value: this.value === undefined ? '<unknown>' : this.value,
|
||||
type: this.type,
|
||||
@@ -80,6 +83,7 @@ export class MIError {
|
||||
/** Returns "<message> (from <source>)". */
|
||||
toString(): string {
|
||||
return `${(this as any).message} (from ${(this as any).source})`;
|
||||
/** Returns "<message> (from <source>)". */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@ import { MemoryTreeProvider } from './frontend/memory_tree_provider';
|
||||
import { PeripheralTreeProvider, RecordType as PeripheralRecordType } from './frontend/peripheral';
|
||||
import { RegisterTreeProvider, RecordType as RegisterRecordType } from './frontend/registers';
|
||||
|
||||
/**
|
||||
* Main entry point and controller for the PlatformIO Debug VS Code extension.
|
||||
*/
|
||||
class PlatformIODebugExtension {
|
||||
private adapterOutputChannel: vscode.OutputChannel = null;
|
||||
private functionSymbols: any[] = null;
|
||||
|
||||
@@ -23,6 +23,7 @@ export class TreeNode extends vscode.TreeItem {
|
||||
title: 'Selected Node',
|
||||
};
|
||||
}
|
||||
/** TreeItem for registers panel. */
|
||||
}
|
||||
|
||||
/** Base for register tree nodes. */
|
||||
@@ -47,6 +48,7 @@ export class BaseNode {
|
||||
setFormat(format: NumberFormat): void {
|
||||
this.format = format;
|
||||
}
|
||||
/** Base for register tree nodes. */
|
||||
}
|
||||
|
||||
/** CPU register node; may have FieldNode children. */
|
||||
@@ -85,6 +87,7 @@ export class RegisterNode extends BaseNode {
|
||||
this.currentValue = 0;
|
||||
}
|
||||
|
||||
/** CPU register node; may have FieldNode children. */
|
||||
extractBits(offset: number, width: number): number {
|
||||
return extractBits(this.currentValue, offset, width);
|
||||
}
|
||||
@@ -153,6 +156,7 @@ export class RegisterNode extends BaseNode {
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
/** Named bit-field within special registers. */
|
||||
}
|
||||
|
||||
/** Named bit-field within special registers. */
|
||||
@@ -217,6 +221,7 @@ export class FieldNode extends BaseNode {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/** TreeDataProvider for platformio-debug.registers. */
|
||||
}
|
||||
|
||||
/** TreeDataProvider for platformio-debug.registers. */
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
* Formats a number as a zero-padded hexadecimal string.
|
||||
*/
|
||||
export function hexFormat(value: number, padding: number = 8, includePrefix: boolean = true): string {
|
||||
/**
|
||||
* Formats a number as a zero-padded hexadecimal string.
|
||||
*/
|
||||
let result = value.toString(16);
|
||||
while (result.length < padding) {
|
||||
result = '0' + result;
|
||||
@@ -18,6 +21,9 @@ export function binaryFormat(
|
||||
includePrefix: boolean = true,
|
||||
groupByNibble: boolean = false
|
||||
): string {
|
||||
/**
|
||||
* Formats a number as a binary string, with optional nibble grouping.
|
||||
*/
|
||||
let result = (value >>> 0).toString(2);
|
||||
while (result.length < padding) {
|
||||
result = '0' + result;
|
||||
@@ -40,6 +46,9 @@ export function binaryFormat(
|
||||
* Creates a bitmask covering the specified bit range.
|
||||
*/
|
||||
export function createMask(offset: number, width: number): number {
|
||||
/**
|
||||
* Creates a bitmask covering the specified bit range.
|
||||
*/
|
||||
let mask = 0;
|
||||
const end = offset + width - 1;
|
||||
for (let i = offset; i <= end; i++) {
|
||||
@@ -52,6 +61,9 @@ export function createMask(offset: number, width: number): number {
|
||||
* Extracts a bit field from a value.
|
||||
*/
|
||||
export function extractBits(value: number, offset: number, width: number): number {
|
||||
/**
|
||||
* Extracts a bit field from a value.
|
||||
*/
|
||||
return ((value & createMask(offset, width)) >>> offset) >>> 0;
|
||||
}
|
||||
|
||||
@@ -59,6 +71,9 @@ export function extractBits(value: number, offset: number, width: number): numbe
|
||||
* Parses a URL query string into a key-value map.
|
||||
*/
|
||||
export function parseQuery(queryString: string): { [key: string]: string } {
|
||||
/**
|
||||
* Parses a URL query string into a key-value map.
|
||||
*/
|
||||
const params: { [key: string]: string } = {};
|
||||
const pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
|
||||
for (const pair of pairs) {
|
||||
@@ -72,6 +87,9 @@ export function parseQuery(queryString: string): { [key: string]: string } {
|
||||
* Encodes a function name and source file into a disassembly:// URI.
|
||||
*/
|
||||
export function encodeDisassembly(name: string, file: string): string {
|
||||
/**
|
||||
* Encodes a function name and source file into a disassembly:// URI.
|
||||
*/
|
||||
let uri = 'disassembly:///';
|
||||
if (file) {
|
||||
uri += `${file}:`;
|
||||
|
||||
Reference in New Issue
Block a user