Skip to content

Commit

Permalink
Ensure --frame is included even for frame 0
Browse files Browse the repository at this point in the history
Some commands take a --frame or --thread, but the code had
a common javascript error of `if (numberVar)` instead of
`if (numberVar !== undefined)`.

For threads this isn't often a problem as GDB doesn't use
thread 0 typically. But for frames this is a problem as
`--frame 0` was being omitted, leaving GDB to return
info about the last frame that was accessed, e.g like this:

-stack-list-variables --thread 4 --frame 1 --simple-values
-stack-list-variables --thread 4 --simple-values

Because the second line doesn't include the frame, GDB uses frame 1
still. However that will lead to errors as it should be
frame 0 that is queried.

Fixes eclipse-cdt-cloud#235
  • Loading branch information
jonahgraham committed Jan 31, 2023
1 parent 9731886 commit f148157
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 22 deletions.
97 changes: 79 additions & 18 deletions src/integration-tests/multithread.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,31 +94,92 @@ describe('multithread', async function () {
}

const stack = await dc.stackTraceRequest({ threadId });
let frameId: number | undefined = undefined;
let printHelloFrameId: number | undefined = undefined;
let callerFrameId: number | undefined = undefined;
for (const frame of stack.body.stackFrames) {
if (frame.name === 'PrintHello') {
frameId = frame.id;
printHelloFrameId = frame.id;
} else if (printHelloFrameId !== undefined) {
callerFrameId = frame.id;
break;
}
}
if (frameId === undefined) {
if (printHelloFrameId === undefined) {
fail("Failed to find frame with name 'PrintHello'");
}
const scopes = await dc.scopesRequest({ frameId });
const vr = scopes.body.scopes[0].variablesReference;
const vars = await dc.variablesRequest({ variablesReference: vr });
const varnameToValue = new Map(
vars.body.variables.map((variable) => [
variable.name,
variable.value,
])
);
expect(varnameToValue.get('thread_id')).to.equal(
idInProgram.toString()
);
// The "name" variable is a pointer, so is displayed as an address + the
// extracted nul terminated string
expect(varnameToValue.get('name')).to.contain(name);
if (callerFrameId === undefined) {
fail("Failed to find frame that called 'PrintHello'");
}

{
const scopes = await dc.scopesRequest({
frameId: callerFrameId,
});
const vr = scopes.body.scopes[0].variablesReference;
const vars = await dc.variablesRequest({
variablesReference: vr,
});
const varnameToValue = new Map(
vars.body.variables.map((variable) => [
variable.name,
variable.value,
])
);
// Make sure we aren't getting the HelloWorld frame's variables.
// The calling method (in glibc or similar) may end up with a local
// variable called thread_id, if so, update this heuristic
expect(varnameToValue.get('thread_id')).to.be.undefined;
}
{
const scopes = await dc.scopesRequest({
frameId: printHelloFrameId,
});
const vr = scopes.body.scopes[0].variablesReference;
const vars = await dc.variablesRequest({
variablesReference: vr,
});
const varnameToValue = new Map(
vars.body.variables.map((variable) => [
variable.name,
variable.value,
])
);
expect(varnameToValue.get('thread_id')).to.equal(
idInProgram.toString()
);
// The "name" variable is a pointer, so is displayed as an address + the
// extracted nul terminated string
expect(varnameToValue.get('name')).to.contain(name);
}
{
// Make sure we can get variables for frame 0,
// the contents of those variables don't actually matter
// as the thread will probably be stopped in a library
// somewhere waiting for a semaphore
// This is a test for #235
const scopes = await dc.scopesRequest({
frameId: stack.body.stackFrames[0].id,
});
const vr = scopes.body.scopes[0].variablesReference;

const vars = await dc.variablesRequest({
variablesReference: vr,
});
const varnameToValue = new Map(
vars.body.variables.map((variable) => [
variable.name,
variable.value,
])
);
// Make sure we aren't getting the HelloWorld frame's variables.
// The calling method (in glibc or similar) may end up with a local
// variable called thread_id, if so, update this heuristic
// We could be stopped PrintHello, so we don't perform the check
// if that is the case
if (stack.body.stackFrames[0].id !== printHelloFrameId) {
expect(varnameToValue.get('thread_id')).to.be.undefined;
}
}
}
});
});
8 changes: 4 additions & 4 deletions src/mi/stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function sendStackInfoDepth(
}
): Promise<MIStackInfoDepthResponse> {
let command = '-stack-info-depth';
if (params.threadId) {
if (params.threadId !== undefined) {
command += ` --thread ${params.threadId}`;
}
if (params.maxDepth) {
Expand All @@ -47,7 +47,7 @@ export function sendStackListFramesRequest(
stack: MIFrameInfo[];
}> {
let command = '-stack-list-frames';
if (params.threadId) {
if (params.threadId !== undefined) {
command += ` --thread ${params.threadId}`;
}
if (params.noFrameFilters) {
Expand Down Expand Up @@ -88,10 +88,10 @@ export function sendStackListVariables(
if (params.skipUnavailable) {
command += ' --skip-unavailable';
}
if (params.thread) {
if (params.thread !== undefined) {
command += ` --thread ${params.thread}`;
}
if (params.frame) {
if (params.frame !== undefined) {
command += ` --frame ${params.frame}`;
}
command += ` --${params.printValues}`;
Expand Down

0 comments on commit f148157

Please sign in to comment.