156 lines
4.4 KiB
C++
156 lines
4.4 KiB
C++
/*!********************************************************************
|
|
*
|
|
Audacity: A Digital Audio Editor
|
|
|
|
CrashReportContext.cpp
|
|
|
|
Vitaly Sverchinsky
|
|
|
|
Some parts of the code are designed to operate while app is crashing,
|
|
so there may be some restrictions on heap usage. For more information
|
|
please read Breakpad documentation.
|
|
|
|
**********************************************************************/
|
|
#include "CrashReportContext.h"
|
|
|
|
#include <errno.h>
|
|
#include <map>
|
|
#include <sstream>
|
|
|
|
#if defined(__APPLE__)
|
|
#include "client/mac/handler/exception_handler.h"
|
|
#else
|
|
#include "client/linux/handler/exception_handler.h"
|
|
#endif
|
|
|
|
bool SendReport(CrashReportContext* c, const char* minidumpPath)
|
|
{
|
|
auto pid = fork();
|
|
if(pid == 0)
|
|
{
|
|
if(c->mParameters[0] != 0)
|
|
{
|
|
execl(c->mSenderPath, CRASHREPORTER_PROGRAM_NAME, "-a", c->mParameters, "-u", c->mReportURL, minidumpPath, NULL);
|
|
}
|
|
else
|
|
{
|
|
execl(c->mSenderPath, CRASHREPORTER_PROGRAM_NAME, "-u", c->mReportURL, minidumpPath, NULL);
|
|
}
|
|
fprintf(stderr, "Failed to start handler: %s\n", strerror(errno));
|
|
abort();
|
|
}
|
|
return pid != -1;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
//converts parameters map to a string, so that the Crash Reporting program
|
|
//would understand them
|
|
std::string StringifyParameters(const std::map<std::string, std::string>& parameters)
|
|
{
|
|
std::stringstream stream;
|
|
|
|
std::size_t parameterIndex = 0;
|
|
std::size_t parametersCount = parameters.size();
|
|
for (auto& pair : parameters)
|
|
{
|
|
stream << pair.first.c_str() << "=\"" << pair.second.c_str() << "\"";
|
|
++parameterIndex;
|
|
if (parameterIndex < parametersCount)
|
|
stream << ",";
|
|
}
|
|
return stream.str();
|
|
}
|
|
|
|
//copy contents of src to a raw char dest buffer,
|
|
//returns false if dest is not large enough
|
|
bool StrcpyChecked(char* dest, size_t destsz, const std::string& src)
|
|
{
|
|
if(src.length() < destsz)
|
|
{
|
|
memcpy(dest, src.c_str(), src.length());
|
|
dest[src.length()] = '\0';
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
static constexpr size_t MaxDumpPathLength{ 4096 };
|
|
static char DumpPath[MaxDumpPathLength];
|
|
|
|
bool DumpCallback(const char* dump_dir, const char* minidump_id, void* context, bool succeeded)
|
|
{
|
|
if(succeeded)
|
|
{
|
|
const int PathDumpLength = strlen(dump_dir) + strlen("/") + strlen(minidump_id) + strlen(".dmp");
|
|
if(PathDumpLength < MaxDumpPathLength)
|
|
{
|
|
strcpy(DumpPath, dump_dir);
|
|
strcat(DumpPath, "/");
|
|
strcat(DumpPath, minidump_id);
|
|
strcat(DumpPath, ".dmp");
|
|
auto crashReportContext = static_cast<CrashReportContext*>(context);
|
|
return SendReport(crashReportContext, DumpPath);
|
|
}
|
|
return false;
|
|
}
|
|
return succeeded;
|
|
}
|
|
#else
|
|
bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
|
|
{
|
|
if(succeeded)
|
|
{
|
|
auto crashReportContext = static_cast<CrashReportContext*>(context);
|
|
return SendReport(crashReportContext, descriptor.path());
|
|
}
|
|
return succeeded;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool CrashReportContext::SetSenderPathUTF8(const std::string& path)
|
|
{
|
|
return StrcpyChecked(mSenderPath, MaxBufferLength, path + "/" + CRASHREPORTER_PROGRAM_NAME);
|
|
}
|
|
|
|
bool CrashReportContext::SetReportURL(const std::string& url)
|
|
{
|
|
return StrcpyChecked(mReportURL, MaxBufferLength, url);
|
|
}
|
|
|
|
bool CrashReportContext::SetParameters(const std::map<std::string, std::string>& p)
|
|
{
|
|
auto str = StringifyParameters(p);
|
|
return StrcpyChecked(mParameters, MaxBufferLength, str);
|
|
}
|
|
|
|
void CrashReportContext::StartHandler(const std::string& databasePath)
|
|
{
|
|
//intentinal leak: error hooks may be useful while application is terminating
|
|
//CrashReportContext data should be alive too...
|
|
#if(__APPLE__)
|
|
static auto handler = new google_breakpad::ExceptionHandler(
|
|
databasePath,
|
|
nullptr,
|
|
DumpCallback,
|
|
this,
|
|
true,
|
|
nullptr
|
|
);
|
|
#else
|
|
google_breakpad::MinidumpDescriptor descriptor(databasePath);
|
|
static auto handler = new google_breakpad::ExceptionHandler(
|
|
descriptor,
|
|
nullptr,
|
|
DumpCallback,
|
|
this,
|
|
true,
|
|
-1
|
|
);
|
|
#endif
|
|
}
|