/*++ 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 #include #include #include #include #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"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 // PCI\VEN_8086&DEV_2532&SUBSYS_00000000&REV_02 // ^ 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 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', '', 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 \n"); } EXIT_API(); return Hr; }