-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: Support program parameter in attach configurations (#14046) #14108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8aeeb69
6b7cebe
81f63e2
2a62420
d65120d
ca240e2
a894144
7cc44c1
050503c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -931,7 +931,13 @@ | |
| "{Locked=\"`${command:pickProcess}`\"}" | ||
| ] | ||
| }, | ||
| "c_cpp.debuggers.symbolSearchPath.description": "Semicolon separated list of directories to use to search for symbol (that is, pdb) files. Example: \"c:\\dir1;c:\\dir2\".", | ||
| "c_cpp.debuggers.program.attach.markdownDescription": { | ||
| "message": "Optional full path to program executable. When specified, the debugger will search for a running process matching this executable name and attach to it. If multiple processes match, a selection prompt will be shown. Use either `program` or `processId`, not both.", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| "comment": [ | ||
| "{Locked=\"`program`\"} {Locked=\"`processId`\"}" | ||
| ] | ||
| }, | ||
| "c_cpp.debuggers.symbolSearchPath.description": "Semicolon separated list of directories to use to search for .so files. Example: \"c:\\dir1;c:\\dir2\".", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On Windows with MSVC it uses .pdb files and not so files, so the description could be something like |
||
| "c_cpp.debuggers.dumpPath.description": "Optional full path to a dump file for the specified program. Example: \"c:\\temp\\app.dmp\". Defaults to null.", | ||
| "c_cpp.debuggers.enableDebugHeap.description": "If false, the process will be launched with debug heap disabled. This sets the environment variable '_NO_DEBUG_HEAP' to '1'.", | ||
| "c_cpp.debuggers.symbolLoadInfo.description": "Explicit control of symbol loading.", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ import { PlatformInformation } from '../platform'; | |
| import { rsync, scp, ssh } from '../SSH/commands'; | ||
| import * as Telemetry from '../telemetry'; | ||
| import { AttachItemsProvider, AttachPicker, RemoteAttachPicker } from './attachToProcess'; | ||
| import { AttachItem, showQuickPick } from './attachQuickPick'; | ||
| import { ConfigMenu, ConfigMode, ConfigSource, CppDebugConfiguration, DebuggerEvent, DebuggerType, DebugType, IConfiguration, IConfigurationSnippet, isDebugLaunchStr, MIConfigurations, PipeTransportConfigurations, TaskStatus, WindowsConfigurations, WSLConfigurations } from './configurations'; | ||
| import { NativeAttachItemsProviderFactory } from './nativeAttach'; | ||
| import { Environment, ParsedEnvironmentFile } from './ParsedEnvironmentFile'; | ||
|
|
@@ -354,13 +355,24 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv | |
| // Pick process if process id is empty | ||
| if (config.request === "attach" && !config.processId) { | ||
| let processId: string | undefined; | ||
| if (config.pipeTransport || config.useExtendedRemote) { | ||
| const remoteAttachPicker: RemoteAttachPicker = new RemoteAttachPicker(); | ||
| processId = await remoteAttachPicker.ShowAttachEntries(config); | ||
|
|
||
| // If program is specified, try to find matching process by name | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if (config.program) { | ||
| processId = await this.findProcessByProgramName(config.program, config, token); | ||
| if (!processId) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like this would cause a failure for users who currently have processName set to an invalid value, which is the default. Can you instead fall back to the process picker if |
||
| void logger.getOutputChannelLogger().showErrorMessage(`No running process found matching "${config.program}".`); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These user facing strings should be passed to the localize function with some unique key, see the example such as I saw a spot in this file where pre-existing code appears to be missing a localize call (we can fix that ourselves later). |
||
| return undefined; | ||
| } | ||
| } else { | ||
| const attachItemsProvider: AttachItemsProvider = NativeAttachItemsProviderFactory.Get(); | ||
| const attacher: AttachPicker = new AttachPicker(attachItemsProvider); | ||
| processId = await attacher.ShowAttachEntries(token); | ||
| // Show process picker if no program specified | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if (config.pipeTransport || config.useExtendedRemote) { | ||
| const remoteAttachPicker: RemoteAttachPicker = new RemoteAttachPicker(); | ||
| processId = await remoteAttachPicker.ShowAttachEntries(config); | ||
| } else { | ||
| const attachItemsProvider: AttachItemsProvider = NativeAttachItemsProviderFactory.Get(); | ||
| const attacher: AttachPicker = new AttachPicker(attachItemsProvider); | ||
| processId = await attacher.ShowAttachEntries(token); | ||
| } | ||
| } | ||
|
|
||
| if (processId) { | ||
|
|
@@ -1157,6 +1169,50 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv | |
| } | ||
| return true; | ||
| } | ||
|
|
||
| private async findProcessByProgramName( | ||
| programPath: string, | ||
| config: CppDebugConfiguration, | ||
| token?: vscode.CancellationToken | ||
| ): Promise<string | undefined> { | ||
| const programBaseName: string = path.basename(programPath); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you first check if the programPath is a valid path? Otherwise, invalid paths like "this is an invalid path.exe" will use "path.exe" as the programBaseName.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe call |
||
| let processes: AttachItem[]; | ||
|
|
||
| // Get process list using the same logic as interactive attach | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if (config.pipeTransport || config.useExtendedRemote) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you move this check to the very beginning before "program" is checked and don't show any error? Otherwise, those users would start to get an error. |
||
| // For remote attach, we need to use RemoteAttachPicker's methods | ||
| void logger.getOutputChannelLogger().showErrorMessage( | ||
| "Finding process by program name is not yet supported for remote attach. Please use processId instead." | ||
| ); | ||
| return undefined; | ||
| } else { | ||
| const attachItemsProvider: AttachItemsProvider = NativeAttachItemsProviderFactory.Get(); | ||
| processes = await attachItemsProvider.getAttachItems(token); | ||
| } | ||
|
|
||
| // Find processes matching the program name | ||
| const matchingProcesses: AttachItem[] = processes.filter(p => { | ||
| const processName: string = p.label.toLowerCase(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The toLowerCase should only be used on Windows where the paths are case insensitive. |
||
| const targetName: string = programBaseName.toLowerCase(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be moved out of the lambda and into a local variable at the out scope to avoid unnecessarily calling it more than once.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And you could use something like |
||
| // Match if the process name exactly matches or starts with the target name | ||
| return processName === targetName || processName.startsWith(targetName); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you remove this startsWith to prevent the an unintended process from being accidentally attached to? |
||
| }); | ||
|
|
||
| if (matchingProcesses.length === 0) { | ||
| return undefined; | ||
| } else if (matchingProcesses.length === 1) { | ||
| void logger.getOutputChannelLogger().appendLine( | ||
| `Found process "${matchingProcesses[0].label}" with PID ${matchingProcesses[0].id}` | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no need to log here. |
||
| ); | ||
| return matchingProcesses[0].id; | ||
| } else { | ||
| // Multiple matches - let user choose | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| void logger.getOutputChannelLogger().appendLine( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logging is unnecessary -- users will see the quick pick UI and not see the logging. |
||
| `Multiple processes found matching "${programBaseName}". Please select one:` | ||
| ); | ||
| return showQuickPick(() => Promise.resolve(matchingProcesses)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export interface IConfigurationAssetProvider { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should
executable namebeexecutable path?