//---------------------------------------------------------------------------- // // triage.ini searching code // // Copyright (C) Microsoft Corporation, 2001. // //---------------------------------------------------------------------------- #include "precomp.h" #pragma hdrstop CTriager *g_pTriager = NULL; typedef struct TRIAGE_LIST { TRIAGE_DATA TriageData; struct TRIAGE_LIST * Next; } TRIAGE_LIST; void DeleteList(TRIAGE_LIST* Start) { TRIAGE_LIST * Next = NULL; while (Start) { Next = Start->Next; free(Start); Start = Next; } } TRIAGE_LIST* InsertEntry( TRIAGE_LIST* Start, PTRIAGE_DATA pData ) { TRIAGE_LIST* NewEntry; NewEntry = (TRIAGE_LIST*) malloc(sizeof(TRIAGE_LIST)); if (!NewEntry) { DeleteList(Start); return NULL; } NewEntry->TriageData = *pData; TRIAGE_LIST *InsertAfter, *InsertBefore; InsertAfter = NULL; InsertBefore = Start; NewEntry->Next = InsertBefore; if (InsertAfter) { InsertAfter->Next = NewEntry; } else { return NewEntry; } return Start; } #define TRIAGE_FILE_OCA 0 #define TRIAGE_FILE_OSSPECIFIC 1 #define TRIAGE_FILE_DEFAULT 2 PCHAR GetTriageFileName( ULONG TriageType ) { static CHAR szTriageFileName[MAX_PATH+50]; PCHAR ExeDir; ExeDir = &szTriageFileName[0]; *ExeDir = 0; // Get the directory the debugger executable is in. if (!GetModuleFileName(NULL, ExeDir, MAX_PATH)) { // Error. Use the current directory. strcpy(ExeDir, "."); } else { // Remove the executable name. PCHAR pszTmp = strrchr(ExeDir, '\\'); if (pszTmp) { *pszTmp = 0; } } switch (TriageType) { case TRIAGE_FILE_OSSPECIFIC: { PSTR OsDir; if (g_TargetBuild <= 1381) { OsDir = "\\nt4fre"; } else if (g_TargetBuild <= 2195) { OsDir = "\\w2kfre"; } else { OsDir = "\\winxp"; } CatString(ExeDir, OsDir, sizeof(szTriageFileName)); CatString(ExeDir, "\\triage.ini", sizeof(szTriageFileName)); break; } case TRIAGE_FILE_OCA: CatString(ExeDir, "\\triage\\oca.ini", sizeof(szTriageFileName)); break; case TRIAGE_FILE_DEFAULT: CatString(ExeDir, "\\triage\\triage.ini", sizeof(szTriageFileName)); } return &szTriageFileName[0]; } int __cdecl TriageDataCmp(const void* Data1, const void* Data2) { TRIAGE_DATA *Triage1 , *Triage2; int ret; Triage1 = (TRIAGE_DATA*) Data1; Triage2 = (TRIAGE_DATA*) Data2; ret=_stricmp(Triage1->Module, Triage2->Module); if (!ret) { ret = _stricmp(Triage1->Routine, Triage2->Routine); } return ret; } CTriager::CTriager() { CHAR FileLine[256]; PCHAR pTriageFile; HANDLE hFile; ULONG Err; ULONG BytesRead; ULONG FileSize; PCHAR FileRead; PCHAR line; ULONG Index; ULONG TriageType; ULONG EntryCount; TRIAGE_DATA Entry; TRIAGE_LIST *Start, *Trav; Start = NULL; EntryCount = 0; TriageType = TRIAGE_FILE_OCA; // // We will always try to load the oca.ini file to get the connection // strings. // Then we will load the OS specific version of triage.ini when present // (it's an internal version of the file only) and load the default // triage\triage.ini if the specific one could not be opened. // GatherTriageInfo: pTriageFile = GetTriageFileName(TriageType); hFile = CreateFile(pTriageFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) { FileSize = GetFileSize(hFile, NULL); FileRead = (PCHAR) malloc(FileSize+1); if (!FileRead) { CloseHandle(hFile); return; } if (!ReadFile(hFile, FileRead, FileSize, &BytesRead, NULL)) { CloseHandle(hFile); free( FileRead ); return; } FileRead[FileSize] = 0; Index = 0; while (Index < FileSize) { ULONG LineLen = 0; line = &FileRead[Index]; while (*line && (*line != '\n')) { if (*line != ' ' && *line > 0x20) { FileLine[LineLen++] = *line; } ++line; ++Index; } FileLine[LineLen] = 0; ++Index; // skip newline if (FileLine[0] == '\0' || FileLine[0] == ';') { continue; } PCHAR Followup; PCHAR Bang; if ((Followup = strchr(FileLine,'='))) { *Followup++ = 0; Entry.fModulPartial = 1; Entry.fRoutinePartial = 1; if (Bang = strchr(FileLine, '!')) { // An entry of type module[*]!routine[*]=followup // ^ ^ // Bang Followup *Bang++ = 0; ULONG eq = (ULONG) ((ULONG64)Followup - (ULONG64)Bang); ULONG modbreak = (ULONG) ((ULONG64)Bang - (ULONG64)&FileLine[0]); Entry.fModulPartial = 0; FillStringBuffer(FileLine, 0, Entry.Module, sizeof(Entry.Module), NULL); if (*(Bang-2) == '*') { Entry.fModulPartial = 1; Entry.Module[modbreak-2] = 0; } modbreak++; Entry.fRoutinePartial = 0; FillStringBuffer(Bang, 0, Entry.Routine, sizeof(Entry.Routine), NULL); if (*(Followup-2)=='*') { Entry.Routine[eq-2] = 0; Entry.fRoutinePartial = 1; } } else { ULONG eq = (ULONG) ((ULONG64)Followup - (ULONG64)&FileLine[0]); Entry.Routine[0] = 0; Entry.fModulPartial = FALSE; FillStringBuffer(FileLine, 0, Entry.Module, sizeof(Entry.Module), NULL); if (*(Followup-2)=='*') { Entry.fModulPartial = TRUE; Entry.Module[eq-2] = 0; } if (!_stricmp(Entry.Routine, "default")) { Entry.Routine[0] = 0; } } CopyString(Entry.Followup , Followup, sizeof(Entry.Followup)); // dprintf("%s\n Mod %s Rou %s\n", FileLine, Entry.Module, Entry.Routine); Start = InsertEntry(Start, &Entry); if (Start) { ++EntryCount; } else { EntryCount = 0; break; } } } free( FileRead ); CloseHandle(hFile); } else { if (TriageType == TRIAGE_FILE_OSSPECIFIC) { TriageType = TRIAGE_FILE_DEFAULT; goto GatherTriageInfo; } } if (TriageType == TRIAGE_FILE_OCA) { TriageType = TRIAGE_FILE_OSSPECIFIC; goto GatherTriageInfo; } // // Now copy it to array for fast access; // if (EntryCount) { m_pTriageData = (PTRIAGE_DATA) malloc(EntryCount * sizeof(TRIAGE_DATA)); if (!m_pTriageData) { DeleteList(Start); return; } m_EntryCount = EntryCount; Trav = Start; for (ULONG i = 0; i < m_EntryCount && Trav; ++i, Trav = Trav->Next) { m_pTriageData[i] = Trav->TriageData; } DeleteList(Start); qsort(m_pTriageData, m_EntryCount, sizeof(*m_pTriageData), &TriageDataCmp); } else { m_pTriageData = NULL; m_EntryCount = 0; } } CTriager::~CTriager() { if (m_pTriageData) { free(m_pTriageData); } } void CTriager::PrintTraigeInfo() { dprintf("Triage data %lx entries:\n" "Module Routine Followup\n", m_EntryCount); for (ULONG i = 0; i < m_EntryCount; ++i) { dprintf("%-15s%c%-29s%c%s\n", m_pTriageData[i].Module, m_pTriageData[i].fModulPartial ? '*' : ' ', m_pTriageData[i].Routine, m_pTriageData[i].fRoutinePartial ? '*' : ' ', m_pTriageData[i].Followup ); } } ULONG CTriager::MatchSymbol( PSTR Module, PSTR Routine ) { int Hi, Lo, Mid; int BestMatch; int cmp1, cmp2; TRIAGE_DATA *Trav; if (m_EntryCount == 0) { return -1; } Lo = 0; Hi = m_EntryCount-1; while (Lo <= Hi) { Mid = (Lo + Hi) / 2; Trav = &m_pTriageData[Mid]; #if 0 dprintf("%3lx: M: %s%c R: %s%c F: %s\n", Mid,m_pTriageData[Mid].Module, m_pTriageData[Mid].fModulPartial ? '*' : ' ', m_pTriageData[Mid].Routine, m_pTriageData[Mid].fRoutinePartial ? '*' : ' ', m_pTriageData[Mid].Followup); #endif //0 cmp1 = _stricmp(m_pTriageData[Mid].Module, Module); if (!cmp1) { cmp1 = _stricmp(m_pTriageData[Mid].Routine, Routine); } if (!cmp1) { return Mid; } else if (cmp1 > 0) { Hi = Mid - 1; } else { Lo = Mid + 1; } } // Backtrace from mid till we find good prefix match if (Lo >= (int)m_EntryCount) { Lo = m_EntryCount-1; } while (Lo) { if (m_pTriageData[Lo].fRoutinePartial || m_pTriageData[Lo].fModulPartial) { // dprintf("- %3lx: M: %s R: %s F: %s\n", // Lo, m_pTriageData[Lo].Module, // m_pTriageData[Lo].Routine,m_pTriageData[Lo].Followup); if (!m_pTriageData[Lo].Routine || !Routine) { cmp2 = 0; } else if (m_pTriageData[Lo].fRoutinePartial) { cmp2 = _strnicmp(m_pTriageData[Lo].Routine, Routine, strlen(m_pTriageData[Lo].Routine)); } else { cmp2 = _stricmp(m_pTriageData[Lo].Routine, Routine); } if (m_pTriageData[Lo].fModulPartial) { cmp1 = _strnicmp(m_pTriageData[Lo].Module, Module, strlen(m_pTriageData[Lo].Module)); } else { cmp1 = _stricmp(m_pTriageData[Lo].Module, Module); } if (!cmp1 && !cmp2) { return Lo; } } --Lo; } return -1; } ULONG CTriager::GetFollowup( PSTR FollowupBuffer, ULONG FollowupBufferSize, PSTR SymbolName ) { CHAR Module[100], Routine[2048]; ULONG index; PCHAR Bang; ULONG ret; if (!SymbolName) { return TRIAGE_FOLLOWUP_FAIL; } Bang = strchr(SymbolName, '!'); if (!Bang) { CopyString(Module, SymbolName, sizeof(Module)); Routine[0] = 0; } else { ULONG len = (ULONG) ((ULONG64) Bang - (ULONG64)SymbolName); if (len > sizeof(Module)-1) { len = sizeof(Module)-1; } strncpy(Module,SymbolName, len); Module[len]=0; CopyString(Routine, Bang+1, sizeof(Routine)); } // // Make sure we followup on image name instead of module name // ULONG Index; ULONG64 Base; if (strcmp(Module, "nt") && (S_OK == g_ExtSymbols-> GetModuleByModuleName(Module, 0, &Index, &Base))) { CHAR ImageBuffer[MAX_PATH]; if (g_ExtSymbols-> GetModuleNames(Index, Base, ImageBuffer, sizeof(ImageBuffer), NULL, NULL, 0, NULL, NULL, 0, NULL) == S_OK) { PCHAR Break = strrchr(ImageBuffer, '\\'); if (Break) { CopyString(ImageBuffer, Break + 1, sizeof(ImageBuffer)); } CopyString(Module, ImageBuffer, sizeof(Module)); if (Break = strchr(Module, '.')) { *Break = 0; } } } PCHAR Followup; Followup = g_pTriager->GetFollowupStr(Module, Routine); if (Followup) { ret = TRIAGE_FOLLOWUP_SUCCESS; if (!strcmp(Followup, "ignore")) { ret = TRIAGE_FOLLOWUP_IGNORE; } } else { Followup = g_pTriager->GetFollowupStr("default", ""); ret = TRIAGE_FOLLOWUP_DEFAULT; } if (Followup) { strncpy(FollowupBuffer, Followup, FollowupBufferSize); FollowupBuffer[FollowupBufferSize-1] = 0; return ret; } else { return TRIAGE_FOLLOWUP_FAIL; } } void CTriager::GetFollowupDate( PSTR Module, PSTR Routine, PULONG Start, PULONG End) { ULONG Index; CHAR DateEntry[32]; PCHAR Break; PCHAR Stop; *Start = 0; *End = 0; if ((Index = MatchSymbol(Module, Routine)) >= m_EntryCount) { return; } CopyString(DateEntry, m_pTriageData[Index].Followup, sizeof(DateEntry)); if (Break = strchr(DateEntry, ',')) { *Start = strtoul(Break+1, &Stop, 16); *Break = 0; } *End = strtoul(DateEntry, &Stop, 16); //dprintf("%08lx\n %08lx\n", *Start, *End); return; }