singrdk/base/Windows/singx86/thread.cpp

218 lines
7.4 KiB
C++

/////////////////////////////////////////////////////////////////////////////
//
// thread.cpp - Extension to select a Singularity thread.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
#include "singx86.h"
struct GDTE
{
USHORT limit;
USHORT base0_15;
BYTE base16_23;
BYTE access;
BYTE granularity;
BYTE base24_31;
};
static void Usage()
{
ExtOut("Usage:\n"
" !thread {options} thread_addr\n"
"Options:\n"
" -p show stack prior to interrupt or exception (if any)\n"
" -t show top stack (i.e. interrupt or exception (if any))\n"
"Notes:\n"
" There are potentially three contexts associated with a thread:\n"
" the scheduler context, the interrupt context, and the exception\n"
" context. The -p flag is only useful if an exception or interrupt\n"
" has occurred. Using -p -p always gets the scheduler context.");
}
static PCSTR ParseArguments(PCSTR args,
OUT PLONG plPriorStack,
OUT PLONG plTopStack)
{
*plPriorStack = 0;
*plTopStack = 0;
while (*args != '\0') {
while (*args == ' ' || *args == '\t') {
args++;
}
if (*args != '-' && *args != '/') {
break;
}
args++;
switch (*args++) {
case 'p':
*plPriorStack = *plPriorStack + 1;
break;
case 't':
*plTopStack = 1;
break;
default:
Usage();
return NULL;
}
}
return args;
}
EXT_DECL(thread) // Defines: PDEBUG_CLIENT Client, PCSTR args
{
EXT_ENTER(); // Defines: HRESULT status = S_OK;
Thread thread;
ThreadContext tc;
LONG priorStack = 0;
LONG topStack = 0;
ULONG64 address = 0;
PVOID extendedRegs = NULL;
PVOID floatingRegs = NULL;
if ((args = ParseArguments(args, &priorStack, &topStack)) == NULL) {
status = S_FALSE;
goto Exit;
}
status = ExtEvalU64(&args, &address);
if (status != S_OK) {
ULONG indexGdtr = 0;
ULONG indexGdtl = 0;
ULONG indexFs = 0;
EXT_CHECK(g_ExtRegisters->GetIndexByName("gdtr", &indexGdtr));
EXT_CHECK(g_ExtRegisters->GetIndexByName("gdtl", &indexGdtl));
EXT_CHECK(g_ExtRegisters->GetIndexByName("fs", &indexFs));
ExtVerb("gdtr: %04x\n", indexGdtr);
ExtVerb("gdtl: %04x\n", indexGdtl);
ExtVerb("fs: %04x\n", indexFs);
ULONG64 gdtr;
ULONG64 gdtl;
ULONG64 fs;
DEBUG_VALUE v;
EXT_CHECK(g_ExtRegisters->GetValue(indexGdtr, &v));
ExtVerb("gdtr: %04x -> %p\n", indexGdtr, v.I64);
gdtr = v.I64;
EXT_CHECK(g_ExtRegisters->GetValue(indexGdtl, &v));
gdtl = v.I64;
ExtVerb("gdtl: %04x -> %p\n", indexGdtl, v.I64);
EXT_CHECK(g_ExtRegisters->GetValue(indexFs, &v));
fs = v.I64;
ExtVerb("fs: %04x -> %p\n", indexFs, v.I64);
GDTE fse;
ZeroMemory(&fse, sizeof(fse));
EXT_CHECK(g_ExtData->ReadVirtual(gdtr + fs, &fse, sizeof(fse), NULL));
ULONG64 fs0 = ((ULONG64)fse.base0_15 +
((ULONG64)fse.base16_23 << 16) |
((ULONG64)fse.base24_31 << 24));
ExtVerb("fs[0] = %p\n", fs0);
ProcessorContext pc;
EXT_CHECK(ProcessorContextStruct.Read(fs0, &pc));
ExtVerb(" threadContext: %p\n", pc.threadContext);
ExtVerb(" _processor: %p\n", pc._processor);
ExtVerb(" exception: %p\n", pc.exception);
ExtVerb(" cpuId: %p\n", pc.cpuId);
ExtOut("%d: Stacks: Int: %p..%p, Exc: %p..%p, Sch: %p..%p\n",
(int)pc.cpuId,
pc.interruptStackLimit, pc.interruptStackBegin - 1,
pc.exceptionStackLimit, pc.exceptionStackBegin - 1,
pc.schedulerStackLimit, pc.schedulerStackBegin - 1);
ThreadContext tc;
EXT_CHECK(ThreadContextStruct.Read(pc.threadContext, &tc));
address = tc._thread;
}
if (address == 0) {
ExtErr("Null is invalid thread address.\n");
return S_FALSE;
}
EXT_CHECK(ThreadStruct.Read(address, &thread));
ULONG64 caddress[3];
int currentStack = 0;
caddress[0] = address + ThreadFields[9].offset;
if (thread.context.next) {
caddress[1] = thread.context.next;
currentStack++;
EXT_CHECK(ThreadContextStruct.Read(caddress[1], &tc));
if (tc.next) {
caddress[2] = tc.next;
EXT_CHECK(ThreadContextStruct.Read(caddress[2], &tc));
currentStack++;
}
}
if (topStack == 0) {
currentStack = 0;
}
else {
if (priorStack != 0) {
currentStack -= priorStack;
if (currentStack < 0) {
currentStack = 0;
}
}
}
EXT_CHECK(ThreadContextStruct.Read(caddress[currentStack], &tc));
EXT_CHECK(ThreadContextStruct.RawAccess(ThreadContextFields[0].offset, &floatingRegs));
EXT_CHECK(ThreadContextStruct.RawAccess(ThreadContextFields[8].offset, &extendedRegs));
ExtOut(" %p { tid=%03x pid=%03x eip=%p, ebp=%p, esp=%p %02x }\n",
address,
(ULONG)(tc.threadIndex == 0xffff ? 0xfff : tc.threadIndex),
(ULONG)(tc.processId == 0xffff ? 0xfff : tc.processId),
tc.eip,
tc.ebp,
tc.esp,
(ULONG)tc.gcStates);
CONTEXT context;
EXT_CHECK(g_ExtSymbols->GetScope(NULL, NULL, &context, sizeof(context)));
context.Eip = (ULONG)tc.eip;
context.Esp = (ULONG)tc.esp;
context.Ebp = (ULONG)tc.ebp;
context.Eax = (ULONG)tc.eax;
context.Ebx = (ULONG)tc.ebx;
context.Ecx = (ULONG)tc.ecx;
context.Edx = (ULONG)tc.edx;
context.Esi = (ULONG)tc.esi;
context.Edi = (ULONG)tc.edi;
context.EFlags = (ULONG)tc.efl;
// CONTEXT_FLOATING_POINT
context.FloatSave.ControlWord = (ULONG)tc.mmx.fcw;
context.FloatSave.StatusWord = (ULONG)tc.mmx.fsw;
context.FloatSave.TagWord = (ULONG)tc.mmx.ftw;
context.FloatSave.ErrorOffset = (ULONG)tc.mmx.cs;
context.FloatSave.ErrorSelector = (ULONG)tc.mmx.eip;
context.FloatSave.DataOffset = (ULONG)tc.mmx.ds;
context.FloatSave.DataSelector = (ULONG)tc.mmx.dp;
memcpy((PBYTE)context.FloatSave.RegisterArea+0, (PBYTE)floatingRegs + 0x00, 10);
memcpy((PBYTE)context.FloatSave.RegisterArea+10, (PBYTE)floatingRegs + 0x10, 10);
memcpy((PBYTE)context.FloatSave.RegisterArea+20, (PBYTE)floatingRegs + 0x20, 10);
memcpy((PBYTE)context.FloatSave.RegisterArea+30, (PBYTE)floatingRegs + 0x30, 10);
memcpy((PBYTE)context.FloatSave.RegisterArea+40, (PBYTE)floatingRegs + 0x40, 10);
memcpy((PBYTE)context.FloatSave.RegisterArea+50, (PBYTE)floatingRegs + 0x50, 10);
memcpy((PBYTE)context.FloatSave.RegisterArea+60, (PBYTE)floatingRegs + 0x60, 10);
memcpy((PBYTE)context.FloatSave.RegisterArea+70, (PBYTE)floatingRegs + 0x70, 10);
memcpy(context.ExtendedRegisters, extendedRegs, 512);
EXT_CHECK(g_ExtSymbols->SetScope(0, NULL, &context, sizeof(context)));
EXT_LEAVE(); // Macro includes: return status;
}