Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 57 additions & 39 deletions lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,79 +21,97 @@ async function isServerModeSupported(exe: string): Promise<boolean> {
}

interface BoolConfig {
type: 'boolean';
type: "boolean";
default: boolean;
}
interface StringConfig {
type: 'string';
type: "string";
default: string;
}
interface NumberConfig {
type: 'number';
type: "number";
default: number;
}
interface StringArrayConfig {
type: 'stringArray';
type: "stringArray";
default: string[];
}
type DefaultConfig = BoolConfig | NumberConfig | StringConfig | StringArrayConfig;
type DefaultConfig =
| BoolConfig
| NumberConfig
| StringConfig
| StringArrayConfig;

const configurations: Record<string, DefaultConfig> = {
// Keys for debugger configurations.
"commandEscapePrefix": { type: "string", default: "`" },
"customFrameFormat": { type: "string", default: "" },
"customThreadFormat": { type: "string", default: "" },
"detachOnError": { type: "boolean", default: false },
"disableASLR": { type: "boolean", default: true },
"disableSTDIO": { type: "boolean", default: false },
"displayExtendedBacktrace": { type: "boolean", default: false },
"enableAutoVariableSummaries": { type: "boolean", default: false },
"enableSyntheticChildDebugging": { type: "boolean", default: false },
"timeout": { type: "number", default: 30 },
commandEscapePrefix: { type: "string", default: "`" },
customFrameFormat: { type: "string", default: "" },
customThreadFormat: { type: "string", default: "" },
detachOnError: { type: "boolean", default: false },
disableASLR: { type: "boolean", default: true },
disableSTDIO: { type: "boolean", default: false },
displayExtendedBacktrace: { type: "boolean", default: false },
enableAutoVariableSummaries: { type: "boolean", default: false },
enableSyntheticChildDebugging: { type: "boolean", default: false },
timeout: { type: "number", default: 30 },

// Keys for platform / target configuration.
"platformName": { type: "string", default: "" },
"targetTriple": { type: "string", default: "" },
platformName: { type: "string", default: "" },
targetTriple: { type: "string", default: "" },

// Keys for debugger command hooks.
"initCommands": { type: "stringArray", default: [] },
"preRunCommands": { type: "stringArray", default: [] },
"postRunCommands": { type: "stringArray", default: [] },
"stopCommands": { type: "stringArray", default: [] },
"exitCommands": { type: "stringArray", default: [] },
"terminateCommands": { type: "stringArray", default: [] },
initCommands: { type: "stringArray", default: [] },
preRunCommands: { type: "stringArray", default: [] },
postRunCommands: { type: "stringArray", default: [] },
stopCommands: { type: "stringArray", default: [] },
exitCommands: { type: "stringArray", default: [] },
terminateCommands: { type: "stringArray", default: [] },
};

