/*++ Copyright (c) 2001 Microsoft Corporation All rights reserved. Module Name: dbgutil.hxx Abstract: LSA Utility functions header Author: Larry Zhu (Lzhu) May 1, 2001 Revision History: --*/ #ifndef _LSAUTIL_HXX_ #define _LSAUTIL_HXX_ #include #include #include namespace LSA_NS { enum ELsaExceptionCode { kInvalid, kIncorrectSymbols, kExitOnControlC, }; LPCTSTR StripPathFromFileName( IN LPCTSTR pszFile ); ULONG GetStructFieldVerbose( IN ULONG64 addrStructBase, IN PCSTR pszStructTypeName, IN PCSTR pszStructFieldName, IN ULONG BufferSize, OUT PVOID Buffer); ULONG GetStructPtrFieldVerbose( IN ULONG64 addrStructBase, IN PCSTR pszStructTypeName, IN PCSTR pszStructFieldName, OUT PULONG64 Buffer); HRESULT GetCurrentProcessor( IN PDEBUG_CLIENT Client, OPTIONAL OUT PULONG pProcessor, OPTIONAL OUT PHANDLE phCurrentThread); PCSTR ReadStructStrField( IN ULONG64 addrStructBase, IN PCSTR pszStructTypeName, IN PCSTR pszStructStringFieldName); PCWSTR ReadStructWStrField( IN ULONG64 addrStructBase, IN PCSTR pszStructTypeName, IN PCSTR pszStructWStringFieldName); BOOL WINAPI LsaLookupAccountNameA( IN LPCSTR lpSystemName, IN LPCSTR lpAccountName, OUT PSID Sid, IN OUT LPDWORD cbSid, OUT LPSTR ReferencedDomainName, IN OUT LPDWORD cbReferencedDomainName, OUT PSID_NAME_USE peUse ); BOOL WINAPI LsaLookupAccountSidA( IN LPCSTR lpSystemName, IN PSID Sid, OUT LPSTR Name, IN OUT LPDWORD cbName, OUT LPSTR ReferencedDomainName, IN OUT LPDWORD cbReferencedDomainName, OUT PSID_NAME_USE peUse ); void LocalPrintGuid(IN const GUID *pGuid); BOOL IsAddressInNonePAEKernelAddressSpace(IN ULONG64 addr); HRESULT HResultFromWin32(IN DWORD dwError); HRESULT GetLastErrorAsHResult(void); BOOLEAN IsEmpty(IN PCSTR pszArgs); void debugPrintHandle(IN HANDLE handle); NTSTATUS NtStatusFromWin32(IN DWORD dwError); NTSTATUS GetLastErrorAsNtStatus(void); HRESULT ProcessKnownOptions(IN PCSTR pszArgs OPTIONAL); HRESULT ProcessHelpRequest(IN PCSTR pszArgs OPTIONAL); LARGE_INTEGER ULONG642LargeInteger( IN ULONG64 value ); VOID ShowSystemTimeAsLocalTime( IN PCSTR pszBanner, IN ULONG64 ul64Time ); void handleLsaException( IN ELsaExceptionCode eExceptionCode, IN PCSTR pszMsg, OPTIONAL IN PCSTR pszSymHint OPTIONAL ); HRESULT GetFileNamePart(IN PCSTR pszFullPath, OUT PCSTR *ppszFileName); void debugPrintHex(IN const void* buffer, IN ULONG cbBuffer); #define LSA_NONE 0x00 #define LSA_WARN 0x01 #define LSA_ERROR 0x02 #define LSA_LOG 0x04 #define LSA_LOG_MORE 0x08 #define LSA_LOG_ALL 0x10 inline void debugPrintLevel(IN ULONG ulLevel) { PCSTR pszText = NULL; switch (ulLevel) { case LSA_WARN: pszText = "[warn] "; break; case LSA_ERROR: pszText = "[error] "; break; case LSA_LOG: pszText = "[log] "; break; case LSA_LOG_MORE: pszText = "[more] "; break; case LSA_LOG_ALL: pszText = "[all] "; break; default: pszText = kstrInvalid; break; } OutputDebugStringA(pszText); } inline void debugPrintf(IN PCSTR pszFmt, ...) { CHAR szBuffer[4096] = {0}; OutputDebugStringA(g_Globals.pszDbgPrompt ? g_Globals.pszDbgPrompt : kstrEmptyA); va_list pArgs; va_start(pArgs, pszFmt); _vsnprintf(szBuffer, sizeof(szBuffer) - 1, pszFmt, pArgs); OutputDebugStringA(szBuffer); va_end(pArgs); } inline PCSTR IoctlErrorStatusToStr(IN PCSTR pszPad, IN ULONG err) { static CHAR szBuf[1024] = {0}; #define BRANCH_AND_PRINT(x) \ \ do { \ if (x == err) { \ _snprintf(szBuf, sizeof(szBuf) - 1, "%s%s", pszPad, #x); \ return szBuf; \ } \ } while (0) BRANCH_AND_PRINT(MEMORY_READ_ERROR); BRANCH_AND_PRINT(SYMBOL_TYPE_INDEX_NOT_FOUND); BRANCH_AND_PRINT(SYMBOL_TYPE_INFO_NOT_FOUND); BRANCH_AND_PRINT(FIELDS_DID_NOT_MATCH); BRANCH_AND_PRINT(NULL_SYM_DUMP_PARAM); BRANCH_AND_PRINT(NULL_FIELD_NAME); BRANCH_AND_PRINT(INCORRECT_VERSION_INFO); BRANCH_AND_PRINT(EXIT_ON_CONTROLC); BRANCH_AND_PRINT(CANNOT_ALLOCATE_MEMORY); BRANCH_AND_PRINT(INSUFFICIENT_SPACE_TO_COPY); #undef BRANCH_AND_PRINT _snprintf(szBuf, sizeof(szBuf) - 1, "%s%#x", pszPad, err); return szBuf; } BOOL IsPtr64WithVoidStar(void); inline ULONG64 toPtr(IN ULONG64 addr) { static BOOL bIsPtr64 = IsPtr64WithVoidStar(); if (!bIsPtr64) { addr = static_cast(addr); } return addr; } inline ULONG GetPtrSize(void) { static ULONG cbPtrSize = 0; if (!cbPtrSize) { cbPtrSize = IsPtr64WithVoidStar() ? sizeof(ULONG64) : sizeof(ULONG); } return cbPtrSize; } inline ULONG ReadPtrSize(void) { static ULONG cbPtrSize = GetPtrSize(); if (!cbPtrSize) { throw "ReadPtrSize failed"; } return cbPtrSize; } inline ULONG GetPtrWithVoidStar(IN ULONG64 Addr, IN ULONG64* pPointer) { return GetFieldData(Addr, kstrVoidStar, NULL, sizeof(ULONG64), (PVOID) pPointer); } inline PCSTR EasyStr(IN PCSTR pszName) { return pszName ? pszName : kstrNullPtrA; } inline void HandleIoctlErrors(IN PCSTR pszBanner, IN ULONG ErrorCode) { if (SYMBOL_TYPE_INFO_NOT_FOUND == ErrorCode) { throw kIncorrectSymbols; } else if (ErrorCode) { DBG_LOG(LSA_ERROR, ("%s: Ioctl failed with error code %s\n", EasyStr(pszBanner), EasyStr(IoctlErrorStatusToStr(kstrEmptyA, ErrorCode)))); throw "Ioctl failed"; } } inline ULONG64 ReadPtrWithVoidStar(IN ULONG64 Addr) { ULONG64 Pointer = 0; HandleIoctlErrors("ReadPtrWithVoidStar", GetFieldData(Addr, kstrVoidStar, NULL, sizeof(ULONG64), &Pointer)); return Pointer; } inline ULONG64 ReadStructPtrField(IN ULONG64 addrStructBase, IN PCSTR pszStructTypeName, IN PCSTR pszStructFieldName) { ULONG64 addr = 0; DBG_LOG(LSA_LOG, ("ReadStructPtrField %s %#I64x %s\n", EasyStr(pszStructTypeName), addrStructBase, EasyStr(pszStructFieldName))); HandleIoctlErrors("ReadStructPtrField", GetStructPtrFieldVerbose(addrStructBase, pszStructTypeName, pszStructFieldName, &addr)); return toPtr(addr); } inline ULONG64 ForwardAdjustPtrAddr(IN ULONG64 addr) { static ULONG uPtrSize = ReadPtrSize(); ULONG64 alignedPtrAddr = addr; // // Only 64bit machines have alignment requirement // if (uPtrSize == sizeof(ULONG64)) { alignedPtrAddr = ROUND_UP_COUNT(addr, sizeof(ULONG64)); // ((addr + uPtrSize - 1) / uPtrSize) * uPtrSize; if (alignedPtrAddr != addr) { DBG_LOG(LSA_LOG, ("ForwardAdjustPtrAddr adjusted addr from %#I64x to %#I64x\n", addr, alignedPtrAddr)); } } return alignedPtrAddr; } inline ULONG64 ReadPtrVar(IN ULONG64 addr) { static uPtrSize = ReadPtrSize(); ULONG64 value = 0; ULONG errorCode = 0; // // Assume 64 bit machine has alignment requirement for pointers // if (uPtrSize == sizeof(ULONG64)) { ULONG64 alignedAddr = addr; alignedAddr = ForwardAdjustPtrAddr(addr); if (alignedAddr != addr) { DBG_LOG(LSA_WARN, ("Adjust pointer address %#I64x to 8 byte boundary %#I64x\n", addr, alignedAddr)); } addr = alignedAddr; } HandleIoctlErrors("ReadPtrVar", GetPtrWithVoidStar(addr, &value)); return toPtr(value); } inline UCHAR ReadUCHARVar(IN ULONG64 addr) { UCHAR value = 0; if (!ReadMemory(addr, &value, sizeof(value), NULL)) { DBG_LOG(LSA_ERROR, ("Can not ReadUCHARVar at %#I64x\n", addr)); throw "ReadUCHARVar failed"; } return value; } inline USHORT ReadUSHORTVar(IN ULONG64 addr) { USHORT value = 0; if (!ReadMemory(addr, &value, sizeof(value), NULL)) { DBG_LOG(LSA_ERROR, ("Can not ReadUSHORTVar at %#I64x\n", addr)); throw "ReadUSHORTVar failed"; } return value; } inline ULONG ReadULONGVar(IN ULONG64 addr) { ULONG value = 0; if (!ReadMemory(addr, &value, sizeof(value), NULL)) { DBG_LOG(LSA_ERROR, ("Can not ReadULONGVar at %#I64x\n", addr)); throw "ReadULONGVar failed"; } return value; } inline ULONG64 ReadULONG64Var(IN ULONG64 addr) { ULONG64 value = 0; if (!ReadMemory(addr, &value, sizeof(value), NULL)) { DBG_LOG(LSA_ERROR, ("Can not ReadULONG64Var at %#I64x\n", addr)); throw "ReadULONG64Var failed"; } return value; } inline ULONG ReadTypeSize(IN PCSTR pszTypeName) { ULONG typeSize = 0; typeSize = GetTypeSize(pszTypeName); DBG_LOG(LSA_LOG, ("Read type size of \"%s\"\n", EasyStr(pszTypeName))); if (!typeSize) { DBG_LOG(LSA_ERROR, ("Can not GetTypeSize on %s\n", EasyStr(pszTypeName))); throw "ReadTypeSize failed\n"; } return typeSize; } inline ULONG ReadFieldOffset(IN PCSTR pszTypeName, IN PCSTR pszFieldName) { ULONG fieldOffset = 0; DBG_LOG(LSA_LOG, ("Read field offset of \"%s\" from \"%s\"\n", EasyStr(pszFieldName), EasyStr(pszTypeName))); HandleIoctlErrors("ReadFieldOffset", GetFieldOffset(pszTypeName, pszFieldName, &fieldOffset)); return fieldOffset; } inline void ReadStructField(IN ULONG64 addrStructBase, IN PCSTR pszStructTypeName, IN PCSTR pszStructFieldName, IN ULONG fieldSize, OUT void* pFieldValue) { DBG_LOG(LSA_LOG, ("ReadStructField %s %#I64x %s\n", EasyStr(pszStructTypeName), addrStructBase, EasyStr(pszStructFieldName))); HandleIoctlErrors("ReadStructField", GetStructFieldVerbose(addrStructBase, pszStructTypeName, pszStructFieldName, fieldSize, pFieldValue)); } inline void LsaReadMemory(IN ULONG64 addr, IN ULONG cbBuffer, OUT void* buffer) { if (!ReadMemory(addr, buffer, cbBuffer, NULL)) { DBG_LOG(LSA_ERROR, ("Unable to read %#x bytes from memory location %#I64x\n", cbBuffer, toPtr(addr))); throw "LsaReadMemory failed"; } } // // Used to read in value of a short (<= 8 bytes) fields // // This is essentially the same as GetShortField with one difference that // it throws exceptions on failures // inline ULONG64 ReadShortField(IN ULONG64 TypeAddress, IN PCSTR pszName, IN USHORT StoreAddress) { static ULONG64 SavedAddress = 0; static PCSTR pszSavedName = NULL; static ULONG ReadPhysical = 0; ULONG Err = 0; FIELD_INFO flds = {reinterpret_cast(const_cast(pszName)), NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}; SYM_DUMP_PARAM Sym = { sizeof (SYM_DUMP_PARAM), reinterpret_cast(const_cast(pszSavedName)), DBG_DUMP_NO_PRINT | ((StoreAddress & 2) ? DBG_DUMP_READ_PHYSICAL : 0), SavedAddress, NULL, NULL, NULL, 1, &flds }; if (StoreAddress) { Sym.sName = reinterpret_cast(const_cast(pszName)); Sym.nFields = 0; pszSavedName = pszName; Sym.addr = SavedAddress = TypeAddress; ReadPhysical = (StoreAddress & 2); if (!SavedAddress) { throw "Invalid arguments to ReadShortField"; } Err = Ioctl(IG_DUMP_SYMBOL_INFO, &Sym, Sym.size); DBG_LOG(LSA_LOG, ("Save address %s %#I64x\n", EasyStr(pszName), TypeAddress)); HandleIoctlErrors("ReadShortField (save address) failed", Err); return 0; // zero on success } else { Sym.Options |= ReadPhysical ? DBG_DUMP_READ_PHYSICAL : 0; } Err = Ioctl(IG_DUMP_SYMBOL_INFO, &Sym, Sym.size); DBG_LOG(LSA_LOG, ("Read %s %#I64x %s\n", EasyStr(pszSavedName), SavedAddress, EasyStr(pszName))); HandleIoctlErrors("ReadShortField (read value) failed", Err); return flds.address; } inline ULONG ReadTypeSizeInArray(IN PCSTR pszType) { ULONG cbOneItem = 0; ULONG cbTwoItems = 0; CHAR szTypeTmp[256] = {0}; DBG_LOG(LSA_LOG, ("ReadTypeSizeInArray %s\n", pszType)); cbOneItem = GetTypeSize(pszType); if (_snprintf(szTypeTmp, sizeof(szTypeTmp) - 1, "%s[2]", pszType) < 0) { throw "ReadTypeSizeInArray failed with insufficient buffer"; } cbTwoItems = GetTypeSize(szTypeTmp); cbOneItem = cbTwoItems - cbOneItem; if (!cbOneItem) { dprintf("Unable to read type size in array for %s\n", pszType); throw "ReadTypeSizeInArray failed"; } return cbOneItem; } inline ULONG64 ReadPtrField(IN PCSTR Field) { return toPtr(ReadShortField(0, Field, 0)); } inline void ExitIfControlC(void) { if (CheckControlC()) { throw kExitOnControlC; } } // // This func is not thread safe // inline PCSTR PtrToStr(IN ULONG64 addr) { static CHAR szBuffer[64] = {0}; if (!addr) { return kstrNullPtrA; } _snprintf(szBuffer, sizeof(szBuffer) - 1, "%#I64x", addr); return szBuffer; } // // This func is not thread safe because it calls PtrToStr which is not // thread safe // inline PCSTR GetSymbolStr(IN ULONG64 addr, IN PCSTR pszBuffer) { ExitIfControlC(); // // null // if (!addr) { return kstrNullPtrA; } // // No symbols resolved, return address // if (!pszBuffer || !*pszBuffer) { return PtrToStr(addr); } // // Return symbols // return pszBuffer; } inline void PrintPtrWithSymbolsLn(IN PCSTR pszBanner, IN ULONG64 addr) { CHAR szBuffer[MAX_PATH] = {0}; ULONG64 Disp = 0; GetSymbol(addr, szBuffer, &Disp); dprintf(kstr2StrLn, pszBanner, GetSymbolStr(addr, szBuffer)); } inline void PrintSpaces(IN LONG cSpaces) { for (LONG i = 0; i < cSpaces; i++) { dprintf(kstrSpace); } } } // LSA_NS #endif