2008-03-05 09:52:00 -05:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// thread.cpp - Extension to select a Singularity thread.
|
|
|
|
//
|
2008-11-17 18:29:00 -05:00
|
|
|
// Copyright Microsoft Corporation. All rights reserved.
|
2008-03-05 09:52:00 -05:00
|
|
|
//
|
|
|
|
#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;
|
|
|
|
|
|
|
|
if ((args = ParseArguments(args, &priorStack, &topStack)) == NULL) {
|
|
|
|
status = S_FALSE;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = ExtEvalU64(&args, &address);
|
|
|
|
if (status != S_OK) {
|
2008-11-17 18:29:00 -05:00
|
|
|
//// This code \/ needs to be replicated for ARM.
|
2008-03-05 09:52:00 -05:00
|
|
|
ULONG indexGdtr = 0;
|
|
|
|
ULONG indexGdtl = 0;
|
|
|
|
ULONG indexFs = 0;
|
|
|
|
EXT_CHECK(g_ExtRegisters->GetIndexByName("gdtr", &indexGdtr));
|
|
|
|
EXT_CHECK(g_ExtRegisters->GetIndexByName("gdtl", &indexGdtl));
|
2008-11-17 18:29:00 -05:00
|
|
|
if (TargetMachine == IMAGE_FILE_MACHINE_AMD64) {
|
|
|
|
EXT_CHECK(g_ExtRegisters->GetIndexByName("gs", &indexFs));
|
|
|
|
}
|
|
|
|
else if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
|
|
|
|
EXT_CHECK(g_ExtRegisters->GetIndexByName("fs", &indexFs));
|
|
|
|
}
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
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));
|
2008-11-17 18:29:00 -05:00
|
|
|
EXT_CHECK(TraceRead(gdtr + fs, &fse, sizeof(fse)));
|
2008-03-05 09:52:00 -05:00
|
|
|
ULONG64 fs0 = ((ULONG64)fse.base0_15 +
|
|
|
|
((ULONG64)fse.base16_23 << 16) |
|
|
|
|
((ULONG64)fse.base24_31 << 24));
|
|
|
|
ExtVerb("fs[0] = %p\n", fs0);
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
// BUG: does not get fs offset from HAL!!!
|
|
|
|
|
|
|
|
ProcessorContext *ppc;
|
|
|
|
EXT_CHECK(TraceRead(fs0, &ppc, sizeof(ppc)));
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
ProcessorContext pc;
|
2008-11-17 18:29:00 -05:00
|
|
|
EXT_CHECK(ProcessorContextStruct.Read((ULONG64)ppc, &pc));
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
ExtVerb(" _processor: %p\n", pc._processor);
|
|
|
|
ExtVerb(" exception: %p\n", pc.exception);
|
2008-11-17 18:29:00 -05:00
|
|
|
ExtVerb(" cpuId: %p\n", pc.cpuRecord.id);
|
|
|
|
ExtOut("%d: Int Stack: %p..%p\n",
|
|
|
|
(int)pc.cpuRecord.id,
|
|
|
|
pc.cpuRecord.interruptStackLimit, pc.cpuRecord.interruptStackBegin - 1);
|
|
|
|
|
|
|
|
ThreadContext *ptc;
|
|
|
|
EXT_CHECK(TraceRead(fs0+sizeof(void*), &ptc, sizeof(ptc)));
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
ThreadContext tc;
|
2008-11-17 18:29:00 -05:00
|
|
|
EXT_CHECK(ProcessorContextStruct.Read((ULONG64)ptc, &tc));
|
|
|
|
|
|
|
|
ExtVerb(" threadContext: %p\n", ptc);
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
address = tc._thread;
|
2008-11-17 18:29:00 -05:00
|
|
|
//// This code /\ needs to be replicated for ARM.
|
2008-03-05 09:52:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (address == 0) {
|
|
|
|
ExtErr("Null is invalid thread address.\n");
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
EXT_CHECK(ThreadStruct->Read(address, &thread));
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
ULONG64 caddress[3];
|
|
|
|
int currentStack = 0;
|
2008-11-17 18:29:00 -05:00
|
|
|
caddress[0] = address + ThreadFields[0].offset; // Thread.context
|
2008-03-05 09:52:00 -05:00
|
|
|
|
|
|
|
if (thread.context.next) {
|
|
|
|
caddress[1] = thread.context.next;
|
|
|
|
currentStack++;
|
2008-11-17 18:29:00 -05:00
|
|
|
EXT_CHECK(ThreadContextStruct->Read(caddress[1], &tc));
|
2008-03-05 09:52:00 -05:00
|
|
|
if (tc.next) {
|
|
|
|
caddress[2] = tc.next;
|
2008-11-17 18:29:00 -05:00
|
|
|
EXT_CHECK(ThreadContextStruct->Read(caddress[2], &tc));
|
2008-03-05 09:52:00 -05:00
|
|
|
currentStack++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (topStack == 0) {
|
|
|
|
currentStack = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (priorStack != 0) {
|
|
|
|
currentStack -= priorStack;
|
|
|
|
if (currentStack < 0) {
|
|
|
|
currentStack = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-17 18:29:00 -05:00
|
|
|
EXT_CHECK(ThreadContextStruct->Read(caddress[currentStack], &tc));
|
|
|
|
|
|
|
|
if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
|
|
|
|
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.threadRecord.spill.ip,
|
|
|
|
tc.threadRecord.spill.bp,
|
|
|
|
tc.threadRecord.spill.sp,
|
|
|
|
(ULONG)tc.gcStates);
|
|
|
|
|
|
|
|
X86_CONTEXT context;
|
|
|
|
PVOID mmxRegs = NULL;
|
|
|
|
PVOID stRegs = NULL;
|
|
|
|
|
|
|
|
EXT_CHECK(g_ExtSymbols->GetScope(NULL, NULL, &context, sizeof(context)));
|
|
|
|
EXT_CHECK(ThreadContextStruct->RawAccess(ThreadContextFields[0].offset, &mmxRegs));
|
|
|
|
EXT_CHECK(ThreadContextStruct->RawAccess(ThreadContextFields[1].offset, &stRegs));
|
|
|
|
|
|
|
|
context.Eip = (ULONG)tc.threadRecord.spill.ip;
|
|
|
|
context.Esp = (ULONG)tc.threadRecord.spill.sp;
|
|
|
|
context.Ebp = (ULONG)tc.threadRecord.spill.bp;
|
|
|
|
context.Eax = (ULONG)tc.threadRecord.spill.ax;
|
|
|
|
context.Ebx = (ULONG)tc.threadRecord.spill.bx;
|
|
|
|
context.Ecx = (ULONG)tc.threadRecord.spill.cx;
|
|
|
|
context.Edx = (ULONG)tc.threadRecord.spill.dx;
|
|
|
|
context.Esi = (ULONG)tc.threadRecord.spill.si;
|
|
|
|
context.Edi = (ULONG)tc.threadRecord.spill.di;
|
|
|
|
context.EFlags = (ULONG)tc.threadRecord.spill.fl;
|
|
|
|
|
|
|
|
// CONTEXT_FLOATING_POINT
|
|
|
|
context.FloatSave.ControlWord = (ULONG)tc.threadRecord.spill.mmx.fcw;
|
|
|
|
context.FloatSave.StatusWord = (ULONG)tc.threadRecord.spill.mmx.fsw;
|
|
|
|
context.FloatSave.TagWord = (ULONG)tc.threadRecord.spill.mmx.ftw;
|
|
|
|
context.FloatSave.ErrorOffset = (ULONG)tc.threadRecord.spill.mmx.ip;
|
|
|
|
context.FloatSave.ErrorSelector = (ULONG)tc.threadRecord.spill.mmx.cs;
|
|
|
|
context.FloatSave.DataOffset = (ULONG)tc.threadRecord.spill.mmx.dp;
|
|
|
|
context.FloatSave.DataSelector = (ULONG)tc.threadRecord.spill.mmx.ds;
|
|
|
|
|
|
|
|
memcpy((PBYTE)context.FloatSave.RegisterArea+0, (PBYTE)stRegs + 0x00, 10);
|
|
|
|
memcpy((PBYTE)context.FloatSave.RegisterArea+10, (PBYTE)stRegs + 0x10, 10);
|
|
|
|
memcpy((PBYTE)context.FloatSave.RegisterArea+20, (PBYTE)stRegs + 0x20, 10);
|
|
|
|
memcpy((PBYTE)context.FloatSave.RegisterArea+30, (PBYTE)stRegs + 0x30, 10);
|
|
|
|
memcpy((PBYTE)context.FloatSave.RegisterArea+40, (PBYTE)stRegs + 0x40, 10);
|
|
|
|
memcpy((PBYTE)context.FloatSave.RegisterArea+50, (PBYTE)stRegs + 0x50, 10);
|
|
|
|
memcpy((PBYTE)context.FloatSave.RegisterArea+60, (PBYTE)stRegs + 0x60, 10);
|
|
|
|
memcpy((PBYTE)context.FloatSave.RegisterArea+70, (PBYTE)stRegs + 0x70, 10);
|
|
|
|
memcpy(context.ExtendedRegisters, mmxRegs, 512);
|
|
|
|
|
|
|
|
EXT_CHECK(g_ExtSymbols->SetScope(0, NULL, &context, sizeof(context)));
|
|
|
|
}
|
|
|
|
else if (TargetMachine == IMAGE_FILE_MACHINE_AMD64) {
|
|
|
|
ExtOut(" %p { tid=%03x pid=%03x rip=%p, rbp=%p, rsp=%p %02x }\n",
|
|
|
|
address,
|
|
|
|
(ULONG)(tc.threadIndex == 0xffff ? 0xfff : tc.threadIndex),
|
|
|
|
(ULONG)(tc.processId == 0xffff ? 0xfff : tc.processId),
|
|
|
|
tc.threadRecord.spill.ip,
|
|
|
|
tc.threadRecord.spill.bp,
|
|
|
|
tc.threadRecord.spill.sp,
|
|
|
|
(ULONG)tc.gcStates);
|
|
|
|
|
|
|
|
X64_CONTEXT context;
|
|
|
|
PVOID mmxRegs = NULL;
|
|
|
|
|
|
|
|
EXT_CHECK(g_ExtSymbols->GetScope(NULL, NULL, &context, sizeof(context)));
|
|
|
|
EXT_CHECK(ThreadContextStruct->RawAccess(ThreadContextFields[0].offset, &mmxRegs));
|
|
|
|
|
|
|
|
// TODO: fix the extension to proper handle different architectures. Copy only
|
|
|
|
// these registers for now
|
|
|
|
|
|
|
|
context.Rip = tc.threadRecord.spill.ip;
|
|
|
|
context.Rsp = tc.threadRecord.spill.sp;
|
|
|
|
context.Rbp = tc.threadRecord.spill.bp;
|
|
|
|
context.Rax = tc.threadRecord.spill.ax;
|
|
|
|
context.Rbx = tc.threadRecord.spill.bx;
|
|
|
|
context.Rcx = tc.threadRecord.spill.cx;
|
|
|
|
context.Rdx = tc.threadRecord.spill.dx;
|
|
|
|
context.Rsi = tc.threadRecord.spill.si;
|
|
|
|
context.Rdi = tc.threadRecord.spill.di;
|
|
|
|
context.R8 = tc.threadRecord.spill.r8;
|
|
|
|
context.R9 = tc.threadRecord.spill.r9;
|
|
|
|
context.R10 = tc.threadRecord.spill.r10;
|
|
|
|
context.R11 = tc.threadRecord.spill.r11;
|
|
|
|
context.R12 = tc.threadRecord.spill.r12;
|
|
|
|
context.R13 = tc.threadRecord.spill.r13;
|
|
|
|
context.R14 = tc.threadRecord.spill.r14;
|
|
|
|
context.R15 = tc.threadRecord.spill.r15;
|
|
|
|
context.EFlags = (ULONG)tc.threadRecord.spill.fl;
|
|
|
|
|
|
|
|
// CONTEXT_FLOATING_POINT
|
|
|
|
memcpy(&context.FltSave, mmxRegs, 512);
|
|
|
|
|
|
|
|
EXT_CHECK(g_ExtSymbols->SetScope(0, NULL, &context, sizeof(context)));
|
|
|
|
}
|
|
|
|
else if (TargetMachine == IMAGE_FILE_MACHINE_ARM) {
|
|
|
|
ExtOut(" %p { tid=%03x pid=%03x pc=%p, sp=%p %02x }\n",
|
|
|
|
address,
|
|
|
|
(ULONG)(tc.threadIndex == 0xffff ? 0xfff : tc.threadIndex),
|
|
|
|
(ULONG)(tc.processId == 0xffff ? 0xfff : tc.processId),
|
|
|
|
tc.threadRecord.spill.pc,
|
|
|
|
tc.threadRecord.spill.sp,
|
|
|
|
(ULONG)tc.gcStates);
|
|
|
|
|
|
|
|
ARM_CONTEXT context;
|
|
|
|
|
|
|
|
EXT_CHECK(g_ExtSymbols->GetScope(NULL, NULL, &context, sizeof(context)));
|
|
|
|
|
|
|
|
// TODO: fix the extension to proper handle different architectures. Copy only
|
|
|
|
// these registers for now
|
|
|
|
|
|
|
|
context.R0 = (ULONG)tc.threadRecord.spill.r0;
|
|
|
|
context.R1 = (ULONG)tc.threadRecord.spill.r1;
|
|
|
|
context.R2 = (ULONG)tc.threadRecord.spill.r2;
|
|
|
|
context.R3 = (ULONG)tc.threadRecord.spill.r3;
|
|
|
|
context.R4 = (ULONG)tc.threadRecord.spill.r4;
|
|
|
|
context.R5 = (ULONG)tc.threadRecord.spill.r5;
|
|
|
|
context.R6 = (ULONG)tc.threadRecord.spill.r6;
|
|
|
|
context.R7 = (ULONG)tc.threadRecord.spill.r7;
|
|
|
|
context.R8 = (ULONG)tc.threadRecord.spill.r8;
|
|
|
|
context.R9 = (ULONG)tc.threadRecord.spill.r9;
|
|
|
|
context.R10 = (ULONG)tc.threadRecord.spill.r10;
|
|
|
|
context.R11 = (ULONG)tc.threadRecord.spill.r11;
|
|
|
|
context.R12 = (ULONG)tc.threadRecord.spill.r12;
|
|
|
|
|
|
|
|
context.Pc = (ULONG)tc.threadRecord.spill.pc;
|
|
|
|
context.Lr = (ULONG)tc.threadRecord.spill.lr;
|
|
|
|
context.Sp = (ULONG)tc.threadRecord.spill.sp;
|
|
|
|
context.Cpsr = (ULONG)tc.threadRecord.spill.cpsr;
|
|
|
|
|
|
|
|
EXT_CHECK(g_ExtSymbols->SetScope(0, NULL, &context, sizeof(context)));
|
|
|
|
}
|
|
|
|
|
2008-03-05 09:52:00 -05:00
|
|
|
EXT_LEAVE(); // Macro includes: return status;
|
|
|
|
}
|