Setting processor context from a windbg extension

I’m trying to set the current processor (CPU) from a windbg kernel-mode extension by using SetCurrentThreadId(). It returns S_OK, but a subsequent GetCurrentThreadId() doesn’t match. Here’s some test code and output from a 4-CPU system. Is this the right way to set processor context? Other suggestions? Thanks!

HRESULT CALLBACK
rc_test(PDEBUG_CLIENT4 Client, PCSTR args)
{
INIT_API();
ULONG numProcs = 0;
if (g_ExtControl->GetNumberProcessors(&numProcs) == S_OK) {

PROCESSORINFO pi;
GetKdContext(&pi);
dprintf(“GetNumberProcessors() => %lu processors; GetKdContext => %hu\n”, numProcs, pi.NumberProcessors);

for (ULONG p = 0; p < numProcs; p++) {

// switch to processor p.
ULONG tid;
dprintf(“switching to processor %lu…\n”, p);
if (g_ExtSystemObjects->GetThreadIdByProcessor(p, &tid) == S_OK) {
dprintf(“processor %lu is mapped to TID %lu.\n”, p, tid);

// When in kernel mode, the “CurrentThread” corresponds to the current CPU.
HRESULT r;
if ((r = g_ExtSystemObjects->SetCurrentThreadId(tid)) == S_OK) {
dprintf(“current processor should now be %lu.\n”, p);
} else {
dprintf(“error: SetCurrentThreadId(%lu) for CPU %lu returned 0x%lx.\n”, tid, p, r);
}
} else {
dprintf(“error: GetThreadIdByProcessor() failed.\n”);
}

// double-check that we have the correct processor.
if (g_ExtSystemObjects->GetCurrentThreadId(&tid) == S_OK) {
dprintf(“current processor according to GetCurrentThreadId() is %hu.\n”, pi.Processor);
} else {
dprintf(“error: GetCurrentThreadId() failed.\n”);
}
GetKdContext(&pi);
dprintf(“current processor according to GetKdContext() is %hu.\n”, pi.Processor);

// print some register values from it.
const char* regNames = { “eax”, “ebx”, “esp”, 0 };
for (int i = 0; regNames[i]; i++) {
ULONG regNum;
DEBUG_VALUE regVal;
if (g_ExtRegisters->GetIndexByName(regNames[i], &regNum) != S_OK) {
dprintf(“error in readReg: cannot get index of ‘%s’ register.\n”, regNames[i]);
}
else if (g_ExtRegisters->GetValue(regNum, &regVal) != S_OK) {
dprintf(“error: cannot read ‘%s’ register.\n”, regNames[i]);
}
else {
dprintf(" ‘%s’ = 0x%08x\n", regNames[i], regVal.I32);
}
}
}
}
EXIT_API();
return S_OK;
}

3: kd> !rc_test
GetNumberProcessors() => 4 processors; GetKdContext => 4
switching to processor 0…
processor 0 is mapped to TID 0.
current processor should now be 0.
current processor according to GetCurrentThreadId() is 3.
current processor according to GetKdContext() is 3.
‘eax’ = 0xcc490d18
‘ebx’ = 0xf788dc70
‘esp’ = 0xf7a34d34
switching to processor 1…
processor 1 is mapped to TID 1.
current processor should now be 1.
current processor according to GetCurrentThreadId() is 3.
current processor according to GetKdContext() is 3.
‘eax’ = 0xcc490d18
‘ebx’ = 0xf788dc70
‘esp’ = 0xf7a34d34
switching to processor 2…
processor 2 is mapped to TID 2.
current processor should now be 2.
current processor according to GetCurrentThreadId() is 3.
current processor according to GetKdContext() is 3.
‘eax’ = 0xcc490d18
‘ebx’ = 0xf788dc70
‘esp’ = 0xf7a34d34
switching to processor 3…
processor 3 is mapped to TID 3.
current processor should now be 3.
current processor according to GetCurrentThreadId() is 3.
current processor according to GetKdContext() is 3.
‘eax’ = 0xcc490d18
‘ebx’ = 0xf788dc70
‘esp’ = 0xf7a34d34

