-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improvements for Breakpoint Logic (#268)
In this update there are update for breakpoint insert logic. We introduce a new method getBreakpointOptions to GDBBackend class. With this new functionality, any child class could override the breakpoint options (including changing the type hardware/software). This will enable a new feature for embedded systems to manage the limited breakpoint capability more efficiently. Also, any error thrown in the getBreakpointOptions will disable the breakpoint, thus, limited capabilities controlled without having errors in the user interface. There are also some refactoring performed during the operation. Perhaps, not all the refactorings are must to have, but tried to handle the namings of functions/methods and object structure to be semantically coherent after the update.
- Loading branch information
Showing
5 changed files
with
300 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2023 Renesas Electronics Corporation and others | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*********************************************************************/ | ||
import * as path from 'path'; | ||
import * as os from 'os'; | ||
import { expect } from 'chai'; | ||
import { CdtDebugClient } from './debugClient'; | ||
import { standardBeforeEach, testProgramsDir, fillDefaults } from './utils'; | ||
|
||
// This mock adapter is overriding the getBreakpointOptions method. | ||
const adapter = | ||
'integration-tests/mocks/debugAdapters/dynamicBreakpointOptions.js'; | ||
const argHardwareBreakpointTrue = '--hardware-breakpoint-true'; | ||
const argHardwareBreakpointFalse = '--hardware-breakpoint-false'; | ||
const argThrowError = '--throw-error'; | ||
|
||
describe('dynamic breakpoint options with hardware set to false', async () => { | ||
let dc: CdtDebugClient; | ||
|
||
beforeEach(async function () { | ||
// Overriding breakpoint option hardware to false | ||
dc = await standardBeforeEach(adapter, [argHardwareBreakpointFalse]); | ||
await dc.launchRequest( | ||
fillDefaults(this.currentTest, { | ||
program: path.join(testProgramsDir, 'count'), | ||
hardwareBreakpoint: true, | ||
}) | ||
); | ||
}); | ||
|
||
afterEach(async () => { | ||
await dc.stop(); | ||
}); | ||
|
||
it('insert breakpoint as software breakpoint', async () => { | ||
const bpResp = await dc.setBreakpointsRequest({ | ||
source: { | ||
name: 'count.c', | ||
path: path.join(testProgramsDir, 'count.c'), | ||
}, | ||
breakpoints: [ | ||
{ | ||
column: 1, | ||
line: 4, | ||
}, | ||
], | ||
}); | ||
expect(bpResp.body.breakpoints.length).eq(1); | ||
expect(bpResp.body.breakpoints[0].verified).eq(true); | ||
expect(bpResp.body.breakpoints[0].message).eq(undefined); | ||
await dc.configurationDoneRequest(); | ||
let isCorrect; | ||
let outputs; | ||
while (!isCorrect) { | ||
// Cover the case of getting event in Linux environment. | ||
// If cannot get correct event, program timeout and test case failed. | ||
outputs = await dc.waitForEvent('output'); | ||
isCorrect = outputs.body.output.includes('breakpoint-modified'); | ||
} | ||
expect(outputs?.body.output).includes('type="breakpoint"'); | ||
}); | ||
}); | ||
|
||
describe('dynamic breakpoint options with hardware set to true', async () => { | ||
let dc: CdtDebugClient; | ||
|
||
beforeEach(async function () { | ||
// Overriding breakpoint option hardware to true | ||
dc = await standardBeforeEach(adapter, [argHardwareBreakpointTrue]); | ||
await dc.launchRequest( | ||
fillDefaults(this.currentTest, { | ||
program: path.join(testProgramsDir, 'count'), | ||
hardwareBreakpoint: false, | ||
}) | ||
); | ||
}); | ||
|
||
afterEach(async () => { | ||
await dc.stop(); | ||
}); | ||
|
||
it('insert breakpoint as hardware breakpoint', async function () { | ||
// Hardware breakpoints are not supported for Windows | ||
if (os.platform() === 'win32') { | ||
this.skip(); | ||
} | ||
const bpResp = await dc.setBreakpointsRequest({ | ||
source: { | ||
name: 'count.c', | ||
path: path.join(testProgramsDir, 'count.c'), | ||
}, | ||
breakpoints: [ | ||
{ | ||
column: 1, | ||
line: 4, | ||
}, | ||
], | ||
}); | ||
expect(bpResp.body.breakpoints.length).eq(1); | ||
expect(bpResp.body.breakpoints[0].verified).eq(true); | ||
expect(bpResp.body.breakpoints[0].message).eq(undefined); | ||
await dc.configurationDoneRequest(); | ||
let isCorrect; | ||
let outputs; | ||
while (!isCorrect) { | ||
// Cover the case of getting event in Linux environment. | ||
// If cannot get correct event, program timeout and test case failed. | ||
outputs = await dc.waitForEvent('output'); | ||
isCorrect = outputs.body.output.includes('breakpoint-modified'); | ||
} | ||
expect(outputs?.body.output).includes('type="hw breakpoint"'); | ||
}); | ||
}); | ||
|
||
describe('dynamic breakpoint options with throwing error', async () => { | ||
let dc: CdtDebugClient; | ||
|
||
beforeEach(async function () { | ||
// Overriding breakpoint options and throwing error when getBreakpointOptions invoked | ||
dc = await standardBeforeEach(adapter, [argThrowError]); | ||
await dc.launchRequest( | ||
fillDefaults(this.currentTest, { | ||
program: path.join(testProgramsDir, 'count'), | ||
hardwareBreakpoint: false, | ||
}) | ||
); | ||
}); | ||
|
||
afterEach(async () => { | ||
await dc.stop(); | ||
}); | ||
|
||
it('insert breakpoint is not performed', async () => { | ||
const bpResp = await dc.setBreakpointsRequest({ | ||
source: { | ||
name: 'count.c', | ||
path: path.join(testProgramsDir, 'count.c'), | ||
}, | ||
breakpoints: [ | ||
{ | ||
column: 1, | ||
line: 4, | ||
}, | ||
], | ||
}); | ||
expect(bpResp.body.breakpoints.length).eq(1); | ||
expect(bpResp.body.breakpoints[0].verified).eq(false); | ||
expect(bpResp.body.breakpoints[0].message).not.eq(undefined); | ||
}); | ||
}); |
58 changes: 58 additions & 0 deletions
58
src/integration-tests/mocks/debugAdapters/dynamicBreakpointOptions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#!/usr/bin/env node | ||
/********************************************************************* | ||
* Copyright (c) 2023 Renesas Electronics Corporation and others | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*********************************************************************/ | ||
import * as process from 'process'; | ||
import { logger } from '@vscode/debugadapter/lib/logger'; | ||
import { GDBBackend } from '../../../GDBBackend'; | ||
import { GDBTargetDebugSession } from '../../../GDBTargetDebugSession'; | ||
import { MIBreakpointLocation, MIBreakpointInsertOptions } from '../../../mi'; | ||
|
||
process.on('uncaughtException', (err: any) => { | ||
logger.error(JSON.stringify(err)); | ||
}); | ||
|
||
// Breakpoint options to override | ||
const hardwareBreakpointTrue = process.argv.includes( | ||
'--hardware-breakpoint-true' | ||
); | ||
const hardwareBreakpointFalse = process.argv.includes( | ||
'--hardware-breakpoint-false' | ||
); | ||
const throwError = process.argv.includes('--throw-error'); | ||
|
||
class DynamicBreakpointOptionsGDBBackend extends GDBBackend { | ||
public async getBreakpointOptions( | ||
_: MIBreakpointLocation, | ||
initialOptions: MIBreakpointInsertOptions | ||
): Promise<MIBreakpointInsertOptions> { | ||
if (throwError) { | ||
throw new Error( | ||
'Some error message providing information that the breakpoint is not valid!' | ||
); | ||
} | ||
const hardware = hardwareBreakpointTrue | ||
? true | ||
: hardwareBreakpointFalse | ||
? false | ||
: initialOptions.hardware; | ||
return { ...initialOptions, hardware }; | ||
} | ||
} | ||
|
||
class DynamicBreakpointOptionsGDBDebugSession extends GDBTargetDebugSession { | ||
gdb = this.createBackend(); | ||
protected createBackend(): GDBBackend { | ||
return new DynamicBreakpointOptionsGDBBackend(); | ||
} | ||
} | ||
|
||
DynamicBreakpointOptionsGDBDebugSession.run( | ||
DynamicBreakpointOptionsGDBDebugSession | ||
); |
Oops, something went wrong.