123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- threads.c
- Abstract:
- This module implements thread related debugger extensions.
- Author:
- Evan Green 4-Oct-2012
- Environment:
- Debug Client
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/kernel/arm.h>
- #include <minoca/debug/dbgext.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define MAX_THREAD_NAME 100
- #define MALLOC(_x) malloc(_x)
- #define FREE(_x) free(_x)
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- ExtThread (
- PDEBUGGER_CONTEXT Context,
- PSTR Command,
- ULONG ArgumentCount,
- PSTR *ArgumentValues
- )
- /*++
- Routine Description:
- This routine prints out the contents of a Memory Descriptor List. Arguments
- to the extension are:
- Address - Supplies the address of the MDL.
- Arguments:
- Context - Supplies a pointer to the debugger applicaton context, which is
- an argument to most of the API functions.
- Command - Supplies the subcommand entered. This parameter is unused.
- ArgumentCount - Supplies the number of arguments in the ArgumentValues
- array.
- ArgumentValues - Supplies the values of each argument. This memory will be
- reused when the function returns, so extensions must not touch this
- memory after returning from this call.
- Return Value:
- 0 if the debugger extension command was successful.
- Returns an error code if a failure occurred along the way.
- --*/
- {
- ULONG AddressSize;
- ULONGLONG BasePointer;
- ULONGLONG BasePointerAddress;
- ULONG BytesRead;
- PVOID Data;
- ULONG DataSize;
- ULONGLONG InstructionPointer;
- REGISTERS_UNION LocalRegisters;
- ULONGLONG Preemptions;
- ULONGLONG StackPointer;
- ULONGLONG State;
- INT Status;
- DEBUG_TARGET_INFORMATION TargetInformation;
- ULONGLONG ThreadAddress;
- PSTR ThreadName;
- PTYPE_SYMBOL ThreadType;
- ULONGLONG Value;
- ULONGLONG Yields;
- Data = NULL;
- if ((Command != NULL) || (ArgumentCount != 2)) {
- DbgOut("Usage: !thread <ThreadAddress>.\n"
- " The thread extension prints out the contents of a "
- " thread object.\n"
- " ThreadAddress - Supplies the address of the thread to "
- "dump.\n");
- return EINVAL;
- }
- AddressSize = DbgGetTargetPointerSize(Context);
- memset(&LocalRegisters, 0, sizeof(REGISTERS_UNION));
- //
- // Get the address of the thread and read in the structure.
- //
- Status = DbgEvaluate(Context, ArgumentValues[1], &ThreadAddress);
- if (Status != 0) {
- DbgOut("Error: Unable to evaluate Address parameter.\n");
- goto ExtThreadEnd;
- }
- DbgOut("Dumping Thread at 0x%08I64x ", ThreadAddress);
- Status = DbgReadTypeByName(Context,
- ThreadAddress,
- "KTHREAD",
- &ThreadType,
- &Data,
- &DataSize);
- if (Status != 0) {
- DbgOut("Error: Could not read KTHREAD at 0x%I64x.\n", ThreadAddress);
- goto ExtThreadEnd;
- }
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "Header.Type",
- ThreadAddress,
- Data,
- DataSize,
- &Value);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- if (Value != ObjectThread) {
- DbgOut("Probably not a thread, has an object type %I64d instead of "
- "%d.\n",
- Value,
- ObjectThread);
- Status = EINVAL;
- goto ExtThreadEnd;
- }
- //
- // If the thread has a name, attempt to read that in and print it.
- //
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "Header.Name",
- ThreadAddress,
- Data,
- DataSize,
- &Value);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- if (Value != 0) {
- DbgOut("Name: ");
- ThreadName = MALLOC(MAX_THREAD_NAME + 1);
- if (ThreadName == NULL) {
- DbgOut("Error: Could not allocate memory\n");
- return ENOMEM;;
- }
- memset(ThreadName, 0, MAX_THREAD_NAME + 1);
- Status = DbgReadMemory(Context,
- TRUE,
- Value,
- MAX_THREAD_NAME,
- ThreadName,
- &BytesRead);
- if ((Status != 0) || (BytesRead == 0)) {
- DbgOut("Error: Could not read thread name.\n");
- } else {
- DbgOut("%s\n", ThreadName);
- }
- FREE(ThreadName);
- }
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "OwningProcess",
- ThreadAddress,
- Data,
- DataSize,
- &Value);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- DbgOut("Process 0x%08I64x ID ", Value);
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "ThreadId",
- ThreadAddress,
- Data,
- DataSize,
- &Value);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- DbgOut("%I64d, Flags: ", Value);
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "Flags",
- ThreadAddress,
- Data,
- DataSize,
- &Value);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- DbgOut("0x%I64x", Value);
- if ((Value & THREAD_FLAG_USER_MODE) != 0) {
- DbgOut(" UserMode ");
- } else {
- DbgOut(" KernelMode ");
- }
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "ThreadRoutine",
- ThreadAddress,
- Data,
- DataSize,
- &Value);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- DbgPrintAddressSymbol(Context, Value);
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "ThreadParameter",
- ThreadAddress,
- Data,
- DataSize,
- &Value);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- DbgOut(" (Param 0x%I64x)", Value);
- DbgOut("\nState: ");
- DbgPrintTypeMember(Context,
- ThreadAddress,
- Data,
- DataSize,
- ThreadType,
- "State",
- 0,
- 0);
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "State",
- ThreadAddress,
- Data,
- DataSize,
- &State);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- if (State == ThreadStateBlocked) {
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "WaitBlock",
- ThreadAddress,
- Data,
- DataSize,
- &Value);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- DbgOut(" on 0x%08I64x", Value);
- }
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "ResourceUsage.Preemptions",
- ThreadAddress,
- Data,
- DataSize,
- &Preemptions);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "ResourceUsage.Yields",
- ThreadAddress,
- Data,
- DataSize,
- &Yields);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- DbgOut(" Runs: %I64d, Preemptions %I64d Yields %I64d",
- Preemptions + Yields,
- Preemptions,
- Yields);
- DbgOut("\n\n");
- //
- // To avoid bad memory accesses, avoid printing call stacks for non-living
- // or currently running threads.
- //
- if ((State == ThreadStateRunning) ||
- (State == ThreadStateExited) ||
- (State == ThreadStateFirstTime)) {
- Status = 0;
- goto ExtThreadEnd;
- }
- //
- // Get the target information, including the architecture being debugged.
- //
- Status = DbgGetTargetInformation(Context,
- &TargetInformation,
- sizeof(DEBUG_TARGET_INFORMATION));
- if (Status != 0) {
- DbgOut("Error getting debug target information.\n");
- return 0;
- }
- //
- // Determine the instruction pointer, stack pointer, and base pointer,
- // which are all needed for printing the call stack.
- //
- InstructionPointer = (UINTN)NULL;
- Status = DbgReadIntegerMember(Context,
- ThreadType,
- "KernelStackPointer",
- ThreadAddress,
- Data,
- DataSize,
- &StackPointer);
- if (Status != 0) {
- goto ExtThreadEnd;
- }
- BasePointer = (UINTN)NULL;
- switch (TargetInformation.MachineType) {
- case MACHINE_TYPE_X86:
- Status = DbgReadMemory(Context,
- TRUE,
- StackPointer + 24,
- AddressSize,
- &BasePointer,
- &BytesRead);
- if ((Status != 0) || (BytesRead != AddressSize)) {
- DbgOut("Error: Could not get base pointer at 0x%08I64x.\n",
- StackPointer + 24);
- if (Status == 0) {
- Status = EINVAL;
- }
- return Status;
- }
- Status = DbgReadMemory(Context,
- TRUE,
- StackPointer + 28,
- AddressSize,
- &InstructionPointer,
- &BytesRead);
- if ((Status != 0) || (BytesRead != AddressSize)) {
- DbgOut("Error: Could not get return address at 0x%08I64x.\n",
- StackPointer + 28);
- if (Status == 0) {
- Status = EINVAL;
- }
- return Status;
- }
- LocalRegisters.X86.Eip = InstructionPointer;
- LocalRegisters.X86.Ebp = BasePointer;
- LocalRegisters.X86.Esp = BasePointer;
- break;
- case MACHINE_TYPE_ARM:
- Status = DbgReadMemory(Context,
- TRUE,
- StackPointer + 40,
- AddressSize,
- &InstructionPointer,
- &BytesRead);
- if ((Status != 0) || (BytesRead != AddressSize)) {
- DbgOut("Error: Could not get return address at 0x%08I64x.\n",
- StackPointer + 36);
- if (Status == 0) {
- Status = EINVAL;
- }
- return Status;
- }
- BasePointerAddress = StackPointer + 32;
- if ((InstructionPointer & ARM_THUMB_BIT) != 0) {
- BasePointerAddress = StackPointer + 16;
- }
- Status = DbgReadMemory(Context,
- TRUE,
- BasePointerAddress,
- AddressSize,
- &BasePointer,
- &BytesRead);
- if ((Status != 0) || (BytesRead != AddressSize)) {
- DbgOut("Error: Could not get base pointer at 0x%08I64x.\n",
- BasePointerAddress);
- if (Status == 0) {
- Status = EINVAL;
- }
- return Status;
- }
- LocalRegisters.Arm.R15Pc = InstructionPointer;
- LocalRegisters.Arm.R11Fp = BasePointer;
- LocalRegisters.Arm.R7 = BasePointer;
- LocalRegisters.Arm.R13Sp = BasePointer;
- break;
- default:
- DbgOut("Error: Unknown machine type %d.\n",
- TargetInformation.MachineType);
- return EINVAL;
- }
- //
- // Print the call stack for the given thread.
- //
- DbgPrintCallStack(Context, &LocalRegisters, FALSE);
- Status = 0;
- ExtThreadEnd:
- if (Data != NULL) {
- free(Data);
- }
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|