summaryrefslogtreecommitdiff
path: root/indra/newview/llappviewerwin32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llappviewerwin32.cpp')
-rw-r--r--indra/newview/llappviewerwin32.cpp127
1 files changed, 123 insertions, 4 deletions
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 48b3a1c485..4701e7bbed 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -66,8 +66,70 @@
#endif
#include "stringize.h"
+#include "lldir.h"
+#include <fstream>
#include <exception>
+
+// Bugsplat (http://bugsplat.com) crash reporting tool
+#ifdef LL_BUGSPLAT
+#include "BugSplat.h"
+#include "reader.h" // JsonCpp
+
+namespace
+{
+ // MiniDmpSender's constructor is defined to accept __wchar_t* instead of
+ // plain wchar_t*. That said, wunder() returns std::basic_string<__wchar_t>,
+ // NOT plain __wchar_t*, despite the apparent convenience. Calling
+ // wunder(something).c_str() as an argument expression is fine: that
+ // std::basic_string instance will survive until the function returns.
+ // Calling c_str() on a std::basic_string local to wunder() would be
+ // Undefined Behavior: we'd be left with a pointer into a destroyed
+ // std::basic_string instance.
+
+ // It would be nice if, when wchar_t is the same as __wchar_t, this whole
+ // function would optimize away. However, we use it only for the arguments
+ // to make exactly one call to initialize BugSplat.
+ inline std::basic_string<__wchar_t> wunder(const std::wstring& str)
+ {
+ return { str.begin(), str.end() };
+ }
+
+ // when what we have in hand is a std::string, convert from UTF-8 using
+ // specific wstringize() overload
+ inline std::basic_string<__wchar_t> wunder(const std::string& str)
+ {
+ return wunder(wstringize(str));
+ }
+
+ // Irritatingly, MiniDmpSender::setCallback() is defined to accept a
+ // classic-C function pointer instead of an arbitrary C++ callable. If it
+ // did accept a modern callable, we could pass a lambda that binds our
+ // MiniDmpSender pointer. As things stand, though, we must define an
+ // actual function and store the pointer statically.
+ static MiniDmpSender *sBugSplatSender = nullptr;
+
+ bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2)
+ {
+ // If we haven't yet initialized LLDir, don't bother trying to
+ // find our log file.
+ // Alternatively -- if we might encounter trouble trying to query
+ // LLDir during crash cleanup -- consider making gDirUtilp an
+ // LLPounceable, and attach a callback that stores the pathname to
+ // the log file here.
+ if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp)
+ {
+ // send the main viewer log file
+ // widen to wstring, convert to __wchar_t, then pass c_str()
+ sBugSplatSender->sendAdditionalFile(
+ wunder(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str());
+ }
+
+ return false;
+ }
+}
+#endif // LL_BUGSPLAT
+
namespace
{
void (*gOldTerminateHandler)() = NULL;
@@ -495,15 +557,72 @@ bool LLAppViewerWin32::init()
LLWinDebug::instance();
#endif
-#if LL_WINDOWS
#if LL_SEND_CRASH_REPORTS
-
+#if ! defined(LL_BUGSPLAT)
LLAppViewer* pApp = LLAppViewer::instance();
pApp->initCrashReporting();
-#endif
-#endif
+#else // LL_BUGSPLAT
+
+ if (! gDirUtilp)
+ {
+ LL_WARNS() << "Can't initialize BugSplat, gDirUtilp not yet set" << LL_ENDL;
+ }
+ else
+ {
+ std::string build_data_fname(
+ gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json"));
+ std::ifstream inf(build_data_fname.c_str());
+ if (! inf.is_open())
+ {
+ LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname
+ << "'" << LL_ENDL;
+ }
+ else
+ {
+ Json::Reader reader;
+ Json::Value build_data;
+ if (! reader.parse(inf, build_data, false)) // don't collect comments
+ {
+ // gah, the typo is baked into their API
+ LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname
+ << "': " << reader.getFormatedErrorMessages() << LL_ENDL;
+ }
+ else
+ {
+ Json::Value BugSplat_DB = build_data["BugSplat DB"];
+ if (! BugSplat_DB)
+ {
+ LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '"
+ << build_data_fname << "'" << LL_ENDL;
+ }
+ else
+ {
+ // Got BugSplat_DB, onward!
+ std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' <<
+ LL_VIEWER_VERSION_MINOR << '.' <<
+ LL_VIEWER_VERSION_PATCH << '.' <<
+ LL_VIEWER_VERSION_BUILD));
+
+ // have to convert normal wide strings to strings of __wchar_t
+ sBugSplatSender = new MiniDmpSender(
+ wunder(BugSplat_DB.asString()).c_str(),
+ wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(),
+ wunder(version_string).c_str(),
+ nullptr);
+ sBugSplatSender->setCallback(bugsplatSendLog);
+
+ // engage stringize() overload that converts from wstring
+ LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL)
+ << stringize(version_string) << ')' << LL_ENDL;
+ } // got BugSplat_DB
+ } // parsed build_data.json
+ } // opened build_data.json
+ } // gDirUtilp set
+
+#endif // LL_BUGSPLAT
+#endif // LL_SEND_CRASH_REPORTS
bool success = LLAppViewer::init();