aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/shared')
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp12
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.h7
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp376
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.h135
-rw-r--r--src/server/shared/Utilities/Util.cpp9
-rw-r--r--src/server/shared/Utilities/Util.h9
6 files changed, 394 insertions, 154 deletions
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp
index de1e5b992e6..488ff18dca4 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp
@@ -69,6 +69,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? , mutereason = ? , muteby = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_LAST_ATTEMPT_IP, "UPDATE account SET last_attempt_ip = ? WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = 1 WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_UPTIME_PLAYERS, "UPDATE uptime SET uptime = ?, maxplayers = ? WHERE realmid = ? AND starttime = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_OLD_LOGS, "DELETE FROM logs WHERE (time + ?) < ?", CONNECTION_ASYNC);
@@ -90,12 +91,21 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_RECRUITER, "SELECT 1 FROM account WHERE recruiter = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_BANS, "SELECT 1 FROM account_banned WHERE id = ? AND active = 1 UNION SELECT 1 FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_LAST_ATTEMPT_IP, "SELECT last_attempt_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP2NATION_COUNTRY, "SELECT c.country FROM ip2nationCountries c, ip2nation i WHERE i.ip < ? AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_GET_EMAIL_BY_ID, "SELECT email FROM account WHERE id = ?", CONNECTION_SYNCH);
-
+ // 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_AccountLoginDeLete_IP_Logging"
+ PrepareStatement(LOGIN_INS_ALDL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_FailedAccountLogin_IP_Logging"
+ PrepareStatement(LOGIN_INS_FACL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_attempt_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: uint32, 1: uint32, 2: uint8, 3: string, 4: string // Complete name: "Login_Insert_CharacterDelete_IP_Logging"
+ PrepareStatement(LOGIN_INS_CHAR_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: string, 1: string, 2: string // Complete name: "Login_Insert_Failed_Account_Login_due_password_IP_Logging"
+ PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES ((SELECT id FROM account WHERE username = ?), 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH);
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h
index 01f9fd973b6..604e9d39551 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.h
+++ b/src/server/shared/Database/Implementation/LoginDatabase.h
@@ -89,6 +89,7 @@ enum LoginDatabaseStatements
LOGIN_UPD_MUTE_TIME,
LOGIN_UPD_MUTE_TIME_LOGIN,
LOGIN_UPD_LAST_IP,
+ LOGIN_UPD_LAST_ATTEMPT_IP,
LOGIN_UPD_ACCOUNT_ONLINE,
LOGIN_UPD_UPTIME_PLAYERS,
LOGIN_DEL_OLD_LOGS,
@@ -114,7 +115,13 @@ enum LoginDatabaseStatements
LOGIN_DEL_ACCOUNT,
LOGIN_SEL_IP2NATION_COUNTRY,
LOGIN_SEL_AUTOBROADCAST,
+ LOGIN_SEL_LAST_ATTEMPT_IP,
+ LOGIN_SEL_LAST_IP,
LOGIN_GET_EMAIL_BY_ID,
+ LOGIN_INS_ALDL_IP_LOGGING,
+ LOGIN_INS_FACL_IP_LOGGING,
+ LOGIN_INS_CHAR_IP_LOGGING,
+ LOGIN_INS_FALP_IP_LOGGING,
LOGIN_SEL_ACCOUNT_ACCESS_BY_ID,
LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS,
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp
index 81825c9055b..350a258f455 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.cpp
+++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp
@@ -60,6 +60,7 @@ HANDLE WheatyExceptionReport::m_hReportFile;
HANDLE WheatyExceptionReport::m_hDumpFile;
HANDLE WheatyExceptionReport::m_hProcess;
SymbolPairs WheatyExceptionReport::symbols;
+std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails;
// Declare global instance of class
WheatyExceptionReport g_WheatyExceptionReport;
@@ -767,18 +768,21 @@ ULONG /*SymbolSize*/,
PVOID UserContext)
{
- char szBuffer[1024 * 64];
+ char szBuffer[WER_LARGE_BUFFER_SIZE];
+ memset(szBuffer, 0, sizeof(szBuffer));
__try
{
ClearSymbols();
if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext,
szBuffer, sizeof(szBuffer)))
- _tprintf(_T("\t%s\r\n"), szBuffer);
+ _tprintf(_T("%s"), szBuffer);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
- _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name);
+ _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name);
+ if (szBuffer[0] != '\0')
+ _tprintf(_T("%s"), szBuffer);
}
return TRUE;
@@ -797,12 +801,6 @@ unsigned /*cbBuffer*/)
{
char * pszCurrBuffer = pszBuffer;
- // Indicate if the variable is a local or parameter
- if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
- pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter ");
- else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
- pszCurrBuffer += sprintf(pszCurrBuffer, "Local ");
-
// If it's a function, don't do anything.
if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK
return false;
@@ -824,19 +822,25 @@ unsigned /*cbBuffer*/)
// return false;
}
else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
- {
return false; // Don't try to report register variable
- }
else
{
pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable
}
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
+
+ // Indicate if the variable is a local or parameter
+ if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
+ symbolDetails.top().Prefix = "Parameter ";
+ else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
+ symbolDetails.top().Prefix = "Local ";
+
// Determine if the variable is a user defined type (UDT). IF so, bHandled
// will return true.
bool bHandled;
pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex,
- 0, pVariable, bHandled, pSym->Name, "");
+ 0, pVariable, bHandled, pSym->Name, "", false, true);
if (!bHandled)
{
@@ -844,15 +848,19 @@ unsigned /*cbBuffer*/)
// variable. Based on the size, we're assuming it's a char, WORD, or
// DWORD.
BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
// Emit the variable name
- pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name);
+ if (pSym->Name[0] != '\0')
+ symbolDetails.top().Name = pSym->Name;
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size,
- (PVOID)pVariable);
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
return true;
}
@@ -868,13 +876,15 @@ DWORD dwTypeIndex,
unsigned nestingLevel,
DWORD_PTR offset,
bool & bHandled,
-char* Name,
-char* suffix)
+const char* Name,
+char* /*suffix*/,
+bool newSymbol,
+bool logChildren)
{
bHandled = false;
- if (!StoreSymbol(dwTypeIndex, offset))
- return pszCurrBuffer;
+ if (newSymbol)
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
DWORD typeTag;
if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
@@ -890,19 +900,39 @@ char* suffix)
if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0)
{
LocalFree(pwszTypeName);
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", "std::string");
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, btStdString, 0, (PVOID)offset);
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
+ symbolDetails.top().Type = "std::string";
+ char buffer[50];
+ FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
bHandled = true;
return pszCurrBuffer;
}
- pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName);
+ char buffer[200];
+ wcstombs(buffer, pwszTypeName, sizeof(buffer));
+ buffer[199] = '\0';
+ if (Name != NULL && Name[0] != '\0')
+ {
+ symbolDetails.top().Type = buffer;
+ symbolDetails.top().Name = Name;
+ }
+ else if (buffer[0] != '\0')
+ symbolDetails.top().Name = buffer;
+
LocalFree(pwszTypeName);
}
+ else if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
- if (strlen(suffix) > 0)
- pszCurrBuffer += sprintf(pszCurrBuffer, "%s", suffix);
+ if (!StoreSymbol(dwTypeIndex, offset))
+ {
+ // Skip printing address and base class if it has been printed already
+ if (typeTag == SymTagBaseClass)
+ bHandled = true;
+ return pszCurrBuffer;
+ }
DWORD innerTypeID;
switch (typeTag)
@@ -910,11 +940,9 @@ char* suffix)
case SymTagPointerType:
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
{
-#define MAX_NESTING_LEVEL 5
- if (nestingLevel >= MAX_NESTING_LEVEL)
- break;
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name);
BOOL isReference;
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
@@ -922,44 +950,56 @@ char* suffix)
memset(addressStr, 0, sizeof(addressStr));
if (isReference)
- addressStr[0] = '&';
+ symbolDetails.top().Suffix += "&";
else
- addressStr[0] = '*';
+ symbolDetails.top().Suffix += "*";
- DWORD_PTR address = *(PDWORD_PTR)offset;
- if (address == NULL)
- {
- pwszTypeName;
- if (SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMNAME,
- &pwszTypeName))
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName);
- LocalFree(pwszTypeName);
- }
+ // Try to dereference the pointer in a try/except block since it might be invalid
+ DWORD_PTR address = DereferenceUnsafePointer(offset);
- pszCurrBuffer += sprintf(pszCurrBuffer, "%s = NULL\r\n", addressStr);
+ char buffer[50];
+ FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
- bHandled = true;
- return pszCurrBuffer;
- }
- else
- {
- FormatOutputValue(&addressStr[1], btVoid, sizeof(PVOID), (PVOID)offset);
- pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
- address, bHandled, "", addressStr);
+ if (nestingLevel >= WER_MAX_NESTING_LEVEL)
+ logChildren = false;
+
+ // no need to log any children since the address is invalid anyway
+ if (address == NULL || address == DWORD_PTR(-1))
+ logChildren = false;
+
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ address, bHandled, Name, addressStr, false, logChildren);
- if (!bHandled)
+ if (!bHandled)
+ {
+ BasicType basicType = GetBasicType(dwTypeIndex, modBase);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+
+ if (address == NULL)
+ symbolDetails.top().Value = "NULL";
+ else if (address == DWORD_PTR(-1))
+ symbolDetails.top().Value = "<Unable to read memory>";
+ else
{
- BasicType basicType = GetBasicType(dwTypeIndex, modBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
// Get the size of the child member
ULONG64 length;
SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, length, (PVOID)address);
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
- bHandled = true;
- return pszCurrBuffer;
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, length, (PVOID)address, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+ bHandled = true;
+ return pszCurrBuffer;
+ }
+ else if (address == NULL)
+ symbolDetails.top().Value = "NULL";
+ else if (address == DWORD_PTR(-1))
+ {
+ symbolDetails.top().Value = "<Unable to read memory>";
+ bHandled = true;
+ return pszCurrBuffer;
}
}
break;
@@ -970,13 +1010,80 @@ char* suffix)
if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
break;
- if (innerTypeTag == SymTagPointerType)
+ switch (innerTypeTag)
{
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name);
+ case SymTagUDT:
+ if (nestingLevel >= WER_MAX_NESTING_LEVEL)
+ logChildren = false;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ case SymTagPointerType:
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ case SymTagArrayType:
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case SymTagArrayType:
+ if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
+ {
+ symbolDetails.top().HasChildren = true;
+
+ BasicType basicType = btNoType;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, Name, "", false, false);
+
+ // Set Value back to an empty string since the Array object itself has no value, only its elements have
+ symbolDetails.top().Value = "";
+
+ DWORD elementsCount;
+ if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
+ symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]";
+ else
+ symbolDetails.top().Suffix += "[<unknown count>]";
- pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
- offset, bHandled, "", "");
+ if (!bHandled)
+ {
+ basicType = GetBasicType(dwTypeIndex, modBase);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+ bHandled = true;
+ }
+
+ // Get the size of the child member
+ ULONG64 length;
+ SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
+
+ char buffer[50];
+ switch (basicType)
+ {
+ case btChar:
+ case btStdString:
+ FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ break;
+ default:
+ for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++)
+ {
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
+ symbolDetails.top().Suffix += "[" + std::to_string(index) + "]";
+ FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
+ }
+ break;
}
+
+ return pszCurrBuffer;
}
break;
case SymTagBaseType:
@@ -1013,26 +1120,37 @@ char* suffix)
return pszCurrBuffer;
}
- // Append a line feed
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
-
// Iterate through each of the children
for (unsigned i = 0; i < dwChildrenCount; i++)
{
DWORD symTag;
SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag);
- if (symTag == SymTagFunction || symTag == SymTagTypedef)
+ if (symTag == SymTagFunction ||
+ symTag == SymTagEnum ||
+ symTag == SymTagTypedef ||
+ symTag == SymTagVTable)
continue;
- // Add appropriate indentation level (since this routine is recursive)
- for (unsigned j = 0; j <= nestingLevel+1; j++)
- pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
+ // Ignore static fields
+ DWORD dataKind;
+ SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind);
+ if (dataKind == DataIsStaticLocal ||
+ dataKind == DataIsGlobal ||
+ dataKind == DataIsStaticMember)
+ continue;
+
+
+ symbolDetails.top().HasChildren = true;
+ if (!logChildren)
+ {
+ bHandled = false;
+ return pszCurrBuffer;
+ }
// Recurse for each of the child types
bool bHandled2;
BasicType basicType = GetBasicType(children.ChildId[i], modBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
// Get the offset of the child member, relative to its parent
DWORD dwMemberOffset;
@@ -1044,11 +1162,14 @@ char* suffix)
pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase,
children.ChildId[i], nestingLevel+1,
- dwFinalOffset, bHandled2, ""/*Name */, "");
+ dwFinalOffset, bHandled2, ""/*Name */, "", true, true);
// If the child wasn't a UDT, format it appropriately
if (!bHandled2)
{
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+
// Get the real "TypeId" of the child. We need this for the
// SymGetTypeInfo(TI_GET_TYPEID) call below.
DWORD typeId;
@@ -1059,75 +1180,75 @@ char* suffix)
ULONG64 length;
SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length);
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType,
- length, (PVOID)dwFinalOffset);
-
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
}
bHandled = true;
return pszCurrBuffer;
}
-char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
+void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
BasicType basicType,
DWORD64 length,
-PVOID pAddress)
+PVOID pAddress,
+size_t bufferSize)
{
__try
{
switch (basicType)
{
case btChar:
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", pAddress);
+ {
+ if (strlen((char*)pAddress) > bufferSize - 6)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress);
+ else
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress);
break;
+ }
case btStdString:
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", static_cast<std::string*>(pAddress)->c_str());
+ {
+ std::string* value = static_cast<std::string*>(pAddress);
+ if (value->length() > bufferSize - 6)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, value->c_str());
+ else
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str());
break;
+ }
default:
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
if (length == 1)
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress);
else if (length == 2)
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress);
else if (length == 4)
{
if (basicType == btFloat)
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress);
- }
- else if (basicType == btChar)
- {
- if (!IsBadStringPtr(*(PSTR*)pAddress, 32))
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"",
- *(PSTR*)pAddress);
- }
- else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X",
- *(PDWORD)pAddress);
- }
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress);
else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress);
}
else if (length == 8)
{
if (basicType == btFloat)
{
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf",
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%lf",
*(double *)pAddress);
}
else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X",
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X",
*(DWORD64*)pAddress);
}
else
{
#if _WIN64
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", (DWORD64*)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64*)pAddress);
#else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", (PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (PDWORD)pAddress);
#endif
}
break;
@@ -1136,13 +1257,11 @@ PVOID pAddress)
__except (EXCEPTION_EXECUTE_HANDLER)
{
#if _WIN64
- pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %I64X", (DWORD64*)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64*)pAddress);
#else
- pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %X", (PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (PDWORD)pAddress);
#endif
}
-
- return pszCurrBuffer;
}
BasicType
@@ -1170,13 +1289,25 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase)
return btNoType;
}
+DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address)
+{
+ __try
+ {
+ return *(PDWORD_PTR)address;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return DWORD_PTR(-1);
+ }
+}
+
//============================================================================
// Helper function that writes to the report file, and allows the user to use
// printf style formating
//============================================================================
int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...)
{
- TCHAR szBuff[1024 * 64];
+ TCHAR szBuff[WER_LARGE_BUFFER_SIZE];
int retValue;
DWORD cbWritten;
va_list argptr;
@@ -1198,6 +1329,41 @@ bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset)
void WheatyExceptionReport::ClearSymbols()
{
symbols.clear();
+ while (!symbolDetails.empty())
+ symbolDetails.pop();
+}
+
+char* WheatyExceptionReport::PushSymbolDetail(char* pszCurrBuffer)
+{
+ // Log current symbol and then add another to the stack to keep the hierarchy format
+ pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer);
+ symbolDetails.emplace();
+ return pszCurrBuffer;
+}
+
+char* WheatyExceptionReport::PopSymbolDetail(char* pszCurrBuffer)
+{
+ pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer);
+ symbolDetails.pop();
+ return pszCurrBuffer;
+}
+
+char* WheatyExceptionReport::PrintSymbolDetail(char* pszCurrBuffer)
+{
+ if (symbolDetails.empty())
+ return pszCurrBuffer;
+
+ // Don't log anything if has been logged already or if it's empty
+ if (symbolDetails.top().Logged || symbolDetails.top().empty())
+ return pszCurrBuffer;
+
+ // Add appropriate indentation level (since this routine is recursive)
+ for (size_t i = 0; i < symbolDetails.size(); i++)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
+
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str());
+
+ return pszCurrBuffer;
}
#endif // _WIN32
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h
index e1cc3050929..9137b91aac9 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.h
+++ b/src/server/shared/Debugging/WheatyExceptionReport.h
@@ -5,12 +5,13 @@
#include <dbghelp.h>
#include <set>
-#if _MSC_VER < 1400
-# define countof(array) (sizeof(array) / sizeof(array[0]))
-#else
-# include <stdlib.h>
-# define countof _countof
-#endif // _MSC_VER < 1400
+#include <stdlib.h>
+#include <stack>
+#define countof _countof
+
+#define WER_MAX_ARRAY_ELEMENTS_COUNT 10
+#define WER_MAX_NESTING_LEVEL 5
+#define WER_LARGE_BUFFER_SIZE 1024 * 128
enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK
{
@@ -37,40 +38,54 @@ enum BasicType // Stolen from CVCON
btStdString = 101
};
+enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK
+{
+ DataIsUnknown,
+ DataIsLocal,
+ DataIsStaticLocal,
+ DataIsParam,
+ DataIsObjectPtr,
+ DataIsFileStatic,
+ DataIsGlobal,
+ DataIsMember,
+ DataIsStaticMember,
+ DataIsConstant
+};
+
const char* const rgBaseType[] =
{
- " <user defined> ", // btNoType = 0,
- " void ", // btVoid = 1,
- " char* ", // btChar = 2,
- " wchar_t* ", // btWChar = 3,
- " signed char ",
- " unsigned char ",
- " int ", // btInt = 6,
- " unsigned int ", // btUInt = 7,
- " float ", // btFloat = 8,
- " <BCD> ", // btBCD = 9,
- " bool ", // btBool = 10,
- " short ",
- " unsigned short ",
- " long ", // btLong = 13,
- " unsigned long ", // btULong = 14,
- " __int8 ",
- " __int16 ",
- " __int32 ",
- " __int64 ",
- " __int128 ",
- " unsigned __int8 ",
- " unsigned __int16 ",
- " unsigned __int32 ",
- " unsigned __int64 ",
- " unsigned __int128 ",
- " <currency> ", // btCurrency = 25,
- " <date> ", // btDate = 26,
- " VARIANT ", // btVariant = 27,
- " <complex> ", // btComplex = 28,
- " <bit> ", // btBit = 29,
- " BSTR ", // btBSTR = 30,
- " HRESULT " // btHresult = 31
+ "<user defined>", // btNoType = 0,
+ "void", // btVoid = 1,
+ "char",//char* // btChar = 2,
+ "wchar_t*", // btWChar = 3,
+ "signed char",
+ "unsigned char",
+ "int", // btInt = 6,
+ "unsigned int", // btUInt = 7,
+ "float", // btFloat = 8,
+ "<BCD>", // btBCD = 9,
+ "bool", // btBool = 10,
+ "short",
+ "unsigned short",
+ "long", // btLong = 13,
+ "unsigned long", // btULong = 14,
+ "int8",
+ "int16",
+ "int32",
+ "int64",
+ "int128",
+ "uint8",
+ "uint16",
+ "uint32",
+ "uint64",
+ "uint128",
+ "<currency>", // btCurrency = 25,
+ "<date>", // btDate = 26,
+ "VARIANT", // btVariant = 27,
+ "<complex>", // btComplex = 28,
+ "<bit>", // btBit = 29,
+ "BSTR", // btBSTR = 30,
+ "HRESULT" // btHresult = 31
};
struct SymbolPair
@@ -92,6 +107,39 @@ struct SymbolPair
};
typedef std::set<SymbolPair> SymbolPairs;
+struct SymbolDetail
+{
+ SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {}
+
+ std::string ToString()
+ {
+ Logged = true;
+ std::string formatted = Prefix + Type + Suffix;
+ if (!Name.empty())
+ {
+ if (!formatted.empty())
+ formatted += " ";
+ formatted += Name;
+ }
+ if (!Value.empty())
+ formatted += " = " + Value;
+ return formatted;
+ }
+
+ bool empty() const
+ {
+ return Value.empty() && !HasChildren;
+ }
+
+ std::string Prefix;
+ std::string Type;
+ std::string Suffix;
+ std::string Name;
+ std::string Value;
+ bool Logged;
+ bool HasChildren;
+};
+
class WheatyExceptionReport
{
public:
@@ -122,11 +170,12 @@ class WheatyExceptionReport
static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer);
- static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, char*, char*);
+ static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool);
- static char * FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress);
+ static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize);
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase);
+ static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address);
static int __cdecl _tprintf(const TCHAR * format, ...);
@@ -141,6 +190,12 @@ class WheatyExceptionReport
static HANDLE m_hDumpFile;
static HANDLE m_hProcess;
static SymbolPairs symbols;
+ static std::stack<SymbolDetail> symbolDetails;
+
+ static char* PushSymbolDetail(char* pszCurrBuffer);
+ static char* PopSymbolDetail(char* pszCurrBuffer);
+ static char* PrintSymbolDetail(char* pszCurrBuffer);
+
};
extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class
diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp
index ffef61557fc..28bbe831a69 100644
--- a/src/server/shared/Utilities/Util.cpp
+++ b/src/server/shared/Utilities/Util.cpp
@@ -547,3 +547,12 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse
return ss.str();
}
+
+uint32 EventMap::GetTimeUntilEvent(uint32 eventId) const
+{
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (eventId == (itr->second & 0x0000FFFF))
+ return itr->first - _time;
+
+ return std::numeric_limits<uint32>::max();
+}
diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h
index d6ead607c55..648edf39abe 100644
--- a/src/server/shared/Utilities/Util.h
+++ b/src/server/shared/Utilities/Util.h
@@ -866,14 +866,7 @@ class EventMap
* @param Id of the event.
* @return Time of next event.
*/
- uint32 GetTimeUntilEvent(uint32 eventId) const
- {
- for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
- if (eventId == (itr->second & 0x0000FFFF))
- return itr->first - _time;
-
- return std::numeric_limits<uint32>::max();
- }
+ uint32 GetTimeUntilEvent(uint32 eventId) const;
private:
/**