From 87bdedbed25826408bebf22b2c9a0ff1a5bfe1ca Mon Sep 17 00:00:00 2001 From: Gregor Anich Date: Thu, 26 Aug 2004 16:04:50 +0000 Subject: [PATCH] Change stabs handling of KDB - does no longer allocate a block of memory for each stub entry, instead each .sym file is loaded completely into (non-paged) memory. svn path=/trunk/; revision=10692 --- reactos/ntoskrnl/Makefile | 4 +- reactos/ntoskrnl/dbg/dbgctrl.c | 4 +- reactos/ntoskrnl/dbg/i386/i386-dis.c | 4 +- reactos/ntoskrnl/dbg/kdb.c | 12 +- reactos/ntoskrnl/dbg/kdb.h | 44 +- reactos/ntoskrnl/dbg/kdb_stabs.c | 966 ++--------------------- reactos/ntoskrnl/dbg/kdb_stabs.h | 69 ++ reactos/ntoskrnl/dbg/kdb_symbols.c | 991 ++++++++++++++++++++++++ reactos/ntoskrnl/dbg/profile.c | 4 +- reactos/ntoskrnl/include/internal/kd.h | 71 +- reactos/ntoskrnl/include/internal/ldr.h | 18 - reactos/ntoskrnl/ke/i386/exp.c | 3 +- 12 files changed, 1227 insertions(+), 963 deletions(-) create mode 100644 reactos/ntoskrnl/dbg/kdb_stabs.h create mode 100644 reactos/ntoskrnl/dbg/kdb_symbols.c diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index d6c270b914c..a99754f1e44 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.139 2004/08/15 16:38:59 chorns Exp $ +# $Id: Makefile,v 1.140 2004/08/26 16:04:49 blight Exp $ # # ReactOS Operating System # @@ -33,7 +33,7 @@ endif ifeq ($(KDBG), 1) OBJECTS_KDBG := dbg/kdb.o dbg/kdb_serial.o dbg/kdb_keyboard.o dbg/rdebug.o \ - dbg/i386/kdb_help.o dbg/kdb_stabs.o dbg/profile.o \ + dbg/i386/kdb_help.o dbg/kdb_stabs.o dbg/kdb_symbols.o dbg/profile.o \ ../dk/w32/lib/kjs.a dbg/i386/i386-dis.o CFLAGS += -I../lib/kjs/include preall: all diff --git a/reactos/ntoskrnl/dbg/dbgctrl.c b/reactos/ntoskrnl/dbg/dbgctrl.c index b678b140671..ac5fdb63afd 100644 --- a/reactos/ntoskrnl/dbg/dbgctrl.c +++ b/reactos/ntoskrnl/dbg/dbgctrl.c @@ -63,10 +63,8 @@ NtSystemDebugControl(DEBUG_CONTROL_CODE ControlCode, case DebugQuerySpecialCalls: case DebugDbgBreakPoint: break; -#ifdef KDBG case DebugDbgLoadSymbols: - KdbLdrLoadUserModuleSymbols((PLDR_MODULE) InputBuffer); -#endif /* KDBG */ + KDB_LOADUSERMODULE_HOOK((PLDR_MODULE) InputBuffer); break; default: break; diff --git a/reactos/ntoskrnl/dbg/i386/i386-dis.c b/reactos/ntoskrnl/dbg/i386/i386-dis.c index c7a1fdeffd9..851009bcc23 100644 --- a/reactos/ntoskrnl/dbg/i386/i386-dis.c +++ b/reactos/ntoskrnl/dbg/i386/i386-dis.c @@ -35,7 +35,7 @@ extern void DbgPrint(const char *format, ...); #define sprintf_vma(BUF, VMA) sprintf(BUF, "0x%X", VMA) #define _setjmp setjmp unsigned int -KdbPrintAddress(void* address); +KdbSymPrintAddress(void* address); struct disassemble_info; @@ -79,7 +79,7 @@ KdbMemoryError(int Status, unsigned int Addr, void static KdbPrintAddressInCode(unsigned int Addr, struct disassemble_info * Ignored) { - if (!KdbPrintAddress((void*)Addr)) + if (!KdbSymPrintAddress((void*)Addr)) { DbgPrint("<0x%X>", Addr); } diff --git a/reactos/ntoskrnl/dbg/kdb.c b/reactos/ntoskrnl/dbg/kdb.c index 9010f8412a2..092182d9f7a 100644 --- a/reactos/ntoskrnl/dbg/kdb.c +++ b/reactos/ntoskrnl/dbg/kdb.c @@ -1,6 +1,6 @@ /* * ReactOS kernel - * Copyright (C) 2001 David Welch + * Copyright (C) 2001-2004 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: kdb.c,v 1.28 2004/08/15 16:39:00 chorns Exp $ +/* $Id: kdb.c,v 1.29 2004/08/26 16:04:49 blight Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/dbg/kdb.c @@ -741,7 +741,7 @@ DbgDisassemble(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf) } for (i = 0; i < 10; i++) { - if (!KdbPrintAddress((PVOID)Address)) + if (!KdbSymPrintAddress((PVOID)Address)) { DbgPrint("<%x>", Address); } @@ -832,7 +832,7 @@ DbgPrintBackTrace(PULONG Frame, ULONG StackBase, ULONG StackLimit) while (Frame != NULL && (ULONG)Frame >= StackLimit && (ULONG)Frame < StackBase) { - KdbPrintAddress((PVOID)Frame[1]); + KdbSymPrintAddress((PVOID)Frame[1]); DbgPrint("\n"); Frame = (PULONG)Frame[0]; i++; @@ -852,7 +852,7 @@ DbgAddrCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME tf) if (Argc == 2) { Addr = (PVOID)strtoul(Argv[1], NULL, 0); - KdbPrintAddress(Addr); + KdbSymPrintAddress(Addr); } return(1); @@ -1499,7 +1499,7 @@ KdbMainLoop(PKTRAP_FRAME Tf) } else { - if (!KdbPrintAddress((PVOID)Tf->Eip)) + if (!KdbSymPrintAddress((PVOID)Tf->Eip)) { DbgPrint("<%x>", Tf->Eip); } diff --git a/reactos/ntoskrnl/dbg/kdb.h b/reactos/ntoskrnl/dbg/kdb.h index 9383b078c01..fb3f1d8b440 100644 --- a/reactos/ntoskrnl/dbg/kdb.h +++ b/reactos/ntoskrnl/dbg/kdb.h @@ -1,12 +1,46 @@ #define NTOS_MODE_KERNEL #include +typedef struct _KDB_MODULE_INFO +{ + WCHAR Name[256]; + ULONG_PTR Base; + ULONG Size; + PIMAGE_SYMBOL_INFO SymbolInfo; +} KDB_MODULE_INFO, *PKDB_MODULE_INFO; + +/* from kdb_symbols.c */ + +BOOLEAN +KdbpSymFindModuleByAddress(IN PVOID Address, + OUT PKDB_MODULE_INFO pInfo); + +BOOLEAN +KdbpSymFindModuleByName(IN LPCWSTR Name, + OUT PKDB_MODULE_INFO pInfo); + +BOOLEAN +KdbpSymFindModuleByIndex(IN INT Index, + OUT PKDB_MODULE_INFO pInfo); + +BOOLEAN +KdbSymPrintAddress(IN PVOID Address); + NTSTATUS -LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, - IN ULONG_PTR RelativeAddress, - OUT PULONG LineNumber, - OUT PCH FileName OPTIONAL, - OUT PCH FunctionName OPTIONAL); +KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, + IN ULONG_PTR RelativeAddress, + OUT PULONG LineNumber OPTIONAL, + OUT PCH FileName OPTIONAL, + OUT PCH FunctionName OPTIONAL); + +BOOLEAN +KdbpSymGetSourceAddress(IN PIMAGE_SYMBOL_INFO SymbolInfo, + IN PCHAR FileName, + IN ULONG LineNumber OPTIONAL, + IN PCHAR FuncName OPTIONAL, + OUT PVOID *Address); + +/* other functions */ CHAR KdbTryGetCharKeyboard(PULONG ScanCode); diff --git a/reactos/ntoskrnl/dbg/kdb_stabs.c b/reactos/ntoskrnl/dbg/kdb_stabs.c index e31a53694ee..c8a918e8fd5 100644 --- a/reactos/ntoskrnl/dbg/kdb_stabs.c +++ b/reactos/ntoskrnl/dbg/kdb_stabs.c @@ -1,6 +1,6 @@ /* * ReactOS kernel - * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team + * Copyright (C) 2004 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,925 +18,101 @@ */ /* * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ke/i386/exp.c - * PURPOSE: Handling exceptions - * PROGRAMMER: David Welch (welch@cwcom.net) + * FILE: ntoskrnl/dbg/kdb_stabs.c + * PURPOSE: Stabs functions... + * PROGRAMMER: Gregor Anich (blight@blight.eu.org) * REVISION HISTORY: - * ??/??/??: Created + * 2004/06/27: Created */ -/* INCLUDES *****************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include #define NDEBUG #include -/* GLOBALS ******************************************************************/ - -typedef struct _SYMBOLFILE_HEADER { - unsigned long StabsOffset; - unsigned long StabsLength; - unsigned long StabstrOffset; - unsigned long StabstrLength; -} SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER; - -typedef struct _IMAGE_SYMBOL_INFO_CACHE { - LIST_ENTRY ListEntry; - UNICODE_STRING FullName; - PVOID FileBuffer; - PVOID SymbolsBase; - ULONG SymbolsLength; - PVOID SymbolStringsBase; - ULONG SymbolStringsLength; -} IMAGE_SYMBOL_INFO_CACHE, *PIMAGE_SYMBOL_INFO_CACHE; +#include "kdb.h" +#include "kdb_stabs.h" -typedef struct _STAB_ENTRY { - unsigned long n_strx; /* index into string table of name */ - unsigned char n_type; /* type of symbol */ - unsigned char n_other; /* misc info (usually empty) */ - unsigned short n_desc; /* description field */ - unsigned long n_value; /* value of symbol */ -} _STAB_ENTRY, *PSTAB_ENTRY; - -/* - * Desc - Line number - * Value - Relative virtual address +/*! \brief Find a stab entry... + * + * Looks through the stab for an entry which matches the specified criteria. + * + * \param SymbolInfo Pointer to the symbol info. + * \param Type Type of stab entry to look for. + * \param RelativeAddress Relative address of stab to look for. + * \param StartEntry Starting stab entry. + * + * \returns Pointer to a STAB_ENTRY + * \retval NULL No entry found. */ -#define N_FUN 0x24 - -/* - * Desc - Line number - * Value - Relative virtual address - */ -#define N_SLINE 0x44 - -/* - * String - First containing a '/' is the compillation directory (CD) - * Not containing a '/' is a source file relative to CD - */ -#define N_SO 0x64 - -static LIST_ENTRY SymbolListHead; -static KSPIN_LOCK SymbolListLock; - -NTSTATUS -LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, - IN ULONG_PTR RelativeAddress, - OUT PULONG LineNumber, - OUT PCH FileName OPTIONAL, - OUT PCH FunctionName OPTIONAL); - -VOID -KdbLdrUnloadModuleSymbols(PIMAGE_SYMBOL_INFO SymbolInfo); - -/* FUNCTIONS ****************************************************************/ - -BOOLEAN -KdbPrintUserAddress(PVOID address) +PSTAB_ENTRY +KdbpStabFindEntry(IN PIMAGE_SYMBOL_INFO SymbolInfo, + IN CHAR Type, + IN PVOID RelativeAddress OPTIONAL, + IN PSTAB_ENTRY StartEntry OPTIONAL) { - PLIST_ENTRY current_entry; - PLDR_MODULE current; - PEPROCESS CurrentProcess; - PPEB Peb = NULL; - ULONG_PTR RelativeAddress; - NTSTATUS Status; - ULONG LineNumber; - CHAR FileName[256]; - CHAR FunctionName[256]; - - CurrentProcess = PsGetCurrentProcess(); - if (NULL != CurrentProcess) - { - Peb = CurrentProcess->Peb; - } - - if (NULL == Peb) - { - DbgPrint("<%x>", address); - return(TRUE); - } - - current_entry = Peb->Ldr->InLoadOrderModuleList.Flink; - - while (current_entry != &Peb->Ldr->InLoadOrderModuleList && - current_entry != NULL) - { - current = - CONTAINING_RECORD(current_entry, LDR_MODULE, InLoadOrderModuleList); - - if (address >= (PVOID)current->BaseAddress && - address < (PVOID)((char*)current->BaseAddress + current->SizeOfImage)) - { - RelativeAddress = (ULONG_PTR) address - (ULONG_PTR)current->BaseAddress; - Status = LdrGetAddressInformation(¤t->SymbolInfo, - RelativeAddress, - &LineNumber, - FileName, - FunctionName); - if (NT_SUCCESS(Status)) - { - DbgPrint("<%wZ: %x (%s:%d (%s))>", - ¤t->BaseDllName, RelativeAddress, FileName, LineNumber, FunctionName); - } - else - { - DbgPrint("<%wZ: %x>", ¤t->BaseDllName, RelativeAddress); - } - return(TRUE); - } - - current_entry = current_entry->Flink; - } - return(FALSE); -} - -BOOLEAN -KdbPrintAddress(PVOID address) -{ - PLIST_ENTRY current_entry; - MODULE_TEXT_SECTION* current; - extern LIST_ENTRY ModuleTextListHead; - ULONG_PTR RelativeAddress; - NTSTATUS Status; - ULONG LineNumber; - CHAR FileName[256]; - CHAR FunctionName[256]; - - current_entry = ModuleTextListHead.Flink; - - while (current_entry != &ModuleTextListHead && - current_entry != NULL) - { - current = - CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry); - - if (address >= (PVOID)current->Base && - address < (PVOID)(current->Base + current->Length)) - { - RelativeAddress = (ULONG_PTR) address - current->Base; - Status = LdrGetAddressInformation(¤t->SymbolInfo, - RelativeAddress, - &LineNumber, - FileName, - FunctionName); - if (NT_SUCCESS(Status)) - { - DbgPrint("<%ws: %x (%s:%d (%s))>", - current->Name, RelativeAddress, FileName, LineNumber, FunctionName); - } - else - { - DbgPrint("<%ws: %x>", current->Name, RelativeAddress); - } - return(TRUE); - } - current_entry = current_entry->Flink; - } - return KdbPrintUserAddress(address); -} - -VOID -KdbFreeSymbolsProcess(PEPROCESS Process) -{ - PLIST_ENTRY CurrentEntry; - PLDR_MODULE Current; - PIMAGE_SYMBOL_INFO SymbolInfo; - PEPROCESS CurrentProcess; - PPEB Peb; - - CurrentProcess = PsGetCurrentProcess(); - if (CurrentProcess != Process) - { - KeAttachProcess(Process); - } - Peb = Process->Peb; - assert (Peb); - assert (Peb->Ldr); - - CurrentEntry = Peb->Ldr->InLoadOrderModuleList.Flink; - while (CurrentEntry != &Peb->Ldr->InLoadOrderModuleList && - CurrentEntry != NULL) - { - Current = CONTAINING_RECORD(CurrentEntry, LDR_MODULE, - InLoadOrderModuleList); - - SymbolInfo = &Current->SymbolInfo; - KdbLdrUnloadModuleSymbols(SymbolInfo); - - CurrentEntry = CurrentEntry->Flink; - } - if (CurrentProcess != Process) - { - KeDetachProcess(); - } -} - -VOID -KdbLdrInit(MODULE_TEXT_SECTION* NtoskrnlTextSection, - MODULE_TEXT_SECTION* LdrHalTextSection) -{ - RtlZeroMemory(&NtoskrnlTextSection->SymbolInfo, - sizeof(NtoskrnlTextSection->SymbolInfo)); - NtoskrnlTextSection->SymbolInfo.ImageBase = - NtoskrnlTextSection->OptionalHeader->ImageBase; - NtoskrnlTextSection->SymbolInfo.ImageSize = NtoskrnlTextSection->Length; - - RtlZeroMemory(&LdrHalTextSection->SymbolInfo, - sizeof(LdrHalTextSection->SymbolInfo)); - LdrHalTextSection->SymbolInfo.ImageBase = - LdrHalTextSection->OptionalHeader->ImageBase; - LdrHalTextSection->SymbolInfo.ImageSize = LdrHalTextSection->Length; - - InitializeListHead(&SymbolListHead); - KeInitializeSpinLock(&SymbolListLock); -} - -VOID -LdrpParseImageSymbols(PIMAGE_SYMBOL_INFO SymbolInfo) -/* Note: It is important that the symbol strings buffer not be released after - this function is called because the strings are still referenced */ -{ - PSYMBOL CurrentFileNameSymbol; - PSYMBOL CurrentFunctionSymbol; - PSYMBOL CurrentLineNumberSymbol; - PSYMBOL Symbol; - PSTAB_ENTRY StabEntry; + PSTAB_ENTRY StabEntry, BestStabEntry = NULL; PVOID StabsEnd; - PCHAR String; - ULONG_PTR FunRelativeAddress; - ULONG FunLineNumber; - ULONG_PTR ImageBase; + ULONG_PTR AddrFound = 0; - assert(SymbolInfo); - - DPRINT("Parsing symbols.\n"); - - SymbolInfo->FileNameSymbols.SymbolCount = 0; - SymbolInfo->FileNameSymbols.Symbols = NULL; - SymbolInfo->FunctionSymbols.SymbolCount = 0; - SymbolInfo->FunctionSymbols.Symbols = NULL; - SymbolInfo->LineNumberSymbols.SymbolCount = 0; - SymbolInfo->LineNumberSymbols.Symbols = NULL; - StabsEnd = SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength; - StabEntry = (PSTAB_ENTRY) SymbolInfo->SymbolsBase; - ImageBase = SymbolInfo->ImageBase; - FunRelativeAddress = 0; - FunLineNumber = 0; - CurrentFileNameSymbol = NULL; - CurrentFunctionSymbol = NULL; - CurrentLineNumberSymbol = NULL; - - DPRINT("Starting Parse: %08x to %08x\n", StabEntry, StabsEnd); - - while ((ULONG_PTR) StabEntry < (ULONG_PTR) StabsEnd) + StabEntry = SymbolInfo->SymbolsBase; + StabsEnd = (PVOID)((ULONG_PTR)SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength); + if (StartEntry != NULL) { - Symbol = NULL; + assert((ULONG_PTR)StartEntry >= (ULONG_PTR)StabEntry); + if ((ULONG_PTR)StartEntry >= (ULONG_PTR)StabsEnd) + return NULL; + StabEntry = StartEntry; + } - if (StabEntry->n_type == N_FUN) + for (; (ULONG_PTR)StabEntry < (ULONG_PTR)StabsEnd; StabEntry++) + { + ULONG_PTR SymbolRelativeAddress; + + if (StabEntry->n_type != Type) + continue; + + if (RelativeAddress != NULL) { - if (StabEntry->n_desc > 0) + if (StabEntry->n_value < (ULONG_PTR)SymbolInfo->ImageBase) + continue; + if (StabEntry->n_value >= ((ULONG_PTR)SymbolInfo->ImageBase + SymbolInfo->ImageSize)) + continue; + + SymbolRelativeAddress = StabEntry->n_value - (ULONG_PTR)SymbolInfo->ImageBase; + if ((SymbolRelativeAddress <= (ULONG_PTR)RelativeAddress) && + (SymbolRelativeAddress > AddrFound)) { - assert(StabEntry->n_value >= ImageBase); - - FunRelativeAddress = StabEntry->n_value - ImageBase; - FunLineNumber = StabEntry->n_desc; - - Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL)); - assert(Symbol); - Symbol->Next = NULL; - Symbol->SymbolType = ST_FUNCTION; - Symbol->RelativeAddress = FunRelativeAddress; - Symbol->LineNumber = FunLineNumber; - String = (PCHAR)SymbolInfo->SymbolStringsBase + StabEntry->n_strx; - RtlInitAnsiString(&Symbol->Name, String); - -#ifdef STABS_DEBUG - DPRINT("FUN found. '%s' %d @ %x\n", - Symbol->Name.Buffer, FunLineNumber, FunRelativeAddress); -#endif + AddrFound = SymbolRelativeAddress; + BestStabEntry = StabEntry; } } - else if (StabEntry->n_type == N_SLINE) - { - Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL)); - assert(Symbol); - Symbol->Next = NULL; - Symbol->SymbolType = ST_LINENUMBER; - Symbol->RelativeAddress = FunRelativeAddress + StabEntry->n_value; - Symbol->LineNumber = StabEntry->n_desc; - -#ifdef STABS_DEBUG - DPRINT("SLINE found. %d @ %x\n", - Symbol->LineNumber, Symbol->RelativeAddress); -#endif - } - else if (StabEntry->n_type == N_SO) - { - Symbol = ExAllocatePool(NonPagedPool, sizeof(SYMBOL)); - assert(Symbol); - Symbol->Next = NULL; - Symbol->SymbolType = ST_FILENAME; - Symbol->RelativeAddress = StabEntry->n_value - ImageBase; - Symbol->LineNumber = 0; - String = (PCHAR)SymbolInfo->SymbolStringsBase + StabEntry->n_strx; - RtlInitAnsiString(&Symbol->Name, String); - -#ifdef STABS_DEBUG - DPRINT("SO found. '%s' @ %x\n", - Symbol->Name.Buffer, Symbol->RelativeAddress); -#endif - } - - if (Symbol != NULL) - { - switch (Symbol->SymbolType) - { - case ST_FILENAME: - if (SymbolInfo->FileNameSymbols.Symbols == NULL) - SymbolInfo->FileNameSymbols.Symbols = Symbol; - else - CurrentFileNameSymbol->Next = Symbol; - - CurrentFileNameSymbol = Symbol; - - SymbolInfo->FileNameSymbols.SymbolCount++; - break; - case ST_FUNCTION: - if (SymbolInfo->FunctionSymbols.Symbols == NULL) - SymbolInfo->FunctionSymbols.Symbols = Symbol; - else - CurrentFunctionSymbol->Next = Symbol; - - CurrentFunctionSymbol = Symbol; - - SymbolInfo->FunctionSymbols.SymbolCount++; - break; - case ST_LINENUMBER: - if (SymbolInfo->LineNumberSymbols.Symbols == NULL) - SymbolInfo->LineNumberSymbols.Symbols = Symbol; - else - CurrentLineNumberSymbol->Next = Symbol; - - CurrentLineNumberSymbol = Symbol; - - SymbolInfo->LineNumberSymbols.SymbolCount++; - break; - } - } - - StabEntry++; - } -} - -static NTSTATUS -LdrpGetFileName(IN PIMAGE_SYMBOL_INFO SymbolInfo, - IN ULONG_PTR RelativeAddress, - OUT PCH FileName) -{ - PSYMBOL NextSymbol; - ULONG_PTR NextAddress; - ULONG_PTR AddrFound = 0; - PSYMBOL Symbol; - - Symbol = SymbolInfo->FileNameSymbols.Symbols; - while (Symbol != NULL) - { - NextSymbol = Symbol->Next; - if (NextSymbol != NULL) - NextAddress = NextSymbol->RelativeAddress; else - NextAddress = SymbolInfo->ImageSize; - - DPRINT("FN SEARCH: Type %d RelativeAddress %x >= Symbol->RelativeAddress %x < NextAddress %x\n", - Symbol->SymbolType, RelativeAddress, Symbol->RelativeAddress, NextAddress); - - if ((Symbol->SymbolType == ST_FILENAME) && - (RelativeAddress >= Symbol->RelativeAddress) && - (RelativeAddress < NextAddress) && - Symbol->RelativeAddress > AddrFound) { - DPRINT("FN found\n"); - strcpy(FileName, Symbol->Name.Buffer); - AddrFound = Symbol->RelativeAddress; + BestStabEntry = StabEntry; + break; } - Symbol = NextSymbol; } - DPRINT("FN not found\n"); - - return AddrFound ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; -} - -static NTSTATUS -LdrpGetFunctionName(IN PIMAGE_SYMBOL_INFO SymbolInfo, - IN ULONG_PTR RelativeAddress, - OUT PCH FunctionName) -{ - PSYMBOL NextSymbol; - ULONG_PTR NextAddress; - ULONG_PTR AddrFound = 0; - PSYMBOL Symbol; - - Symbol = SymbolInfo->FunctionSymbols.Symbols; - while (Symbol != NULL) - { - NextSymbol = Symbol->Next; - if (NextSymbol != NULL) - NextAddress = NextSymbol->RelativeAddress; - else - NextAddress = SymbolInfo->ImageSize; - -#ifdef STABS_DEBUG - DPRINT("FUN SEARCH: Type %d RelativeAddress %x >= Symbol->RelativeAddress %x < NextAddress %x\n", - Symbol->SymbolType, RelativeAddress, Symbol->RelativeAddress, NextAddress); -#endif - - if ((Symbol->SymbolType == ST_FUNCTION) && - (RelativeAddress >= Symbol->RelativeAddress) && - (RelativeAddress < NextAddress) && - Symbol->RelativeAddress > AddrFound) - { - PCHAR ExtraInfo; - ULONG Length; - - DPRINT("FUN found\n"); - - /* Remove the extra information from the function name */ - ExtraInfo = strchr(Symbol->Name.Buffer, ':'); - if (ExtraInfo != NULL) - Length = ExtraInfo - Symbol->Name.Buffer; - else - Length = strlen(Symbol->Name.Buffer); - - strncpy(FunctionName, Symbol->Name.Buffer, Length); - FunctionName[Length]=0; - AddrFound = Symbol->RelativeAddress; - } - Symbol = NextSymbol; - } - - DPRINT("FUN not found\n"); - - return AddrFound ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; -} - -static NTSTATUS -LdrpGetLineNumber(IN PIMAGE_SYMBOL_INFO SymbolInfo, - IN ULONG_PTR RelativeAddress, - OUT PULONG LineNumber) -{ - PSYMBOL NextSymbol; - ULONG_PTR NextAddress; - ULONG_PTR AddrFound = 0; - PSYMBOL Symbol; - - Symbol = SymbolInfo->LineNumberSymbols.Symbols; - while (Symbol != NULL) - { - NextSymbol = Symbol->Next; - if (NextSymbol != NULL) - NextAddress = NextSymbol->RelativeAddress; - else - NextAddress = SymbolInfo->ImageSize; - -#ifdef STABS_DEBUG - DPRINT("LN SEARCH: Type %d RelativeAddress %x >= Symbol->RelativeAddress %x < NextAddress %x\n", - Symbol->SymbolType, RelativeAddress, Symbol->RelativeAddress, NextAddress); -#endif - - if ((Symbol->SymbolType == ST_LINENUMBER) && - (RelativeAddress >= Symbol->RelativeAddress) && - (RelativeAddress < NextAddress) && - Symbol->RelativeAddress > AddrFound) - { - DPRINT("LN found\n"); - *LineNumber = Symbol->LineNumber; - AddrFound = Symbol->RelativeAddress; - } - Symbol = NextSymbol; - } - - DPRINT("LN not found\n"); - - return AddrFound ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; -} - -NTSTATUS -LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, - IN ULONG_PTR RelativeAddress, - OUT PULONG LineNumber, - OUT PCH FileName OPTIONAL, - OUT PCH FunctionName OPTIONAL) -{ - NTSTATUS Status; - - *LineNumber = 0; - - DPRINT("RelativeAddress %p\n", RelativeAddress); - -#ifdef PEDANTIC_STABS - if (RelativeAddress >= SymbolInfo->ImageSize) - { - DPRINT("Address is not within .text section. RelativeAddress %p Length 0x%x\n", - RelativeAddress, SymbolInfo->ImageSize); - return STATUS_UNSUCCESSFUL; - } -#endif - - if (!AreSymbolsParsed(SymbolInfo)) - { - LdrpParseImageSymbols(SymbolInfo); - } - - Status = LdrpGetLineNumber(SymbolInfo, RelativeAddress, LineNumber); - if (!NT_SUCCESS(Status)) - { - DPRINT("LdrpGetLineNumber failed (%08x)\n", Status); - return Status; - } - - if (FileName) - { - Status = LdrpGetFileName(SymbolInfo, RelativeAddress, FileName); - if (!NT_SUCCESS(Status)) - { - strcpy(FileName, ""); - } - } - - if (FunctionName) - { - Status = LdrpGetFunctionName(SymbolInfo, RelativeAddress, FunctionName); - if (!NT_SUCCESS(Status)) - { - strcpy(FunctionName, ""); - } - } - - return STATUS_SUCCESS; -} - -VOID -LdrpLoadModuleSymbols(PUNICODE_STRING FileName, - PIMAGE_SYMBOL_INFO SymbolInfo) -{ - FILE_STANDARD_INFORMATION FileStdInfo; - OBJECT_ATTRIBUTES ObjectAttributes; - WCHAR TmpFileName[MAX_PATH]; - UNICODE_STRING SymFileName; - LPWSTR Start, Ext; - HANDLE FileHandle; - PVOID FileBuffer; - NTSTATUS Status; - ULONG Length; - IO_STATUS_BLOCK IoStatusBlock; - PSYMBOLFILE_HEADER SymbolFileHeader; - - /* Get the path to the symbol store */ - wcscpy(TmpFileName, L"\\SystemRoot\\symbols\\"); - - /* Get the symbol filename from the module name */ - Start = wcsrchr(FileName->Buffer, L'\\'); - if (Start == NULL) - Start = FileName->Buffer; + if (BestStabEntry == NULL) + DPRINT("StabEntry not found!\n"); else - Start++; + DPRINT("StabEntry found!\n"); - Ext = wcsrchr(FileName->Buffer, L'.'); - if (Ext != NULL) - Length = Ext - Start; - else - Length = wcslen(Start); - - wcsncat(TmpFileName, Start, Length); - wcscat(TmpFileName, L".sym"); - RtlInitUnicodeString(&SymFileName, TmpFileName); - - /* Open the file */ - InitializeObjectAttributes(&ObjectAttributes, - &SymFileName, - 0, - NULL, - NULL); - - DPRINT("Attempting to open symbols: %wZ\n", &SymFileName); - - Status = ZwOpenFile(&FileHandle, - FILE_ALL_ACCESS, - &ObjectAttributes, - &IoStatusBlock, - 0, - FILE_SYNCHRONOUS_IO_NONALERT|FILE_NO_INTERMEDIATE_BUFFERING); - if (!NT_SUCCESS(Status)) - { - DPRINT("Could not open symbol file: %wZ\n", &SymFileName); - return; - } - - DPRINT("Loading symbols from %wZ...\n", &SymFileName); - - /* Get the size of the file */ - Status = ZwQueryInformationFile(FileHandle, - &IoStatusBlock, - &FileStdInfo, - sizeof(FileStdInfo), - FileStandardInformation); - if (!NT_SUCCESS(Status)) - { - DPRINT("Could not get file size\n"); - ZwClose(FileHandle); - return; - } - - DPRINT("Symbol file is %08x bytes\n", FileStdInfo.EndOfFile.u.LowPart); - - /* Allocate nonpageable memory for symbol file */ - FileBuffer = ExAllocatePool(NonPagedPool, - FileStdInfo.AllocationSize.u.LowPart); - - if (FileBuffer == NULL) - { - DPRINT("Could not allocate memory for symbol file\n"); - ZwClose(FileHandle); - return; - } - - /* Load file into memory chunk */ - Status = ZwReadFile(FileHandle, - 0, 0, 0, - &IoStatusBlock, - FileBuffer, - FileStdInfo.EndOfFile.u.LowPart, - 0, 0); - if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) - { - DPRINT("Could not read symbol file into memory (Status 0x%x)\n", Status); - ExFreePool(FileBuffer); - ZwClose(FileHandle); - return; - } - - ZwClose(FileHandle); - - DPRINT("Symbols loaded.\n"); - - SymbolFileHeader = (PSYMBOLFILE_HEADER) FileBuffer; - SymbolInfo->FileBuffer = FileBuffer; - SymbolInfo->SymbolsBase = FileBuffer + SymbolFileHeader->StabsOffset; - SymbolInfo->SymbolsLength = SymbolFileHeader->StabsLength; - SymbolInfo->SymbolStringsBase = FileBuffer + SymbolFileHeader->StabstrOffset; - SymbolInfo->SymbolStringsLength = SymbolFileHeader->StabstrLength; - - DPRINT("Installed stabs: %wZ (%08x-%08x,%08x)\n", - FileName, - SymbolInfo->SymbolsBase, - SymbolInfo->SymbolsLength + SymbolInfo->SymbolsBase, - SymbolInfo->SymbolStringsBase); + return BestStabEntry; } -VOID -KdbLdrUnloadModuleSymbols(PIMAGE_SYMBOL_INFO SymbolInfo) -{ - PSYMBOL NextSymbol; - PSYMBOL Symbol; - - DPRINT("Unloading symbols\n"); - - if (SymbolInfo != NULL) - { - Symbol = SymbolInfo->FileNameSymbols.Symbols; - while (Symbol != NULL) - { - NextSymbol = Symbol->Next; - RtlFreeAnsiString(&Symbol->Name); - ExFreePool(Symbol); - Symbol = NextSymbol; - } - - SymbolInfo->FileNameSymbols.SymbolCount = 0; - SymbolInfo->FileNameSymbols.Symbols = NULL; - - Symbol = SymbolInfo->FunctionSymbols.Symbols; - while (Symbol != NULL) - { - NextSymbol = Symbol->Next; - RtlFreeAnsiString(&Symbol->Name); - ExFreePool(Symbol); - Symbol = NextSymbol; - } - - SymbolInfo->FunctionSymbols.SymbolCount = 0; - SymbolInfo->FunctionSymbols.Symbols = NULL; - - Symbol = SymbolInfo->LineNumberSymbols.Symbols; - while (Symbol != NULL) - { - NextSymbol = Symbol->Next; - RtlFreeAnsiString(&Symbol->Name); - ExFreePool(Symbol); - Symbol = NextSymbol; - } - - SymbolInfo->LineNumberSymbols.SymbolCount = 0; - SymbolInfo->LineNumberSymbols.Symbols = NULL; -#if 0 - /* Don't free buffers because we cache symbol buffers - (eg. they are shared across processes) */ - /* FIXME: We can free them if we do reference counting */ - if (SymbolInfo->FileBuffer != NULL) - { - ExFreePool(SymbolInfo->FileBuffer); - SymbolInfo->FileBuffer = NULL; - SymbolInfo->SymbolsBase = NULL; - SymbolInfo->SymbolsLength = 0; - } -#endif - } -} - - -PIMAGE_SYMBOL_INFO_CACHE -LdrpLookupUserSymbolInfo(PLDR_MODULE LdrModule) -{ - PIMAGE_SYMBOL_INFO_CACHE Current; - PLIST_ENTRY CurrentEntry; - KIRQL Irql; - - DPRINT("Searching symbols for %S\n", LdrModule->FullDllName.Buffer); - - KeAcquireSpinLock(&SymbolListLock, &Irql); - - CurrentEntry = SymbolListHead.Flink; - while (CurrentEntry != (&SymbolListHead)) - { - Current = CONTAINING_RECORD(CurrentEntry, IMAGE_SYMBOL_INFO_CACHE, ListEntry); - - if (RtlEqualUnicodeString(&Current->FullName, &LdrModule->FullDllName, TRUE)) - { - KeReleaseSpinLock(&SymbolListLock, Irql); - return Current; - } - - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&SymbolListLock, Irql); - - return(NULL); -} - -VOID -KdbLdrLoadUserModuleSymbols(PLDR_MODULE LdrModule) -{ - PIMAGE_SYMBOL_INFO_CACHE CacheEntry; - - DPRINT("LdrModule %p\n", LdrModule); - - RtlZeroMemory(&LdrModule->SymbolInfo, sizeof(LdrModule->SymbolInfo)); - LdrModule->SymbolInfo.ImageBase = (ULONG_PTR) LdrModule->BaseAddress; - LdrModule->SymbolInfo.ImageSize = LdrModule->SizeOfImage; - - CacheEntry = LdrpLookupUserSymbolInfo(LdrModule); - if (CacheEntry != NULL) - { - DPRINT("Symbol cache hit for %S\n", CacheEntry->FullName.Buffer); - - LdrModule->SymbolInfo.FileBuffer = CacheEntry->FileBuffer; - LdrModule->SymbolInfo.SymbolsBase = CacheEntry->SymbolsBase; - LdrModule->SymbolInfo.SymbolsLength = CacheEntry->SymbolsLength; - LdrModule->SymbolInfo.SymbolStringsBase = CacheEntry->SymbolStringsBase; - LdrModule->SymbolInfo.SymbolStringsLength = CacheEntry->SymbolStringsLength; - } - else - { - CacheEntry = ExAllocatePool(NonPagedPool, sizeof(IMAGE_SYMBOL_INFO_CACHE)); - assert(CacheEntry); - RtlZeroMemory(CacheEntry, sizeof(IMAGE_SYMBOL_INFO_CACHE)); - - RtlCreateUnicodeString(&CacheEntry->FullName, LdrModule->FullDllName.Buffer); - assert(CacheEntry->FullName.Buffer); - LdrpLoadModuleSymbols(&LdrModule->FullDllName, &LdrModule->SymbolInfo); - CacheEntry->FileBuffer = LdrModule->SymbolInfo.FileBuffer; - CacheEntry->SymbolsBase = LdrModule->SymbolInfo.SymbolsBase; - CacheEntry->SymbolsLength = LdrModule->SymbolInfo.SymbolsLength; - CacheEntry->SymbolStringsBase = LdrModule->SymbolInfo.SymbolStringsBase; - CacheEntry->SymbolStringsLength = LdrModule->SymbolInfo.SymbolStringsLength; - InsertTailList(&SymbolListHead, &CacheEntry->ListEntry); - } -} - -VOID -KdbLoadDriver(PUNICODE_STRING Filename, PMODULE_OBJECT Module) -{ - /* Load symbols for the image if available */ - DPRINT1("Loading driver %wZ symbols (driver @ %08x)\n", - Filename, Module->Base); - LdrpLoadModuleSymbols(Filename, &Module->TextSection->SymbolInfo); - -} - -VOID -KdbUnloadDriver(PMODULE_OBJECT ModuleObject) -{ - /* Unload symbols for module if available */ - KdbLdrUnloadModuleSymbols(&ModuleObject->TextSection->SymbolInfo); -} - -/* Length here is the length of the loaded module, not the file name. */ - -VOID -KdbProcessSymbolFile(PVOID ModuleLoadBase, PCHAR FileName, ULONG Length) -{ - PMODULE_OBJECT ModuleObject; - UNICODE_STRING ModuleName; - CHAR TmpBaseName[MAX_PATH]; - CHAR TmpFileName[MAX_PATH]; - PSYMBOLFILE_HEADER SymbolFileHeader; - PIMAGE_SYMBOL_INFO SymbolInfo; - ANSI_STRING AnsiString; - PCHAR Extension; - - DPRINT("Module %s is a symbol file\n", FileName); - - strncpy(TmpBaseName, FileName, MAX_PATH-1); - TmpBaseName[MAX_PATH-1] = '\0'; - /* remove the extension '.sym' */ - Extension = strrchr(TmpBaseName, '.'); - if (Extension && 0 == _stricmp(Extension, ".sym")) - { - *Extension = 0; - } - - DPRINT("base: %s (Length %d)\n", TmpBaseName, Length); - - strcpy(TmpFileName, TmpBaseName); - strcat(TmpFileName, ".sys"); - RtlInitAnsiString(&AnsiString, TmpFileName); - - RtlAnsiStringToUnicodeString(&ModuleName, &AnsiString, TRUE); - ModuleObject = LdrGetModuleObject(&ModuleName); - RtlFreeUnicodeString(&ModuleName); - if (ModuleObject == NULL) - { - strcpy(TmpFileName, TmpBaseName); - strcat(TmpFileName, ".exe"); - RtlInitAnsiString(&AnsiString, TmpFileName); - RtlAnsiStringToUnicodeString(&ModuleName, &AnsiString, TRUE); - ModuleObject = LdrGetModuleObject(&ModuleName); - RtlFreeUnicodeString(&ModuleName); - } - if (ModuleObject != NULL) - { - SymbolInfo = (PIMAGE_SYMBOL_INFO) &ModuleObject->TextSection->SymbolInfo; - SymbolFileHeader = (PSYMBOLFILE_HEADER) ModuleLoadBase; - SymbolInfo->FileBuffer = ModuleLoadBase; - SymbolInfo->SymbolsBase = ModuleLoadBase + SymbolFileHeader->StabsOffset; - SymbolInfo->SymbolsLength = SymbolFileHeader->StabsLength; - SymbolInfo->SymbolStringsBase = ModuleLoadBase + SymbolFileHeader->StabstrOffset; - SymbolInfo->SymbolStringsLength = SymbolFileHeader->StabstrLength; - DPRINT("Installed stabs: %s@%08x-%08x (%08x-%08x,%08x)\n", - FileName, - ModuleObject->Base, ModuleObject->Length + ModuleObject->Base, - SymbolInfo->SymbolsBase, - SymbolInfo->SymbolsLength + SymbolInfo->SymbolsBase, - SymbolInfo->SymbolStringsBase); - } -} - -VOID -KdbInitializeDriver(PMODULE_TEXT_SECTION ModuleTextSection) -{ - RtlZeroMemory(&ModuleTextSection->SymbolInfo, sizeof(ModuleTextSection->SymbolInfo)); - ModuleTextSection->SymbolInfo.ImageBase = - ModuleTextSection->OptionalHeader->ImageBase; - ModuleTextSection->SymbolInfo.ImageSize = ModuleTextSection->Length; -} - -VOID -KdbLdrLoadAutoConfigDrivers(VOID) -{ - UNICODE_STRING ModuleName; - PMODULE_OBJECT ModuleObject; - - /* - * Load symbols for ntoskrnl.exe and hal.dll because \SystemRoot - * is created after their module entries - */ - - RtlRosInitUnicodeStringFromLiteral(&ModuleName, KERNEL_MODULE_NAME); - ModuleObject = LdrGetModuleObject(&ModuleName); - if (ModuleObject != NULL) - { - LdrpLoadModuleSymbols(&ModuleName, - &ModuleObject->TextSection->SymbolInfo); - } - - RtlRosInitUnicodeStringFromLiteral(&ModuleName, HAL_MODULE_NAME); - ModuleObject = LdrGetModuleObject(&ModuleName); - if (ModuleObject != NULL) - { - LdrpLoadModuleSymbols(&ModuleName, - &ModuleObject->TextSection->SymbolInfo); - } -} diff --git a/reactos/ntoskrnl/dbg/kdb_stabs.h b/reactos/ntoskrnl/dbg/kdb_stabs.h new file mode 100644 index 00000000000..00e4c087335 --- /dev/null +++ b/reactos/ntoskrnl/dbg/kdb_stabs.h @@ -0,0 +1,69 @@ +#ifndef __KDB_STABS_H__ +#define __KDB_STABS_H__ + +typedef struct _STAB_ENTRY { + unsigned long n_strx; /* index into string table of name */ + unsigned char n_type; /* type of symbol */ + unsigned char n_other; /* misc info (usually empty) */ + unsigned short n_desc; /* description field */ + unsigned long n_value; /* value of symbol */ +} STAB_ENTRY, *PSTAB_ENTRY; + +/* + * String - Function name with type information + * Desc - Line number + * Value - Absolute virtual address + */ +#define N_FUN 0x24 + +/* + * Desc - Line number + * Value - Relative virtual address + */ +#define N_SLINE 0x44 + +/* + * String - First ending with a '/' is the compillation directory (CD) + * Not ending with a '/' is a source file relative to CD + */ +#define N_SO 0x64 + +/* + * String - Variable name with type information + * Value - Register + */ +#define N_RSYM 0x40 + +/* + * String - Variable name with type information + * Value - Offset of variable within local variables (from %ebp) + */ +#define N_LSYM 0x80 + +#define N_SOL 0x84 + + +#define N_PSYM 0xa0 + +/* + * Value - Start address of code block + */ +#define N_LBRAC 0xc0 + +/* + * Value - End address of code block + */ +#define N_RBRAC 0xe0 + + +/* + * Functions + */ + +PSTAB_ENTRY +KdbpStabFindEntry(IN PIMAGE_SYMBOL_INFO SymbolInfo, + IN CHAR Type, + IN PVOID RelativeAddress OPTIONAL, + IN PSTAB_ENTRY StartEntry OPTIONAL); + +#endif /* __KDB_STABS_H__ */ diff --git a/reactos/ntoskrnl/dbg/kdb_symbols.c b/reactos/ntoskrnl/dbg/kdb_symbols.c new file mode 100644 index 00000000000..e1ac54a8330 --- /dev/null +++ b/reactos/ntoskrnl/dbg/kdb_symbols.c @@ -0,0 +1,991 @@ +/* + * ReactOS kernel + * Copyright (C) 1998-2004 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/dbg/kdb_symbols.c + * PURPOSE: Getting symbol information... + * PROGRAMMER: David Welch (welch@cwcom.net), ... + * REVISION HISTORY: + * ??/??/??: Created + */ + +/* INCLUDES *****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NDEBUG +#include + +#include "kdb.h" +#include "kdb_stabs.h" + +/* GLOBALS ******************************************************************/ + +typedef struct _SYMBOLFILE_HEADER { + ULONG StabsOffset; + ULONG StabsLength; + ULONG StabstrOffset; + ULONG StabstrLength; +} SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER; + +typedef struct _IMAGE_SYMBOL_INFO_CACHE { + LIST_ENTRY ListEntry; + ULONG RefCount; + UNICODE_STRING FileName; + PVOID FileBuffer; + PVOID SymbolsBase; + ULONG SymbolsLength; + PVOID SymbolStringsBase; + ULONG SymbolStringsLength; +} IMAGE_SYMBOL_INFO_CACHE, *PIMAGE_SYMBOL_INFO_CACHE; + + +static LIST_ENTRY SymbolFileListHead; +static KSPIN_LOCK SymbolFileListLock; + + +/* FUNCTIONS ****************************************************************/ + +/*! \brief Find a user-mode module... + * + * \param Address If \a Address is not NULL the module containing \a Address + * is searched. + * \param Name If \a Name is not NULL the module named \a Name will be + * searched. + * \param Index If \a Index is >= 0 the Index'th module will be returned. + * \param pInfo Pointer to a KDB_MODULE_INFO which is filled. + * + * \retval TRUE Module was found, \a pInfo was filled. + * \retval FALSE No module was found. + * + * \sa KdbpSymFindModule + */ +STATIC BOOLEAN +KdbpSymFindUserModule(IN PVOID Address OPTIONAL, + IN LPCWSTR Name OPTIONAL, + IN INT Index OPTIONAL, + OUT PKDB_MODULE_INFO pInfo) +{ + PLIST_ENTRY current_entry; + PLDR_MODULE current; + PEPROCESS CurrentProcess; + PPEB Peb = NULL; + INT Count = 0; + + CurrentProcess = PsGetCurrentProcess(); + if (CurrentProcess != NULL) + { + Peb = CurrentProcess->Peb; + } + + if (Peb == NULL) + { + return FALSE; + } + + current_entry = Peb->Ldr->InLoadOrderModuleList.Flink; + + while (current_entry != &Peb->Ldr->InLoadOrderModuleList && + current_entry != NULL) + { + current = CONTAINING_RECORD(current_entry, LDR_MODULE, InLoadOrderModuleList); + + if ((Address != NULL && (Address >= (PVOID)current->BaseAddress && + Address < (PVOID)((char *)current->BaseAddress + current->SizeOfImage))) || + (Name != NULL && _wcsicmp(current->BaseDllName.Buffer, Name) == 0) || + (Index >= 0 && Count++ == Index)) + { + INT Length = current->BaseDllName.Length; + if (Length > 255) + Length = 255; + wcsncpy(pInfo->Name, current->BaseDllName.Buffer, Length); + pInfo->Name[Length] = L'\0'; + pInfo->Base = (ULONG_PTR)current->BaseAddress; + pInfo->Size = current->SizeOfImage; + pInfo->SymbolInfo = ¤t->SymbolInfo; + return TRUE; + } + current_entry = current_entry->Flink; + } + + return FALSE; +} + +/*! \brief Find a kernel-mode module... + * + * Works like \a KdbpSymFindUserModule. + * + * \sa KdbpSymFindUserModule + */ +STATIC BOOLEAN +KdbpSymFindModule(IN PVOID Address OPTIONAL, + IN LPCWSTR Name OPTIONAL, + IN INT Index OPTIONAL, + OUT PKDB_MODULE_INFO pInfo) +{ + PLIST_ENTRY current_entry; + MODULE_TEXT_SECTION* current; + extern LIST_ENTRY ModuleTextListHead; + INT Count = 0; + + current_entry = ModuleTextListHead.Flink; + + while (current_entry != &ModuleTextListHead && + current_entry != NULL) + { + current = CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry); + + if ((Address != NULL && (Address >= (PVOID)current->Base && + Address < (PVOID)(current->Base + current->Length))) || + (Name != NULL && _wcsicmp(current->Name, Name) == 0) || + (Index >= 0 && Count++ == Index)) + { + wcsncpy(pInfo->Name, current->Name, 255); + pInfo->Name[255] = L'\0'; + pInfo->Base = (ULONG_PTR)current->Base; + pInfo->Size = current->Length; + pInfo->SymbolInfo = ¤t->SymbolInfo; + return TRUE; + } + current_entry = current_entry->Flink; + } + + return KdbpSymFindUserModule(Address, Name, Index-Count, pInfo); +} + +/*! \brief Find module by address... + * + * \param Address Any address inside the module to look for. + * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on + * success. + * + * \retval TRUE Success - module found. + * \retval FALSE Failure - module not found. + * + * \sa KdbpSymFindModuleByName + * \sa KdbpSymFindModuleByIndex + */ +BOOLEAN +KdbpSymFindModuleByAddress(IN PVOID Address, + OUT PKDB_MODULE_INFO pInfo) +{ + return KdbpSymFindModule(Address, NULL, -1, pInfo); +} + +/*! \brief Find module by name... + * + * \param Name Name of the module to look for. + * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on + * success. + * + * \retval TRUE Success - module found. + * \retval FALSE Failure - module not found. + * + * \sa KdbpSymFindModuleByAddress + * \sa KdbpSymFindModuleByIndex + */ +BOOLEAN +KdbpSymFindModuleByName(IN LPCWSTR Name, + OUT PKDB_MODULE_INFO pInfo) +{ + return KdbpSymFindModule(NULL, Name, -1, pInfo); +} + +/*! \brief Find module by index... + * + * \param Index Index of the module to return. + * \param pInfo Pointer to a KDB_MODULE_INFO struct which is filled on + * success. + * + * \retval TRUE Success - module found. + * \retval FALSE Failure - module not found. + * + * \sa KdbpSymFindModuleByName + * \sa KdbpSymFindModuleByAddress + */ +BOOLEAN +KdbpSymFindModuleByIndex(IN INT Index, + OUT PKDB_MODULE_INFO pInfo) +{ + return KdbpSymFindModule(NULL, NULL, Index, pInfo); +} + +/*! \brief Print address... + * + * Tries to lookup line number, file name and function name for the given + * address and prints it. + * If no such information is found the address is printed in the format + * , otherwise the format will be + * + * + * \retval TRUE Module containing \a Address was found, \a Address was printed. + * \retval FALSE No module containing \a Address was found, nothing was printed. + */ +BOOLEAN +KdbSymPrintAddress(IN PVOID Address) +{ + KDB_MODULE_INFO Info; + ULONG_PTR RelativeAddress; + NTSTATUS Status; + ULONG LineNumber; + CHAR FileName[256]; + CHAR FunctionName[256]; + + if (!KdbpSymFindModuleByAddress(Address, &Info)) + return FALSE; + + RelativeAddress = (ULONG_PTR) Address - Info.Base; + Status = KdbSymGetAddressInformation(Info.SymbolInfo, + RelativeAddress, + &LineNumber, + FileName, + FunctionName); + if (NT_SUCCESS(Status)) + { + DbgPrint("<%ws: %x (%s:%d (%s))>", + Info.Name, RelativeAddress, FileName, LineNumber, FunctionName); + } + else + { + DbgPrint("<%ws: %x>", Info.Name, RelativeAddress); + } + + return TRUE; +} + + +/*! \brief Get information for an address (source file, line number, + * function name) + * + * \param SymbolInfo Pointer to IMAGE_SYMBOL_INFO. + * \param RelativeAddress Relative address to look up. + * \param LineNumber Pointer to an ULONG which is filled with the line + * number (can be NULL) + * \param FileName Pointer to an array of CHARs which gets filled with + * the filename (can be NULL) + * \param FunctionName Pointer to an array of CHARs which gets filled with + * the function name (can be NULL) + * + * \returns NTSTATUS error code. + * \retval STATUS_SUCCESS At least one of the requested informations was found. + * \retval STATUS_UNSUCCESSFUL None of the requested information was found. + */ +NTSTATUS +KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, + IN ULONG_PTR RelativeAddress, + OUT PULONG LineNumber OPTIONAL, + OUT PCH FileName OPTIONAL, + OUT PCH FunctionName OPTIONAL) +{ + PSTAB_ENTRY FunctionEntry = NULL, FileEntry = NULL, LineEntry = NULL; + + DPRINT("RelativeAddress = 0x%08x\n", RelativeAddress); + + if (SymbolInfo->SymbolsBase == NULL || SymbolInfo->SymbolsLength == 0 || + SymbolInfo->SymbolStringsBase == NULL || SymbolInfo->SymbolStringsLength == 0) + { + return STATUS_UNSUCCESSFUL; + } + +#ifdef PEDANTIC_STABS + if (RelativeAddress >= SymbolInfo->ImageSize) + { + DPRINT("Address is not within .text section. RelativeAddress %p Length 0x%x\n", + RelativeAddress, SymbolInfo->ImageSize); + return STATUS_UNSUCCESSFUL; + } +#endif + + assert(LineNumber || FileName || FunctionName); + + if (LineNumber != NULL || FunctionName != NULL) + { + /* find stab entry for function */ + FunctionEntry = KdbpStabFindEntry(SymbolInfo, N_FUN, (PVOID)RelativeAddress, NULL); + if (FunctionEntry == NULL) + { + DPRINT("No function stab entry found. RelativeAddress %p\n", RelativeAddress); + } + + if (LineNumber != NULL && FunctionEntry != NULL) + { + /* find stab entry for line number */ + ULONG_PTR FunctionRelativeAddress = FunctionEntry->n_value - (ULONG_PTR)SymbolInfo->ImageBase; + ULONG_PTR AddrFound = 0; + PSTAB_ENTRY NextLineEntry; + + LineEntry = NextLineEntry = FunctionEntry; + while (NextLineEntry != NULL) + { + NextLineEntry++; + if ((ULONG_PTR)NextLineEntry >= ((ULONG_PTR)SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength)) + break; + if (NextLineEntry->n_type == N_FUN) + break; + if (NextLineEntry->n_type != N_SLINE) + continue; + + if (((NextLineEntry->n_value+FunctionRelativeAddress) <= RelativeAddress) && + (NextLineEntry->n_value > AddrFound)) + { + AddrFound = NextLineEntry->n_value; + LineEntry = NextLineEntry; + } + } + } + } + + if (FileName != NULL) + { + /* find stab entry for file name */ + PCHAR p; + INT Length; + + FileEntry = KdbpStabFindEntry(SymbolInfo, N_SO, (PVOID)RelativeAddress, NULL); + if (FileEntry != NULL) + { + p = (PCHAR)SymbolInfo->SymbolStringsBase + FileEntry->n_strx; + Length = strlen(p); + if (p[Length - 1] == '/' || p[Length - 1] == '\\') /* source dir */ + FileEntry = KdbpStabFindEntry(SymbolInfo, N_SO, (PVOID)RelativeAddress, FileEntry + 1); + } + if (FileEntry == NULL) + { + DPRINT("No filename stab entry found. RelativeAddress %p\n", RelativeAddress); + } + } + + if (((LineNumber != NULL && LineEntry == NULL) || LineNumber == NULL) && + ((FileName != NULL && FileEntry == NULL) || FileName == NULL) && + ((FunctionName != NULL && FunctionEntry == NULL) || FunctionName == NULL)) + { + DPRINT("None of the requested information was found!\n"); + return STATUS_UNSUCCESSFUL; + } + + if (LineNumber != NULL) + { + *LineNumber = 0; + if (LineEntry != NULL) + *LineNumber = LineEntry->n_desc; + } + if (FileName != NULL) + { + PCHAR Name = ""; + if (FileEntry != NULL) + { + Name = (PCHAR)SymbolInfo->SymbolStringsBase + FileEntry->n_strx; + } + strcpy(FileName, Name); + } + if (FunctionName != NULL) + { + PCHAR Name = "", p; + if (FunctionEntry != NULL) + Name = (PCHAR)SymbolInfo->SymbolStringsBase + FunctionEntry->n_strx; + strcpy(FunctionName, Name); + if ((p = strchr(FunctionName, ':')) != NULL) /* remove extra info from function name */ + *p = '\0'; + } + + return STATUS_SUCCESS; +} + + +/*! \brief Get absolute source-line number or function address + * + * \param SymbolInfo IMAGE_SYMBOL_INFO of the module containing source file/line number. + * \param FileName Source filename. + * \param LineNumber Line number in source file. + * \param FuncName Function name. + * \param Address Filled with the address on success. + * + * \retval TRUE Success. + * \retval FALSE Failure. + */ +BOOLEAN +KdbpSymGetSourceAddress(IN PIMAGE_SYMBOL_INFO SymbolInfo, + IN PCHAR FileName, + IN ULONG LineNumber OPTIONAL, + IN PCHAR FuncName OPTIONAL, + OUT PVOID *Address) +{ + PSTAB_ENTRY Entry, FunctionEntry = NULL; + PCHAR SymbolName, p; + CHAR Buffer[512] = ""; + INT Length, FileNameLength, FuncNameLength = 0; + + if (FuncName == NULL && LineNumber < 1) + return FALSE; + + FileNameLength = strlen(FileName); + FuncNameLength = strlen(FuncName); + for (Entry = SymbolInfo->SymbolsBase; + (ULONG_PTR)Entry < (ULONG_PTR)(SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength); + Entry++) + { + if (Entry->n_type != N_SO) + continue; + + SymbolName = (PCHAR)SymbolInfo->SymbolStringsBase + Entry->n_strx; + Length = strlen(SymbolName); + if (SymbolName[Length - 1] == '/' || + SymbolName[Length - 1] == '\\') + { + strncpy(Buffer, SymbolName, sizeof (Buffer) - 1); + Buffer[sizeof (Buffer) - 1] = '\0'; + continue; + } + strncat(Buffer, SymbolName, sizeof (Buffer) - 1); + Buffer[sizeof (Buffer) - 1] = '\0'; + + Length = strlen(Buffer); + if (strcmp(Buffer + Length - FileNameLength, FileName) != 0) + continue; + + Entry++; + for (;(ULONG_PTR)Entry < (ULONG_PTR)(SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength); + Entry++) + { + if (Entry->n_type == N_FUN) + FunctionEntry = Entry; + else if (Entry->n_type == N_SO) + break; + else if (Entry->n_type != N_SLINE || LineNumber < 1) + continue; + + if (LineNumber > 0 && Entry->n_desc != LineNumber) + continue; + else /* if (FunctionName != NULL) */ + { + SymbolName = (PCHAR)SymbolInfo->SymbolStringsBase + Entry->n_strx; + p = strchr(SymbolName, ':'); + if (p == NULL) + return FALSE; + Length = p - SymbolName; + if (Length != FuncNameLength) + continue; + if (strncmp(FuncName, SymbolName, Length) != 0) + continue; + } + + /* found */ + if (Entry->n_type == N_FUN) + { + *Address = (PVOID)Entry->n_value; /* FIXME: relocate address */ + return TRUE; + } + + if (FunctionEntry == NULL) + return FALSE; + + *Address = (PVOID)((ULONG_PTR)Entry->n_value + FunctionEntry->n_value); /* FIXME: relocate address */ + return TRUE; + } + break; + } + + return FALSE; +} + +/*! \brief Find cached symbol file. + * + * Looks through the list of cached symbol files and tries to find an already + * loaded one. + * + * \param FileName FileName of the symbol file to look for. + * + * \returns A pointer to the cached symbol info. + * \retval NULL No cached info found. + * + * \sa KdbpSymAddCachedFile + */ +STATIC PIMAGE_SYMBOL_INFO_CACHE +KdbpSymFindCachedFile(IN PUNICODE_STRING FileName) +{ + PIMAGE_SYMBOL_INFO_CACHE Current; + PLIST_ENTRY CurrentEntry; + KIRQL Irql; + + DPRINT("Looking for cached symbol file %wZ\n", FileName); + + KeAcquireSpinLock(&SymbolFileListLock, &Irql); + + CurrentEntry = SymbolFileListHead.Flink; + while (CurrentEntry != (&SymbolFileListHead)) + { + Current = CONTAINING_RECORD(CurrentEntry, IMAGE_SYMBOL_INFO_CACHE, ListEntry); + + DPRINT("Current->FileName %wZ FileName %wZ\n", &Current->FileName, FileName); + if (RtlEqualUnicodeString(&Current->FileName, FileName, TRUE)) + { + KeReleaseSpinLock(&SymbolFileListLock, Irql); + DPRINT("Found cached file!\n"); + return Current; + } + + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&SymbolFileListLock, Irql); + + DPRINT("Cached file not found!\n"); + return NULL; +} + +/*! \brief Add a symbol file to the cache. + * + * \param FileName Filename of the symbol file. + * \param SymbolInfo Pointer to the symbol info. + * + * \sa KdbpSymRemoveCachedFile + */ +STATIC VOID +KdbpSymAddCachedFile(IN PUNICODE_STRING FileName, + IN PIMAGE_SYMBOL_INFO SymbolInfo) +{ + PIMAGE_SYMBOL_INFO_CACHE CacheEntry; + + DPRINT("Adding symbol file: FileBuffer = %p, ImageBase = %p\n", + SymbolInfo->FileBuffer, SymbolInfo->ImageBase); + + /* allocate entry */ + CacheEntry = ExAllocatePool(NonPagedPool, sizeof (IMAGE_SYMBOL_INFO_CACHE)); + assert(CacheEntry); + RtlZeroMemory(CacheEntry, sizeof (IMAGE_SYMBOL_INFO_CACHE)); + + /* fill entry */ + RtlCreateUnicodeString(&CacheEntry->FileName, FileName->Buffer); + assert(CacheEntry->FileName.Buffer); + CacheEntry->RefCount = 1; + CacheEntry->FileBuffer = SymbolInfo->FileBuffer; + CacheEntry->SymbolsBase = SymbolInfo->SymbolsBase; + CacheEntry->SymbolsLength = SymbolInfo->SymbolsLength; + CacheEntry->SymbolStringsBase = SymbolInfo->SymbolStringsBase; + CacheEntry->SymbolStringsLength = SymbolInfo->SymbolStringsLength; + InsertTailList(&SymbolFileListHead, &CacheEntry->ListEntry); /* FIXME: Lock list? */ +} + +/*! \brief Remove a symbol file (reference) from the cache. + * + * Tries to find a cache entry matching the given symbol info and decreases + * it's reference count. If the refcount is 0 after decreasing it the cache + * entry will be removed from the list and freed. + * + * \param SymbolInfo Pointer to the symbol info. + * + * \sa KdbpSymAddCachedFile + */ +STATIC VOID +KdbpSymRemoveCachedFile(IN PIMAGE_SYMBOL_INFO SymbolInfo) +{ + PIMAGE_SYMBOL_INFO_CACHE Current; + PLIST_ENTRY CurrentEntry; + KIRQL Irql; + + KeAcquireSpinLock(&SymbolFileListLock, &Irql); + + CurrentEntry = SymbolFileListHead.Flink; + while (CurrentEntry != (&SymbolFileListHead)) + { + Current = CONTAINING_RECORD(CurrentEntry, IMAGE_SYMBOL_INFO_CACHE, ListEntry); + + if (Current->FileBuffer == SymbolInfo->FileBuffer) /* found */ + { + assert(Current->RefCount > 0); + Current->RefCount--; + if (Current->RefCount < 1) + { + RemoveEntryList(&Current->ListEntry); + ExFreePool(Current->FileBuffer); + ExFreePool(Current); + } + KeReleaseSpinLock(&SymbolFileListLock, Irql); + return; + } + + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&SymbolFileListLock, Irql); + DPRINT1("Warning: Removing unknown symbol file: FileBuffer = %p, ImageBase = %p\n", + SymbolInfo->FileBuffer, SymbolInfo->ImageBase); + assert(0); +} + +/*! \brief Loads a symbol file. + * + * \param FileName Filename of the symbol file to load. + * \param SymbolInfo Pointer to a SymbolInfo which gets filled. + * + * \sa KdbpSymUnloadModuleSymbols + */ +STATIC VOID +KdbpSymLoadModuleSymbols(IN PUNICODE_STRING FileName, + OUT PIMAGE_SYMBOL_INFO SymbolInfo) +{ + FILE_STANDARD_INFORMATION FileStdInfo; + OBJECT_ATTRIBUTES ObjectAttributes; + WCHAR TmpFileName[MAX_PATH]; + UNICODE_STRING SymFileName; + LPWSTR Start, Ext; + HANDLE FileHandle; + PVOID FileBuffer; + NTSTATUS Status; + ULONG Length; + IO_STATUS_BLOCK IoStatusBlock; + PSYMBOLFILE_HEADER SymbolFileHeader; + PIMAGE_SYMBOL_INFO_CACHE CachedSymbolFile; + + /* Get the path to the symbol store */ + wcscpy(TmpFileName, L"\\SystemRoot\\symbols\\"); + + /* Get the symbol filename from the module name */ + Start = wcsrchr(FileName->Buffer, L'\\'); + if (Start == NULL) + Start = FileName->Buffer; + else + Start++; + + Ext = wcsrchr(FileName->Buffer, L'.'); + if (Ext != NULL) + Length = Ext - Start; + else + Length = wcslen(Start); + + wcsncat(TmpFileName, Start, Length); + wcscat(TmpFileName, L".sym"); + RtlInitUnicodeString(&SymFileName, TmpFileName); + + /* Try to find cached (already loaded) symbol file */ + CachedSymbolFile = KdbpSymFindCachedFile(&SymFileName); + if (CachedSymbolFile != NULL) + { + DPRINT("Found cached symbol file %wZ\n", &SymFileName); + CachedSymbolFile->RefCount++; + SymbolInfo->FileBuffer = CachedSymbolFile->FileBuffer; + SymbolInfo->SymbolsBase = CachedSymbolFile->SymbolsBase; + SymbolInfo->SymbolsLength = CachedSymbolFile->SymbolsLength; + SymbolInfo->SymbolStringsBase = CachedSymbolFile->SymbolStringsBase; + SymbolInfo->SymbolStringsLength = CachedSymbolFile->SymbolStringsLength; + return; + } + + /* Open the file */ + InitializeObjectAttributes(&ObjectAttributes, + &SymFileName, + 0, + NULL, + NULL); + + DPRINT("Attempting to open symbols: %wZ\n", &SymFileName); + + Status = ZwOpenFile(&FileHandle, + FILE_ALL_ACCESS, + &ObjectAttributes, + &IoStatusBlock, + 0, + FILE_SYNCHRONOUS_IO_NONALERT|FILE_NO_INTERMEDIATE_BUFFERING); + if (!NT_SUCCESS(Status)) + { + DPRINT("Could not open symbol file: %wZ\n", &SymFileName); + return; + } + + DPRINT("Loading symbols from %wZ...\n", &SymFileName); + + /* Get the size of the file */ + Status = ZwQueryInformationFile(FileHandle, + &IoStatusBlock, + &FileStdInfo, + sizeof(FileStdInfo), + FileStandardInformation); + if (!NT_SUCCESS(Status)) + { + DPRINT("Could not get file size\n"); + ZwClose(FileHandle); + return; + } + + DPRINT("Symbol file is %08x bytes\n", FileStdInfo.EndOfFile.u.LowPart); + + /* Allocate nonpageable memory for symbol file */ + FileBuffer = ExAllocatePool(NonPagedPool, + FileStdInfo.AllocationSize.u.LowPart); + + if (FileBuffer == NULL) + { + DPRINT("Could not allocate memory for symbol file\n"); + ZwClose(FileHandle); + return; + } + + /* Load file into memory chunk */ + Status = ZwReadFile(FileHandle, + 0, 0, 0, + &IoStatusBlock, + FileBuffer, + FileStdInfo.EndOfFile.u.LowPart, + 0, 0); + if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) + { + DPRINT("Could not read symbol file into memory (Status 0x%x)\n", Status); + ExFreePool(FileBuffer); + ZwClose(FileHandle); + return; + } + + ZwClose(FileHandle); + + DPRINT("Symbols loaded.\n"); + + SymbolFileHeader = (PSYMBOLFILE_HEADER) FileBuffer; + SymbolInfo->FileBuffer = FileBuffer; + SymbolInfo->SymbolsBase = FileBuffer + SymbolFileHeader->StabsOffset; + SymbolInfo->SymbolsLength = SymbolFileHeader->StabsLength; + SymbolInfo->SymbolStringsBase = FileBuffer + SymbolFileHeader->StabstrOffset; + SymbolInfo->SymbolStringsLength = SymbolFileHeader->StabstrLength; + + /* add file to cache */ + KdbpSymAddCachedFile(&SymFileName, SymbolInfo); + + DPRINT("Installed stabs: %wZ (%08x-%08x,%08x)\n", + FileName, + SymbolInfo->SymbolsBase, + SymbolInfo->SymbolsLength + SymbolInfo->SymbolsBase, + SymbolInfo->SymbolStringsBase); +} + +/*! \brief Unloads symbol info. + * + * \param SymbolInfo Pointer to the symbol info to unload. + * + * \sa KdbpSymLoadModuleSymbols + */ +STATIC VOID +KdbpSymUnloadModuleSymbols(IN PIMAGE_SYMBOL_INFO SymbolInfo) +{ + DPRINT("Unloading symbols\n"); + + if (SymbolInfo != NULL && SymbolInfo->FileBuffer != NULL) + { + KdbpSymRemoveCachedFile(SymbolInfo); + SymbolInfo->FileBuffer = NULL; + SymbolInfo->SymbolsBase = NULL; + SymbolInfo->SymbolsLength = 0; + } +} + +/*! \brief Load symbol info for a user module. + * + * \param LdrModule Pointer to the module to load symbols for. + */ +VOID +KdbSymLoadUserModuleSymbols(IN PLDR_MODULE LdrModule) +{ + DPRINT("LdrModule %p\n", LdrModule); + + RtlZeroMemory(&LdrModule->SymbolInfo, sizeof (LdrModule->SymbolInfo)); + LdrModule->SymbolInfo.ImageBase = (ULONG_PTR)LdrModule->BaseAddress; + LdrModule->SymbolInfo.ImageSize = LdrModule->SizeOfImage; + + KdbpSymLoadModuleSymbols(&LdrModule->FullDllName, &LdrModule->SymbolInfo); +} + +/*! \brief Frees all symbols loaded for a process. + * + * \param Process Pointer to a process. + */ +VOID +KdbSymFreeProcessSymbols(IN PEPROCESS Process) +{ + PLIST_ENTRY CurrentEntry; + PLDR_MODULE Current; + PIMAGE_SYMBOL_INFO SymbolInfo; + PEPROCESS CurrentProcess; + PPEB Peb; + + CurrentProcess = PsGetCurrentProcess(); + if (CurrentProcess != Process) + { + KeAttachProcess(Process); + } + Peb = Process->Peb; + assert (Peb); + assert (Peb->Ldr); + + CurrentEntry = Peb->Ldr->InLoadOrderModuleList.Flink; + while (CurrentEntry != &Peb->Ldr->InLoadOrderModuleList && + CurrentEntry != NULL) + { + Current = CONTAINING_RECORD(CurrentEntry, LDR_MODULE, InLoadOrderModuleList); + + SymbolInfo = &Current->SymbolInfo; + KdbpSymUnloadModuleSymbols(SymbolInfo); + + CurrentEntry = CurrentEntry->Flink; + } + if (CurrentProcess != Process) + { + KeDetachProcess(); + } +} + +/*! \brief Load symbol info for a driver. + * + * \param Filename Filename of the driver. + * \param Module Pointer to the driver MODULE_OBJECT. + */ +VOID +KdbSymLoadDriverSymbols(IN PUNICODE_STRING Filename, + IN PMODULE_OBJECT Module) +{ + /* Load symbols for the image if available */ + DPRINT("Loading driver %wZ symbols (driver @ %08x)\n", Filename, Module->Base); + + RtlZeroMemory(&Module->TextSection->SymbolInfo, sizeof (Module->TextSection->SymbolInfo)); + Module->TextSection->SymbolInfo.ImageBase = Module->TextSection->Base; + Module->TextSection->SymbolInfo.ImageSize = Module->TextSection->Length; + + KdbpSymLoadModuleSymbols(Filename, &Module->TextSection->SymbolInfo); +} + +/*! \brief Unloads symbol info for a driver. + * + * \param ModuleObject Pointer to the driver MODULE_OBJECT. + */ +VOID +KdbSymUnloadDriverSymbols(IN PMODULE_OBJECT ModuleObject) +{ + /* Unload symbols for module if available */ + KdbpSymUnloadModuleSymbols(&ModuleObject->TextSection->SymbolInfo); +} + +/*! \brief Called when a symbol file is loaded by the loader? + * + * Tries to find a driver (.sys) or executable (.exe) with the same base name + * as the symbol file and sets the drivers/exes symbol info to the loaded + * module. + * Used to load ntoskrnl and hal symbols before the SystemRoot is available to us. + * + * \param ModuleLoadBase Base address of the loaded symbol file. + * \param FileName Filename of the symbol file. + * \param Length Length of the loaded symbol file/module. + */ +VOID +KdbSymProcessSymbolFile(IN PVOID ModuleLoadBase, + IN PCHAR FileName, + IN ULONG Length) +{ + PMODULE_OBJECT ModuleObject; + UNICODE_STRING ModuleName; + CHAR TmpBaseName[MAX_PATH]; + CHAR TmpFileName[MAX_PATH]; + PSYMBOLFILE_HEADER SymbolFileHeader; + PIMAGE_SYMBOL_INFO SymbolInfo; + ANSI_STRING AnsiString; + PCHAR Extension; + + DPRINT("Module %s is a symbol file\n", FileName); + + strncpy(TmpBaseName, FileName, MAX_PATH-1); + TmpBaseName[MAX_PATH-1] = '\0'; + /* remove the extension '.sym' */ + Extension = strrchr(TmpBaseName, '.'); + if (Extension && 0 == _stricmp(Extension, ".sym")) + { + *Extension = 0; + } + + DPRINT("base: %s (Length %d)\n", TmpBaseName, Length); + + strcpy(TmpFileName, TmpBaseName); + strcat(TmpFileName, ".sys"); + RtlInitAnsiString(&AnsiString, TmpFileName); + + RtlAnsiStringToUnicodeString(&ModuleName, &AnsiString, TRUE); + ModuleObject = LdrGetModuleObject(&ModuleName); + RtlFreeUnicodeString(&ModuleName); + if (ModuleObject == NULL) + { + strcpy(TmpFileName, TmpBaseName); + strcat(TmpFileName, ".exe"); + RtlInitAnsiString(&AnsiString, TmpFileName); + RtlAnsiStringToUnicodeString(&ModuleName, &AnsiString, TRUE); + ModuleObject = LdrGetModuleObject(&ModuleName); + RtlFreeUnicodeString(&ModuleName); + } + if (ModuleObject != NULL) + { + SymbolInfo = (PIMAGE_SYMBOL_INFO) &ModuleObject->TextSection->SymbolInfo; + if (SymbolInfo->FileBuffer != NULL) + { + KdbpSymRemoveCachedFile(SymbolInfo); + } + + SymbolFileHeader = (PSYMBOLFILE_HEADER) ModuleLoadBase; + SymbolInfo->FileBuffer = ModuleLoadBase; + SymbolInfo->SymbolsBase = ModuleLoadBase + SymbolFileHeader->StabsOffset; + SymbolInfo->SymbolsLength = SymbolFileHeader->StabsLength; + SymbolInfo->SymbolStringsBase = ModuleLoadBase + SymbolFileHeader->StabstrOffset; + SymbolInfo->SymbolStringsLength = SymbolFileHeader->StabstrLength; + DPRINT("Installed stabs: %s@%08x-%08x (%08x-%08x,%08x)\n", + FileName, + ModuleObject->Base, ModuleObject->Length + ModuleObject->Base, + SymbolInfo->SymbolsBase, + SymbolInfo->SymbolsLength + SymbolInfo->SymbolsBase, + SymbolInfo->SymbolStringsBase); + } +} + +/*! \brief Initializes the KDB symbols implementation. + * + * \param NtoskrnlTextSection MODULE_TEXT_SECTION of ntoskrnl.exe + * \param LdrHalTextSection MODULE_TEXT_SECTION of hal.sys + */ +VOID +KdbSymInit(IN PMODULE_TEXT_SECTION NtoskrnlTextSection, + IN PMODULE_TEXT_SECTION LdrHalTextSection) +{ + RtlZeroMemory(&NtoskrnlTextSection->SymbolInfo, sizeof(NtoskrnlTextSection->SymbolInfo)); + NtoskrnlTextSection->SymbolInfo.ImageBase = NtoskrnlTextSection->OptionalHeader->ImageBase; + NtoskrnlTextSection->SymbolInfo.ImageSize = NtoskrnlTextSection->Length; + + RtlZeroMemory(&LdrHalTextSection->SymbolInfo, sizeof(LdrHalTextSection->SymbolInfo)); + LdrHalTextSection->SymbolInfo.ImageBase = LdrHalTextSection->OptionalHeader->ImageBase; + LdrHalTextSection->SymbolInfo.ImageSize = LdrHalTextSection->Length; + + InitializeListHead(&SymbolFileListHead); + KeInitializeSpinLock(&SymbolFileListLock); +} + +/* EOF */ diff --git a/reactos/ntoskrnl/dbg/profile.c b/reactos/ntoskrnl/dbg/profile.c index 98860529e13..f432d38cc1a 100755 --- a/reactos/ntoskrnl/dbg/profile.c +++ b/reactos/ntoskrnl/dbg/profile.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: profile.c,v 1.8 2004/08/15 16:39:00 chorns Exp $ +/* $Id: profile.c,v 1.9 2004/08/26 16:04:49 blight Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/dbg/profile.c @@ -170,7 +170,7 @@ KdbProfilerGetSymbolInfo(PVOID address, OUT PCH NameBuffer) address < (PVOID)(current->Base + current->Length)) { RelativeAddress = (ULONG_PTR) address - current->Base; - Status = LdrGetAddressInformation(¤t->SymbolInfo, + Status = KdbSymGetAddressInformation(¤t->SymbolInfo, RelativeAddress, &LineNumber, FileName, diff --git a/reactos/ntoskrnl/include/internal/kd.h b/reactos/ntoskrnl/include/internal/kd.h index be4235f4e1d..ed2b2e45958 100644 --- a/reactos/ntoskrnl/include/internal/kd.h +++ b/reactos/ntoskrnl/include/internal/kd.h @@ -1,4 +1,4 @@ -/* $Id: kd.h,v 1.26 2004/08/07 03:41:30 sedwards Exp $ +/* $Id: kd.h,v 1.27 2004/08/26 16:04:50 blight Exp $ * * kernel debugger prototypes */ @@ -108,42 +108,57 @@ VOID KdInitializeMda(VOID); VOID KdPrintMda(PCH pch); #ifndef KDBG -#define KDB_DELETEPROCESS_HOOK(PROCESS) -#define KDB_LOADDRIVER_HOOK(FILENAME, MODULE) -#define KDB_UNLOADDRIVER_HOOK(MODULE) -#define KDB_LOADERINIT_HOOK(NTOS, HAL) -#define KDB_SYMBOLFILE_HOOK(LOADBASE, FILENAME, LENGTH) -#define KDB_CREATE_THREAD_HOOK(CONTEXT) +# define KDB_LOADUSERMODULE_HOOK(LDRMOD) do { } while (0) +# define KDB_DELETEPROCESS_HOOK(PROCESS) do { } while (0) +# define KDB_LOADDRIVER_HOOK(FILENAME, MODULE) do { } while (0) +# define KDB_UNLOADDRIVER_HOOK(MODULE) do { } while (0) +# define KDB_LOADERINIT_HOOK(NTOS, HAL) do { } while (0) +# define KDB_SYMBOLFILE_HOOK(LOADBASE, FILENAME, LENGTH) do { } while (0) +# define KDB_CREATE_THREAD_HOOK(CONTEXT) do { } while (0) #else -#define KDB_DELETEPROCESS_HOOK(PROCESS) KdbFreeSymbolsProcess(PROCESS) -#define KDB_LOADDRIVER_HOOK(FILENAME, MODULE) KdbLoadDriver(FILENAME, MODULE) -#define KDB_UNLOADDRIVER_HOOK(MODULE) KdbUnloadDriver(MODULE) -#define KDB_LOADERINIT_HOOK(NTOS, HAL) KdbLdrInit(NTOS, HAL) -#define KDB_SYMBOLFILE_HOOK(LOADBASE, FILENAME, LENGTH) \ - KdbProcessSymbolFile(LOADBASE, FILENAME, LENGTH) -#define KDB_CREATE_THREAD_HOOK(CONTEXT) \ - KdbCreateThreadHook(CONTEXT) -#endif /* KDBG */ +# define KDB_LOADUSERMODULE_HOOK(LDRMOD) KdbSymLoadUserModuleSymbols(LDRMOD) +# define KDB_DELETEPROCESS_HOOK(PROCESS) KdbSymFreeProcessSymbols(PROCESS) +# define KDB_LOADDRIVER_HOOK(FILENAME, MODULE) KdbSymLoadDriverSymbols(FILENAME, MODULE) +# define KDB_UNLOADDRIVER_HOOK(MODULE) KdbSymUnloadDriverSymbols(MODULE) +# define KDB_LOADERINIT_HOOK(NTOS, HAL) KdbSymInit(NTOS, HAL) +# define KDB_SYMBOLFILE_HOOK(LOADBASE, FILENAME, LENGTH) \ + KdbSymProcessSymbolFile(LOADBASE, FILENAME, LENGTH) +/*#define KDB_CREATE_THREAD_HOOK(CONTEXT) \ + KdbCreateThreadHook(CONTEXT) +*/ +VOID +KdbSymLoadUserModuleSymbols(IN PLDR_MODULE LdrModule); VOID -KdbLdrLoadUserModuleSymbols(PLDR_MODULE LdrModule); +KdbSymFreeProcessSymbols(IN PEPROCESS Process); + VOID -KdbProcessSymbolFile(PVOID ModuleLoadBase, PCHAR FileName, ULONG Length); +KdbSymLoadDriverSymbols(IN PUNICODE_STRING Filename, + IN PMODULE_OBJECT Module); + VOID -KdbLdrInit(MODULE_TEXT_SECTION* NtoskrnlTextSection, - MODULE_TEXT_SECTION* LdrHalTextSection); +KdbSymUnloadDriverSymbols(IN PMODULE_OBJECT ModuleObject); + VOID -KdbUnloadDriver(PMODULE_OBJECT ModuleObject); +KdbSymProcessSymbolFile(IN PVOID ModuleLoadBase, + IN PCHAR FileName, + IN ULONG Length); + VOID -KdbLoadDriver(PUNICODE_STRING Filename, PMODULE_OBJECT Module); -VOID -KdbFreeSymbolsProcess(PEPROCESS Process); -BOOLEAN -KdbPrintAddress(PVOID address); +KdbSymInit(IN PMODULE_TEXT_SECTION NtoskrnlTextSection, + IN PMODULE_TEXT_SECTION LdrHalTextSection); + + +BOOLEAN +KdbSymPrintAddress(IN PVOID Address); + KD_CONTINUE_TYPE KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord, - PCONTEXT Context, - PKTRAP_FRAME TrapFrame); + PCONTEXT Context, + PKTRAP_FRAME TrapFrame); + +#endif /* KDBG */ + VOID DebugLogDumpMessages(VOID); diff --git a/reactos/ntoskrnl/include/internal/ldr.h b/reactos/ntoskrnl/include/internal/ldr.h index ef93e8f0c19..21d8519e33b 100644 --- a/reactos/ntoskrnl/include/internal/ldr.h +++ b/reactos/ntoskrnl/include/internal/ldr.h @@ -108,22 +108,4 @@ LdrUnloadModule(PMODULE_OBJECT ModuleObject); PMODULE_OBJECT LdrGetModuleObject(PUNICODE_STRING ModuleName); -NTSTATUS -LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, - IN ULONG_PTR RelativeAddress, - OUT PULONG LineNumber, - OUT PCH FileName OPTIONAL, - OUT PCH FunctionName OPTIONAL); - - -#ifdef DBG - -VOID -LdrLoadUserModuleSymbols(PLDR_MODULE LdrModule); - -VOID -LdrUnloadModuleSymbols(PIMAGE_SYMBOL_INFO SymbolInfo); - -#endif /* DBG */ - #endif /* __INCLUDE_INTERNAL_LDR_H */ diff --git a/reactos/ntoskrnl/ke/i386/exp.c b/reactos/ntoskrnl/ke/i386/exp.c index 6f24039aa20..fcdeadba6cd 100644 --- a/reactos/ntoskrnl/ke/i386/exp.c +++ b/reactos/ntoskrnl/ke/i386/exp.c @@ -115,8 +115,7 @@ static NTSTATUS ExceptionToNtStatus[] = BOOLEAN STDCALL KeRosPrintAddress(PVOID address) { - KdbPrintAddress(address); - return TRUE; + return KdbSymPrintAddress(address); } #else /* KDBG */ BOOLEAN STDCALL