PS: I’m using WinDbg 6.12.0002.633 connected to a 32-bit WinXP target.

Changing the thread context doesn’t change the processor context:

0: kd> ln @rip
(fffff880`03e7a9c0) intelppm!C1Halt+0x2
0: kd> !running

System Processors: (000000000000000f)
Idle Processors: (000000000000000b)
Prcbs Current Next
2 fffff88002f64180 fffffa80042912f0

0: kd> .thread /r /p fffffa80042912f0
Implicit thread is now fffffa80042912f0 Implicit process is now fffffa80035eb040
Loading User Symbols

0: kd> ln @rip
(fffff800`02bb59b0) nt!PpmPerfRecordUtility+0x186

Note that I still appear to be on processor 0 even after switching threads.

There doesn’t appear to be a way to directly switch processor context using
DbgEng. You could always just use IDebugControl::Execute and run ~n
directly.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@windbg…
> I’m trying to set the current processor (CPU) from a windbg kernel-mode
> extension by using SetCurrentThreadId(). It returns S_OK, but a subsequent
> GetCurrentThreadId() doesn’t match. Here’s some test code and output from
> a 4-CPU system. Is this the right way to set processor context? Other
> suggestions? Thanks!
>
> HRESULT CALLBACK
> rc_test(PDEBUG_CLIENT4 Client, PCSTR args)
> {
> INIT_API();
> ULONG numProcs = 0;
> if (g_ExtControl->GetNumberProcessors(&numProcs) == S_OK) {
>
> PROCESSORINFO pi;
> GetKdContext(&pi);
> dprintf(“GetNumberProcessors() => %lu processors; GetKdContext => %hu\n”,
> numProcs, pi.NumberProcessors);
>
> for (ULONG p = 0; p < numProcs; p++) {
>
> // switch to processor p.
> ULONG tid;
> dprintf(“switching to processor %lu…\n”, p);
> if (g_ExtSystemObjects->GetThreadIdByProcessor(p, &tid) == S_OK) {
> dprintf(“processor %lu is mapped to TID %lu.\n”, p, tid);
>
> // When in kernel mode, the “CurrentThread” corresponds to the current
> CPU.
> HRESULT r;
> if ((r = g_ExtSystemObjects->SetCurrentThreadId(tid)) == S_OK) {
> dprintf(“current processor should now be %lu.\n”, p);
> } else {
> dprintf(“error: SetCurrentThreadId(%lu) for CPU %lu returned 0x%lx.\n”,
> tid, p, r);
> }
> } else {
> dprintf(“error: GetThreadIdByProcessor() failed.\n”);
> }
>
> // double-check that we have the correct processor.
> if (g_ExtSystemObjects->GetCurrentThreadId(&tid) == S_OK) {
> dprintf(“current processor according to GetCurrentThreadId() is %hu.\n”,
> pi.Processor);
> } else {
> dprintf(“error: GetCurrentThreadId() failed.\n”);
> }
> GetKdContext(&pi);
> dprintf(“current processor according to GetKdContext() is %hu.\n”,
> pi.Processor);
>
> // print some register values from it.
> const char* regNames = { “eax”, “ebx”, “esp”, 0 };
> for (int i = 0; regNames[i]; i++) {
> ULONG regNum;
> DEBUG_VALUE regVal;
> if (g_ExtRegisters->GetIndexByName(regNames[i], &regNum) != S_OK) {
> dprintf(“error in readReg: cannot get index of ‘%s’ register.\n”,
> regNames[i]);
> }
> else if (g_ExtRegisters->GetValue(regNum, &regVal) != S_OK) {
> dprintf(“error: cannot read ‘%s’ register.\n”, regNames[i]);
> }
> else {
> dprintf(" ‘%s’ = 0x%08x\n", regNames[i], regVal.I32);
> }
> }
> }
> }
> EXIT_API();
> return S_OK;
> }
>
> 3: kd> !rc_test
> GetNumberProcessors() => 4 processors; GetKdContext => 4
> switching to processor 0…
> processor 0 is mapped to TID 0.
> current processor should now be 0.
> current processor according to GetCurrentThreadId() is 3.
> current processor according to GetKdContext() is 3.
> ‘eax’ = 0xcc490d18
> ‘ebx’ = 0xf788dc70
> ‘esp’ = 0xf7a34d34
> switching to processor 1…
> processor 1 is mapped to TID 1.
> current processor should now be 1.
> current processor according to GetCurrentThreadId() is 3.
> current processor according to GetKdContext() is 3.
> ‘eax’ = 0xcc490d18
> ‘ebx’ = 0xf788dc70
> ‘esp’ = 0xf7a34d34
> switching to processor 2…
> processor 2 is mapped to TID 2.
> current processor should now be 2.
> current processor according to GetCurrentThreadId() is 3.
> current processor according to GetKdContext() is 3.
> ‘eax’ = 0xcc490d18
> ‘ebx’ = 0xf788dc70
> ‘esp’ = 0xf7a34d34
> switching to processor 3…
> processor 3 is mapped to TID 3.
> current processor should now be 3.
> current processor according to GetCurrentThreadId() is 3.
> current processor according to GetKdContext() is 3.
> ‘eax’ = 0xcc490d18
> ‘ebx’ = 0xf788dc70
> ‘esp’ = 0xf7a34d34
>
>

