-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support SteppingGranularity & instruction stepping
- Loading branch information
1 parent
acc14b5
commit 4a3154a
Showing
8 changed files
with
234 additions
and
41 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
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,177 @@ | ||
/********************************************************************* | ||
* Copyright (c) 2023 Ericsson 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 { expect } from 'chai'; | ||
import { CdtDebugClient } from './debugClient'; | ||
import { standardBeforeEach, testProgramsDir, fillDefaults } from './utils'; | ||
import { DebugProtocol } from '@vscode/debugprotocol'; | ||
|
||
interface StackState { | ||
main: DebugProtocol.StackFrame | undefined; | ||
elsewhere: DebugProtocol.StackFrame | undefined; | ||
} | ||
|
||
interface StackStateCheck { | ||
elsewhereDefined: boolean; | ||
line: number; | ||
} | ||
|
||
describe('Stepping', async function () { | ||
let dc: CdtDebugClient; | ||
const steppingProgram = path.join(testProgramsDir, 'stepping'); | ||
const steppingSource = path.join(testProgramsDir, 'stepping.c'); | ||
|
||
beforeEach(async function () { | ||
dc = await standardBeforeEach(); | ||
|
||
await dc.hitBreakpoint( | ||
fillDefaults(this.currentTest, { program: steppingProgram }), | ||
{ | ||
path: steppingSource, | ||
line: 8, | ||
} | ||
); | ||
}); | ||
|
||
afterEach(async () => { | ||
await dc.stop(); | ||
}); | ||
|
||
async function getFrameState(threadId: number) { | ||
const stack = await dc.stackTraceRequest({ threadId }); | ||
const main = stack.body.stackFrames.find( | ||
(frame) => frame.name === 'main' | ||
); | ||
const elsewhere = stack.body.stackFrames.find( | ||
(frame) => frame.name === 'getFromElsewhere' | ||
); | ||
return { main, elsewhere }; | ||
} | ||
|
||
function expectStackState(state: StackState, check: StackStateCheck) { | ||
if (check.elsewhereDefined) { | ||
expect(state.elsewhere).not.to.be.undefined; | ||
} else { | ||
expect(state.elsewhere).to.be.undefined; | ||
} | ||
const target = check.elsewhereDefined ? 'elsewhere' : 'main'; | ||
expect(state[target]).not.to.be.undefined; | ||
expect(state[target]?.line).equal( | ||
check.line, | ||
`It should have stopped at line ${check.line}` | ||
); | ||
} | ||
|
||
it('steps in by line', async () => { | ||
const threads = await dc.threadsRequest(); | ||
const threadId = threads.body.threads[0].id; | ||
expectStackState(await getFrameState(threadId), { | ||
elsewhereDefined: false, | ||
line: 8, | ||
}); | ||
await Promise.all([ | ||
dc.stepInRequest({ threadId, granularity: 'statement' }), | ||
dc.waitForEvent('stopped'), | ||
]); | ||
expectStackState(await getFrameState(threadId), { | ||
elsewhereDefined: true, | ||
line: 15, | ||
}); | ||
await Promise.all([ | ||
dc.stepInRequest({ threadId, granularity: 'statement' }), | ||
dc.waitForEvent('stopped'), | ||
]); | ||
expectStackState(await getFrameState(threadId), { | ||
elsewhereDefined: true, | ||
line: 16, | ||
}); | ||
}); | ||
|
||
it('steps in by instruction', async () => { | ||
const threads = await dc.threadsRequest(); | ||
const threadId = threads.body.threads[0].id; | ||
let state = await getFrameState(threadId); | ||
expectStackState(state, { | ||
elsewhereDefined: false, | ||
line: 8, | ||
}); | ||
await Promise.all([ | ||
dc.stepInRequest({ threadId, granularity: 'instruction' }), | ||
dc.waitForEvent('stopped'), | ||
]); | ||
// First step should not take us straight to the function. | ||
expectStackState((state = await getFrameState(threadId)), { | ||
elsewhereDefined: false, | ||
line: 8, | ||
}); | ||
// Step until we leave that line. | ||
while (state.main?.line === 8 && !state.elsewhere) { | ||
await Promise.all([ | ||
dc.stepInRequest({ threadId, granularity: 'instruction' }), | ||
dc.waitForEvent('stopped'), | ||
]); | ||
state = await getFrameState(threadId); | ||
} | ||
// First line we see should be inside `getFromElsewhere` | ||
expectStackState(state, { | ||
elsewhereDefined: true, | ||
line: 14, | ||
}); | ||
}); | ||
|
||
it('steps next by line and skips a function', async () => { | ||
const threads = await dc.threadsRequest(); | ||
const threadId = threads.body.threads[0].id; | ||
expectStackState(await getFrameState(threadId), { | ||
elsewhereDefined: false, | ||
line: 8, | ||
}); | ||
await Promise.all([ | ||
dc.nextRequest({ threadId, granularity: 'statement' }), | ||
dc.waitForEvent('stopped'), | ||
]); | ||
expectStackState(await getFrameState(threadId), { | ||
elsewhereDefined: false, | ||
line: 9, | ||
}); | ||
await Promise.all([ | ||
dc.nextRequest({ threadId, granularity: 'statement' }), | ||
dc.waitForEvent('stopped'), | ||
]); | ||
expectStackState(await getFrameState(threadId), { | ||
elsewhereDefined: false, | ||
line: 6, | ||
}); | ||
}); | ||
|
||
it('steps next by instruction and skips a function', async () => { | ||
const threads = await dc.threadsRequest(); | ||
const threadId = threads.body.threads[0].id; | ||
let state = await getFrameState(threadId); | ||
expectStackState(state, { | ||
elsewhereDefined: false, | ||
line: 8, | ||
}); | ||
// Step until we get off line 8. | ||
while (state.main?.line === 8 && !state.elsewhere) { | ||
await Promise.all([ | ||
dc.nextRequest({ threadId, granularity: 'instruction' }), | ||
dc.waitForEvent('stopped'), | ||
]); | ||
state = await getFrameState(threadId); | ||
} | ||
// The first line we should see after 8 is nine, not something in `getFromElsewhere`. | ||
expectStackState(state, { | ||
elsewhereDefined: false, | ||
line: 9, | ||
}); | ||
}); | ||
}); |
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 |
---|---|---|
|
@@ -21,3 +21,4 @@ MultiThreadRunControl | |
/log | ||
stderr | ||
bug275-测试 | ||
stepping |
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,22 @@ | ||
#include <stdio.h> | ||
|
||
int main (int argc, char *argv[]) { | ||
char knownLocally = 10; | ||
int i; | ||
for (i = 0; i < 3; i++) { | ||
knownLocally += 1; | ||
int gottenFromElsewhere = getFromElsewhere(knownLocally); | ||
printf("Saw it here first: %d", knownLocally); | ||
} | ||
return 0; | ||
} | ||
|
||
// make the line of code the same as opening brace to account for different gdb/gcc combinations | ||
int getFromElsewhere(int start) | ||
{ int result = start; int i; | ||
for (i = 1; i <= 5; i++) { | ||
result += i; | ||
printf("Eventually, I'll return something like... %d", result); | ||
} | ||
return result; | ||
} |
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