summaryrefslogtreecommitdiff
path: root/indra/win_crash_logger
diff options
context:
space:
mode:
authorMerov Linden <merov@lindenlab.com>2014-04-07 16:31:32 -0700
committerMerov Linden <merov@lindenlab.com>2014-04-07 16:31:32 -0700
commitc9a9ab1b6a23525229e39c42440e302feef0288e (patch)
tree687e5690f9f6ea91577f0075aaffcddedbdd5022 /indra/win_crash_logger
parent78eada5b6c3a8d20a2ea49887ab7c091e4b6fa14 (diff)
parent7e966f28da79d2d24f93a2615c8807421300700c (diff)
Pull merge from lindenlab/viewer-release
Diffstat (limited to 'indra/win_crash_logger')
-rwxr-xr-xindra/win_crash_logger/CMakeLists.txt3
-rw-r--r--[-rwxr-xr-x]indra/win_crash_logger/llcrashloggerwindows.cpp184
-rw-r--r--[-rwxr-xr-x]indra/win_crash_logger/llcrashloggerwindows.h34
-rwxr-xr-xindra/win_crash_logger/win_crash_logger.cpp12
4 files changed, 226 insertions, 7 deletions
diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt
index 3c9a4b9756..c6070020db 100755
--- a/indra/win_crash_logger/CMakeLists.txt
+++ b/indra/win_crash_logger/CMakeLists.txt
@@ -12,6 +12,7 @@ include(LLWindow)
include(LLXML)
include(Linking)
include(LLSharedLibs)
+include(GoogleBreakpad)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
@@ -20,6 +21,7 @@ include_directories(
${LLWINDOW_INCLUDE_DIRS}
${LLXML_INCLUDE_DIRS}
${LLVFS_INCLUDE_DIRS}
+ ${BREAKPAD_INCLUDE_DIRECTORIES}
)
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
@@ -68,6 +70,7 @@ find_library(DXGUID_LIBRARY dxguid ${DIRECTX_LIBRARY_DIR})
add_executable(windows-crash-logger WIN32 ${win_crash_logger_SOURCE_FILES})
target_link_libraries(windows-crash-logger
+ ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
${LLCRASHLOGGER_LIBRARIES}
${LLWINDOW_LIBRARIES}
${LLVFS_LIBRARIES}
diff --git a/indra/win_crash_logger/llcrashloggerwindows.cpp b/indra/win_crash_logger/llcrashloggerwindows.cpp
index 36d988ead7..9fd66d5421 100755..100644
--- a/indra/win_crash_logger/llcrashloggerwindows.cpp
+++ b/indra/win_crash_logger/llcrashloggerwindows.cpp
@@ -42,6 +42,11 @@
#include "lldxhardware.h"
#include "lldir.h"
#include "llsdserialize.h"
+#include "llsdutil.h"
+#include "stringize.h"
+
+#include <client/windows/crash_generation/crash_generation_server.h>
+#include <client/windows/crash_generation/client_info.h>
#define MAX_LOADSTRING 100
#define MAX_STRING 2048
@@ -64,6 +69,7 @@ BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialo
std::stringstream gDXInfo;
bool gSendLogs = false;
+LLCrashLoggerWindows* LLCrashLoggerWindows::sInstance = NULL;
//Conversion from char* to wchar*
//Replacement for ATL macros, doesn't allocate memory
@@ -240,10 +246,178 @@ LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
LLCrashLoggerWindows::LLCrashLoggerWindows(void)
{
+ if (LLCrashLoggerWindows::sInstance==NULL)
+ {
+ sInstance = this;
+ }
}
LLCrashLoggerWindows::~LLCrashLoggerWindows(void)
{
+ sInstance = NULL;
+}
+
+bool LLCrashLoggerWindows::getMessageWithTimeout(MSG *msg, UINT to)
+{
+ bool res;
+ UINT_PTR timerID = SetTimer(NULL, NULL, to, NULL);
+ res = GetMessage(msg, NULL, 0, 0);
+ KillTimer(NULL, timerID);
+ if (!res)
+ return false;
+ if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == 1)
+ return false; //TIMEOUT! You could call SetLastError() or something...
+ return true;
+}
+
+int LLCrashLoggerWindows::processingLoop() {
+ const int millisecs=1000;
+ int retries = 0;
+ const int max_retries = 60;
+
+ LL_DEBUGS("CRASHREPORT") << "Entering processing loop for OOP server" << LL_ENDL;
+
+ LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE );
+
+ MSG msg;
+
+ bool result;
+
+ while (1)
+ {
+ result = getMessageWithTimeout(&msg, millisecs);
+ if ( result )
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ if ( retries < max_retries ) //Wait up to 1 minute for the viewer to say hello.
+ {
+ if (mClientsConnected == 0)
+ {
+ LL_DEBUGS("CRASHREPORT") << "Waiting for client to connect." << LL_ENDL;
+ ++retries;
+ }
+ else
+ {
+ LL_INFOS("CRASHREPORT") << "Client has connected!" << LL_ENDL;
+ retries = max_retries;
+ }
+ }
+ else
+ {
+ if (mClientsConnected == 0)
+ {
+ break;
+ }
+ if (!mKeyMaster.isProcessAlive(mPID, mProcName) )
+ {
+ break;
+ }
+ }
+ }
+
+ llinfos << "session ending.." << llendl;
+
+ std::string per_run_dir = options["dumpdir"].asString();
+ std::string per_run_file = per_run_dir + "\\SecondLife.log";
+ std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
+
+ if (gDirUtilp->fileExists(per_run_dir))
+ {
+ LL_INFOS ("CRASHREPORT") << "Copying " << log_file << " to " << per_run_file << llendl;
+ LLFile::copy(log_file, per_run_file);
+ }
+ return 0;
+}
+
+
+void LLCrashLoggerWindows::OnClientConnected(void* context,
+ const google_breakpad::ClientInfo* client_info)
+{
+ sInstance->mClientsConnected++;
+ LL_INFOS("CRASHREPORT") << "Client connected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL;
+}
+
+void LLCrashLoggerWindows::OnClientExited(void* context,
+ const google_breakpad::ClientInfo* client_info)
+{
+ sInstance->mClientsConnected--;
+ LL_INFOS("CRASHREPORT") << "Client disconnected. pid = " << client_info->pid() << " total clients " << sInstance->mClientsConnected << LL_ENDL;
+}
+
+
+void LLCrashLoggerWindows::OnClientDumpRequest(void* context,
+ const google_breakpad::ClientInfo* client_info,
+ const std::wstring* file_path)
+{
+ if (!file_path)
+ {
+ llwarns << "dump with no file path" << llendl;
+ return;
+ }
+ if (!client_info)
+ {
+ llwarns << "dump with no client info" << llendl;
+ return;
+ }
+
+ LLCrashLoggerWindows* self = static_cast<LLCrashLoggerWindows*>(context);
+ if (!self)
+ {
+ llwarns << "dump with no context" << llendl;
+ return;
+ }
+
+ //DWORD pid = client_info->pid();
+}
+
+
+bool LLCrashLoggerWindows::initCrashServer()
+{
+ //For Breakpad on Windows we need a full Out of Process service to get good data.
+ //This routine starts up the service on a named pipe that the viewer will then
+ //communicate with.
+ using namespace google_breakpad;
+
+ LLSD options = getOptionData( LLApp::PRIORITY_COMMAND_LINE );
+ std::string dump_path = options["dumpdir"].asString();
+ mClientsConnected = 0;
+ mPID = options["pid"].asInteger();
+ mProcName = options["procname"].asString();
+
+ //Generate a quasi-uniq name for the named pipe. For our purposes
+ //this is unique-enough with least hassle. Worst case for duplicate name
+ //is a second instance of the viewer will not do crash reporting.
+ std::wstring wpipe_name;
+ wpipe_name = mCrashReportPipeStr + std::wstring(wstringize(mPID));
+
+ std::wstring wdump_path( wstringize(dump_path) );
+
+ //Pipe naming conventions: http://msdn.microsoft.com/en-us/library/aa365783%28v=vs.85%29.aspx
+ mCrashHandler = new CrashGenerationServer( wpipe_name,
+ NULL,
+ &LLCrashLoggerWindows::OnClientConnected, this,
+ /*NULL, NULL, */ &LLCrashLoggerWindows::OnClientDumpRequest, this,
+ &LLCrashLoggerWindows::OnClientExited, this,
+ NULL, NULL,
+ true, &wdump_path);
+
+ if (!mCrashHandler) {
+ //Failed to start the crash server.
+ llwarns << "Failed to init crash server." << llendl;
+ return false;
+ }
+
+ // Start servicing clients.
+ if (!mCrashHandler->Start()) {
+ llwarns << "Failed to start crash server." << llendl;
+ return false;
+ }
+
+ LL_INFOS("CRASHREPORT") << "Initialized OOP server with pipe named " << stringize(wpipe_name) << LL_ENDL;
+ return true;
}
bool LLCrashLoggerWindows::init(void)
@@ -251,10 +425,12 @@ bool LLCrashLoggerWindows::init(void)
bool ok = LLCrashLogger::init();
if(!ok) return false;
+ initCrashServer();
+
/*
mbstowcs( gProductName, mProductName.c_str(), LL_ARRAY_SIZE(gProductName) );
gProductName[ LL_ARRY_SIZE(gProductName) - 1 ] = 0;
- swprintf(gProductName, L"Second Life");
+ swprintf(gProductName, L"Second Life");
*/
llinfos << "Loading dialogs" << llendl;
@@ -291,18 +467,16 @@ void LLCrashLoggerWindows::gatherPlatformSpecificFiles()
SetCursor(gCursorWait);
// At this point we're responsive enough the user could click the close button
SetCursor(gCursorArrow);
- mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo();
+ //mDebugLog["DisplayDeviceInfo"] = gDXHardware.getDisplayInfo(); //Not initialized.
}
bool LLCrashLoggerWindows::mainLoop()
{
llinfos << "CrashSubmitBehavior is " << mCrashBehavior << llendl;
-
// Note: parent hwnd is 0 (the desktop). No dlg proc. See Petzold (5th ed) HexCalc example, Chapter 11, p529
// win_crash_logger.rc has been edited by hand.
// Dialogs defined with CLASS "WIN_CRASH_LOGGER" (must be same as szWindowClass)
gProductName = mProductName;
-
gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL);
ProcessCaption(gHwndProgress);
ShowWindow(gHwndProgress, SW_HIDE );
@@ -371,5 +545,7 @@ bool LLCrashLoggerWindows::cleanup()
}
PostQuitMessage(0);
commonCleanup();
+ mKeyMaster.releaseMaster();
return true;
}
+
diff --git a/indra/win_crash_logger/llcrashloggerwindows.h b/indra/win_crash_logger/llcrashloggerwindows.h
index 5c45a998b3..1812e2737e 100755..100644
--- a/indra/win_crash_logger/llcrashloggerwindows.h
+++ b/indra/win_crash_logger/llcrashloggerwindows.h
@@ -31,20 +31,54 @@
#include "windows.h"
#include "llstring.h"
+class LLSD;
+
+namespace google_breakpad {
+ class CrashGenerationServer;
+ class ClientInfo;
+}
+
class LLCrashLoggerWindows : public LLCrashLogger
{
public:
LLCrashLoggerWindows(void);
~LLCrashLoggerWindows(void);
+ static LLCrashLoggerWindows* sInstance;
+
virtual bool init();
virtual bool mainLoop();
virtual void updateApplication(const std::string& message = LLStringUtil::null);
virtual bool cleanup();
virtual void gatherPlatformSpecificFiles();
void setHandle(HINSTANCE hInst) { mhInst = hInst; }
+ int clients_connected() const {
+ return mClientsConnected;
+ }
+ bool getMessageWithTimeout(MSG *msg, UINT to);
+
+ // Starts the processing loop. This function does not return unless the
+ // user is logging off or the user closes the crash service window. The
+ // return value is a good number to pass in ExitProcess().
+ int processingLoop();
private:
void ProcessDlgItemText(HWND hWnd, int nIDDlgItem);
void ProcessCaption(HWND hWnd);
+ bool initCrashServer();
+ google_breakpad::CrashGenerationServer* mCrashHandler;
+ static void OnClientConnected(void* context,
+ const google_breakpad::ClientInfo* client_info);
+
+ static void OnClientDumpRequest(
+ void* context,
+ const google_breakpad::ClientInfo* client_info,
+ const std::wstring* file_path);
+
+ static void OnClientExited(void* context,
+ const google_breakpad::ClientInfo* client_info);
+ int mClientsConnected;
+ int mPID;
+ std::string mProcName;
+
HINSTANCE mhInst;
};
diff --git a/indra/win_crash_logger/win_crash_logger.cpp b/indra/win_crash_logger/win_crash_logger.cpp
index 8e916ae437..79b8514725 100755
--- a/indra/win_crash_logger/win_crash_logger.cpp
+++ b/indra/win_crash_logger/win_crash_logger.cpp
@@ -34,18 +34,24 @@ int APIENTRY WinMain(HINSTANCE hInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
- llinfos << "Starting crash reporter." << llendl;
-
+ llinfos << "Starting crash reporter with args" << &lpCmdLine << llendl;
LLCrashLoggerWindows app;
app.setHandle(hInstance);
app.parseCommandOptions(__argc, __argv);
+ LLSD options = LLApp::instance()->getOptionData(
+ LLApp::PRIORITY_COMMAND_LINE);
+ if (!(options.has("pid") && options.has("dumpdir")))
+ {
+ llwarns << "Insufficient parameters to crash report." << llendl;
+ }
if (! app.init())
{
llwarns << "Unable to initialize application." << llendl;
- return -1;
+ return 1;
}
+ app.processingLoop();
app.mainLoop();
app.cleanup();
llinfos << "Crash reporter finished normally." << llendl;