You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2523 lines
61 KiB
2523 lines
61 KiB
/*++
|
|
|
|
Copyright (c) 1992-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
crdb.cpp
|
|
|
|
Abstract:
|
|
Handles database queries for crash buckets
|
|
|
|
Environment:
|
|
|
|
User Mode.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#define STRSAFE_NO_DEPRECATE
|
|
#include <strsafe.h>
|
|
#include <shlwapi.h>
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
#include <stdio.h>
|
|
#include "ocamon.h"
|
|
|
|
#define LvlDatabaseInitDone 1
|
|
#define LvlCrashAddedToDB 2
|
|
#define LvlCustomerDbUpdate 4
|
|
#define LvlMessageQReply 8
|
|
|
|
LPOLESTR g_lpwszGetAll = L"SELECT * from CrashInstances";
|
|
LPOLESTR g_lpwszCrashInstanceTable = L"CrashInstances";
|
|
LPOLESTR g_lpwszBucketTable = L"BucketToInt";
|
|
LPOLESTR g_lpwszBucketMapTable = L"BucketToCrash";
|
|
LPOLESTR g_lpwszMachineInfoTable = L"MachineDescription";
|
|
LPOLESTR g_lpwszOverClkTable = L"OverClocked";
|
|
LPOLESTR g_lpwszSolutionsTable = L"SolutionMap";
|
|
LPOLESTR g_lpwszRaidTable = L"RaidBugs";
|
|
LPSTR g_lpszBaseUrl = "https://oca.microsoft.com/secure/response.asp?";
|
|
|
|
CrashDatabaseHandler *g_CrDb = NULL;
|
|
CustDatabaseHandler *g_CustDb = NULL;
|
|
SolutionDatabaseHandler *g_SolDb = NULL;
|
|
BOOL g_ComInitialized = FALSE;
|
|
|
|
static bool fResetFilter = false;
|
|
|
|
void
|
|
ansi2wchr(
|
|
const PCHAR astr,
|
|
PWCHAR wstr
|
|
);
|
|
|
|
|
|
HRESULT
|
|
ExtDllInitDynamicCalls(
|
|
PDEBUG_CONTROL3 DebugControl
|
|
)
|
|
//
|
|
// Load Ole32 and OleAut32 dlls
|
|
//
|
|
{
|
|
HRESULT Hr;
|
|
ULONG EngineOptions;
|
|
|
|
if ((Hr = DebugControl->GetEngineOptions(&EngineOptions)) == S_OK)
|
|
{
|
|
if (EngineOptions & DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS)
|
|
{
|
|
// Do not use ole32 APIs when we disallow network paths
|
|
return E_FAIL;
|
|
}
|
|
if ((Hr = InitDynamicCalls(&g_Ole32CallsDesc)) != S_OK)
|
|
{
|
|
return Hr;
|
|
}
|
|
if ((Hr = InitDynamicCalls(&g_OleAut32CallsDesc)) != S_OK)
|
|
{
|
|
return Hr;
|
|
}
|
|
if ((Hr = InitDynamicCalls(&g_ShlWapiCallsDesc)) != S_OK)
|
|
{
|
|
return Hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
return Hr;
|
|
}
|
|
void BuildCrashId(ULONG UpTime, ULONG CrashTime, PULONG64 pCID)
|
|
{
|
|
ULONG64 u64 = CrashTime;
|
|
*pCID = (u64 << 32) + UpTime;
|
|
}
|
|
|
|
#ifdef _NEED_EVENT_LOGS_
|
|
|
|
LPCSTR c_szEventLogKey = "System\\CurrentControlSet\\Services\\EventLog\\Application";
|
|
LPCSTR c_szEventLogSource = "OcaDbAddCrash";
|
|
LPCSTR c_szEventLogMsgFile = "EventMessageFile";
|
|
LPCSTR c_szEventLogTypes = "TypesSupported";
|
|
|
|
|
|
HRESULT
|
|
SetupEventLogging(
|
|
void
|
|
)
|
|
{
|
|
HKEY hEvLog = NULL;
|
|
HKEY hEvLogSource = NULL;
|
|
LONG err = ERROR_SUCCESS;
|
|
CHAR AppName[MAX_PATH];
|
|
|
|
if ((err = RegOpenKey(HKEY_LOCAL_MACHINE,
|
|
c_szEventLogKey, &hEvLog)) != ERROR_SUCCESS)
|
|
{
|
|
return HRESULT_FROM_WIN32( err );
|
|
}
|
|
|
|
if ((err = RegOpenKey(hEvLog, c_szEventLogSource,
|
|
&hEvLogSource)) != ERROR_SUCCESS)
|
|
{
|
|
DWORD AllowTypes;
|
|
//
|
|
// OCA logging hasn't been registered on this system yet
|
|
// try to setup the registry values for logging
|
|
//
|
|
err = RegCreateKey(hEvLog, c_szEventLogSource, &hEvLogSource);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (!GetModuleFileName(NULL, AppName, sizeof(AppName)))
|
|
{
|
|
err = GetLastError();
|
|
goto Exit;
|
|
} else
|
|
{
|
|
PSTR FileName = strrchr(AppName, '\\');
|
|
|
|
if (FileName)
|
|
{
|
|
StringCbCopy(FileName+1, sizeof(AppName) - strlen(FileName), "winext\\ext.dll");
|
|
}
|
|
}
|
|
if ((err = RegSetValueEx(hEvLogSource, c_szEventLogMsgFile, 0,
|
|
REG_SZ, (BYTE *) AppName,
|
|
strlen(AppName)+1)) != ERROR_SUCCESS)
|
|
{
|
|
goto Exit;
|
|
}
|
|
AllowTypes = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
|
|
if ((err = RegSetValueEx(hEvLogSource, c_szEventLogTypes, 0,
|
|
REG_DWORD, (BYTE *) &AllowTypes,
|
|
sizeof(AllowTypes))) != ERROR_SUCCESS)
|
|
{
|
|
goto Exit;
|
|
}
|
|
} else
|
|
{
|
|
//
|
|
// Assume we have values set up propperly...
|
|
//
|
|
}
|
|
Exit:
|
|
if (hEvLog != NULL)
|
|
{
|
|
RegCloseKey(hEvLog);
|
|
}
|
|
if (hEvLogSource != NULL)
|
|
{
|
|
RegCloseKey(hEvLogSource);
|
|
}
|
|
return HRESULT_FROM_WIN32(err);
|
|
}
|
|
|
|
void
|
|
DbAddCrashEventLog(
|
|
HRESULT hrAddCrash,
|
|
DWORD LevelFinished,
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
HANDLE hEventSrc;
|
|
HRESULT Hr;
|
|
CHAR LogBuffer[2048];
|
|
|
|
if (FAILED(SetupEventLogging()))
|
|
{
|
|
return;
|
|
}
|
|
hEventSrc = RegisterEventSource(NULL, c_szEventLogSource);
|
|
|
|
if (hEventSrc == NULL ||
|
|
hEventSrc == INVALID_HANDLE_VALUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Hr = StringCbPrintf(LogBuffer, sizeof(LogBuffer),
|
|
"GUID: %s\n"
|
|
"BUCKET: %s\n"
|
|
"GENERIC_BUCKET: %s\n"
|
|
"SOLUTION_ID: 0x%03lx\n"
|
|
"SOLUTION_TYPE: %ld\n"
|
|
"ARCHIVE_PATH: %s\n"
|
|
"RESULT: 0x%08lx\n",
|
|
Crash->MesgGuid,
|
|
Crash->Bucket,
|
|
Crash->DefaultBucket,
|
|
Crash->SolutionId,
|
|
Crash->SolutionType,
|
|
Crash->Path,
|
|
hrAddCrash);
|
|
if (Hr == S_OK)
|
|
{
|
|
WORD wCategory = 0;
|
|
LPCSTR pStringArr = LogBuffer;
|
|
ReportEvent(hEventSrc,
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
wCategory,
|
|
FAILED(hrAddCrash) ? EXT_ADDCRASH_FAILED : EXT_CRASH_SOLVED,
|
|
NULL,
|
|
1,
|
|
0,
|
|
&pStringArr,
|
|
NULL);
|
|
|
|
}
|
|
DeregisterEventSource(hEventSrc);
|
|
}
|
|
#endif // _NEED_EVENT_LOGS_
|
|
|
|
void
|
|
DbAddCrashReportToMonitor(
|
|
HRESULT hrAddCrash,
|
|
DWORD LevelFinished,
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
HANDLE hPipe;
|
|
DWORD dwMode, cbWritten;
|
|
OCAKD_MONITOR_MESSAGE Msg;
|
|
OVERLAPPED WriteOverlapped;
|
|
|
|
Msg.MessageId = OKD_MESSAGE_DEBUGGER_RESULT;
|
|
Msg.u.KdResult.SizeOfStruct = sizeof(Msg.u.KdResult);
|
|
Msg.u.KdResult.hrAddCrash = hrAddCrash;
|
|
Msg.u.KdResult.SolutionId = Crash->SolutionId;
|
|
Msg.u.KdResult.ResponseType = Crash->SolutionType;
|
|
Msg.u.KdResult.CrashGuid[0] = 0;
|
|
Msg.u.KdResult.BucketId[0] = 0;
|
|
Msg.u.KdResult.ArchivePath[0] = 0;
|
|
if (Crash->MesgGuid)
|
|
{
|
|
StringCbCopy(Msg.u.KdResult.CrashGuid, sizeof(Msg.u.KdResult.CrashGuid),
|
|
Crash->MesgGuid);
|
|
}
|
|
if (Crash->Bucket)
|
|
{
|
|
StringCbCopy(Msg.u.KdResult.BucketId, sizeof(Msg.u.KdResult.BucketId),
|
|
Crash->Bucket);
|
|
}
|
|
if (Crash->ArchiveFileName)
|
|
{
|
|
StringCbCopy(Msg.u.KdResult.ArchivePath, sizeof(Msg.u.KdResult.ArchivePath),
|
|
Crash->ArchiveFileName);
|
|
}
|
|
|
|
|
|
for (;;)
|
|
{
|
|
hPipe = CreateFile(c_tszCollectPipeName, FILE_WRITE_DATA,
|
|
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
if (hPipe != INVALID_HANDLE_VALUE)
|
|
{
|
|
break;
|
|
}
|
|
if (GetLastError() != ERROR_PIPE_BUSY)
|
|
{
|
|
return;
|
|
}
|
|
if (!WaitNamedPipe(c_tszCollectPipeName, 5*60*1000))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// We are now connected to pipe
|
|
|
|
// Set the message mode on pipe
|
|
/* dwMode = PIPE_READMODE_MESSAGE;
|
|
if (!SetNamedPipeHandleState(hPipe, &dwMode,
|
|
NULL, NULL))
|
|
{
|
|
CloseHandle(hPipe);
|
|
return;
|
|
}
|
|
*/
|
|
|
|
WriteOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (WriteOverlapped.hEvent != NULL)
|
|
{
|
|
// Send crash information to monitor pipe
|
|
if (!WriteFile(hPipe, (LPVOID) &Msg, sizeof(Msg),
|
|
&cbWritten, &WriteOverlapped))
|
|
{
|
|
|
|
if (GetLastError() == ERROR_IO_PENDING ||
|
|
!GetOverlappedResult(hPipe, &WriteOverlapped, &cbWritten,
|
|
TRUE))
|
|
{
|
|
// failed to write, exit silently
|
|
// Its up to monitor if it is keeping track of kds launched
|
|
}
|
|
|
|
}
|
|
CloseHandle(WriteOverlapped.hEvent);
|
|
}
|
|
FlushFileBuffers(hPipe);
|
|
CloseHandle(hPipe);
|
|
return;
|
|
}
|
|
|
|
void
|
|
OcaKdLog(
|
|
LPSTR Qual,
|
|
LPSTR szMesg1,
|
|
LPSTR szMesg2,
|
|
ULONG Err
|
|
)
|
|
{
|
|
BOOL bOnce = FALSE;
|
|
PSTR szLogFile;
|
|
|
|
|
|
if (szLogFile = g_pTriager->GetFollowupStr("debugger-params",
|
|
"dbfailurelog"))
|
|
{
|
|
int hLogFile;
|
|
CHAR Log[300];
|
|
|
|
|
|
hLogFile = _open(szLogFile, O_APPEND | O_CREAT | O_RDWR,
|
|
S_IREAD | S_IWRITE);
|
|
|
|
if (hLogFile != -1 &&
|
|
StringCbPrintf(Log, sizeof(Log), "%15s: %0lx - %20s, %s\n",
|
|
Qual, Err, szMesg1, szMesg2) == S_OK)
|
|
{
|
|
_write(hLogFile, Log, strlen(Log));
|
|
_close(hLogFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
OpenSysDataFileFromCab(
|
|
CHAR *CabFile,
|
|
HANDLE *FileHandle
|
|
)
|
|
{
|
|
CHAR SysDataFile[2 * MAX_PATH];
|
|
INT_PTR CabFh;
|
|
HRESULT Status;
|
|
|
|
Status = ExpandDumpCab(CabFile,
|
|
_O_CREAT | _O_EXCL | _O_TEMPORARY,
|
|
"sysdata.xml",
|
|
SysDataFile, DIMA(SysDataFile),
|
|
&CabFh);
|
|
if (Status != S_OK)
|
|
{
|
|
goto exitSysDataFileOpen;
|
|
}
|
|
|
|
|
|
*FileHandle = CreateFile(SysDataFile, GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE |
|
|
FILE_SHARE_DELETE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (*FileHandle == NULL || *FileHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
Status = E_FAIL;
|
|
}
|
|
if (CabFh >= 0)
|
|
{
|
|
// no longer needed
|
|
_close((int)CabFh);
|
|
}
|
|
|
|
exitSysDataFileOpen:
|
|
|
|
return Status == S_OK;
|
|
}
|
|
|
|
|
|
ULONG
|
|
ScanForId(
|
|
PVOID pBuffer,
|
|
ULONG64 Size
|
|
)
|
|
{
|
|
const WCHAR cwszOEMIdTag[] = L"<HARDWAREID>PCI\\VEN_";
|
|
PWCHAR Scan, Match, End;
|
|
ULONG FreqId = 0;
|
|
#define MAX_OEM_IDS 50
|
|
struct {
|
|
ULONG Id;
|
|
ULONG Count;
|
|
} FoundIds[MAX_OEM_IDS] = {0};
|
|
|
|
Scan = (PWCHAR) pBuffer;
|
|
End = (PWCHAR) ( ((PCHAR) pBuffer) + (ULONG_PTR) Size );
|
|
while (Scan < End)
|
|
{
|
|
Match = (PWCHAR) &cwszOEMIdTag[0];
|
|
while (*Scan++ == *Match++);
|
|
if (!*Match)
|
|
{
|
|
--Scan;
|
|
// Match the tag
|
|
// <HARDWAREID>PCI\VEN_8086&DEV_2532&SUBSYS_00000000&REV_02</HARDWAREID>
|
|
// ^ Scan
|
|
WCHAR Line[61], *Subsys;
|
|
ULONG Id1 = 0, Id2 = 0;
|
|
StringCbCopyNW(Line, sizeof(Line),Scan, sizeof(Line) - sizeof(WCHAR));
|
|
swscanf(Line, L"%lx", &Id1);
|
|
Subsys = wcsstr(Line, L"SUBSYS_");
|
|
if (Subsys)
|
|
{
|
|
Subsys += 7;
|
|
swscanf(Subsys, L"%lx", &Id2);
|
|
Id2 &= 0xffff;
|
|
|
|
if (Id2 != Id1 && Id2 != 0)
|
|
{
|
|
// We foud a oem Id, store it
|
|
for (int i = 0; i<MAX_OEM_IDS; i++)
|
|
{
|
|
if (FoundIds[i].Id == Id2)
|
|
{
|
|
FoundIds[i].Count++;
|
|
} else if (FoundIds[i].Id == 0)
|
|
{
|
|
FoundIds[i].Count = 1;
|
|
FoundIds[i].Id = Id2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// dprintf("PCI\\VEN_%ws\n Id1 %lx Id2 %lx\n", Line, Id1, Id2);
|
|
}
|
|
}
|
|
|
|
ULONG Count = 0;
|
|
for (int i = 0; i<MAX_OEM_IDS; i++)
|
|
{
|
|
if (FoundIds[i].Count > Count)
|
|
{
|
|
FreqId = FoundIds[i].Id;
|
|
}
|
|
}
|
|
// dprintf("Found %lx\n", FreqId);
|
|
return FreqId;
|
|
}
|
|
|
|
|
|
ULONG
|
|
GetOEMId(
|
|
PCHAR szCabFile
|
|
)
|
|
{
|
|
ULONG SizeLow, SizeHigh;
|
|
HANDLE hSysDataFile = NULL, hMap = NULL;
|
|
PVOID pFileMap = NULL;
|
|
ULONG OEMId = 0;
|
|
|
|
if (!OpenSysDataFileFromCab(szCabFile, &hSysDataFile))
|
|
{
|
|
goto exitGetOEMID;
|
|
}
|
|
|
|
SizeLow = GetFileSize(hSysDataFile, &SizeHigh);
|
|
|
|
ULONG BytesRead;
|
|
|
|
hMap = CreateFileMapping(hSysDataFile, NULL, PAGE_READONLY,
|
|
0, 0, NULL);
|
|
|
|
if (hMap == NULL)
|
|
{
|
|
goto exitGetOEMID;
|
|
}
|
|
pFileMap = MapViewOfFile(hMap, FILE_MAP_READ,
|
|
0, 0, 0);
|
|
if (!pFileMap)
|
|
{
|
|
goto exitGetOEMID;
|
|
}
|
|
|
|
OEMId = ScanForId(pFileMap, SizeLow + ((ULONG64)SizeHigh << 32));
|
|
|
|
exitGetOEMID:
|
|
if (pFileMap)
|
|
{
|
|
UnmapViewOfFile(pFileMap);
|
|
}
|
|
if (hMap)
|
|
{
|
|
CloseHandle(hMap);
|
|
}
|
|
if (hSysDataFile)
|
|
{
|
|
CloseHandle(hSysDataFile);
|
|
}
|
|
return OEMId;
|
|
}
|
|
|
|
|
|
CVar::CVar()
|
|
{
|
|
g_OleAut32Calls.VariantInit(this);
|
|
}
|
|
|
|
CVar::CVar(VARTYPE vt, SCODE scode)
|
|
{
|
|
g_OleAut32Calls.VariantInit(this);
|
|
this->vt = vt;
|
|
this->scode = scode;
|
|
}
|
|
CVar::CVar(VARIANT var)
|
|
{
|
|
*this = var;
|
|
}
|
|
|
|
CVar::~CVar()
|
|
{
|
|
g_OleAut32Calls.VariantClear(this);
|
|
}
|
|
|
|
// ASSIGNMENT OPS.
|
|
CVar &
|
|
CVar::operator=(PCWSTR pcwstr)
|
|
{
|
|
g_OleAut32Calls.VariantClear(this);
|
|
if (NULL == (this->bstrVal = g_OleAut32Calls.SysAllocStringLen(pcwstr, wcslen(pcwstr))))
|
|
throw E_OUTOFMEMORY;
|
|
this->vt = VT_BSTR;
|
|
return *this;
|
|
}
|
|
|
|
CVar &
|
|
CVar::operator=(VARIANT var)
|
|
{
|
|
HRESULT hr;
|
|
|
|
g_OleAut32Calls.VariantClear(this);
|
|
if (FAILED(hr = g_OleAut32Calls.VariantCopy(this, &var)))
|
|
throw hr;
|
|
return *this;
|
|
}
|
|
|
|
// CAST OPS.
|
|
// doesn't change type. only returns BSTR if variant is of type
|
|
// bstr. asserts otherwise.
|
|
CVar::operator BSTR() const
|
|
{
|
|
if(VT_BSTR == this->vt)
|
|
return this->bstrVal;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT
|
|
CVar::Clear()
|
|
{
|
|
return g_OleAut32Calls.VariantClear(this);
|
|
}
|
|
|
|
|
|
BOOL
|
|
CCrashInstance::InitData(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
SYSTEMTIME Systime;
|
|
|
|
if (!Crash || !Crash->Build || !Crash->Bucket || !Crash->Path)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (strlen(Crash->Path) < sizeof(m_sz_Path))
|
|
{
|
|
CopyString(m_sz_Path, Crash->Path, sizeof(m_sz_Path));
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_iBuild = Crash->Build;
|
|
|
|
m_iCpuId = Crash->uCpu;
|
|
|
|
BuildCrashId(Crash->UpTime, Crash->CrashTime, &m_CrashId);
|
|
|
|
// GetSystemTime(&Systime);
|
|
// m_Date = Systime.wYear
|
|
|
|
m_lSourceStatus = 0;
|
|
m_lBuildSatus = 0;
|
|
m_lPathStatus = 0;
|
|
m_lCrashIdStatus = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
CCrashInstance::OutPut()
|
|
{
|
|
dprintf("%I64lx, %s\n",
|
|
m_CrashId,
|
|
m_sz_Path);
|
|
dprintf("Build %ld, CPU Id %I64lx\n",
|
|
m_iBuild,
|
|
m_iCpuId);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CBucketMap::InitData(
|
|
ULONG64 CrashId,
|
|
PCHAR Bucket
|
|
)
|
|
{
|
|
m_CrashId = CrashId;
|
|
|
|
if (!Bucket)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (strlen(Bucket) < sizeof(m_sz_BucketId))
|
|
{
|
|
CopyString(m_sz_BucketId, Bucket, sizeof(m_sz_BucketId));
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
COverClocked::InitData(
|
|
ULONG64 CrashId
|
|
)
|
|
{
|
|
m_CrashId = CrashId;
|
|
|
|
m_lCrashIdStatus = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CMachineInfo::InitData(
|
|
ULONG64 CpuId,
|
|
PSTR Desc
|
|
)
|
|
{
|
|
if (Desc && strlen(Desc) < sizeof(m_sz_Desc))
|
|
{
|
|
CopyString(m_sz_Desc, Desc, sizeof(m_sz_Desc));
|
|
}
|
|
else
|
|
{
|
|
m_sz_Desc[0] = 0;
|
|
}
|
|
|
|
m_iCpuId = CpuId;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
CBucketSolution::Output()
|
|
{
|
|
dprintf("Solution for bucket %s:\n%s\nFixed in %s\n",
|
|
m_sz_BucketId,
|
|
m_sz_SolText,
|
|
m_sz_OSVersion);
|
|
return;
|
|
}
|
|
|
|
HRESULT
|
|
ArchiveCrash(
|
|
PSTR OriginalPath,
|
|
PSTR ShareName,
|
|
PSTR DestFileName OPTIONAL,
|
|
PSTR ArchivedPath,
|
|
ULONG SizeofArchivedPath
|
|
)
|
|
//
|
|
// Copy over crashfile to the share
|
|
//
|
|
{
|
|
CHAR CopyTo[MAX_PATH], Date[20];
|
|
PCHAR FileName;
|
|
SYSTEMTIME Time;
|
|
|
|
if (!OriginalPath || !ShareName)
|
|
{
|
|
dprintf("Invalid original dumppath or archive share\n");
|
|
return E_FAIL;
|
|
}
|
|
GetLocalTime(&Time);
|
|
StringCbPrintf(Date, sizeof(Date), "%02ld-%02ld-%04ld",
|
|
Time.wMonth,
|
|
Time.wDay,
|
|
Time.wYear);
|
|
|
|
StringCbCopy(CopyTo, sizeof(CopyTo), ShareName);
|
|
StringCbCat(CopyTo, sizeof(CopyTo), "\\");
|
|
StringCbCat(CopyTo, sizeof(CopyTo), Date);
|
|
StringCbCat(CopyTo, sizeof(CopyTo), "\\");
|
|
|
|
if (!g_ShlWapiCalls.PathIsDirectoryA(CopyTo))
|
|
{
|
|
CreateDirectory(CopyTo, NULL);
|
|
}
|
|
if (DestFileName != NULL && DestFileName[0] != '\0')
|
|
{
|
|
FileName = DestFileName;
|
|
} else
|
|
{
|
|
FileName = strrchr(OriginalPath, '\\');
|
|
if (!FileName)
|
|
{
|
|
dprintf("Bad filename in '%s'\n", OriginalPath);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
if (*FileName == '\\')
|
|
{
|
|
FileName++;
|
|
}
|
|
StringCbCat(CopyTo, sizeof(CopyTo), FileName);
|
|
|
|
if (!CopyFile(OriginalPath, CopyTo, TRUE))
|
|
{
|
|
dprintf("Cannot Copy %s to %s\n", OriginalPath, CopyTo);
|
|
return E_FAIL;
|
|
}
|
|
StringCchCopy(ArchivedPath, SizeofArchivedPath, CopyTo);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
MQNotifyCrashProcessed(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
WCHAR wszGuid[50], wszMQConnectStr[100], wszMQMessage[2*MAX_PATH];
|
|
typedef HRESULT (WINAPI* MQSENDMSGPROC)(LPWSTR, LPWSTR, LPWSTR);
|
|
MQSENDMSGPROC SendMQMessageText;
|
|
ULONG64 hMQExt = 0;
|
|
HRESULT Hr;
|
|
PSTR BaseUrl;
|
|
HINSTANCE hMod;
|
|
|
|
|
|
if (!(BaseUrl = g_pTriager->GetFollowupStr("debugger-params",
|
|
"solutionurl")))
|
|
{
|
|
BaseUrl = g_lpszBaseUrl;
|
|
}
|
|
|
|
if (!Crash->MqConnectStr || !Crash->MesgGuid)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ((StringCbPrintfW(wszGuid, sizeof(wszGuid), L"%S", Crash->MesgGuid) != S_OK) ||
|
|
(StringCbPrintfW(wszMQConnectStr, sizeof(wszMQConnectStr), L"%S", Crash->MqConnectStr) != S_OK))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
if (Crash->SourceId == CiSrcCER ||
|
|
Crash->SourceId == CiSrcStress)
|
|
{
|
|
Hr = StringCbPrintfW(wszMQMessage, sizeof(wszMQMessage),
|
|
L"%Ssid=%ld&State=%ld&szSBucket=%S&iSBucket=%ld&szGBucket=%S&iGBucket=%ld&gsid=%ld",
|
|
BaseUrl,
|
|
(Crash->SolutionId ? Crash->SolutionId : -1),
|
|
Crash->SolutionType != CiSolFixed && Crash->SolutionType != CiSolWorkaround,
|
|
Crash->Bucket,
|
|
Crash->iBucket,
|
|
Crash->DefaultBucket,
|
|
Crash->iDefaultBucket,
|
|
(Crash->GenericSolId ? Crash->GenericSolId : -1)
|
|
);
|
|
} else
|
|
{
|
|
ULONG State, Solution;
|
|
|
|
//
|
|
// Set the tracking state for caller
|
|
//
|
|
if (Crash->SolutionType == CiSolFixed ||
|
|
Crash->SolutionType == CiSolWorkaround)
|
|
{
|
|
State = 0;
|
|
} else
|
|
{
|
|
State = 1;
|
|
}
|
|
Solution = Crash->SolutionId && (Crash->SolutionId != -1) ? Crash->SolutionId : Crash->GenericSolId;
|
|
|
|
if (Solution)
|
|
{
|
|
Hr = StringCbPrintfW(wszMQMessage, sizeof(wszMQMessage),
|
|
L"%Ssid=%ld&State=%ld",
|
|
BaseUrl,
|
|
Solution,
|
|
State);
|
|
}
|
|
else
|
|
{
|
|
Hr = StringCbPrintfW(wszMQMessage, sizeof(wszMQMessage),
|
|
L"NO_SOLUTION");
|
|
}
|
|
}
|
|
|
|
hMod = LoadLibrary("winxp\\mqext.dll");
|
|
|
|
if (hMod == NULL)
|
|
{
|
|
hMod = LoadLibrary("oca\\mqext.dll");
|
|
|
|
if (hMod == NULL)
|
|
{
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
SendMQMessageText = (MQSENDMSGPROC) GetProcAddress(hMod, "_EFN_SendMQMessageText");
|
|
if (SendMQMessageText != NULL)
|
|
{
|
|
Hr = SendMQMessageText(wszMQConnectStr, wszGuid, wszMQMessage);
|
|
} else
|
|
{
|
|
Hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
FreeLibrary(hMod);
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
ULONG
|
|
GetAdoCommandTimeOut()
|
|
{
|
|
#define DEFAULT_TIMEOUT 200
|
|
|
|
PSTR String;
|
|
ULONG TimeOut;
|
|
|
|
TimeOut = 0;
|
|
String = g_pTriager->GetFollowupStr("debugger-params", "DbCommandTimeout");
|
|
|
|
if (String)
|
|
{
|
|
TimeOut = atoi(String);
|
|
}
|
|
|
|
if (!TimeOut)
|
|
{
|
|
TimeOut = DEFAULT_TIMEOUT;
|
|
}
|
|
return TimeOut;
|
|
}
|
|
|
|
|
|
ULONG
|
|
GetAdoConnectionTimeOut()
|
|
{
|
|
#define DEFAULT_CONNECTION_TIMEOUT 5
|
|
|
|
PSTR String;
|
|
ULONG TimeOut;
|
|
|
|
TimeOut = 0;
|
|
|
|
String = g_pTriager->GetFollowupStr("debugger-params", "DbConnectionTimeout");
|
|
|
|
if (String)
|
|
{
|
|
TimeOut = atoi(String);
|
|
}
|
|
if (!TimeOut)
|
|
{
|
|
TimeOut = DEFAULT_CONNECTION_TIMEOUT;
|
|
}
|
|
return TimeOut;
|
|
}
|
|
|
|
HRESULT
|
|
InitializeDatabaseHandlers(
|
|
PDEBUG_CONTROL3 DebugControl,
|
|
ULONG Flags
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
ULONG EngineOptions;
|
|
|
|
if (!ExtensionApis.lpOutputRoutine)
|
|
{
|
|
ExtensionApis.nSize = sizeof (ExtensionApis);
|
|
if ((Hr = DebugControl->GetWindbgExtensionApis64(&ExtensionApis)) != S_OK) {
|
|
return Hr;
|
|
}
|
|
}
|
|
|
|
if ((Hr = ExtDllInitDynamicCalls(DebugControl)) != S_OK)
|
|
{
|
|
return Hr;
|
|
}
|
|
|
|
if (!g_pTriager)
|
|
{
|
|
g_pTriager = new CTriager();
|
|
}
|
|
|
|
if (!g_CrDb || !g_CustDb || !g_SolDb)
|
|
{
|
|
if (!g_ComInitialized)
|
|
{
|
|
if (FAILED(Hr = g_Ole32Calls.CoInitializeEx(NULL, COM_THREAD_MODEL)))
|
|
{
|
|
dprintf("CoInitialize failed %lx\n", Hr);
|
|
return Hr;
|
|
}
|
|
g_ComInitialized = TRUE;
|
|
}
|
|
if (!g_CrDb && (Flags & 1))
|
|
{
|
|
g_CrDb = new CrashDatabaseHandler();
|
|
if (!g_CrDb)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if (!g_CustDb && (Flags & 2))
|
|
{
|
|
g_CustDb = new CustDatabaseHandler();
|
|
if (!g_CustDb)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
if (!g_SolDb && (Flags & 4))
|
|
{
|
|
g_SolDb = new SolutionDatabaseHandler();
|
|
if (!g_SolDb)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_CrDb && !g_CrDb->IsConnected() && (Flags & 1))
|
|
{
|
|
if (!g_CrDb->ConnectToDataBase())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
}
|
|
if (g_CustDb && !g_CustDb->IsConnected() && (Flags & 2))
|
|
{
|
|
if (!g_CustDb->ConnectToDataBase())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
if (g_SolDb && !g_SolDb->IsConnected() && (Flags & 4))
|
|
{
|
|
if (!g_SolDb->ConnectToDataBase())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
UnInitializeDatabaseHandlers(
|
|
BOOL bUninitCom
|
|
)
|
|
{
|
|
if (g_CrDb)
|
|
{
|
|
delete g_CrDb;
|
|
}
|
|
if (g_CustDb)
|
|
{
|
|
delete g_CustDb;
|
|
}
|
|
if (g_SolDb)
|
|
{
|
|
delete g_SolDb;
|
|
}
|
|
g_CrDb = NULL;
|
|
g_CustDb = NULL;
|
|
g_SolDb = NULL;
|
|
if (g_ComInitialized && bUninitCom)
|
|
{
|
|
g_Ole32Calls.CoUninitialize();
|
|
g_ComInitialized = FALSE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
ReportSolution(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
|
|
if (!Crash->SolutionId ||
|
|
(Crash->SourceId == CiSrcCER && !Crash->GenericSolId))
|
|
{
|
|
// Get the solution, we need generic bucket solution for CER even if sBugcket is solved
|
|
Hr = g_SolDb->CheckSolutionExists(Crash->Bucket, Crash->DefaultBucket,
|
|
&Crash->SolutionId, (PULONG) &Crash->SolutionType,
|
|
(PULONG) &Crash->GenericSolId,
|
|
(Crash->SourceId == CiSrcCER) ? 1 : 0);
|
|
if (FAILED(Hr) || !Crash->SolutionId)
|
|
{
|
|
Crash->SolutionId = -1;
|
|
Crash->SolutionType = CiSolUnsolved;
|
|
}
|
|
|
|
}
|
|
|
|
if (Crash->SolutionId != -1)
|
|
{
|
|
OcaKdLog(Crash->MesgGuid, "SOLVED", Crash->Bucket, Crash->SolutionId);
|
|
} else
|
|
{
|
|
OcaKdLog(Crash->MesgGuid, "UNSOLVED", Crash->Bucket, Hr);
|
|
}
|
|
|
|
if (Crash->SourceId == CiSrcCER)
|
|
{
|
|
// get bucket ids
|
|
}
|
|
|
|
//
|
|
// Check if we have info to connect to solution queue and a solution exists
|
|
//
|
|
// if (Crash->SolutionId)
|
|
{
|
|
if (Crash->MesgGuid && Crash->MqConnectStr &&
|
|
Crash->MesgGuid[0] && Crash->MqConnectStr[0])
|
|
|
|
{
|
|
// Notify the sender that crash has been processed
|
|
MQNotifyCrashProcessed(Crash);
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
_EFN_DbAddCrashDirect(
|
|
PCRASH_INSTANCE Crash,
|
|
PDEBUG_CONTROL3 DebugControl
|
|
)
|
|
{
|
|
|
|
ULONG LevelCompleted;
|
|
HRESULT Hr=S_OK;
|
|
ULONG SleepFor;
|
|
|
|
LevelCompleted = 0;
|
|
SleepFor = 0;
|
|
ReTry:
|
|
|
|
if (SleepFor > 5)
|
|
{
|
|
dprintf("Could not succeed after %ld tries, quitting.\n", SleepFor);
|
|
DbAddCrashReportToMonitor(Hr, LevelCompleted, Crash);
|
|
return Hr;
|
|
}
|
|
else if (SleepFor)
|
|
{
|
|
dprintf("Level Finished %lx, sleep for %ld sec before retry.\n", LevelCompleted, SleepFor);
|
|
Sleep(SleepFor*1000);
|
|
|
|
}
|
|
|
|
if (!(LevelCompleted & LvlDatabaseInitDone))
|
|
{
|
|
ULONG Flags = 1;
|
|
|
|
if (!Crash->bResetBucket)
|
|
{
|
|
if (!Crash->SolutionId ||
|
|
(Crash->SourceId == CiSrcCER &&
|
|
Crash->GenericSolId == 0))
|
|
{
|
|
Flags |= 4;
|
|
}
|
|
}
|
|
if (Crash->bUpdateCustomer)
|
|
{
|
|
Flags |= 2;
|
|
}
|
|
if ((Hr = InitializeDatabaseHandlers(DebugControl, Flags)) != S_OK)
|
|
{
|
|
|
|
dprintf("Initializtion error.\n");
|
|
++SleepFor;
|
|
goto ReTry;
|
|
}
|
|
LevelCompleted |= LvlDatabaseInitDone;
|
|
}
|
|
|
|
while (!(LevelCompleted & LvlMessageQReply) ||
|
|
!(LevelCompleted & LvlCrashAddedToDB))
|
|
{
|
|
if (!(LevelCompleted & LvlMessageQReply) &&
|
|
((Crash->SourceId != CiSrcCER) || (LevelCompleted & LvlCrashAddedToDB)))
|
|
// For CER we need ibuckets to report solution
|
|
{
|
|
if (!Crash->bResetBucket)
|
|
{
|
|
ReportSolution(Crash); // Ignore return value, we fail quietly if there is
|
|
// any problem in reporting solution to Q
|
|
}
|
|
LevelCompleted |= LvlMessageQReply;
|
|
}
|
|
|
|
if (!(LevelCompleted & LvlCrashAddedToDB))
|
|
{
|
|
Hr = g_CrDb->AddCrashInstance(Crash);
|
|
|
|
if (FAILED(Hr))
|
|
{
|
|
++SleepFor;
|
|
goto ReTry;
|
|
}
|
|
LevelCompleted |= LvlCrashAddedToDB;
|
|
}
|
|
|
|
if (Crash->SourceId == CiSrcCER && Crash->iBucket == 0)
|
|
{
|
|
g_CrDb->LookupCrashBucket(Crash->Bucket, &Crash->iBucket,
|
|
Crash->DefaultBucket, &Crash->iDefaultBucket);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Only update the customer DB for kernel mode failures as the user
|
|
// mode failures don't go in that DB.
|
|
//
|
|
|
|
if (!(LevelCompleted & LvlCustomerDbUpdate))
|
|
{
|
|
if (Crash->bUpdateCustomer &&
|
|
(Crash->FailureType == DEBUG_FLR_KERNEL))
|
|
{
|
|
if (Crash->iBucket && Crash->iDefaultBucket)
|
|
{
|
|
Hr = g_CustDb->AddCrashToDB(Crash);
|
|
if (FAILED(Hr))
|
|
{
|
|
++SleepFor;
|
|
goto ReTry;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf("Cannot retrieve bucket Ids\n");
|
|
Hr = E_FAIL;
|
|
}
|
|
}
|
|
LevelCompleted |= LvlCustomerDbUpdate;
|
|
}
|
|
|
|
DbAddCrashReportToMonitor(Hr, LevelCompleted, Crash);
|
|
return Hr;
|
|
}
|
|
|
|
//
|
|
// DatabaseHandler Methods
|
|
//
|
|
|
|
|
|
DatabaseHandler::DatabaseHandler()
|
|
{
|
|
m_piConnection = NULL;
|
|
m_piCrRecordSet = NULL;
|
|
m_fConnected = FALSE;
|
|
m_fRecordsetEmpty = TRUE;
|
|
m_pADOResult = NULL;
|
|
m_fPrintIt = FALSE;
|
|
m_piCrCommandObj = NULL;
|
|
}
|
|
|
|
DatabaseHandler::~DatabaseHandler()
|
|
{
|
|
|
|
if (m_piCrRecordSet != NULL)
|
|
{
|
|
m_piCrRecordSet->Release();
|
|
}
|
|
if (m_piCrCommandObj != NULL)
|
|
{
|
|
m_piCrCommandObj->Release();
|
|
}
|
|
if (m_piConnection != NULL)
|
|
{
|
|
if (m_fConnected)
|
|
{
|
|
m_piConnection->Close();
|
|
m_fConnected = FALSE;
|
|
}
|
|
m_piConnection->Release();
|
|
}
|
|
|
|
m_piCrRecordSet = NULL;
|
|
m_piConnection = NULL;
|
|
}
|
|
|
|
BOOL
|
|
DatabaseHandler::ConnectToDataBase(
|
|
LPSTR szDB
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
WCHAR szConnectStr[200];
|
|
|
|
PSTR String;
|
|
|
|
String = g_pTriager->GetFollowupStr("debugger-params", szDB);
|
|
|
|
if (!String)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// bstrConnect = (PCRDB_ADOBSTR) &szConnectStr[0];
|
|
// bstrConnect->dwLength = sizeof(szConnectStr)/sizeof(WCHAR) - sizeof(DWORD);
|
|
ansi2wchr(String, szConnectStr);
|
|
CVar vNull(VT_ERROR, DISP_E_PARAMNOTFOUND);
|
|
CVar bstrConnect(VT_ERROR, DISP_E_PARAMNOTFOUND);
|
|
|
|
__try
|
|
{
|
|
if ((Hr = g_Ole32Calls.CoCreateInstance(CLSID_CADOConnection,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IADOConnection,
|
|
(LPVOID *)&m_piConnection)) != S_OK)
|
|
{
|
|
dprintf("CoCreate failed for connection %lx\n", Hr);
|
|
return FALSE;
|
|
}
|
|
|
|
m_piConnection->put_ConnectionTimeout(GetAdoConnectionTimeOut());
|
|
|
|
bstrConnect = szConnectStr;
|
|
|
|
if (bstrConnect == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ((Hr = m_piConnection->put_ConnectionString((BSTR)bstrConnect)) != S_OK)
|
|
{
|
|
dprintf("put_ConnectionString ( %ws ) failed %lx\n", szConnectStr, Hr);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Hr = m_piConnection->Open(NULL,
|
|
NULL, NULL,
|
|
adConnectUnspecified)) != S_OK)
|
|
{
|
|
dprintf("Debugger %s Connection::Open failed %lx\n\n", m_szDbName, Hr);
|
|
return FALSE;
|
|
}
|
|
m_fConnected = TRUE;
|
|
|
|
// Set command timeout to 60, crashdatabase is huge and commands
|
|
// takte long time
|
|
m_piConnection->put_CommandTimeout(GetAdoCommandTimeOut());
|
|
|
|
if ((Hr = g_Ole32Calls.CoCreateInstance(CLSID_CADORecordset,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IADORecordset,
|
|
(LPVOID *)&m_piCrRecordSet)) != S_OK )
|
|
{
|
|
dprintf("CoCreate failed for recordset %lx\n", Hr);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Hr = m_piCrRecordSet->putref_ActiveConnection(m_piConnection)) != S_OK)
|
|
{
|
|
dprintf("putref_ActiveConn failed %lx\n", Hr);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Hr = g_Ole32Calls.CoCreateInstance(CLSID_CADOCommand,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IADOCommand15,
|
|
(LPVOID *)&m_piCrCommandObj)) != S_OK )
|
|
{
|
|
dprintf("CoCreate failed for Command %lx\n", Hr);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Hr = m_piCrCommandObj->putref_ActiveConnection(m_piConnection)) != S_OK)
|
|
{
|
|
dprintf("putref_ActiveConn failed %lx\n", Hr);
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
__except (Hr)
|
|
{
|
|
dprintf("Unhandled exception %lx\n", Hr);
|
|
return (FALSE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DatabaseHandler::GetRecords(
|
|
PULONG Count,
|
|
BOOL bEnumerateAll
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
CVar vSource(VT_ERROR, DISP_E_PARAMNOTFOUND);
|
|
CVar vNull(VT_ERROR, DISP_E_PARAMNOTFOUND);
|
|
LONG State;
|
|
// dprintf("Executing %ws\n", m_wszQueryCommand);
|
|
|
|
if (!m_fConnected || !m_wszQueryCommand[0])
|
|
{
|
|
dprintf("Not connected\n");
|
|
return E_FAIL;
|
|
}
|
|
__try
|
|
{
|
|
vSource = m_wszQueryCommand;
|
|
if (m_piCrRecordSet == NULL)
|
|
{
|
|
if ((hr = g_Ole32Calls.CoCreateInstance(CLSID_CADORecordset,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IADORecordset,
|
|
(LPVOID *)&m_piCrRecordSet)) != S_OK )
|
|
{
|
|
dprintf("CoCreate failed for recordset %lx\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
if ((hr = m_piCrRecordSet->putref_ActiveConnection(m_piConnection)) != S_OK)
|
|
{
|
|
dprintf("putref_ActiveConn failed %lx\n", hr);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if ((hr = m_piCrRecordSet->Open(vSource, vNull, adOpenKeyset, adLockReadOnly, adCmdText)) != S_OK)
|
|
{
|
|
if (m_fPrintIt)
|
|
{
|
|
dprintf("RecordSet::Open Failed %lx, \n %ws \n", hr, m_wszQueryCommand);
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (Count)
|
|
{
|
|
ADO_LONGPTR MaxRec;
|
|
|
|
if ((hr = m_piCrRecordSet->get_RecordCount(&MaxRec)) != S_OK)
|
|
{
|
|
*Count = 0;
|
|
hr = S_FALSE;
|
|
}
|
|
*Count = (ULONG) MaxRec;
|
|
}
|
|
|
|
if (bEnumerateAll)
|
|
{
|
|
if ((hr = EnumerateAllRows()) != S_OK)
|
|
{
|
|
// dprintf("Cannot enumerate rows %lx\n", hr);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
__except (hr)
|
|
{
|
|
dprintf("Unhandled Exception in GetRecordForFollowup %lx\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
Cleanup:
|
|
State = -1;
|
|
|
|
m_piCrRecordSet->get_State(&State);
|
|
if (State & 1)
|
|
{
|
|
m_piCrRecordSet->Close();
|
|
}
|
|
|
|
m_piCrRecordSet->Release();
|
|
m_piCrRecordSet = NULL;
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
DatabaseHandler::EnumerateAllRows(
|
|
void
|
|
)
|
|
{
|
|
VARIANT avarRecords;
|
|
HRESULT Hr;
|
|
ADO_LONGPTR MaxRec;
|
|
ULONG Count=0;
|
|
CHAR Text[100];
|
|
CVar vNull(VT_ERROR, DISP_E_PARAMNOTFOUND);
|
|
IADORecordBinding *picRs = NULL;
|
|
COutputQueryRecords *QueryResult;
|
|
CCrashInstance CrashInstance;
|
|
|
|
if (m_pADOResult)
|
|
{
|
|
QueryResult = m_pADOResult;
|
|
} else
|
|
{
|
|
QueryResult = &CrashInstance;
|
|
}
|
|
__try
|
|
{
|
|
ULONG lUbound;
|
|
LONG State = -1;
|
|
|
|
if ((Hr = m_piCrRecordSet->get_RecordCount(&MaxRec)) != S_OK)
|
|
{
|
|
Hr = S_FALSE;
|
|
}
|
|
|
|
Count = (ULONG) MaxRec;
|
|
if (m_fPrintIt)
|
|
{
|
|
// dprintf("Enumerating %lx rows\n", MaxRec);
|
|
}
|
|
|
|
picRs = NULL;
|
|
m_piCrRecordSet->get_State(&State);
|
|
if ((Hr = m_piCrRecordSet->QueryInterface(__uuidof(IADORecordBinding),(LPVOID*)&picRs)) != S_OK)
|
|
{
|
|
dprintf("RecordSet::QueryInterface (IADORecordBinding) Failed %lx, State %lx\n", Hr, State);
|
|
return Hr;
|
|
}
|
|
|
|
|
|
//Bind the Recordset
|
|
if ((Hr = picRs->BindToRecordset(QueryResult)) != S_OK)
|
|
{
|
|
dprintf("RecordSet::BindToRecordset (IADORecordBinding) Failed %lx, State %lx\n", Hr, State);
|
|
picRs->Release();
|
|
return Hr;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
VARIANT_BOOL IsEof;
|
|
|
|
if (m_piCrRecordSet->get_EOF(&IsEof) == S_OK)
|
|
{
|
|
if (IsEof)
|
|
{
|
|
// preserve last valut for the caller
|
|
m_piCrRecordSet->MovePrevious();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_pADOResult && m_fPrintIt)
|
|
{
|
|
m_pADOResult->Output();
|
|
} else
|
|
{
|
|
// CrashInstance.OutPut();
|
|
}
|
|
|
|
--Count;
|
|
if (m_piCrRecordSet->MoveNext() != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (picRs)
|
|
{
|
|
picRs->Release();
|
|
}
|
|
|
|
}
|
|
__except (Hr)
|
|
{
|
|
dprintf("Unhandled Exception in EnumerateAllRows %lx\n", Hr);
|
|
return Hr;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// CrashDatabaseHandler Methods
|
|
//
|
|
|
|
CrashDatabaseHandler::CrashDatabaseHandler()
|
|
{
|
|
m_szDbName = "CrashDb";
|
|
}
|
|
|
|
CrashDatabaseHandler::~CrashDatabaseHandler()
|
|
{
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::BuildQueryForCrashInstance(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
ULONG64 CrashId;
|
|
|
|
BuildCrashId(Crash->UpTime, Crash->CrashTime, &CrashId);
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"SELECT * FROM %ws WHERE CrashId = %I64ld",
|
|
g_lpwszCrashInstanceTable,
|
|
CrashId
|
|
);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL
|
|
CrashDatabaseHandler::CheckCrashExists(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
ULONG nRecords = 0;
|
|
CCheckCrashExists Exists;
|
|
|
|
Exists.m_CrashIdExists = 0;
|
|
m_pADOResult = ∃
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"sp_CheckCrashExists '%S'",
|
|
Crash->MesgGuid);
|
|
|
|
HRESULT Hr = GetRecords(&nRecords, TRUE);
|
|
m_pADOResult = NULL;
|
|
if (FAILED(Hr) || !Exists.m_CrashIdExists)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
CrashDatabaseHandler::CheckSRExists(
|
|
PSTR szSR,
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
ULONG nRecords = 0;
|
|
CIntValue Exists;
|
|
|
|
Exists.m_dw_Value1 = 0;
|
|
m_pADOResult = ∃
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"sp_CheckSRExists '%S'",
|
|
szSR);
|
|
|
|
HRESULT Hr = GetRecords(&nRecords, TRUE);
|
|
m_pADOResult = NULL;
|
|
if (FAILED(Hr) || !Exists.m_dw_Value1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::LinkCrashToSR(
|
|
PSTR szSR,
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
ULONG nRecords = 0;
|
|
CIntValue lnk;
|
|
|
|
lnk.m_dw_Value1 = 0;
|
|
m_pADOResult = &lnk;
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"sp_LinkCrashSR '%S', '%S'",
|
|
szSR,
|
|
Crash->MesgGuid);
|
|
|
|
Hr = GetRecords(&nRecords, TRUE);
|
|
m_pADOResult = NULL;
|
|
if (!lnk.m_dw_Value1)
|
|
{
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
return Hr;
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::FindSRBuckets(
|
|
PSTR szSR,
|
|
PSTR szSBucket,
|
|
ULONG sBucketSize,
|
|
PSTR szGBucket,
|
|
ULONG gBucketSize
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
ULONG nRecords = 0;
|
|
CRetriveBucket Buckets;
|
|
|
|
Buckets.m_sz_gBucketId[0] = Buckets.m_sz_sBucketId[0] = 0;
|
|
|
|
m_pADOResult = &Buckets;
|
|
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"sp_RetriveSRBuckets '%S'",
|
|
szSR);
|
|
Hr = GetRecords(&nRecords, TRUE);
|
|
m_pADOResult = NULL;
|
|
if (FAILED(Hr) || !Buckets.m_sz_gBucketId[0])
|
|
{
|
|
return Hr;
|
|
}
|
|
|
|
StringCchCopy(szSBucket, sBucketSize, Buckets.m_sz_sBucketId);
|
|
StringCchCopy(szGBucket, gBucketSize, Buckets.m_sz_gBucketId);
|
|
return Hr;
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::GetBucketComments(
|
|
PSTR szBuckt,
|
|
PSTR szComments,
|
|
ULONG SizeofComment,
|
|
PULONG pBugId
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
|
|
ULONG nRecords = 0;
|
|
CBugAndComment Comments;
|
|
|
|
Comments.m_dw_BugId = 0;
|
|
Comments.m_sz_CommentBy[0] = Comments.m_sz_Comments[0] = 0;
|
|
|
|
m_pADOResult = &Comments;
|
|
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"sp_GetBucketComments '%S'",
|
|
szBuckt);
|
|
Hr = GetRecords(&nRecords, TRUE);
|
|
m_pADOResult = NULL;
|
|
if (FAILED(Hr))
|
|
{
|
|
return Hr;
|
|
}
|
|
if (Comments.m_dw_BugId == 0 &&
|
|
Comments.m_sz_Comments[0] == 0)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
StringCchCopy(szComments, SizeofComment, Comments.m_sz_Comments);
|
|
*pBugId = Comments.m_dw_BugId;
|
|
return Hr;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::AddCrashInstance(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
PSTR OriginalPath = Crash->Path;
|
|
|
|
if (!Crash->bResetBucket &&
|
|
(Crash->SolutionId != 0) &&
|
|
(Crash->iBucket != -1) &&
|
|
(Crash->SolutionType == CiSolFixed))
|
|
{
|
|
//
|
|
// No need to add this to CrashDB, just update the count
|
|
//
|
|
Crash->bExpendableDump = TRUE;
|
|
Hr = UpdateBucketCount(Crash);
|
|
} else
|
|
{
|
|
PSTR ArchiveShare, ArchParam;
|
|
ULONG index;
|
|
CHAR ArchivePath[MAX_PATH];
|
|
|
|
ArchParam = ArchivePath;
|
|
StringCchPrintf(ArchParam, MAX_PATH, "archshare-k-%s",
|
|
(Crash->DumpClass == DEBUG_DUMP_SMALL) ? "mini" : "full");
|
|
|
|
ArchiveShare = g_pTriager->GetFollowupStr("debugger-params", ArchParam);
|
|
|
|
ArchivePath[0] = 0;
|
|
if ((Crash->bExpendableDump) || Crash->bResetBucket ||
|
|
((Hr = ArchiveCrash(Crash->Path, ArchiveShare, Crash->ArchiveFileName,
|
|
ArchivePath, sizeof(ArchivePath))) == S_OK))
|
|
{
|
|
if (!Crash->bExpendableDump && !Crash->bResetBucket)
|
|
{
|
|
Crash->Path = ArchivePath;
|
|
Crash->OEMId = GetOEMId(OriginalPath);
|
|
}
|
|
Crash->bExpendableDump = TRUE;
|
|
Hr = AddCrashToDBByStoreProc(Crash);
|
|
Crash->Path = OriginalPath;
|
|
|
|
if (SUCCEEDED(Hr) && Crash->PssSr && Crash->PssSr[0])
|
|
{
|
|
Hr = LinkCrashToSR(Crash->PssSr, Crash);
|
|
OcaKdLog(Crash->MesgGuid, "CRASH SR", Crash->PssSr, Hr);
|
|
}
|
|
} else
|
|
{
|
|
dprintf("ArchiveCrash failed with %lx\n", Hr);
|
|
}
|
|
|
|
OcaKdLog(Crash->MesgGuid, "ARCHIVED CRASH", ArchivePath, Hr);
|
|
}
|
|
if (OriginalPath && SUCCEEDED(Hr) &&
|
|
(Crash->SourceId != CiSrcErClient) &&
|
|
(Crash->SourceId != CiSrcUser) &&
|
|
!Crash->bResetBucket)
|
|
{
|
|
DeleteFile(OriginalPath);
|
|
}
|
|
return Hr;
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::AddCrashToDBByStoreProc(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
CVar vNull(VT_ERROR, DISP_E_PARAMNOTFOUND);
|
|
CIntValue IntValue;
|
|
ULONG sBucket, gBucket;
|
|
|
|
Hr = S_OK;
|
|
|
|
if (Crash->SourceId == CiSrcManualFullDump)
|
|
{
|
|
// we already have a FailureType field to show full dumps
|
|
Crash->SourceId = CiSrcManual;
|
|
}
|
|
Crash->ServicePack %= 10000;
|
|
|
|
dprintf("ADDING CRASH:\n");
|
|
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"EXEC sp_AddCrashInstance2 "
|
|
L" @ip_retriageBucket = %ld, "
|
|
L" @ip_Bucketid = '%S', "
|
|
L" @ip_Path = '%S', "
|
|
L" @ip_FollowUp = '%S', "
|
|
L" @ip_BuildNo = %ld, "
|
|
L" @ip_Source = %ld, "
|
|
L" @ip_CpuId = %I64ld, "
|
|
L" @ip_OverClocked = %ld, "
|
|
L" @ip_Guid = '%S', "
|
|
L" @ip_gBucketId = '%S', "
|
|
L" @ip_DriverName = '%S', "
|
|
L" @ip_Type = %ld, "
|
|
L" @ip_UpTime = %ld, "
|
|
L" @ip_SKU = %ld,"
|
|
L" @ip_LangId = 0,"
|
|
L" @ip_OemId = %ld\n",
|
|
Crash->bResetBucket,
|
|
Crash->Bucket,
|
|
Crash->Path,
|
|
Crash->Followup,
|
|
Crash->Build * 10000 + Crash->ServicePack,
|
|
Crash->SourceId,
|
|
Crash->uCpu,
|
|
Crash->OverClocked,
|
|
Crash->MesgGuid,
|
|
Crash->DefaultBucket,
|
|
Crash->FaultyDriver,
|
|
Crash->FailureType | ((Crash->DumpClass == DEBUG_DUMP_SMALL) ? 0 : 4),
|
|
Crash->UpTime,
|
|
Crash->Sku,
|
|
Crash->OEMId
|
|
);
|
|
|
|
m_pADOResult = &IntValue;
|
|
__try
|
|
{
|
|
// Build query for store proc
|
|
// LATER: modify this to use adStoreProc Interface instead of query
|
|
ULONG nRecords;
|
|
|
|
IntValue.m_dw_Value1 = 0;
|
|
|
|
m_fPrintIt = TRUE;
|
|
|
|
if (!strcmp(Crash->Bucket, "BAD_DUMPFILE"))
|
|
{
|
|
sBucket = gBucket = -1;
|
|
}
|
|
else
|
|
{
|
|
sBucket = gBucket = 0;
|
|
|
|
// This proc returns sBucket and gBucket on success
|
|
// CALL FindBucketId directly to get those
|
|
|
|
dprintf("%ws", m_wszQueryCommand);
|
|
Hr = FindBucketId(&sBucket, &gBucket);
|
|
|
|
dprintf("%d %d \n", sBucket, gBucket);
|
|
|
|
m_fPrintIt = FALSE;
|
|
if (FAILED(Hr))
|
|
{
|
|
dprintf("GerRecord Failed %lx for store proc AddCrashToDBByStoreProc \n", Hr);
|
|
dprintf("Query:\n%ws\n", m_wszQueryCommand);
|
|
return Hr;
|
|
}
|
|
|
|
if (!CheckCrashExists(Crash))
|
|
{
|
|
dprintf("Crash could not be added to crash database: %s\n", Crash->MesgGuid);
|
|
Hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
dprintf("Crash instance %s now exists in DB\n", Crash->MesgGuid);
|
|
}
|
|
|
|
// Get Integer mappings for buckets
|
|
if (!sBucket || !gBucket)
|
|
{
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"sp_GetIntBucket '%S', '%S'",
|
|
Crash->Bucket, Crash->DefaultBucket);
|
|
|
|
//
|
|
// Now Try finding with explicit query
|
|
//
|
|
FindBucketId(&sBucket, &gBucket);
|
|
|
|
if (!sBucket || !gBucket)
|
|
{
|
|
dprintf("Unable to retrive int bucketids from crashdb\n");
|
|
Hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
Crash->iBucket = sBucket;
|
|
Crash->iDefaultBucket = gBucket;
|
|
}
|
|
__except (Hr)
|
|
{
|
|
dprintf("Unhandled Exception in AddCrashToDB %lx\n", Hr);
|
|
return Hr;
|
|
}
|
|
return Hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::UpdateBucketCount(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
ULONG sBucket, Count;
|
|
CIntValue RetVal;
|
|
|
|
dprintf("Update Bucket Count:\n");
|
|
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"EXEC sp_UpdateCount '%S', %ld",
|
|
Crash->Bucket,
|
|
Crash->Build * 10000 + Crash->ServicePack
|
|
);
|
|
|
|
__try
|
|
{
|
|
// Build query for store proc
|
|
// LATER: modify this to use adStoreProc Interface instead of query
|
|
ULONG nRecords;
|
|
|
|
// This proc returns sBucket and gBucket on success
|
|
// CALL FindBucketId directly to get those
|
|
|
|
dprintf("%ws", m_wszQueryCommand);
|
|
m_pADOResult = &RetVal;
|
|
Hr = GetRecords(&Count, FALSE);
|
|
m_pADOResult = NULL;
|
|
dprintf("sp_UpdateCount returned %d \n", RetVal.m_dw_Value1);
|
|
}
|
|
__except (Hr)
|
|
{
|
|
dprintf("Unhandled Exception in UpdateBucketCount %lx\n", Hr);
|
|
return Hr;
|
|
}
|
|
return Hr;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::FindRaidBug(
|
|
PSTR Bucket,
|
|
PULONG RaidBug
|
|
)
|
|
{
|
|
WCHAR wszBkt[100];
|
|
CBucketRaid BktRaid;
|
|
ULONG Count=0;
|
|
HRESULT result;
|
|
|
|
if (Bucket && strlen(Bucket) < sizeof(wszBkt)/sizeof(WCHAR))
|
|
{
|
|
ansi2wchr(Bucket, wszBkt);
|
|
}
|
|
|
|
StringCchPrintfW(m_wszQueryCommand,
|
|
sizeof(m_wszQueryCommand)/sizeof(WCHAR),
|
|
L"SELECT BucketId, BugId from %ws b, %ws r "
|
|
L" WHERE BucketId='%ws' AND b.iBucket = r.iBucket",
|
|
g_lpwszBucketTable,
|
|
g_lpwszRaidTable,
|
|
wszBkt);
|
|
|
|
m_pADOResult = &BktRaid;
|
|
|
|
result = GetRecords(&Count, TRUE);
|
|
|
|
if (Count == 0)
|
|
{
|
|
result = S_FALSE;
|
|
}
|
|
|
|
if (result == S_OK)
|
|
{
|
|
*RaidBug = BktRaid.m_dw_Raid;
|
|
}
|
|
|
|
m_pADOResult = NULL;
|
|
return result;
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::FindBucketId(
|
|
PULONG isBucket,
|
|
PULONG igBucket
|
|
)
|
|
{
|
|
CGetIntBucket BktIds;
|
|
CBuckets Bkt;
|
|
ULONG Count=0;
|
|
HRESULT result;
|
|
|
|
|
|
BktIds.m_iBucket1 = BktIds.m_iBucket2 = 0;
|
|
|
|
m_pADOResult = &BktIds;
|
|
|
|
result = GetRecords(&Count, TRUE);
|
|
|
|
if (result == S_OK)
|
|
{
|
|
//
|
|
// BUGBUG - what is this supposed to check ?
|
|
//
|
|
if (Count == 0)
|
|
{
|
|
result = S_FALSE;
|
|
}
|
|
|
|
*isBucket = BktIds.m_iBucket1;
|
|
*igBucket = BktIds.m_iBucket2;
|
|
}
|
|
//dprintf("%ws : %ld, %ld\n", m_wszQueryCommand, *isBucket, *igBucket);
|
|
|
|
m_pADOResult = NULL;
|
|
return result;
|
|
}
|
|
|
|
HRESULT
|
|
CrashDatabaseHandler::LookupCrashBucket(
|
|
PSTR SBucket,
|
|
PULONG iSBucket,
|
|
PSTR GBucket,
|
|
PULONG iGBucket
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
ULONG Dummy;
|
|
|
|
if (!m_fConnected)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
Hr = StringCchPrintfW(m_wszQueryCommand,
|
|
sizeof(m_wszQueryCommand)/sizeof(WCHAR),
|
|
L"sp_GetIntBucket '%S', '%S'",
|
|
SBucket, GBucket ? GBucket : "");
|
|
if (Hr == S_OK)
|
|
{
|
|
Hr = FindBucketId(iSBucket, iGBucket ? iGBucket : &Dummy);
|
|
}
|
|
return Hr;
|
|
}
|
|
|
|
|
|
//
|
|
// CustDatabaseHandler Methods
|
|
//
|
|
|
|
CustDatabaseHandler::CustDatabaseHandler()
|
|
{
|
|
m_szDbName = "CustomerDb";
|
|
}
|
|
|
|
CustDatabaseHandler::~CustDatabaseHandler()
|
|
{
|
|
}
|
|
|
|
HRESULT
|
|
CustDatabaseHandler::AddCrashToDB(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
if (!m_fConnected)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT Hr = S_OK;
|
|
CVar vNull(VT_ERROR, DISP_E_PARAMNOTFOUND);
|
|
PCHAR CallSp;
|
|
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"SetDBGResults '%S', %ld, '%S', %ld, '%S', %ld, %ld, '%S'",
|
|
Crash->MesgGuid,
|
|
Crash->iDefaultBucket,
|
|
Crash->DefaultBucket,
|
|
Crash->iBucket,
|
|
Crash->Bucket,
|
|
Crash->StopCode,
|
|
Crash->bSendMail ? 1 : 0,
|
|
Crash->OriginalDumpFileName);
|
|
|
|
ULONG nRecords;
|
|
CIntValue ReturnVal;
|
|
|
|
ReturnVal.m_dw_Value1 = 0;
|
|
m_fPrintIt = TRUE;
|
|
|
|
m_pADOResult = &ReturnVal;
|
|
|
|
Hr = GetRecords(&nRecords, TRUE);
|
|
|
|
m_fPrintIt = FALSE;
|
|
dprintf("Query:\n%ws\n", m_wszQueryCommand);
|
|
|
|
if ((Hr == S_OK) && (ReturnVal.m_dw_Value1 == 0))
|
|
{
|
|
Hr = E_FAIL;
|
|
}
|
|
|
|
m_pADOResult = NULL;
|
|
if (FAILED(Hr))
|
|
{
|
|
dprintf("GerRecord Failed %lx for store proc SetDBGResults on AddToCustomerDb \n", Hr);
|
|
} else
|
|
{
|
|
dprintf("Added to customer DB (%ld)\n", ReturnVal.m_dw_Value1);
|
|
}
|
|
return Hr;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// SolutionDatabaseHandler Methods
|
|
//
|
|
|
|
SolutionDatabaseHandler::SolutionDatabaseHandler()
|
|
{
|
|
m_szDbName = "SolutionDb";
|
|
}
|
|
|
|
SolutionDatabaseHandler::~SolutionDatabaseHandler()
|
|
{
|
|
}
|
|
|
|
HRESULT
|
|
SolutionDatabaseHandler::GetSolution(
|
|
PCRASH_INSTANCE Crash
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
|
|
if (!m_fConnected)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT
|
|
SolutionDatabaseHandler::CheckSolutionExists(
|
|
PSTR szSBucket,
|
|
PSTR szGBucket,
|
|
PULONG pSolnId,
|
|
PULONG pSolutionType,
|
|
PULONG pgSolutionId,
|
|
BOOL bForcegSolLookup
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
ULONG nRecords = 0;
|
|
CIntValue3 SolnId;
|
|
|
|
if (!m_fConnected)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
SolnId.m_dw_Value1 = 0;
|
|
m_pADOResult = &SolnId;
|
|
|
|
StringCbPrintfW(
|
|
m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"sp_CheckForSolution '%S', '<Driver>', 0, '%S', %ld",
|
|
szSBucket,
|
|
szGBucket ? szGBucket : "",
|
|
bForcegSolLookup // we need gbucket solution
|
|
);
|
|
// returns: SolutionId, SolutionType, gSolutionId
|
|
|
|
Hr = GetRecords(&nRecords, TRUE);
|
|
m_pADOResult = NULL;
|
|
if (FAILED(Hr))
|
|
{
|
|
return Hr;
|
|
}
|
|
|
|
if (!SolnId.m_dw_Value1 && !SolnId.m_dw_Value3)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
*pSolnId = SolnId.m_dw_Value1;
|
|
if (pSolutionType)
|
|
{
|
|
*pSolutionType = SolnId.m_dw_Value2;
|
|
}
|
|
if (pgSolutionId)
|
|
{
|
|
*pgSolutionId = SolnId.m_dw_Value3;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
SolutionDatabaseHandler::GetSolutionFromDB(
|
|
PSTR szBucket,
|
|
PSTR szGBucket,
|
|
LPSTR DriverName,
|
|
ULONG TimeStamp,
|
|
ULONG OS,
|
|
OUT PSTR pszSolution,
|
|
ULONG SolutionBufferSize,
|
|
OUT PULONG pSolutionId,
|
|
OUT PULONG pSolutionType,
|
|
OUT PULONG pGenericSolutionId
|
|
)
|
|
{
|
|
if (!m_fConnected)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT Hr = S_OK;
|
|
PSTR BaseUrl;
|
|
ULONG SolnId = 0, GenSolId = 0;
|
|
|
|
if (!(BaseUrl = g_pTriager->GetFollowupStr("debugger-params",
|
|
"solutionurl")))
|
|
{
|
|
BaseUrl = g_lpszBaseUrl;
|
|
}
|
|
|
|
if ((Hr = CheckSolutionExists(szBucket, szGBucket, &SolnId,
|
|
pSolutionType, &GenSolId,
|
|
TRUE)) == S_OK)
|
|
{
|
|
*pSolutionId = SolnId;
|
|
if (pGenericSolutionId)
|
|
{
|
|
*pGenericSolutionId = GenSolId;
|
|
}
|
|
|
|
if (!SolnId && !GenSolId)
|
|
{
|
|
Hr = S_FALSE;
|
|
}
|
|
else if (pszSolution && SolnId)
|
|
{
|
|
Hr = StringCbPrintfA(pszSolution, SolutionBufferSize,
|
|
"%ssid=%ld&State=1",
|
|
BaseUrl,
|
|
SolnId);
|
|
} else if (!SolnId)
|
|
{
|
|
Hr = S_FALSE;
|
|
}
|
|
}
|
|
|
|
return Hr;
|
|
}
|
|
|
|
HRESULT
|
|
SolutionDatabaseHandler::GetSolutiontext(
|
|
PSTR szBucket,
|
|
PSTR szSolText,
|
|
ULONG SolTextSize
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
|
|
ULONG nRecords = 0;
|
|
CSolutionDesc Solution;
|
|
|
|
Solution.m_dw_SolType = 0;
|
|
Solution.m_sz_Solution[0] = 0;
|
|
|
|
m_pADOResult = &Solution;
|
|
|
|
StringCbPrintfW(m_wszQueryCommand, sizeof(m_wszQueryCommand),
|
|
L"sp_GetBucketSolution '%S', ''",
|
|
szBucket);
|
|
Hr = GetRecords(&nRecords, TRUE);
|
|
m_pADOResult = NULL;
|
|
if (FAILED(Hr))
|
|
{
|
|
return Hr;
|
|
}
|
|
if (Solution.m_dw_SolType == 0 &&
|
|
Solution.m_sz_Solution[0] == 0)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
StringCchCopy(szSolText, SolTextSize, Solution.m_sz_Solution);
|
|
return Hr;
|
|
|
|
}
|
|
|
|
HRESULT
|
|
SolutionDatabaseHandler::PrintBucketInfo(
|
|
PSTR sBucket,
|
|
PSTR gBucket
|
|
)
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
CHAR SolutionText[MAX_PATH];
|
|
|
|
|
|
dprintf("BUCKET ID : %s\n", sBucket);
|
|
if (SUCCEEDED(GetSolutiontext(sBucket, SolutionText, sizeof(SolutionText))))
|
|
{
|
|
dprintf("ISSUE IS SOLVED : %s\n\n", SolutionText);
|
|
} else
|
|
{
|
|
dprintf("ISSUE IS UNSOLVED\n");
|
|
}
|
|
return Hr;
|
|
}
|
|
|
|
HRESULT
|
|
SolutionDatabaseHandler::AddKnownFailureToDB(LPSTR Bucket)
|
|
{
|
|
if (!m_fConnected)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT Hr = S_OK;
|
|
return Hr;
|
|
}
|
|
|
|
HRESULT
|
|
BuildGuidForSR(
|
|
PSTR szSR,
|
|
PSTR Guid,
|
|
ULONG GuidSize
|
|
)
|
|
{
|
|
GUID srGuid = {0};
|
|
PUCHAR szTempGuid = NULL;
|
|
HRESULT hr = g_Ole32Calls.CoCreateGuid(&srGuid);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
hr = UuidToString(&srGuid, &szTempGuid);
|
|
if (hr == S_OK)
|
|
{
|
|
hr = StringCchCopy(Guid, GuidSize, (PCHAR) szTempGuid);
|
|
RpcStringFree(&szTempGuid);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
FindSrInfo(
|
|
PSTR szSR,
|
|
PSTR szDumpPath,
|
|
PDEBUG_CONTROL3 DebugControl
|
|
)
|
|
{
|
|
HRESULT Hr;
|
|
CHAR szSBucket[100], szGBucket[100];
|
|
CHAR BktComment[200];
|
|
ULONG BugId;
|
|
|
|
if (!szSR || *szSR == '\0')
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
if (FAILED(Hr = InitializeDatabaseHandlers(DebugControl ? DebugControl : g_ExtControl, 5)))
|
|
{
|
|
return Hr;
|
|
}
|
|
|
|
BktComment[0] = 0;
|
|
BugId = 0;
|
|
// Validate if SR# is present in DB
|
|
if (g_CrDb->CheckSRExists(szSR, NULL))
|
|
{
|
|
// SR present info DB
|
|
if (szDumpPath && *szDumpPath != '\0')
|
|
{
|
|
// we already have an entry
|
|
Hr = E_INVALIDARG;
|
|
|
|
dprintf("\n\nThere is already an entry in DB for SR %s. It cannot be linked to another\n"
|
|
"dumpfile. Specifiy only the SR ID to retrive the crash info.\n",
|
|
szSR);
|
|
} else
|
|
{
|
|
// Get bucket info
|
|
|
|
dprintf("\nFound entry for %s in database.\n\n", szSR);
|
|
Hr = g_CrDb->FindSRBuckets(szSR, szSBucket, sizeof(szSBucket),
|
|
szGBucket, sizeof(szGBucket));
|
|
if (SUCCEEDED(Hr))
|
|
{
|
|
g_CrDb->GetBucketComments(szSBucket, BktComment, sizeof(BktComment),
|
|
&BugId);
|
|
Hr = S_OK;
|
|
}
|
|
}
|
|
|
|
} else if (szDumpPath && *szDumpPath != '\0')
|
|
{
|
|
CRASH_INSTANCE Crash = {0};
|
|
CHAR szGUID[50];
|
|
PCHAR Ext;
|
|
|
|
Ext = strrchr(szDumpPath, '.');
|
|
|
|
if (Ext == NULL || _stricmp(Ext, ".cab"))
|
|
{
|
|
dprintf("\n\nERROR: %s is not CABed dump.\n Please add only the CAB dumps through ticket.\n\n",
|
|
szDumpPath);
|
|
Hr = E_INVALIDARG;
|
|
} else if ((Hr = BuildGuidForSR(szSR, szGUID, sizeof(szGUID))) == S_OK)
|
|
{
|
|
CHAR FileName[100];
|
|
|
|
StringCchCopy(FileName, sizeof(FileName) - 5, szSR);
|
|
StringCchCat(FileName, sizeof(FileName), ".cab");
|
|
Crash.MesgGuid = szGUID;
|
|
Crash.PssSr = szSR;
|
|
Crash.ArchiveFileName = FileName;
|
|
Crash.Bucket = szSBucket;
|
|
Crash.BucketSize = sizeof(szSBucket);
|
|
Crash.DefaultBucket = szGBucket;
|
|
Crash.DefaultBucketSize = sizeof(szGBucket);
|
|
Crash.Path = szDumpPath;
|
|
|
|
// Add crash entry to DB
|
|
Hr = AddCrashToDB(2, &Crash);
|
|
if (Hr == S_OK)
|
|
{
|
|
// Hr = g_CrDb->LinkCrashToSR(szSR, &Crash);
|
|
|
|
if (SUCCEEDED(Hr))
|
|
{
|
|
g_CrDb->GetBucketComments(szSBucket, BktComment, sizeof(BktComment),
|
|
&BugId);
|
|
Hr = S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Get bucket info
|
|
} else
|
|
{
|
|
dprintf("SR %s does not exist in database\n", szSR);
|
|
Hr = S_FALSE;
|
|
}
|
|
|
|
CHAR szSolution[300];
|
|
ULONG SolutionId;
|
|
|
|
if (Hr == S_OK)
|
|
{
|
|
// Print comment, bug id, solution
|
|
|
|
if (BugId != 0)
|
|
{
|
|
dprintf("KNOWN BUG # %ld\n\n", BugId);
|
|
}
|
|
if (BktComment[0])
|
|
{
|
|
dprintf("DEV COMMENT ON ISSUE : %s\n\n", BktComment);
|
|
}
|
|
if (g_SolDb->PrintBucketInfo(szSBucket, szGBucket))
|
|
{
|
|
}
|
|
|
|
}
|
|
UnInitializeDatabaseHandlers( TRUE );
|
|
return Hr;
|
|
}
|
|
|
|
HRESULT
|
|
_EFN_FindSrInfo(
|
|
PSTR szSR,
|
|
PSTR szDumpPath,
|
|
PDEBUG_CONTROL3 DebugControl
|
|
)
|
|
{
|
|
return FindSrInfo(szSR, szDumpPath, DebugControl);
|
|
}
|
|
|
|
DECLARE_API( ticket )
|
|
{
|
|
HRESULT Hr = S_OK;
|
|
CHAR szSR[100] = {0}, szDumpPath[MAX_PATH] = {0};
|
|
INIT_API();
|
|
|
|
if (sscanf(args, "%100s %240s", szSR, szDumpPath))
|
|
{
|
|
Hr = FindSrInfo(szSR, szDumpPath, g_ExtControl);
|
|
} else
|
|
{
|
|
dprintf("Usage: !ticket <SR#> <dumppath>\n");
|
|
}
|
|
|
|
EXIT_API();
|
|
return Hr;
|
|
}
|