//---------------------------------------------------------------------------- // // AutoDump Plus support extension DLL. // // Copyright (C) Microsoft Corporation, 2000-2001. // //---------------------------------------------------------------------------- #include "dbgexts.h" #define STATUS_CPP_EH_EXCEPTION 0xe06d7363 #define MAX_NAME 64 #define MAX_MACHINE 64 #define MAX_COMMENT 256 char g_BaseDir[MAX_PATH - 1]; char g_Machine[MAX_MACHINE]; struct PARAM { ULONG Len; PSTR Buf; }; PARAM g_DirMachParams[2] = { sizeof(g_BaseDir), g_BaseDir, sizeof(g_Machine), g_Machine, }; union LAST_EVENT_INFO_ALL { DEBUG_LAST_EVENT_INFO_BREAKPOINT Breakpoint; DEBUG_LAST_EVENT_INFO_EXCEPTION Exception; DEBUG_LAST_EVENT_INFO_EXIT_THREAD ExitThread; DEBUG_LAST_EVENT_INFO_EXIT_PROCESS ExitProcess; DEBUG_LAST_EVENT_INFO_LOAD_MODULE LoadModule; DEBUG_LAST_EVENT_INFO_UNLOAD_MODULE UnloadModule; DEBUG_LAST_EVENT_INFO_SYSTEM_ERROR SystemError; }; ULONG g_LastEventType; LAST_EVENT_INFO_ALL g_LastEventInfo; PSTR g_LastExName; char g_UnknownExceptionName[64]; PSTR g_LastExChanceStr; ULONG g_ProcessId; char g_ProcessName[MAX_NAME]; struct EXCEPTION_NAME { PSTR Name; ULONG Code; }; EXCEPTION_NAME g_ExceptionNames[] = { "Access Violation", STATUS_ACCESS_VIOLATION, "C++ EH Exception", STATUS_CPP_EH_EXCEPTION, "Invalid Handle Exception", STATUS_INVALID_HANDLE, "Stack Overflow", STATUS_STACK_OVERFLOW, NULL, 0, }; PCSTR GetParams(PCSTR Args, ULONG Count, PARAM* Params) { PCSTR Start; ULONG Len; ULONG Index = 0; while (Count-- > 0) { while (*Args == ' ' || *Args == '\t') { Args++; } Start = Args; while (*Args && *Args != ' ' && *Args != '\t') { Args++; } Len = (ULONG)(Args - Start); if ((Count > 0 && !*Args) || Len >= Params[Index].Len) { ExtErr("Invalid extension command arguments\n"); return NULL; } memcpy(Params[Index].Buf, Start, Len); Params[Index].Buf[Len] = 0; Index++; } return Args; } HRESULT GetProcessInfo(void) { HRESULT Status; if ((Status = g_ExtSystem-> GetCurrentProcessSystemId(&g_ProcessId)) != S_OK) { ExtErr("Unable to get current process ID\n"); return Status; } if (FAILED(g_ExtClient-> GetRunningProcessDescription(0, g_ProcessId, DEBUG_PROC_DESC_NO_PATHS, NULL, 0, NULL, g_ProcessName, MAX_NAME, NULL))) { g_ProcessName[0] = 0; } else { PSTR Scan; // Use the MTS package name as the name if it exists. Scan = strstr(g_ProcessName, "MTS Packages: "); if (Scan) { PSTR Start; ULONG Len; Scan += 14; Start = Scan; Scan = strchr(Start, ','); if (!Scan) { Scan = strchr(Start, ' '); } if (Scan) { *Scan = 0; } Len = strlen(Start) + 1; if (Len > 2) { memmove(g_ProcessName, Start, Len); } else { g_ProcessName[0] = 0; } } else { g_ProcessName[0] = 0; } } if (!g_ProcessName[0]) { if (FAILED(g_ExtSystem-> GetCurrentProcessExecutableName(g_ProcessName, MAX_NAME, NULL))) { // This can happen in some situations so handle it // rather than exiting. ExtErr("Unable to get current process name\n"); strcpy(g_ProcessName, "UnknownProcess"); } } return S_OK; } HRESULT GetEventInfo(void) { HRESULT Status; ULONG ProcessId, ThreadId; if ((Status = g_ExtControl-> GetLastEventInformation(&g_LastEventType, &ProcessId, &ThreadId, &g_LastEventInfo, sizeof(g_LastEventInfo), NULL, NULL, 0, NULL)) != S_OK) { ExtErr("Unable to get event information\n"); return Status; } if ((Status = GetProcessInfo()) != S_OK) { return Status; } switch(g_LastEventType) { case DEBUG_EVENT_EXCEPTION: { EXCEPTION_NAME* ExName = g_ExceptionNames; while (ExName->Name != NULL) { if (ExName->Code == g_LastEventInfo.Exception. ExceptionRecord.ExceptionCode) { break; } ExName++; } if (ExName->Name != NULL) { g_LastExName = ExName->Name; } else { sprintf(g_UnknownExceptionName, "Unknown Exception (%08X)", g_LastEventInfo.Exception. ExceptionRecord.ExceptionCode); g_LastExName = g_UnknownExceptionName; } if (g_LastEventInfo.Exception.FirstChance) { g_LastExChanceStr = "First"; } else { g_LastExChanceStr = "Second"; } } break; } return S_OK; } void SanitizeFileName(PSTR FileName) { while (*FileName) { switch(*FileName) { case ' ': case '\t': case '\n': case '\r': *FileName = '_'; break; case '\\': case '/': case ':': *FileName = '-'; break; } FileName++; } } void GetDumpPath(PSTR NameQual, PSTR TypeStr, PSTR Path) { SYSTEMTIME Time; PSTR FilePart; GetLocalTime(&Time); strcpy(Path, g_BaseDir); FilePart = Path + strlen(Path) - 1; if (*FilePart != '/' && *FilePart != '\\') { *++FilePart = '\\'; } FilePart++; _snprintf(FilePart, MAX_PATH - (FilePart - Path), "PID-%d__%s__Date_%02d-%02d-%04d__Time_%02d-%02d-%02d__%s__%s.dmp", g_ProcessId, g_ProcessName, Time.wMonth, Time.wDay, Time.wYear, Time.wHour, Time.wMinute, Time.wSecond, NameQual, TypeStr); Path[MAX_PATH - 1] = 0; SanitizeFileName(FilePart); } void WriteDump(PSTR NameQual, PSTR Comment, ULONG DumpQual, ULONG DumpFormat, PSTR TypeStr) { char Path[MAX_PATH]; ULONG Len; Len = strlen(Comment); _snprintf(Comment + Len, MAX_COMMENT - Len, " - %s dump from %s", TypeStr, g_Machine); Comment[MAX_COMMENT - 1] = 0; GetDumpPath(NameQual, TypeStr, Path); g_ExtClient->WriteDumpFile2(Path, DumpQual, DumpFormat, Comment); } extern "C" HRESULT AdpEventControlC(PDEBUG_CLIENT Client, PCSTR Args) { char Comment[MAX_COMMENT]; INIT_API(); // // Parameters: directory, machine name. // Args = GetParams(Args, 2, g_DirMachParams); if (Args == NULL) { goto Exit; } // // Retrieve standard information. // if ((Status = GetEventInfo()) != S_OK) { goto Exit; } // // Log information. // ExtOut("\n\n----------------------------------------------------------------------\n"); ExtOut("CTRL-C was pressed to stop debugging this process!\n"); ExtOut("----------------------------------------------------------------------\n"); ExtOut("Exiting the debugger at:\n"); ExtExec(".time"); ExtOut("\n\n--- Listing all thread stacks: ---\n"); ExtExec("~*kb250"); ExtOut("\n--- Listing loaded modules: ---\n"); ExtExec("lmv"); ExtOut("\n--- Modules with matching symbols:\n"); ExtExec("lml"); ExtOut("\n--- Listing all locks: ---\n"); ExtExec("!locks"); // // Create a dump file. // strcpy(Comment, "CTRL-C was pressed to stop the debugger while running in crash mode"); WriteDump("CTRL-C", Comment, DEBUG_DUMP_SMALL, DEBUG_FORMAT_DEFAULT, "mini"); Exit: EXIT_API(); return Status; } extern "C" HRESULT AdpEventException(PDEBUG_CLIENT Client, PCSTR Args) { char Comment[MAX_COMMENT]; char Qual[MAX_COMMENT]; ULONG Format; PSTR TypeStr; INIT_API(); // // Parameters: directory, machine name. // Args = GetParams(Args, 2, g_DirMachParams); if (Args == NULL) { goto Exit; } // // Retrieve standard information. // if ((Status = GetEventInfo()) != S_OK) { goto Exit; } if (g_LastEventType != DEBUG_EVENT_EXCEPTION) { ExtErr("Last event was not an exception\n"); goto Exit; } if (g_LastEventInfo.Exception.FirstChance) { Format = DEBUG_FORMAT_DEFAULT; TypeStr = "mini"; } else { Format = DEBUG_FORMAT_USER_SMALL_FULL_MEMORY | DEBUG_FORMAT_USER_SMALL_HANDLE_DATA; TypeStr = "mini full handle"; } // // Log information. // ExtOut("\n---- %s-chance %s - Exception stack below ----\n", g_LastExChanceStr, g_LastExName); ExtExec(".time"); ExtOut("\n"); ExtExec("kvn250"); ExtOut("-----------------------------------\n"); // // Create a dump file. // _snprintf(Comment, sizeof(Comment), "%s-chance %s in %s", g_LastExChanceStr, g_LastExName, g_ProcessName); Comment[sizeof(Comment) - 1] = 0; _snprintf(Qual, sizeof(Qual), "%s-chance %s", g_LastExChanceStr, g_LastExName); Qual[sizeof(Qual) - 1] = 0; WriteDump(Qual, Comment, DEBUG_DUMP_SMALL, Format, TypeStr); ExtOut("\n\n"); Exit: EXIT_API(); return Status; } extern "C" HRESULT AdpEventExitProcess(PDEBUG_CLIENT Client, PCSTR Args) { INIT_API(); UNREFERENCED_PARAMETER(Args); // // Log information. // ExtOut("\n\n----------------------------------------------------------------------\n"); ExtOut("This process is shutting down!\n"); ExtOut("\nThis can happen for the following reasons:\n"); ExtOut("1.) Someone killed the process with Task Manager or the kill command.\n"); ExtOut("\n2.) If this process is an MTS or COM+ server package, it could be\n"); ExtOut("* exiting because an MTS/COM+ server package idle limit was reached.\n"); ExtOut("\n3.) If this process is an MTS or COM+ server package,\n"); ExtOut("* someone may have shutdown the package via the MTS Explorer or\n"); ExtOut("* Component Services MMC snap-in.\n"); ExtOut("\n4.) If this process is an MTS or COM+ server package,\n"); ExtOut("* MTS or COM+ could be shutting down the process because an internal\n"); ExtOut("* error was detected in the process (MTS/COM+ fail fast condition).\n"); ExtOut("----------------------------------------------------------------------\n"); ExtOut("\nThe process was shut down at:\n"); ExtExec(".time"); ExtOut("\n\n"); EXIT_API(); return Status; }