Skip to content

Commit f681142

Browse files
authored
feat: Support program parameter in attach configurations (#14046) (#14108)
* feat: support program parameter in attach configs
1 parent 1cd186b commit f681142

File tree

3 files changed

+71
-16
lines changed

3 files changed

+71
-16
lines changed

Extension/package.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4775,11 +4775,6 @@
47754775
"program"
47764776
],
47774777
"properties": {
4778-
"program": {
4779-
"type": "string",
4780-
"description": "%c_cpp.debuggers.program.description%",
4781-
"default": "${workspaceRoot}/a.out"
4782-
},
47834778
"targetArchitecture": {
47844779
"type": "string",
47854780
"description": "%c_cpp.debuggers.targetArchitecture.description%",
@@ -4825,6 +4820,10 @@
48254820
"description": "%c_cpp.debuggers.useExtendedRemote.description%",
48264821
"default": false
48274822
},
4823+
"program": {
4824+
"type": "string",
4825+
"markdownDescription": "%c_cpp.debuggers.program.attach.markdownDescription%"
4826+
},
48284827
"processId": {
48294828
"markdownDescription": "%c_cpp.debuggers.processId.anyOf.markdownDescription%",
48304829
"anyOf": [
@@ -5790,15 +5789,17 @@
57905789
"attach": {
57915790
"type": "object",
57925791
"default": {},
5793-
"required": [
5794-
"processId"
5795-
],
5792+
"required": [],
57965793
"properties": {
57975794
"symbolSearchPath": {
57985795
"type": "string",
57995796
"description": "%c_cpp.debuggers.symbolSearchPath.description%",
58005797
"default": ""
58015798
},
5799+
"program": {
5800+
"type": "string",
5801+
"markdownDescription": "%c_cpp.debuggers.program.attach.markdownDescription%"
5802+
},
58025803
"processId": {
58035804
"markdownDescription": "%c_cpp.debuggers.processId.anyOf.markdownDescription%",
58045805
"anyOf": [

Extension/package.nls.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,13 @@
931931
"{Locked=\"`${command:pickProcess}`\"}"
932932
]
933933
},
934-
"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\".",
934+
"c_cpp.debuggers.program.attach.markdownDescription": {
935+
"message": "Full path to the program executable. The debugger will search for a running process matching this executable path and attach to it. If multiple processes match, a selection prompt will be shown. This field is required to load debug symbols for the attached process.",
936+
"comment": [
937+
"{Locked=\"`program`\"}"
938+
]
939+
},
940+
"c_cpp.debuggers.symbolSearchPath.description": "Semicolon separated list of directories to use to search for symbol (that is, pdb or .so) files. Example: \"c:\\dir1;c:\\dir2\".",
935941
"c_cpp.debuggers.dumpPath.description": "Optional full path to a dump file for the specified program. Example: \"c:\\temp\\app.dmp\". Defaults to null.",
936942
"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'.",
937943
"c_cpp.debuggers.symbolLoadInfo.description": "Explicit control of symbol loading.",

Extension/src/Debugger/configurationProvider.ts

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { PlatformInformation } from '../platform';
2323
import { rsync, scp, ssh } from '../SSH/commands';
2424
import * as Telemetry from '../telemetry';
2525
import { AttachItemsProvider, AttachPicker, RemoteAttachPicker } from './attachToProcess';
26+
import { AttachItem, showQuickPick } from './attachQuickPick';
2627
import { ConfigMenu, ConfigMode, ConfigSource, CppDebugConfiguration, DebuggerEvent, DebuggerType, DebugType, IConfiguration, IConfigurationSnippet, isDebugLaunchStr, MIConfigurations, PipeTransportConfigurations, TaskStatus, WindowsConfigurations, WSLConfigurations } from './configurations';
2728
import { NativeAttachItemsProviderFactory } from './nativeAttach';
2829
import { Environment, ParsedEnvironmentFile } from './ParsedEnvironmentFile';
@@ -353,13 +354,22 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
353354
// Pick process if process id is empty
354355
if (config.request === "attach" && !config.processId) {
355356
let processId: string | undefined;
356-
if (config.pipeTransport || config.useExtendedRemote) {
357-
const remoteAttachPicker: RemoteAttachPicker = new RemoteAttachPicker();
358-
processId = await remoteAttachPicker.ShowAttachEntries(config);
359-
} else {
360-
const attachItemsProvider: AttachItemsProvider = NativeAttachItemsProviderFactory.Get();
361-
const attacher: AttachPicker = new AttachPicker(attachItemsProvider);
362-
processId = await attacher.ShowAttachEntries(token);
357+
358+
// If program is specified and not remote attach, try to find the matching process by name
359+
if (config.program && !config.pipeTransport && !config.useExtendedRemote) {
360+
processId = await this.findProcessByProgramName(config.program, token);
361+
}
362+
363+
// Fall back to process picker if program wasn't specified or didn't match
364+
if (!processId) {
365+
if (config.pipeTransport || config.useExtendedRemote) {
366+
const remoteAttachPicker: RemoteAttachPicker = new RemoteAttachPicker();
367+
processId = await remoteAttachPicker.ShowAttachEntries(config);
368+
} else {
369+
const attachItemsProvider: AttachItemsProvider = NativeAttachItemsProviderFactory.Get();
370+
const attacher: AttachPicker = new AttachPicker(attachItemsProvider);
371+
processId = await attacher.ShowAttachEntries(token);
372+
}
363373
}
364374

365375
if (processId) {
@@ -1154,6 +1164,44 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
11541164
}
11551165
return true;
11561166
}
1167+
1168+
private async findProcessByProgramName(
1169+
programPath: string,
1170+
token?: vscode.CancellationToken
1171+
): Promise<string | undefined> {
1172+
// Validate that the program path is valid
1173+
if (!await util.checkExecutableWithoutExtensionExists(programPath)) {
1174+
return undefined;
1175+
}
1176+
1177+
const programBaseName: string = path.basename(programPath);
1178+
1179+
// Get the process list using the same logic as interactive attach
1180+
const attachItemsProvider: AttachItemsProvider = NativeAttachItemsProviderFactory.Get();
1181+
const processes: AttachItem[] = await attachItemsProvider.getAttachItems(token);
1182+
1183+
// Prepare target name for matching (case-insensitive on Windows only)
1184+
let targetName: string = programBaseName;
1185+
if (isWindows) {
1186+
targetName = targetName.toLowerCase();
1187+
targetName = targetName.endsWith(".exe") ? targetName : (targetName + ".exe");
1188+
}
1189+
1190+
// Find processes matching the program name
1191+
const matchingProcesses: AttachItem[] = processes.filter(p => {
1192+
const processName: string = isWindows ? p.label.toLowerCase() : p.label;
1193+
return processName === targetName;
1194+
});
1195+
1196+
if (matchingProcesses.length === 0) {
1197+
return undefined;
1198+
} else if (matchingProcesses.length === 1) {
1199+
return matchingProcesses[0].id;
1200+
} else {
1201+
// Multiple matches - let the user choose
1202+
return showQuickPick(() => Promise.resolve(matchingProcesses));
1203+
}
1204+
}
11571205
}
11581206

11591207
export interface IConfigurationAssetProvider {

0 commit comments

Comments
 (0)