Scott: thanks for your reply. I tried Execute(…“~n”…), but it seems to cause unpredictable exceptions and callbacks to DebugExtensionNotify() that make writing a reliable extension difficult. (Based on the comment “This message *might* immediately reappear” in the exception-handling message printed by WinDbg, this unpredicability is well-known.)

Bummer. The lack of an obvious DbgEng call makes me think this is a concept
that is maintained inside the DbgEng library just to support ~, so not sure
if there’s any easy solution if Execute doesn’t work.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@windbg…
> Scott: thanks for your reply. I tried Execute(…“~n”…), but it seems to
> cause unpredictable exceptions and callbacks to DebugExtensionNotify()
> that make writing a reliable extension difficult. (Based on the comment
> “This message might immediately reappear” in the exception-handling
> message printed by WinDbg, this unpredicability is well-known.)
>

The problem here is that switching processors isn’t always a synchronous operation.

IDebugSystemObjects::SetCurrentThreadId is the correct call as the documentation for that routine states. The ~ command will go to the same place as SetCurrentThreadId internally.

The issue here is that switching processors on a live (non-dump) target is asynchronous; it actually only takes effect once the debugger command loop runs and gets a chance to communicate with the target and ask it to switch active processors

In the case of typing a ~ command, this happens once the ~ command finishes processing. But in the case of the debugger extension as the OP has described it, the debugger loop isn’t being entered again before the extension is making additional calls.

The usual workaround I have seen here is to call Execute with ~%lu. In any case, you’ll have to allow for the fact that the debugger needs to run the dispatch loop for a little bit for the processor switch to happen on a non-dump kernel target (i.e. I don’t think that the OP will be able to get out of receiving event delivery as a result of this happening).

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Scott Noone
Sent: Wednesday, August 25, 2010 11:37 AM
To: Kernel Debugging Interest List
Subject: Re:[windbg] Setting processor context from a windbg extension

Bummer. The lack of an obvious DbgEng call makes me think this is a concept that is maintained inside the DbgEng library just to support ~, so not sure if there’s any easy solution if Execute doesn’t work.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@windbg…
> Scott: thanks for your reply. I tried Execute(…“~n”…), but it seems to
> cause unpredictable exceptions and callbacks to DebugExtensionNotify()
> that make writing a reliable extension difficult. (Based on the comment
> “This message might immediately reappear” in the exception-handling
> message printed by WinDbg, this unpredicability is well-known.)
>


WINDBG is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer