Skip to content

Commit c276ad1

Browse files
tam18902Nguyen Minh Tam
andauthored
Add thread and frame params for assigning variables (#470)
Co-authored-by: Nguyen Minh Tam <[email protected]>
1 parent 0e1244b commit c276ad1

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

src/gdb/GDBDebugSessionBase.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,12 +1771,14 @@ export abstract class GDBDebugSessionBase extends LoggingDebugSession {
17711771
assign = await mi.sendVarAssign(this.gdb, {
17721772
varname: varobj.varname,
17731773
expression: args.value,
1774+
frameRef: frameRef,
17741775
});
17751776
} else {
17761777
try {
17771778
assign = await mi.sendVarAssign(this.gdb, {
17781779
varname,
17791780
expression: args.value,
1781+
frameRef: frameRef,
17801782
});
17811783
} catch (err) {
17821784
if (parentVarname === '') {
@@ -1801,6 +1803,7 @@ export abstract class GDBDebugSessionBase extends LoggingDebugSession {
18011803
assign = await mi.sendVarAssign(this.gdb, {
18021804
varname: grandchildVarname,
18031805
expression: args.value,
1806+
frameRef: frameRef,
18041807
});
18051808
break;
18061809
} catch {

src/integration-tests/multithread.spec.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,4 +392,131 @@ describe('multithread', async function () {
392392
}
393393
}
394394
});
395+
396+
it('gets and sets register values at different frames for different threads', async function () {
397+
if (!gdbNonStop) {
398+
// This test is covering only gdb-non-stop on
399+
this.skip();
400+
}
401+
402+
await dc.launchRequest(
403+
fillDefaults(this.test, {
404+
program,
405+
})
406+
);
407+
await dc.setBreakpointsRequest({
408+
source: {
409+
path: source,
410+
},
411+
breakpoints: [
412+
{
413+
line: lineTags['LINE_MAIN_ALL_THREADS_STARTED'],
414+
},
415+
{
416+
line: lineTags['LINE_THREAD_INNER'],
417+
},
418+
],
419+
});
420+
421+
const waitForStop = dc.waitForEvent('stopped');
422+
await dc.configurationDoneRequest();
423+
await waitForStop;
424+
425+
// make sure that all the threads have stopped
426+
// TODO instead of a sleep, wait until all threads have stopped
427+
await new Promise((f) => setTimeout(f, 1000));
428+
const threads = await dc.threadsRequest();
429+
const runningThreads = threads.body.threads.filter(
430+
(t) => (t as unknown as { running?: boolean }).running
431+
);
432+
expect(runningThreads).to.be.an('array').that.is.empty;
433+
const nameToId = new Map(
434+
threads.body.threads.map((thread) => [thread.name, thread.id])
435+
);
436+
437+
// check that each thread can be communicated with individually
438+
for (const [name, idInProgram] of Object.entries(threadNames)) {
439+
// There are multiple ids/indexes.
440+
// idInProgram cooresponds to the variable thread_id in the C++ source
441+
// threadId is the id of the thread in DAP
442+
const threadId = nameToId.get(name);
443+
if (threadId === undefined) {
444+
// unreachable because of expect above
445+
fail('unreachable');
446+
}
447+
448+
const stack = await dc.stackTraceRequest({ threadId });
449+
450+
// Iterate through stack frames:
451+
// Stack frame 0 is the inner method
452+
// Stack frames 1 to id + 1 are the recursive method
453+
// Stack frame id + 2 is PrintHello
454+
for (let i = 0; i < idInProgram + 3; i++) {
455+
if (i == 0) {
456+
expect(stack.body.stackFrames[i].name).to.eq(
457+
'inner_method'
458+
);
459+
} else if (i == idInProgram + 2) {
460+
expect(stack.body.stackFrames[i].name).to.eq('PrintHello');
461+
} else {
462+
expect(stack.body.stackFrames[i].name).to.eq('recursive');
463+
}
464+
465+
const scopes = await dc.scopesRequest({
466+
frameId: stack.body.stackFrames[i].id,
467+
});
468+
const vr = scopes.body.scopes[1].variablesReference;
469+
const vars = await dc.variablesRequest({
470+
variablesReference: vr,
471+
});
472+
473+
const regPC = vars.body.variables.find(
474+
(v) => v.name === 'pc' || v.name === 'rip'
475+
);
476+
expect(regPC).to.exist;
477+
const reg0 = vars.body.variables[0];
478+
479+
const setRegPC = await dc.setVariableRequest({
480+
name: regPC!.name,
481+
value: '0x200',
482+
variablesReference: vr,
483+
});
484+
expect(setRegPC.body.value).to.equal('0x200');
485+
486+
const setReg0 = await dc.setVariableRequest({
487+
name: reg0.name,
488+
value: '0x55555',
489+
variablesReference: vr,
490+
});
491+
expect(setReg0.body.value).to.equal('0x55555');
492+
493+
const vars1 = await dc.variablesRequest({
494+
variablesReference: vr,
495+
});
496+
expect(vars1.body.variables.length).to.equal(
497+
vars.body.variables.length
498+
);
499+
500+
const varnameToValue1 = new Map(
501+
vars1.body.variables.map((variable) => [
502+
variable.name,
503+
variable.value,
504+
])
505+
);
506+
expect(varnameToValue1.get(regPC!.name)).to.equal('0x200');
507+
expect(varnameToValue1.get(reg0.name)).to.equal('0x55555');
508+
509+
await dc.setVariableRequest({
510+
name: regPC!.name,
511+
value: regPC!.value,
512+
variablesReference: vr,
513+
});
514+
await dc.setVariableRequest({
515+
name: reg0.name,
516+
value: reg0.value,
517+
variablesReference: vr,
518+
});
519+
}
520+
}
521+
});
395522
});

src/integration-tests/test-programs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ evaluate
77
mem
88
vars
99
vars_env
10+
var_globals
1011
segv
1112
loopforever
1213
MultiThread

src/mi/var.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,17 @@ export function sendVarAssign(
175175
params: {
176176
varname: string;
177177
expression: string;
178+
frameRef?: FrameReference;
178179
}
179180
): Promise<MIVarAssignResponse> {
180-
const command = `-var-assign ${params.varname} ${params.expression}`;
181+
let command = '-var-assign';
182+
if (params.frameRef?.threadId !== undefined) {
183+
command += ` --thread ${params.frameRef.threadId}`;
184+
}
185+
if (params.frameRef?.frameId !== undefined) {
186+
command += ` --frame ${params.frameRef.frameId}`;
187+
}
188+
command += ` ${params.varname} ${params.expression}`;
181189
return gdb.sendCommand(command);
182190
}
183191

0 commit comments

Comments
 (0)