Skip to content

Commit 0fe51bf

Browse files
authored
Extract Pname from debug config name to select correct SVD file (#458)
* extract pname and validate against processor list in cbuild-run * extended utils.ts tests, fixed regexp * renamed simple to multi-core.cbuild-run.yml and cleaned up/extended extended tests for multi-core case * tests for SVD file selection based on pname --------- Signed-off-by: Jens Reinecke <[email protected]>
1 parent abbcafe commit 0fe51bf

File tree

9 files changed

+186
-27
lines changed

9 files changed

+186
-27
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Change Log
22

3+
## Unreleased
4+
5+
- Fixes [#439](https://github.com/Open-CMSIS-Pack/vscode-cmsis-debugger/issues/439): Peripheral Inspector receives wrong SVD file path for secondary core of a multi-core connection.
6+
37
## 1.0.0
48

59
- Removes `Preview` status from extension.

src/cbuild-run/__snapshots__/cbuild-run-reader.test.ts.snap

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Jest Snapshot v1, https://goo.gl/fbAQLP
1+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
22

33
exports[`CbuildRunReader Parser successfully parses a *.cbuild-run.yml file 1`] = `
44
{
@@ -67,8 +67,16 @@ exports[`CbuildRunReader Parser successfully parses a *.cbuild-run.yml file 1`]
6767
},
6868
"debugger": {
6969
"clock": 10000000,
70-
"gdbserver": "My Server Options
71-
",
70+
"gdbserver": [
71+
{
72+
"pname": "Core0",
73+
"port": 3336,
74+
},
75+
{
76+
"pname": "Core1",
77+
"port": 3339,
78+
},
79+
],
7280
"name": "<default>",
7381
"port": "swd",
7482
"start-pname": "Core0",
@@ -81,18 +89,19 @@ exports[`CbuildRunReader Parser successfully parses a *.cbuild-run.yml file 1`]
8189
{
8290
"file": "out/MyApp.bin",
8391
"info": "generate by MyApp",
92+
"load": "image",
8493
"type": "bin",
8594
},
8695
{
8796
"file": "out/out/MyApp.axf",
8897
"info": "generate by MyApp",
98+
"load": "symbols",
8999
"type": "elf",
90100
},
91101
],
92102
"programming": [
93103
{
94104
"algorithm": "\${CMSIS_PACK_ROOT}/MyVendor/MyDevice/1.0.0/Flash/algorithms/MyAlgorithm_Core0.FLM",
95-
"default": true,
96105
"pname": "Core0",
97106
"ram-size": 131072,
98107
"ram-start": 536870912,
@@ -101,7 +110,6 @@ exports[`CbuildRunReader Parser successfully parses a *.cbuild-run.yml file 1`]
101110
},
102111
{
103112
"algorithm": "\${CMSIS_PACK_ROOT}/MyVendor/MyDevice/1.0.0/Flash/algorithms/MyAlgorithm_Extern.FLM",
104-
"default": true,
105113
"pname": "Core0",
106114
"ram-size": 131072,
107115
"ram-start": 536870912,
@@ -116,12 +124,16 @@ exports[`CbuildRunReader Parser successfully parses a *.cbuild-run.yml file 1`]
116124
"pname": "Core0",
117125
"type": "svd",
118126
},
127+
{
128+
"file": "\${CMSIS_PACK_ROOT}/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core1.svd",
129+
"pname": "Core1",
130+
"type": "svd",
131+
},
119132
],
120133
"system-resources": {
121134
"memory": [
122135
{
123136
"access": "rx",
124-
"default": true,
125137
"from-pack": "MyVendor::[email protected]",
126138
"name": "Flash",
127139
"pname": "Core0",
@@ -130,7 +142,6 @@ exports[`CbuildRunReader Parser successfully parses a *.cbuild-run.yml file 1`]
130142
},
131143
{
132144
"access": "rwx",
133-
"default": true,
134145
"from-pack": "MyVendor::[email protected]",
135146
"name": "SRAM0",
136147
"pname": "Core0",
@@ -139,7 +150,6 @@ exports[`CbuildRunReader Parser successfully parses a *.cbuild-run.yml file 1`]
139150
},
140151
{
141152
"access": "rwx",
142-
"default": true,
143153
"from-pack": "MyVendor::[email protected]",
144154
"name": "SRAM1",
145155
"pname": "Core0",

src/cbuild-run/cbuild-run-reader.test.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import { CbuildRunReader } from './cbuild-run-reader';
1818

19-
const TEST_CBUILD_RUN_FILE = 'test-data/simple.cbuild-run.yml'; // Relative to repo root
19+
const TEST_CBUILD_RUN_FILE = 'test-data/multi-core.cbuild-run.yml'; // Relative to repo root
2020
const TEST_FILE_PATH = 'test-data/fileReaderTest.txt'; // Relative to repo root
2121

2222
describe('CbuildRunReader', () => {
@@ -53,11 +53,37 @@ describe('CbuildRunReader', () => {
5353
cbuildRunReader = new CbuildRunReader();
5454
});
5555

56-
it('returns SVD file path', async () => {
57-
const expectedSvdFilePaths = ['/my/pack/root/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core0.svd'];
56+
it.each([
57+
{
58+
info: 'no pname',
59+
pname: undefined,
60+
expectedSvdPaths: [
61+
'/my/pack/root/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core0.svd',
62+
'/my/pack/root/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core1.svd'
63+
]
64+
},
65+
{
66+
info: 'Core0',
67+
pname: 'Core0',
68+
expectedSvdPaths: [
69+
'/my/pack/root/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core0.svd',
70+
]
71+
},
72+
{
73+
info: 'Core1',
74+
pname: 'Core1',
75+
expectedSvdPaths: [
76+
'/my/pack/root/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core1.svd'
77+
]
78+
},
79+
])('returns SVD file path ($info)', async ({ pname, expectedSvdPaths }) => {
5880
await cbuildRunReader.parse(TEST_CBUILD_RUN_FILE);
59-
const svdFilePaths = cbuildRunReader.getSvdFilePaths('/my/pack/root');
60-
expect(svdFilePaths).toEqual(expectedSvdFilePaths);
81+
const svdFilePaths = cbuildRunReader.getSvdFilePaths('/my/pack/root', pname);
82+
expect(svdFilePaths.length).toEqual(svdFilePaths.length);
83+
for (let i = 0; i < svdFilePaths.length; i++) {
84+
// eslint-disable-next-line security/detect-object-injection
85+
expect(expectedSvdPaths[i]).toEqual(svdFilePaths[i]);
86+
}
6187
});
6288

6389
it('returns empty SVD file path list if nothing is parsed', () => {

src/cbuild-run/cbuild-run-reader.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class CbuildRunReader {
4343
}
4444
}
4545

46-
public getSvdFilePaths(cmsisPackRoot?: string): string[] {
46+
public getSvdFilePaths(cmsisPackRoot?: string, pname?: string): string[] {
4747
if (!this.cbuildRun) {
4848
return [];
4949
}
@@ -56,10 +56,23 @@ export class CbuildRunReader {
5656
// Replace potential ${CMSIS_PACK_ROOT} placeholder
5757
const effectiveCmsisPackRoot = cmsisPackRoot ?? getCmsisPackRootPath();
5858
// Map to copies, leave originals untouched
59-
const svdFilePaths = svdFileDescriptors.map(descriptor => `${effectiveCmsisPackRoot
59+
const filteredSvdDescriptors = pname ? svdFileDescriptors.filter(descriptor => descriptor.pname === pname): svdFileDescriptors;
60+
const svdFilePaths = filteredSvdDescriptors.map(descriptor => `${effectiveCmsisPackRoot
6061
? descriptor.file.replaceAll(CMSIS_PACK_ROOT_ENVVAR, effectiveCmsisPackRoot)
6162
: descriptor.file}`);
6263
return svdFilePaths;
6364
}
6465

66+
public getPnames(): string[] {
67+
if (!this.cbuildRun) {
68+
return [];
69+
}
70+
const processors = this.cbuildRun['debug-topology']?.processors;
71+
const pnameProcessors = processors?.filter(p => p.pname);
72+
if (!pnameProcessors?.length) {
73+
return [];
74+
}
75+
return pnameProcessors.map(p => p.pname!);
76+
}
77+
6578
}

src/debug-configuration/subproviders/base-configuration-provider.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import * as vscode from 'vscode';
1818
import { ExtendedGDBTargetConfiguration, GDBTargetConfiguration } from '../gdbtarget-configuration';
1919
import { CbuildRunReader } from '../../cbuild-run';
2020
import { logger } from '../../logger';
21+
import { extractPname } from '../../utils';
2122

2223
export abstract class BaseConfigurationProvider implements vscode.DebugConfigurationProvider {
2324
protected _cbuildRunReader?: CbuildRunReader;
@@ -51,18 +52,38 @@ export abstract class BaseConfigurationProvider implements vscode.DebugConfigura
5152
return !this.parameterExists(paramName, params) && (!commandName || await this.commandExists(commandName));
5253
}
5354

54-
protected resolveSvdFile(debugConfiguration: GDBTargetConfiguration) {
55+
protected resolveSvdFile(debugConfiguration: GDBTargetConfiguration, pname?: string) {
5556
const extDebugConfig = debugConfiguration as ExtendedGDBTargetConfiguration;
5657
const cbuildRunFilePath = debugConfiguration.cmsis?.cbuildRunFile;
5758
// 'definitionPath' is current default name for SVD file settings in Eclipse CDT Cloud Peripheral Inspector.
5859
if (extDebugConfig.definitionPath !== undefined || !cbuildRunFilePath?.length) {
5960
return;
6061
}
61-
const svdFilePaths = this.cbuildRunReader.getSvdFilePaths(debugConfiguration?.target?.environment?.CMSIS_PACK_ROOT);
62-
// Needs update when we better support multiple `debugger:` YAML nodes
62+
const svdFilePaths = this.cbuildRunReader.getSvdFilePaths(debugConfiguration?.target?.environment?.CMSIS_PACK_ROOT, pname);
63+
if (!svdFilePaths.length) {
64+
// No SVD file found for config
65+
return;
66+
}
67+
// Only one SVD file per pname should be left, log a warning if more
68+
if (svdFilePaths.length > 1) {
69+
let message = 'Found more than one SVD file';
70+
if (pname) {
71+
message += ` for Pname '${pname}'`;
72+
}
73+
message += ', using first';
74+
logger.warn(message);
75+
}
6376
extDebugConfig.definitionPath = svdFilePaths[0];
6477
}
6578

79+
protected extractPnameFromDebugConfig(debugConfiguration: GDBTargetConfiguration): string | undefined {
80+
const pnames = this.cbuildRunReader.getPnames();
81+
if (!pnames.length) {
82+
return undefined;
83+
}
84+
return extractPname(debugConfiguration.name, pnames);
85+
}
86+
6687
protected abstract resolveServerParameters(debugConfiguration: GDBTargetConfiguration): Promise<GDBTargetConfiguration>;
6788

6889
public async resolveDebugConfigurationWithSubstitutedVariables(
@@ -71,7 +92,7 @@ export abstract class BaseConfigurationProvider implements vscode.DebugConfigura
7192
_token?: vscode.CancellationToken
7293
): Promise<vscode.DebugConfiguration | null | undefined> {
7394
await this.parseCbuildRunFile(debugConfiguration);
74-
this.resolveSvdFile(debugConfiguration);
95+
this.resolveSvdFile(debugConfiguration, this.extractPnameFromDebugConfig(debugConfiguration));
7596
return this.resolveServerParameters(debugConfiguration);
7697
}
7798

src/debug-configuration/subproviders/generic-configuration-provider.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
*/
1616

1717
import { gdbTargetConfiguration, targetConfigurationFactory } from '../debug-configuration.factory';
18+
import { ExtendedGDBTargetConfiguration } from '../gdbtarget-configuration';
1819
import { GenericConfigurationProvider } from './generic-configuration-provider';
1920

21+
const TEST_CBUILD_RUN_FILE = 'test-data/multi-core.cbuild-run.yml'; // Relative to repo root
22+
2023
describe('GenericConfigurationProvider', () => {
2124

2225
describe('resolveDebugConfigurationWithSubstitutedVariables', () => {
@@ -29,6 +32,25 @@ describe('GenericConfigurationProvider', () => {
2932
const debugConfig = await configProvider.resolveDebugConfigurationWithSubstitutedVariables(undefined, config, undefined);
3033
expect(debugConfig).toBeDefined();
3134
});
35+
36+
it.each([
37+
{ info: 'no pname', pname: undefined, expectedSvdPath: '/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core0.svd' },
38+
{ info: 'Core0', pname: 'Core0', expectedSvdPath: '/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core0.svd' },
39+
{ info: 'Core1', pname: 'Core1', expectedSvdPath: '/MyVendor/MyDevice/1.0.0/Debug/SVD/MyDevice_Core1.svd' },
40+
])('parses a cbuild-run file and returns pname and svd file paths ($info)', async ({ pname, expectedSvdPath }) => {
41+
const configProvider = new GenericConfigurationProvider();
42+
const config = gdbTargetConfiguration({
43+
name: `${pname} probe@gdbserver (launch)`,
44+
target: targetConfigurationFactory(),
45+
cmsis: {
46+
cbuildRunFile: TEST_CBUILD_RUN_FILE
47+
}
48+
});
49+
const debugConfig = await configProvider.resolveDebugConfigurationWithSubstitutedVariables(undefined, config, undefined);
50+
const gdbTargetConfig = debugConfig as ExtendedGDBTargetConfiguration;
51+
expect(gdbTargetConfig.definitionPath?.endsWith(expectedSvdPath)).toBeTruthy();
52+
});
53+
3254
});
3355

3456
});

src/utils.test.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
jest.mock('path');
1818
import * as os from 'os';
1919
import * as path from 'path';
20-
import { getCmsisPackRootPath, isWindows } from './utils';
20+
import { extractPname, getCmsisPackRootPath, isWindows } from './utils';
2121

2222
const CMSIS_PACK_ROOT_DEFAULT = 'mock/path';
2323
describe('getCmsisPackRoot', () => {
@@ -47,3 +47,46 @@ describe('getCmsisPackRoot', () => {
4747
process.env = originalProcessEnv;
4848
});
4949
});
50+
51+
describe('extractPname', () => {
52+
53+
afterEach(() => {
54+
jest.clearAllMocks();
55+
});
56+
57+
it('extracts pname if first part of string but with now pname list', () => {
58+
const result = extractPname('dev-ice_name01 probe@gdbserver');
59+
expect(result).toEqual('dev-ice_name01');
60+
});
61+
62+
it('extracts pname if first part of string and in pname list', () => {
63+
const result = extractPname('dev-ice_name01 probe@gdbserver', ['dev2', 'dev-ice_name01']);
64+
expect(result).toEqual('dev-ice_name01');
65+
});
66+
67+
it('fails to extract if pname not first part of string but in pname list', () => {
68+
const result = extractPname('prefix dev-ice_name01 probe@gdbserver', ['dev2', 'dev-ice_name01']);
69+
expect(result).toBeUndefined();
70+
});
71+
72+
it('fails to extract if pname first part of string but not in pname list', () => {
73+
const result = extractPname('dev-ice_name01 probe@gdbserver', ['dev2', 'dev-ice_name03']);
74+
expect(result).toBeUndefined();
75+
});
76+
77+
it('fails to extract if first part contains char invalid in pname', () => {
78+
const result = extractPname('dev-ice_*name01 probe@gdbserver', ['dev2', 'dev-ice_*name01']);
79+
expect(result).toBeUndefined();
80+
});
81+
82+
it('fails to extract if first part contains char invalid in pname and in pname list', () => {
83+
const result = extractPname('dev-ice_*name01 probe@gdbserver', ['dev2', 'dev-ice_*name01']);
84+
expect(result).toBeUndefined();
85+
});
86+
87+
it('fails to extract if first part contains char invalid in pname and no pname list', () => {
88+
const result = extractPname('dev-ice_*name01 probe@gdbserver');
89+
expect(result).toBeUndefined();
90+
});
91+
92+
});

src/utils.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,20 @@ export const getCmsisPackRootPath = (): string => {
3232

3333
return cmsisPackRootDefault;
3434
};
35+
36+
export const extractPname = (configString: string, pnames?: string[]): string | undefined => {
37+
const trimmedString = configString.trim();
38+
// Config names in debugger templates are pretty free-form. Hence, can't do a lot
39+
// of format validation without reading debugger templates. Only check if name
40+
// begins with valid pname string, and if string is part of processor list.
41+
const pnameRegexp = /^[-_A-Za-z0-9]+\s+.+$/;
42+
if (!pnameRegexp.test(trimmedString)) {
43+
// Not the right format, Pname is 'RestrictedString' in PDSC format.
44+
return undefined;
45+
}
46+
const pname = trimmedString.slice(0, trimmedString.indexOf(' '));
47+
if (!pnames || pnames.includes(pname)) {
48+
return pname;
49+
}
50+
return undefined;
51+
};

0 commit comments

Comments
 (0)