diff options
Diffstat (limited to 'toolkit/crashreporter/client/crashreporter.cpp')
-rw-r--r-- | toolkit/crashreporter/client/crashreporter.cpp | 852 |
1 files changed, 0 insertions, 852 deletions
diff --git a/toolkit/crashreporter/client/crashreporter.cpp b/toolkit/crashreporter/client/crashreporter.cpp deleted file mode 100644 index 2887b16170..0000000000 --- a/toolkit/crashreporter/client/crashreporter.cpp +++ /dev/null @@ -1,852 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "crashreporter.h" - -#ifdef _MSC_VER -// Disable exception handler warnings. -# pragma warning(disable : 4530) -#endif - -#include <fstream> -#include <iomanip> -#include <sstream> -#include <memory> -#include <ctime> -#include <cstdlib> -#include <cstring> -#include <string> -#include <utility> - -#ifdef XP_LINUX -# include <dlfcn.h> -#endif - -#include "json/json.h" -#include "nss.h" -#include "sechash.h" - -using std::ifstream; -using std::ios; -using std::istream; -using std::istringstream; -using std::ofstream; -using std::ostream; -using std::ostringstream; -using std::string; -using std::unique_ptr; -using std::vector; - -namespace CrashReporter { - -StringTable gStrings; -Json::Value gData; -string gSettingsPath; -string gEventsPath; -string gPingPath; -int gArgc; -char** gArgv; -bool gAutoSubmit; - -enum SubmissionResult { Succeeded, Failed }; - -static unique_ptr<ofstream> gLogStream(nullptr); -static string gReporterDumpFile; -static string gExtraFile; -static string gMemoryFile; - -static const char kExtraDataExtension[] = ".extra"; -static const char kMemoryReportExtension[] = ".memory.json.gz"; - -void UIError(const string& message) { - if (gAutoSubmit) { - return; - } - - string errorMessage; - if (!gStrings[ST_CRASHREPORTERERROR].empty()) { - char buf[2048]; - snprintf(buf, 2048, gStrings[ST_CRASHREPORTERERROR].c_str(), - message.c_str()); - errorMessage = buf; - } else { - errorMessage = message; - } - - UIError_impl(errorMessage); -} - -static string Unescape(const string& str) { - string ret; - for (string::const_iterator iter = str.begin(); iter != str.end(); iter++) { - if (*iter == '\\') { - iter++; - if (*iter == '\\') { - ret.push_back('\\'); - } else if (*iter == 'n') { - ret.push_back('\n'); - } else if (*iter == 't') { - ret.push_back('\t'); - } - } else { - ret.push_back(*iter); - } - } - - return ret; -} - -bool ReadStrings(istream& in, StringTable& strings, bool unescape) { - while (!in.eof()) { - string line; - std::getline(in, line); - int sep = line.find('='); - if (sep >= 0) { - string key, value; - key = line.substr(0, sep); - value = line.substr(sep + 1); - if (unescape) value = Unescape(value); - strings[key] = value; - } - } - - return true; -} - -bool ReadStringsFromFile(const string& path, StringTable& strings, - bool unescape) { - ifstream* f = UIOpenRead(path, ios::in); - bool success = false; - if (f->is_open()) { - success = ReadStrings(*f, strings, unescape); - f->close(); - } - - delete f; - return success; -} - -static bool ReadExtraFile(const string& aExtraDataPath, Json::Value& aExtra) { - bool success = false; - ifstream* f = UIOpenRead(aExtraDataPath, ios::in); - if (f->is_open()) { - Json::CharReaderBuilder builder; - success = parseFromStream(builder, *f, &aExtra, nullptr); - } - - delete f; - return success; -} - -static string Basename(const string& file) { - string::size_type slashIndex = file.rfind(UI_DIR_SEPARATOR); - if (slashIndex != string::npos) { - return file.substr(slashIndex + 1); - } - return file; -} - -static bool ReadEventFile(const string& aPath, string& aEventVersion, - string& aTime, string& aUuid, Json::Value& aData) { - bool res = false; - ifstream* f = UIOpenRead(aPath, ios::binary); - - if (f->is_open()) { - std::getline(*f, aEventVersion, '\n'); - res = f->good(); - std::getline(*f, aTime, '\n'); - res &= f->good(); - std::getline(*f, aUuid, '\n'); - res &= f->good(); - - if (res) { - Json::CharReaderBuilder builder; - res = parseFromStream(builder, *f, &aData, nullptr); - } - } - - delete f; - return res; -} - -static void OverwriteEventFile(const string& aPath, const string& aEventVersion, - const string& aTime, const string& aUuid, - const Json::Value& aData) { - ofstream* f = UIOpenWrite(aPath, ios::binary | ios::trunc); - if (f->is_open()) { - f->write(aEventVersion.c_str(), aEventVersion.length()) << '\n'; - f->write(aTime.c_str(), aTime.length()) << '\n'; - f->write(aUuid.c_str(), aUuid.length()) << '\n'; - - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter()); - writer->write(aData, f); - *f << "\n"; - } - - delete f; -} - -static void UpdateEventFile(const Json::Value& aExtraData, const string& aHash, - const string& aPingUuid) { - if (gEventsPath.empty()) { - // If there is no path for finding the crash event, skip this step. - return; - } - - string localId = CrashReporter::GetDumpLocalID(); - string path = gEventsPath + UI_DIR_SEPARATOR + localId; - string eventVersion; - string crashTime; - string crashUuid; - Json::Value eventData; - - if (!ReadEventFile(path, eventVersion, crashTime, crashUuid, eventData)) { - return; - } - - if (!aHash.empty()) { - eventData["MinidumpSha256Hash"] = aHash; - } - - if (!aPingUuid.empty()) { - eventData["CrashPingUUID"] = aPingUuid; - } - - if (aExtraData.isMember("StackTraces")) { - eventData["StackTraces"] = aExtraData["StackTraces"]; - } - - OverwriteEventFile(path, eventVersion, crashTime, crashUuid, eventData); -} - -static void WriteSubmissionEvent(SubmissionResult result, - const string& remoteId) { - if (gEventsPath.empty()) { - // If there is no path for writing the submission event, skip it. - return; - } - - string localId = CrashReporter::GetDumpLocalID(); - string fpath = gEventsPath + UI_DIR_SEPARATOR + localId + "-submission"; - ofstream* f = UIOpenWrite(fpath, ios::binary); - time_t tm; - time(&tm); - - if (f->is_open()) { - *f << "crash.submission.1\n"; - *f << tm << "\n"; - *f << localId << "\n"; - *f << (result == Succeeded ? "true" : "false") << "\n"; - *f << remoteId; - - f->close(); - } - - delete f; -} - -void LogMessage(const std::string& message) { - if (gLogStream.get()) { - char date[64]; - time_t tm; - time(&tm); - if (strftime(date, sizeof(date) - 1, "%c", localtime(&tm)) == 0) - date[0] = '\0'; - (*gLogStream) << "[" << date << "] " << message << '\n'; - } -} - -static void OpenLogFile() { - string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log"; - gLogStream.reset(UIOpenWrite(logPath, ios::app)); -} - -static bool ReadConfig() { - string iniPath; - if (!UIGetIniPath(iniPath)) { - return false; - } - - if (!ReadStringsFromFile(iniPath, gStrings, true)) return false; - - // See if we have a string override file, if so process it - char* overrideEnv = getenv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE"); - if (overrideEnv && *overrideEnv && UIFileExists(overrideEnv)) - ReadStringsFromFile(overrideEnv, gStrings, true); - - return true; -} - -static string GetAdditionalFilename(const string& dumpfile, - const char* extension) { - string filename(dumpfile); - int dot = filename.rfind('.'); - if (dot < 0) return ""; - - filename.replace(dot, filename.length() - dot, extension); - return filename; -} - -static bool MoveCrashData(const string& toDir, string& dumpfile, - string& extrafile, string& memoryfile) { - if (!UIEnsurePathExists(toDir)) { - UIError(gStrings[ST_ERROR_CREATEDUMPDIR]); - return false; - } - - string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile); - string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile); - string newMemory = toDir + UI_DIR_SEPARATOR + Basename(memoryfile); - - if (!UIMoveFile(dumpfile, newDump)) { - UIError(gStrings[ST_ERROR_DUMPFILEMOVE]); - return false; - } - - if (!UIMoveFile(extrafile, newExtra)) { - UIError(gStrings[ST_ERROR_EXTRAFILEMOVE]); - return false; - } - - if (!memoryfile.empty()) { - // Ignore errors from moving the memory file - if (!UIMoveFile(memoryfile, newMemory)) { - UIDeleteFile(memoryfile); - newMemory.erase(); - } - memoryfile = newMemory; - } - - dumpfile = newDump; - extrafile = newExtra; - - return true; -} - -static bool AddSubmittedReport(const string& serverResponse) { - StringTable responseItems; - istringstream in(serverResponse); - ReadStrings(in, responseItems, false); - - if (responseItems.find("StopSendingReportsFor") != responseItems.end()) { - // server wants to tell us to stop sending reports for a certain version - string reportPath = gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + - responseItems["StopSendingReportsFor"]; - - ofstream* reportFile = UIOpenWrite(reportPath, ios::trunc); - if (reportFile->is_open()) { - // don't really care about the contents - *reportFile << 1 << "\n"; - reportFile->close(); - } - delete reportFile; - } - - if (responseItems.find("Discarded") != responseItems.end()) { - // server discarded this report... save it so the user can resubmit it - // manually - return false; - } - - if (responseItems.find("CrashID") == responseItems.end()) return false; - - string submittedDir = gSettingsPath + UI_DIR_SEPARATOR + "submitted"; - if (!UIEnsurePathExists(submittedDir)) { - return false; - } - - string path = - submittedDir + UI_DIR_SEPARATOR + responseItems["CrashID"] + ".txt"; - - ofstream* file = UIOpenWrite(path, ios::trunc); - if (!file->is_open()) { - delete file; - return false; - } - - char buf[1024]; - snprintf(buf, 1024, gStrings["CrashID"].c_str(), - responseItems["CrashID"].c_str()); - *file << buf << "\n"; - - if (responseItems.find("ViewURL") != responseItems.end()) { - snprintf(buf, 1024, gStrings["CrashDetailsURL"].c_str(), - responseItems["ViewURL"].c_str()); - *file << buf << "\n"; - } - - file->close(); - delete file; - - WriteSubmissionEvent(Succeeded, responseItems["CrashID"]); - return true; -} - -void DeleteDump() { - const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP"); - if (!noDelete || *noDelete == '\0') { - if (!gReporterDumpFile.empty()) UIDeleteFile(gReporterDumpFile); - if (!gExtraFile.empty()) UIDeleteFile(gExtraFile); - if (!gMemoryFile.empty()) UIDeleteFile(gMemoryFile); - } -} - -void SendCompleted(bool success, const string& serverResponse) { - if (success) { - if (AddSubmittedReport(serverResponse)) { - DeleteDump(); - } else { - string directory = gReporterDumpFile; - int slashpos = directory.find_last_of("/\\"); - if (slashpos < 2) return; - directory.resize(slashpos); - UIPruneSavedDumps(directory); - WriteSubmissionEvent(Failed, ""); - } - } else { - WriteSubmissionEvent(Failed, ""); - } -} - -static string ComputeDumpHash() { -#ifdef XP_LINUX - // On Linux we rely on the system-provided libcurl which uses nss so we have - // to also use the system-provided nss instead of the ones we have bundled. - const char* libnssNames[] = { - "libnss3.so", -# ifndef HAVE_64BIT_BUILD - // 32-bit versions on 64-bit hosts - "/usr/lib32/libnss3.so", -# endif - }; - void* lib = nullptr; - - for (const char* libname : libnssNames) { - lib = dlopen(libname, RTLD_NOW); - - if (lib) { - break; - } - } - - if (!lib) { - return ""; - } - - SECStatus (*NSS_Initialize)(const char*, const char*, const char*, - const char*, PRUint32); - HASHContext* (*HASH_Create)(HASH_HashType); - void (*HASH_Destroy)(HASHContext*); - void (*HASH_Begin)(HASHContext*); - void (*HASH_Update)(HASHContext*, const unsigned char*, unsigned int); - void (*HASH_End)(HASHContext*, unsigned char*, unsigned int*, unsigned int); - - *(void**)(&NSS_Initialize) = dlsym(lib, "NSS_Initialize"); - *(void**)(&HASH_Create) = dlsym(lib, "HASH_Create"); - *(void**)(&HASH_Destroy) = dlsym(lib, "HASH_Destroy"); - *(void**)(&HASH_Begin) = dlsym(lib, "HASH_Begin"); - *(void**)(&HASH_Update) = dlsym(lib, "HASH_Update"); - *(void**)(&HASH_End) = dlsym(lib, "HASH_End"); - - if (!HASH_Create || !HASH_Destroy || !HASH_Begin || !HASH_Update || - !HASH_End) { - return ""; - } -#endif - // Minimal NSS initialization so we can use the hash functions - const PRUint32 kNssFlags = NSS_INIT_READONLY | NSS_INIT_NOROOTINIT | - NSS_INIT_NOMODDB | NSS_INIT_NOCERTDB; - if (NSS_Initialize(nullptr, "", "", "", kNssFlags) != SECSuccess) { - return ""; - } - - HASHContext* hashContext = HASH_Create(HASH_AlgSHA256); - - if (!hashContext) { - return ""; - } - - HASH_Begin(hashContext); - - ifstream* f = UIOpenRead(gReporterDumpFile, ios::binary); - bool error = false; - - // Read the minidump contents - if (f->is_open()) { - uint8_t buff[4096]; - - do { - f->read((char*)buff, sizeof(buff)); - - if (f->bad()) { - error = true; - break; - } - - HASH_Update(hashContext, buff, f->gcount()); - } while (!f->eof()); - - f->close(); - } else { - error = true; - } - - delete f; - - // Finalize the hash computation - uint8_t result[SHA256_LENGTH]; - uint32_t resultLen = 0; - - HASH_End(hashContext, result, &resultLen, SHA256_LENGTH); - - if (resultLen != SHA256_LENGTH) { - error = true; - } - - HASH_Destroy(hashContext); - - if (!error) { - ostringstream hash; - - for (size_t i = 0; i < SHA256_LENGTH; i++) { - hash << std::setw(2) << std::setfill('0') << std::hex - << static_cast<unsigned int>(result[i]); - } - - return hash.str(); - } - return ""; // If we encountered an error, return an empty hash -} - -string GetDumpLocalID() { - string localId = Basename(gReporterDumpFile); - string::size_type dot = localId.rfind('.'); - - if (dot == string::npos) return ""; - - return localId.substr(0, dot); -} - -string GetProgramPath(const string& exename) { - string path = gArgv[0]; - size_t pos = path.rfind(UI_CRASH_REPORTER_FILENAME BIN_SUFFIX); - path.erase(pos); -#ifdef XP_MACOSX - // On macOS the crash reporter client is shipped as an application bundle - // contained within Firefox' main application bundle. So when it's invoked - // its current working directory looks like: - // Firefox.app/Contents/MacOS/crashreporter.app/Contents/MacOS/ - // The other applications we ship with Firefox are stored in the main bundle - // (Firefox.app/Contents/MacOS/) so we we need to go back three directories - // to reach them. - path.erase(pos - 1); - for (size_t i = 0; i < 3; i++) { - pos = path.rfind(UI_DIR_SEPARATOR, pos - 1); - } - - path.erase(pos + 1); -#endif // XP_MACOSX - path.append(exename + BIN_SUFFIX); - - return path; -} - -} // namespace CrashReporter - -using namespace CrashReporter; - -Json::Value kEmptyJsonString(""); - -void RewriteStrings(Json::Value& aExtraData) { - // rewrite some UI strings with the values from the query parameters - string product = aExtraData.get("ProductName", kEmptyJsonString).asString(); - Json::Value mozilla("Mozilla"); - string vendor = aExtraData.get("Vendor", mozilla).asString(); - - char buf[4096]; - snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERVENDORTITLE].c_str(), - vendor.c_str()); - gStrings[ST_CRASHREPORTERTITLE] = buf; - - string str = gStrings[ST_CRASHREPORTERPRODUCTERROR]; - // Only do the replacement here if the string has two - // format specifiers to start. Otherwise - // we assume it has the product name hardcoded. - string::size_type pos = str.find("%s"); - if (pos != string::npos) pos = str.find("%s", pos + 2); - if (pos != string::npos) { - // Leave a format specifier for UIError to fill in - snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERPRODUCTERROR].c_str(), - product.c_str(), "%s"); - gStrings[ST_CRASHREPORTERERROR] = buf; - } else { - // product name is hardcoded - gStrings[ST_CRASHREPORTERERROR] = str; - } - - snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(), - product.c_str()); - gStrings[ST_CRASHREPORTERDESCRIPTION] = buf; - - snprintf(buf, sizeof(buf), gStrings[ST_CHECKSUBMIT].c_str(), vendor.c_str()); - gStrings[ST_CHECKSUBMIT] = buf; - - snprintf(buf, sizeof(buf), gStrings[ST_RESTART].c_str(), product.c_str()); - gStrings[ST_RESTART] = buf; - - snprintf(buf, sizeof(buf), gStrings[ST_QUIT].c_str(), product.c_str()); - gStrings[ST_QUIT] = buf; - - snprintf(buf, sizeof(buf), gStrings[ST_ERROR_ENDOFLIFE].c_str(), - product.c_str()); - gStrings[ST_ERROR_ENDOFLIFE] = buf; -} - -bool CheckEndOfLifed(const Json::Value& aVersion) { - if (!aVersion.isString()) { - return false; - } - - string reportPath = - gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + aVersion.asString(); - return UIFileExists(reportPath); -} - -int main(int argc, char** argv) { - gArgc = argc; - gArgv = argv; - - string autoSubmitEnv = UIGetEnv("MOZ_CRASHREPORTER_AUTO_SUBMIT"); - gAutoSubmit = !autoSubmitEnv.empty(); - - if (!ReadConfig()) { - UIError("Couldn't read configuration."); - return 0; - } - - if (!UIInit()) { - return 0; - } - - if (argc > 1) { - gReporterDumpFile = argv[1]; - } - - if (gReporterDumpFile.empty()) { - // no dump file specified, run the default UI - if (!gAutoSubmit) { - UIShowDefaultUI(); - } - } else { - // Start by running minidump analyzer to gather stack traces. - string reporterDumpFile = gReporterDumpFile; - vector<string> args = {reporterDumpFile}; - string dumpAllThreadsEnv = UIGetEnv("MOZ_CRASHREPORTER_DUMP_ALL_THREADS"); - if (!dumpAllThreadsEnv.empty()) { - args.insert(args.begin(), "--full"); - } - UIRunProgram(CrashReporter::GetProgramPath(UI_MINIDUMP_ANALYZER_FILENAME), - args, - /* wait */ true); - - // go ahead with the crash reporter - gExtraFile = GetAdditionalFilename(gReporterDumpFile, kExtraDataExtension); - if (gExtraFile.empty()) { - UIError(gStrings[ST_ERROR_BADARGUMENTS]); - return 0; - } - - if (!UIFileExists(gExtraFile)) { - UIError(gStrings[ST_ERROR_EXTRAFILEEXISTS]); - return 0; - } - - gMemoryFile = - GetAdditionalFilename(gReporterDumpFile, kMemoryReportExtension); - if (!UIFileExists(gMemoryFile)) { - gMemoryFile.erase(); - } - - Json::Value extraData; - if (!ReadExtraFile(gExtraFile, extraData)) { - UIError(gStrings[ST_ERROR_EXTRAFILEREAD]); - return 0; - } - - if (!extraData.isMember("ProductName")) { - UIError(gStrings[ST_ERROR_NOPRODUCTNAME]); - return 0; - } - - // There is enough information in the extra file to rewrite strings - // to be product specific - RewriteStrings(extraData); - - if (!extraData.isMember("ServerURL")) { - UIError(gStrings[ST_ERROR_NOSERVERURL]); - return 0; - } - - // Hopefully the settings path exists in the environment. Try that before - // asking the platform-specific code to guess. - gSettingsPath = UIGetEnv("MOZ_CRASHREPORTER_DATA_DIRECTORY"); - if (gSettingsPath.empty()) { - string product = - extraData.get("ProductName", kEmptyJsonString).asString(); - string vendor = extraData.get("Vendor", kEmptyJsonString).asString(); - - if (!UIGetSettingsPath(vendor, product, gSettingsPath)) { - gSettingsPath.clear(); - } - } - - if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) { - UIError(gStrings[ST_ERROR_NOSETTINGSPATH]); - return 0; - } - - OpenLogFile(); - - gEventsPath = UIGetEnv("MOZ_CRASHREPORTER_EVENTS_DIRECTORY"); - gPingPath = UIGetEnv("MOZ_CRASHREPORTER_PING_DIRECTORY"); - - // Assemble and send the crash ping - string hash = ComputeDumpHash(); - - string pingUuid; - SendCrashPing(extraData, hash, pingUuid, gPingPath); - UpdateEventFile(extraData, hash, pingUuid); - - if (!UIFileExists(gReporterDumpFile)) { - UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]); - return 0; - } - - string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending"; - if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile, - gMemoryFile)) { - return 0; - } - - string sendURL = extraData.get("ServerURL", kEmptyJsonString).asString(); - // we don't need to actually send these - extraData.removeMember("ServerURL"); - extraData.removeMember("StackTraces"); - - extraData["SubmittedFrom"] = "Client"; - extraData["Throttleable"] = "1"; - - // re-set XUL_APP_FILE for xulrunner wrapped apps - const char* appfile = getenv("MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE"); - if (appfile && *appfile) { - const char prefix[] = "XUL_APP_FILE="; - char* env = (char*)malloc(strlen(appfile) + strlen(prefix) + 1); - if (!env) { - UIError("Out of memory"); - return 0; - } - strcpy(env, prefix); - strcat(env, appfile); - putenv(env); - free(env); - } - - vector<string> restartArgs; - - if (!extraData.isMember("WindowsErrorReporting")) { - // We relaunch the application associated with the client, but only when - // we encountered a crash caught by the exception handler. Crashes handled - // by WER are prevented from directly restarting the application. - string programPath = GetProgramPath(MOZ_APP_NAME); -#ifndef XP_WIN - const char* moz_app_launcher = getenv("MOZ_APP_LAUNCHER"); - if (moz_app_launcher) { - programPath = moz_app_launcher; - } -#endif // XP_WIN - - restartArgs.push_back(programPath); - - ostringstream paramName; - int i = 1; - paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++; - const char* param = getenv(paramName.str().c_str()); - while (param && *param) { - restartArgs.push_back(param); - - paramName.str(""); - paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++; - param = getenv(paramName.str().c_str()); - } - } - - // allow override of the server url via environment variable - // XXX: remove this in the far future when our robot - // masters force everyone to use XULRunner - char* urlEnv = getenv("MOZ_CRASHREPORTER_URL"); - if (urlEnv && *urlEnv) { - sendURL = urlEnv; - } - - // see if this version has been end-of-lifed - - if (extraData.isMember("Version") && - CheckEndOfLifed(extraData["Version"])) { - UIError(gStrings[ST_ERROR_ENDOFLIFE]); - DeleteDump(); - return 0; - } - - StringTable files; - files["upload_file_minidump"] = gReporterDumpFile; - if (!gMemoryFile.empty()) { - files["memory_report"] = gMemoryFile; - } - - if (!UIShowCrashUI(files, extraData, sendURL, restartArgs)) { - DeleteDump(); - } - } - - UIShutdown(); - - return 0; -} - -#if defined(XP_WIN) && !defined(__GNUC__) -# include <windows.h> - -// We need WinMain in order to not be a console app. This function is unused -// if we are a console application. -int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR args, int) { - // Remove everything except close window from the context menu - { - HKEY hkApp; - RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications", 0, - nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr, - &hkApp, nullptr); - RegCloseKey(hkApp); - if (RegCreateKeyExW(HKEY_CURRENT_USER, - L"Software\\Classes\\Applications\\crashreporter.exe", - 0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE, nullptr, - &hkApp, nullptr) == ERROR_SUCCESS) { - RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0); - RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0); - RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0); - RegCloseKey(hkApp); - } - } - - char** argv = static_cast<char**>(malloc(__argc * sizeof(char*))); - for (int i = 0; i < __argc; i++) { - argv[i] = strdup(WideToUTF8(__wargv[i]).c_str()); - } - - // Do the real work. - return main(__argc, argv); -} -#endif |