export class LLDBDapConfigurationProvider
implements vscode.DebugConfigurationProvider {
constructor(private readonly server: LLDBDapServer) { }
implements vscode.DebugConfigurationProvider
{
constructor(private readonly server: LLDBDapServer) {}

async resolveDebugConfiguration(
folder: vscode.WorkspaceFolder | undefined,
debugConfiguration: vscode.DebugConfiguration,
token?: vscode.CancellationToken): Promise<vscode.DebugConfiguration> {
let config = vscode.workspace.getConfiguration('lldb-dap.defaults');
token?: vscode.CancellationToken,
): Promise<vscode.DebugConfiguration> {
let config = vscode.workspace.getConfiguration("lldb-dap.defaults");
for (const [key, cfg] of Object.entries(configurations)) {
if (Reflect.has(debugConfiguration, key)) continue;
if (Reflect.has(debugConfiguration, key)) {
continue;
}
const value = config.get(key);
if (value === cfg.default) continue;
if (!value || value === cfg.default) {
continue;
}
switch (cfg.type) {
case 'string':
if (typeof value !== 'string')
case "string":
if (typeof value !== "string") {
throw new Error(`Expected ${key} to be a string, got ${value}`);
}
break;
case 'number':
if (typeof value !== 'number')
case "number":
if (typeof value !== "number") {
throw new Error(`Expected ${key} to be a number, got ${value}`);
}
break;
case 'boolean':
if (typeof value !== 'boolean')
case "boolean":
if (typeof value !== "boolean") {
throw new Error(`Expected ${key} to be a boolean, got ${value}`);
}
break;
case 'stringArray':
if (typeof value !== 'object' && Array.isArray(value))
throw new Error(`Expected ${key} to be a array of strings, got ${value}`);
if ((value as string[]).length === 0) continue;
case "stringArray":
if (typeof value !== "object" && Array.isArray(value)) {
throw new Error(
`Expected ${key} to be a array of strings, got ${value}`,
);
}
if ((value as string[]).length === 0) {
continue;
}
break;
}

Expand Down
168 changes: 96 additions & 72 deletions lldb/tools/lldb-dap/src-ts/uri-launch-handler.ts
Original file line number Diff line number Diff line change
@@ -1,78 +1,102 @@
import * as vscode from "vscode";

export class LaunchUriHandler implements vscode.UriHandler {
async handleUri(uri: vscode.Uri) {
try {
const params = new URLSearchParams(uri.query);
if (uri.path == '/start') {
// Some properties have default values
let debugConfig: vscode.DebugConfiguration = {
type: 'lldb-dap',
request: 'launch',
name: '',
};
// The `config` parameter allows providing a complete JSON-encoded configuration
const configJson = params.get("config");
if (configJson !== null) {
Object.assign(debugConfig, JSON.parse(configJson));
}
// Furthermore, some frequently used parameters can also be provided as separate parameters
const stringKeys = ["name", "request", "program", "cwd", "debuggerRoot"];
const numberKeys = ["pid"];
const arrayKeys = [
"args", "initCommands", "preRunCommands", "stopCommands", "exitCommands",
"terminateCommands", "launchCommands", "attachCommands"
];
for (const key of stringKeys) {
const value = params.get(key);
if (value) {
debugConfig[key] = value;
}
}
for (const key of numberKeys) {
const value = params.get(key);
if (value) {
debugConfig[key] = Number(value);
}
}
for (const key of arrayKeys) {
// `getAll()` returns an array of strings.
const value = params.getAll(key);
if (value) {
debugConfig[key] = value;
}
}
// Report an error if we received any unknown parameters
const supportedKeys = new Set<string>(["config"].concat(stringKeys).concat(numberKeys).concat(arrayKeys));
const presentKeys = new Set<string>(params.keys());
// FIXME: Use `Set.difference` as soon as ES2024 is widely available
const unknownKeys = new Set<string>();
for (const k of presentKeys.keys()) {
if (!supportedKeys.has(k)) {
unknownKeys.add(k);
}
}
if (unknownKeys.size > 0) {
throw new Error(`Unsupported URL parameters: ${Array.from(unknownKeys.keys()).join(", ")}`);
}
// Prodide a default for the config name
const defaultName = debugConfig.request == 'launch' ? "URL-based Launch" : "URL-based Attach";
debugConfig.name = debugConfig.name || debugConfig.program || defaultName;
// Force the type to `lldb-dap`. We don't want to allow launching any other
// Debug Adapters using this URI scheme.
if (debugConfig.type != "lldb-dap") {
throw new Error(`Unsupported debugger type: ${debugConfig.type}`);
}
await vscode.debug.startDebugging(undefined, debugConfig);
} else {
throw new Error(`Unsupported Uri path: ${uri.path}`);
}
} catch (err) {
if (err instanceof Error) {
await vscode.window.showErrorMessage(`Failed to handle lldb-dap URI request: ${err.message}`);
} else {
await vscode.window.showErrorMessage(`Failed to handle lldb-dap URI request: ${JSON.stringify(err)}`);
}
async handleUri(uri: vscode.Uri) {
try {
const params = new URLSearchParams(uri.query);
if (uri.path == "/start") {
// Some properties have default values
let debugConfig: vscode.DebugConfiguration = {
type: "lldb-dap",
request: "launch",
name: "",
};
// The `config` parameter allows providing a complete JSON-encoded configuration
const configJson = params.get("config");
if (configJson !== null) {
Object.assign(debugConfig, JSON.parse(configJson));
}
// Furthermore, some frequently used parameters can also be provided as separate parameters
const stringKeys = [
"name",
"request",
"program",
"cwd",
"debuggerRoot",
];
const numberKeys = ["pid"];
const arrayKeys = [
"args",
"initCommands",
"preRunCommands",
"stopCommands",
"exitCommands",
"terminateCommands",
"launchCommands",
"attachCommands",
];
for (const key of stringKeys) {
const value = params.get(key);
if (value) {
debugConfig[key] = value;
}
}
for (const key of numberKeys) {
const value = params.get(key);
if (value) {
debugConfig[key] = Number(value);
}
}
for (const key of arrayKeys) {
// `getAll()` returns an array of strings.
const value = params.getAll(key);
if (value) {
debugConfig[key] = value;
}
}
// Report an error if we received any unknown parameters
const supportedKeys = new Set<string>(
["config"].concat(stringKeys).concat(numberKeys).concat(arrayKeys),
);
const presentKeys = new Set<string>(params.keys());
// FIXME: Use `Set.difference` as soon as ES2024 is widely available
const unknownKeys = new Set<string>();
for (const k of presentKeys.keys()) {
if (!supportedKeys.has(k)) {
unknownKeys.add(k);
}
}
if (unknownKeys.size > 0) {
throw new Error(
`Unsupported URL parameters: ${Array.from(unknownKeys.keys()).join(", ")}`,
);
}
// Prodide a default for the config name
const defaultName =
debugConfig.request == "launch"
? "URL-based Launch"
: "URL-based Attach";
debugConfig.name =
debugConfig.name || debugConfig.program || defaultName;
// Force the type to `lldb-dap`. We don't want to allow launching any other
// Debug Adapters using this URI scheme.
if (debugConfig.type != "lldb-dap") {
throw new Error(`Unsupported debugger type: ${debugConfig.type}`);
}
await vscode.debug.startDebugging(undefined, debugConfig);
} else {
throw new Error(`Unsupported Uri path: ${uri.path}`);
}
} catch (err) {
if (err instanceof Error) {
await vscode.window.showErrorMessage(
`Failed to handle lldb-dap URI request: ${err.message}`,
);
} else {
await vscode.window.showErrorMessage(
`Failed to handle lldb-dap URI request: ${JSON.stringify(err)}`,
);
}
}
}
}
Loading