diff --git a/debugger.md b/debugger.md index f1ca107c3..bfaa1b0d6 100644 --- a/debugger.md +++ b/debugger.md @@ -77,7 +77,7 @@ The C# debugger supports attaching to processes. To do this, switch to the Debug ![Debug launch configuration drop down](https://raw.githubusercontent.com/wiki/OmniSharp/omnisharp-vscode/images/debug-launch-configurations.png) -Select the '.NET Core Attach' configuration. Clicking the play button (or pressing F5) will then try to attach. In launch.json, if `processId` is set to `"${command:pickProcess}"` this will provide UI to select which process to attach to. +Select the '.NET Core Attach' configuration. Clicking the play button (or pressing F5) will then try to attach. In launch.json, if `processId` is set to `""` this will provide UI to select which process to attach to. #### Remote Debugging diff --git a/package.json b/package.json index 5f1fdd9c4..0fbbace4b 100644 --- a/package.json +++ b/package.json @@ -1624,12 +1624,12 @@ "anyOf": [ { "type": "string", - "description": "The process id to attach to. Use \"${command:pickProcess}\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", - "default": "${command:pickProcess}" + "description": "The process id to attach to. Use \"\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", + "default": "" }, { "type": "integer", - "description": "The process id to attach to. Use \"${command:pickProcess}\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", + "description": "The process id to attach to. Use \"\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", "default": 0 } ] @@ -2061,8 +2061,7 @@ "body": { "name": ".NET Core Attach", "type": "coreclr", - "request": "attach", - "processId": "^\"\\${command:pickProcess}\"" + "request": "attach" } }, { @@ -2117,7 +2116,6 @@ "name": ".NET Core Attach", "type": "coreclr", "request": "attach", - "processId": "^\"\\${command:pickRemoteProcess}\"", "pipeTransport": { "pipeCwd": "^\"\\${workspaceFolder}\"", "pipeProgram": "^\"${1:enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'}\"", @@ -2725,12 +2723,12 @@ "anyOf": [ { "type": "string", - "description": "The process id to attach to. Use \"${command:pickProcess}\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", - "default": "${command:pickProcess}" + "description": "The process id to attach to. Use \"\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", + "default": "" }, { "type": "integer", - "description": "The process id to attach to. Use \"${command:pickProcess}\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", + "description": "The process id to attach to. Use \"\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", "default": 0 } ] diff --git a/scripts/remoteProcessPickerScript b/scripts/remoteProcessPickerScript index fd2e75a76..4c6e94748 100644 --- a/scripts/remoteProcessPickerScript +++ b/scripts/remoteProcessPickerScript @@ -1 +1 @@ -uname && if [ "$(uname)" = "Linux" ] ; then ps -axww -o pid=,comm=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,args= ; exit; elif [ "$(uname)" = "Darwin" ] ; then ps -axww -o pid=,comm=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,args= -c; fi +uname && if [ "$(uname)" = "Linux" ] ; then ps -axww -o pid=,flags=,comm=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,args= ; exit; elif [ "$(uname)" = "Darwin" ] ; then ps -axww -o pid=,flags=,comm=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,args= -c; fi \ No newline at end of file diff --git a/src/assets.ts b/src/assets.ts index 96a5e9757..5b931aec9 100644 --- a/src/assets.ts +++ b/src/assets.ts @@ -420,8 +420,7 @@ export function createAttachConfiguration(): string { const configuration = { "name": ".NET Core Attach", "type": "coreclr", - "request": "attach", - "processId": "\${command:pickProcess}" + "request": "attach" }; return JSON.stringify(configuration); diff --git a/src/coreclr-debug/activate.ts b/src/coreclr-debug/activate.ts index 8c8ca72d7..e515ac285 100644 --- a/src/coreclr-debug/activate.ts +++ b/src/coreclr-debug/activate.ts @@ -13,6 +13,7 @@ import { EventStream } from '../EventStream'; import CSharpExtensionExports from '../CSharpExtensionExports'; import { getRuntimeDependencyPackageWithId } from '../tools/RuntimeDependencyPackageUtils'; import { getDotnetInfo, DotnetInfo } from '../utils/getDotnetInfo'; +import { DotnetDebugConfigurationProvider } from './debugConfigurationProvider'; let _debugUtil: CoreClrDebugUtil = null; @@ -30,6 +31,8 @@ export async function activate(thisExtension: vscode.Extension + { + if (!debugConfiguration) + { + return null; + } + + // Process Id is empty, handle Attach to Process Dialog. + if (debugConfiguration.request === "attach" && !debugConfiguration.processId && !debugConfiguration.processName) + { + let process: AttachItem = undefined; + if (debugConfiguration.pipeTransport) + { + process = await RemoteAttachPicker.ShowAttachEntries(debugConfiguration, this.platformInformation); + } + else + { + let attachItemsProvider = DotNetAttachItemsProviderFactory.Get(); + let attacher = new AttachPicker(attachItemsProvider); + process = await attacher.ShowAttachEntries(); + } + + if (process) + { + debugConfiguration.processId = process.id; + + if (debugConfiguration.type == "coreclr" && + this.platformInformation.isMacOS() && + this.platformInformation.architecture == 'arm64') + { + // For Apple Silicon M1, it is possible that the process we are attaching to is being emulated as x86_64. + // The process is emulated if it has process flags has P_TRANSLATED (0x20000). + if (process.flags & 0x20000) + { + debugConfiguration.targetArchitecture = "x86_64"; + } + else + { + debugConfiguration.targetArchitecture = "arm64"; + } + } + } + else + { + throw new Error("No process was selected."); + } + } + + return debugConfiguration; + } +} \ No newline at end of file diff --git a/src/features/commands.ts b/src/features/commands.ts index df2312b56..efae7cc47 100644 --- a/src/features/commands.ts +++ b/src/features/commands.ts @@ -11,7 +11,6 @@ import * as fs from 'fs'; import * as path from 'path'; import * as protocol from '../omnisharp/protocol'; import * as vscode from 'vscode'; -import { DotNetAttachItemsProviderFactory, AttachPicker, RemoteAttachPicker } from './processPicker'; import { generateAssets } from '../assets'; import { ShowOmniSharpChannel, CommandDotNetRestoreStart, CommandDotNetRestoreProgress, CommandDotNetRestoreSucceeded, CommandDotNetRestoreFailed } from '../omnisharp/loggingEvents'; import { EventStream } from '../EventStream'; @@ -40,14 +39,13 @@ export default function registerCommands(context: vscode.ExtensionContext, serve // running the command activates the extension, which is all we need for installation to kickoff disposable.add(vscode.commands.registerCommand('csharp.downloadDebugger', () => { })); - // register process picker for attach - let attachItemsProvider = DotNetAttachItemsProviderFactory.Get(); - let attacher = new AttachPicker(attachItemsProvider); - disposable.add(vscode.commands.registerCommand('csharp.listProcess', async () => attacher.ShowAttachEntries())); + // register process picker for attach for legacy configurations. + disposable.add(vscode.commands.registerCommand('csharp.listProcess', () => "")); + disposable.add(vscode.commands.registerCommand('csharp.listRemoteProcess', () => "")); + + // Register command for generating tasks.json and launch.json assets. disposable.add(vscode.commands.registerCommand('dotnet.generateAssets', async (selectedIndex) => generateAssets(server, selectedIndex))); - // Register command for remote process picker for attach - disposable.add(vscode.commands.registerCommand('csharp.listRemoteProcess', async (args) => RemoteAttachPicker.ShowAttachEntries(args, platformInfo))); disposable.add(vscode.commands.registerCommand('csharp.reportIssue', async () => reportIssue(vscode, eventStream, getDotnetInfo, platformInfo.isValidPlatformForMono(), optionProvider.GetLatestOptions(), monoResolver))); diff --git a/src/features/processPicker.ts b/src/features/processPicker.ts index 2a2294df1..900efe37b 100644 --- a/src/features/processPicker.ts +++ b/src/features/processPicker.ts @@ -14,6 +14,7 @@ import { getExtensionPath } from '../common'; export interface AttachItem extends vscode.QuickPickItem { id: string; + flags: number; } export interface AttachItemsProvider { @@ -23,7 +24,7 @@ export interface AttachItemsProvider { export class AttachPicker { constructor(private attachItemsProvider: AttachItemsProvider) { } - public async ShowAttachEntries(): Promise { + public async ShowAttachEntries(): Promise { return this.attachItemsProvider.getAttachItems() .then(processEntries => { let attachPickOptions: vscode.QuickPickOptions = { @@ -35,7 +36,7 @@ export class AttachPicker { return vscode.window.showQuickPick(processEntries, attachPickOptions) .then(chosenProcess => { - return chosenProcess ? chosenProcess.id : null; + return chosenProcess; }); }); } @@ -50,8 +51,8 @@ interface IPipeTransportOptions { export class RemoteAttachPicker { public static get commColumnTitle() { return Array(PsOutputParser.secondColumnCharacters).join("a"); } - public static get linuxPsCommand() { return `ps axww -o pid=,comm=${RemoteAttachPicker.commColumnTitle},args=`; } - public static get osxPsCommand() { return `ps axww -o pid=,comm=${RemoteAttachPicker.commColumnTitle},args= -c`; } + public static get linuxPsCommand() { return `ps axww -o pid=,flags=,comm=${RemoteAttachPicker.commColumnTitle},args=`; } + public static get osxPsCommand() { return `ps axww -o pid=,flags=,comm=${RemoteAttachPicker.commColumnTitle},args= -c`; } public static get debuggerCommand() { return "${debuggerCommand}"; } public static get scriptShellCmd() { return "sh -s"; } @@ -196,7 +197,7 @@ export class RemoteAttachPicker { return args.map(arg => this.quoteArg(arg)).join(" "); } - public static async ShowAttachEntries(args: any, platformInfo: PlatformInformation): Promise { + public static async ShowAttachEntries(args: any, platformInfo: PlatformInformation): Promise { // Create remote attach output channel for errors. if (!RemoteAttachPicker._channel) { RemoteAttachPicker._channel = vscode.window.createOutputChannel('remote-attach'); @@ -210,13 +211,13 @@ export class RemoteAttachPicker { if (!name) { // Config name not found. - return Promise.reject(new Error("Name not defined in current configuration.")); + return Promise.reject(new Error("Name not defined in current configuration.")); } if (!args.pipeTransport || !args.pipeTransport.debuggerPath) { // Missing PipeTransport and debuggerPath, prompt if user wanted to just do local attach. - return Promise.reject(new Error("Configuration \"" + name + "\" in launch.json does not have a " + - "pipeTransport argument with debuggerPath for pickRemoteProcess. Use pickProcess for local attach.")); + return Promise.reject(new Error("Configuration \"" + name + "\" in launch.json does not have a " + + "pipeTransport argument with debuggerPath for remote process listing.")); } else { let pipeTransport = this.getPipeTransportOptions(args.pipeTransport, os.platform()); @@ -230,8 +231,7 @@ export class RemoteAttachPicker { placeHolder: "Select the process to attach to" }; return vscode.window.showQuickPick(processes, attachPickOptions); - }) - .then(item => { return item ? item.id : Promise.reject(new Error("Could not find a process id to attach.")); }); + }); } } @@ -266,14 +266,15 @@ export class RemoteAttachPicker { } class Process { - constructor(public name: string, public pid: string, public commandLine: string) { } + constructor(public name: string, public pid: string, public commandLine: string, public flags: number) { } public toAttachItem(): AttachItem { return { label: this.name, description: this.pid, detail: this.commandLine, - id: this.pid + id: this.pid, + flags: this.flags }; } } @@ -404,17 +405,20 @@ export class PsOutputParser { // - any leading whitespace // - PID // - whitespace + // - flags (hex value) + // - whitespace // - executable name --> this is PsAttachItemsProvider.secondColumnCharacters - 1 because ps reserves one character // for the whitespace separator // - whitespace // - args (might be empty) - const psEntry = new RegExp(`^\\s*([0-9]+)\\s+(.{${PsOutputParser.secondColumnCharacters - 1}})\\s+(.*)$`); + const psEntry = new RegExp(`^\\s*([0-9]+)\\s+([0-9a-fA-F]+)\\s+(.{${PsOutputParser.secondColumnCharacters - 1}})\\s+(.*)$`); const matches = psEntry.exec(line); - if (matches && matches.length === 4) { + if (matches && matches.length === 5) { const pid = matches[1].trim(); - const executable = matches[2].trim(); - const cmdline = matches[3].trim(); - return new Process(executable, pid, cmdline); + const flags = parseInt(matches[2].trim(), 16); // flags comes in as hex + const executable = matches[3].trim(); + const cmdline = matches[4].trim(); + return new Process(executable, pid, cmdline, flags); } } } @@ -444,7 +448,7 @@ export class WmicOutputParser { // Only public for tests. public static parseProcessFromWmic(processes: string): Process[] { let lines = processes.split(os.EOL); - let currentProcess: Process = new Process(null, null, null); + let currentProcess: Process = new Process(null, null, null, null); let processEntries: Process[] = []; for (let i = 0; i < lines.length; i++) { @@ -458,7 +462,7 @@ export class WmicOutputParser { // Each entry of processes has ProcessId as the last line if (line.startsWith(WmicOutputParser.wmicPidTitle)) { processEntries.push(currentProcess); - currentProcess = new Process(null, null, null); + currentProcess = new Process(null, null, null, null); } } diff --git a/src/tools/OptionsSchema.json b/src/tools/OptionsSchema.json index f43342d28..8dc938413 100644 --- a/src/tools/OptionsSchema.json +++ b/src/tools/OptionsSchema.json @@ -406,12 +406,12 @@ "anyOf": [ { "type": "string", - "description": "The process id to attach to. Use \"${command:pickProcess}\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", - "default": "${command:pickProcess}" + "description": "The process id to attach to. Use \"\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", + "default": "" }, { "type": "integer", - "description": "The process id to attach to. Use \"${command:pickProcess}\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", + "description": "The process id to attach to. Use \"\" to get a list of running processes to attach to. If 'processId' used, 'processName' should not be used.", "default": 0 } ]