No known key found for this signature in database
GPG Key ID: 340F6A4848C5F849
20 changed files with 0 additions and 1468 deletions
-
2.github/workflows/cmake_build.yml
-
7CMakeLists.txt
-
4cmake-proxies/CMakeLists.txt
-
51crashreports/BreakpadConfigurer.cpp
-
45crashreports/BreakpadConfigurer.h
-
53crashreports/CMakeLists.txt
-
41crashreports/crashreporter/CMakeLists.txt
-
464crashreports/crashreporter/CrashReportApp.cpp
-
36crashreports/crashreporter/CrashReportApp.h
-
138crashreports/crashreporter/warning.xpm
-
155crashreports/internal/unix/CrashReportContext.cpp
-
43crashreports/internal/unix/CrashReportContext.h
-
165crashreports/internal/win32/CrashReportContext.cpp
-
47crashreports/internal/win32/CrashReportContext.h
-
35src/AudacityApp.cpp
-
7src/CMakeLists.txt
-
119src/CrashReport.cpp
-
36src/CrashReport.h
-
4src/Experimental.cmake
-
16src/menus/HelpMenus.cpp
@ -1,51 +0,0 @@ |
|||
/*!********************************************************************
|
|||
* |
|||
Audacity: A Digital Audio Editor |
|||
|
|||
BreakpadConfigurer.cpp |
|||
|
|||
Vitaly Sverchinsky |
|||
|
|||
**********************************************************************/ |
|||
|
|||
#include "BreakpadConfigurer.h"
|
|||
|
|||
#if defined(WIN32)
|
|||
#include "internal/win32/CrashReportContext.h"
|
|||
#else
|
|||
#include "internal/unix/CrashReportContext.h"
|
|||
#endif
|
|||
|
|||
BreakpadConfigurer& BreakpadConfigurer::SetDatabasePathUTF8(const std::string& pathUTF8) |
|||
{ |
|||
mDatabasePathUTF8 = pathUTF8; |
|||
return *this; |
|||
} |
|||
|
|||
BreakpadConfigurer& BreakpadConfigurer::SetReportURL(const std::string& reportURL) |
|||
{ |
|||
mReportURL = reportURL; |
|||
return *this; |
|||
} |
|||
|
|||
BreakpadConfigurer& BreakpadConfigurer::SetParameters(const std::map<std::string, std::string>& parameters) |
|||
{ |
|||
mParameters = parameters; |
|||
return *this; |
|||
} |
|||
|
|||
BreakpadConfigurer& BreakpadConfigurer::SetSenderPathUTF8(const std::string& pathUTF8) |
|||
{ |
|||
mSenderPathUTF8 = pathUTF8; |
|||
return *this; |
|||
} |
|||
|
|||
void BreakpadConfigurer::Start() |
|||
{ |
|||
static CrashReportContext context{}; |
|||
bool ok = context.SetSenderPathUTF8(mSenderPathUTF8); |
|||
ok = ok && context.SetReportURL(mReportURL); |
|||
ok = ok && context.SetParameters(mParameters); |
|||
if (ok) |
|||
context.StartHandler(mDatabasePathUTF8); |
|||
} |
@ -1,45 +0,0 @@ |
|||
/*!******************************************************************** |
|||
* |
|||
Audacity: A Digital Audio Editor |
|||
|
|||
BreakpadConfigurer.h |
|||
|
|||
Vitaly Sverchinsky |
|||
|
|||
**********************************************************************/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <map> |
|||
|
|||
//! This class is used to configure Breakpad's handler before start. |
|||
/*! Typically handler should be started as early as possible. |
|||
* BreakpadConfigurer may be a short living object, it is used to configure |
|||
* Breakpad handler, and run it with BreakpadConfigurer::Start() method, |
|||
* It's expected that Start() will be called once during application |
|||
* lifetime, any calls to Set* methods after handler is started will be ignored. |
|||
* The handler itself simply starts crash sender program, passing all the details |
|||
* (path crash dump, report url, parameters...) as a command-line arguments to it. |
|||
* Please read official documentation for details: |
|||
* https://chromium.googlesource.com/breakpad/breakpad |
|||
*/ |
|||
class BreakpadConfigurer final |
|||
{ |
|||
std::string mDatabasePathUTF8; |
|||
std::string mSenderPathUTF8; |
|||
std::string mReportURL; |
|||
std::map<std::string, std::string> mParameters; |
|||
public: |
|||
//! Sets the directory where crashreports will be stored (should have rw permission) |
|||
BreakpadConfigurer& SetDatabasePathUTF8(const std::string& pathUTF8); |
|||
//! Sets report URL to the crash reporting server (URL-Encoded, optional) |
|||
BreakpadConfigurer& SetReportURL(const std::string& reportURL); |
|||
//! Sets an additional parameters that should be sent to a crash reporting server (ASCII encoded) |
|||
BreakpadConfigurer& SetParameters(const std::map<std::string, std::string>& parameters); |
|||
//! Sets a path to a directory where crash reporter sending program is located |
|||
BreakpadConfigurer& SetSenderPathUTF8(const std::string& pathUTF8); |
|||
|
|||
//! Starts the handler |
|||
void Start(); |
|||
}; |
@ -1,53 +0,0 @@ |
|||
# This module provides an interface to configure and start Breakpad handler |
|||
# in a platform independent way. |
|||
|
|||
set(TARGET crashreports) |
|||
set(TARGET_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) |
|||
|
|||
message( STATUS "========== Configuring ${TARGET} ==========" ) |
|||
|
|||
add_library(${TARGET} STATIC) |
|||
|
|||
set(SOURCES "") |
|||
set(INCLUDES INTERFACE ./) |
|||
set(LIBRARIES "") |
|||
set(DEFINIES "") |
|||
|
|||
# also adding Crash Reporting dialog |
|||
add_subdirectory(crashreporter) |
|||
|
|||
list(APPEND SOURCES |
|||
PRIVATE |
|||
BreakpadConfigurer.h |
|||
BreakpadConfigurer.cpp |
|||
) |
|||
list(APPEND LIBRARIES |
|||
PRIVATE |
|||
breakpad::client |
|||
) |
|||
list(APPEND DEFINES |
|||
PUBLIC |
|||
-DUSE_BREAKPAD |
|||
PRIVATE |
|||
-DCRASHREPORTER_PROGRAM_NAME="$<TARGET_FILE_NAME:crashreporter>" |
|||
) |
|||
|
|||
if(WIN32) |
|||
list(APPEND SOURCES |
|||
PRIVATE |
|||
internal/win32/CrashReportContext.h |
|||
internal/win32/CrashReportContext.cpp |
|||
) |
|||
elseif(UNIX) |
|||
list(APPEND SOURCES |
|||
PRIVATE |
|||
internal/unix/CrashReportContext.h |
|||
internal/unix/CrashReportContext.cpp) |
|||
endif() |
|||
|
|||
target_include_directories(${TARGET} ${INCLUDES}) |
|||
target_sources(${TARGET} ${SOURCES}) |
|||
target_link_libraries(${TARGET} ${LIBRARIES}) |
|||
target_compile_definitions(${TARGET} ${DEFINES}) |
|||
|
|||
organize_source( "${TARGET_ROOT}" "" "${SOURCES}" ) |
@ -1,41 +0,0 @@ |
|||
#Adds a Crash Reporting dialog which may be invoked by a crashing program |
|||
|
|||
set(TARGET crashreporter) |
|||
set(TARGET_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) |
|||
|
|||
message( STATUS "========== Configuring ${TARGET} ==========" ) |
|||
|
|||
set(SOURCES |
|||
PRIVATE |
|||
warning.xpm |
|||
CrashReportApp.h |
|||
CrashReportApp.cpp |
|||
) |
|||
|
|||
add_executable(${TARGET}) |
|||
target_sources(${TARGET} ${SOURCES}) |
|||
target_link_libraries(${TARGET} breakpad::processor breakpad::sender wxwidgets::wxwidgets) |
|||
|
|||
if(WIN32) |
|||
set_target_properties(${TARGET} PROPERTIES WIN32_EXECUTABLE ON) |
|||
endif() |
|||
|
|||
if( CMAKE_SYSTEM_NAME MATCHES "Darwin" ) |
|||
add_custom_command( |
|||
TARGET |
|||
${TARGET} |
|||
COMMAND |
|||
${CMAKE_COMMAND} -D SRC="${_EXEDIR}/crashreporter" |
|||
-D DST="${_PKGLIB}" |
|||
-D WXWIN="${_SHARED_PROXY_BASE_PATH}/$<CONFIG>" |
|||
-P ${AUDACITY_MODULE_PATH}/CopyLibs.cmake |
|||
POST_BUILD |
|||
) |
|||
elseif(UNIX) |
|||
target_compile_definitions(${TARGET} PRIVATE -DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") |
|||
install(TARGETS ${TARGET} RUNTIME) |
|||
endif() |
|||
|
|||
set_target_property_all( ${TARGET} RUNTIME_OUTPUT_DIRECTORY "${_EXEDIR}" ) |
|||
|
|||
organize_source( "${TARGET_ROOT}" "" "${SOURCES}" ) |
@ -1,464 +0,0 @@ |
|||
#include "CrashReportApp.h"
|
|||
|
|||
#include <sstream>
|
|||
#include <memory>
|
|||
|
|||
#include <wx/cmdline.h>
|
|||
#include <wx/chartype.h>
|
|||
#include <wx/artprov.h>
|
|||
#include <wx/filename.h>
|
|||
#include <wx/stdpaths.h>
|
|||
|
|||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
|||
#include "google_breakpad/processor/minidump_processor.h"
|
|||
#include "google_breakpad/processor/process_state.h"
|
|||
#include "google_breakpad/processor/minidump.h"
|
|||
#include "processor/stackwalk_common.h"
|
|||
|
|||
#include "warning.xpm"
|
|||
|
|||
//Temporary solution until lib-strings is added
|
|||
#define XC(msg, ctx) (wxGetTranslation(msg, wxEmptyString, ctx))
|
|||
|
|||
#if defined(_WIN32)
|
|||
#include <locale>
|
|||
#include <codecvt>
|
|||
#include "client/windows/sender/crash_report_sender.h"
|
|||
|
|||
namespace |
|||
{ |
|||
std::wstring ToPlatformString(const std::string& utf8) |
|||
{ |
|||
return std::wstring_convert<std::codecvt_utf8<std::wstring::traits_type::char_type>, std::wstring::traits_type::char_type>().from_bytes(utf8); |
|||
} |
|||
|
|||
bool SendMinidump(const std::string& url, const wxString& minidumpPath, const std::map<std::string, std::string>& arguments, const wxString& commentsFilePath) |
|||
{ |
|||
std::map<std::wstring, std::wstring> files; |
|||
files[L"upload_file_minidump"] = minidumpPath.wc_str(); |
|||
if (!commentsFilePath.empty()) |
|||
{ |
|||
files[wxFileName(commentsFilePath).GetFullName().wc_str()] = commentsFilePath.wc_str(); |
|||
} |
|||
|
|||
std::map<std::wstring, std::wstring> parameters; |
|||
for (auto& p : arguments) |
|||
{ |
|||
parameters[ToPlatformString(p.first)] = ToPlatformString(p.second); |
|||
} |
|||
|
|||
google_breakpad::CrashReportSender sender(L""); |
|||
|
|||
auto result = sender.SendCrashReport( |
|||
ToPlatformString(url), |
|||
parameters, |
|||
files, |
|||
nullptr |
|||
); |
|||
return result == google_breakpad::RESULT_SUCCEEDED; |
|||
} |
|||
} |
|||
#else
|
|||
|
|||
#include "common/linux/http_upload.h"
|
|||
|
|||
namespace |
|||
{ |
|||
bool SendMinidump(const std::string& url, const wxString& minidumpPath, const std::map<std::string, std::string>& arguments, const wxString& commentsFilePath) |
|||
{ |
|||
std::map<std::string, std::string> files; |
|||
files["upload_file_minidump"] = minidumpPath.ToStdString(); |
|||
if (!commentsFilePath.empty()) |
|||
{ |
|||
files["comments.txt"] = commentsFilePath.ToStdString(); |
|||
} |
|||
|
|||
std::string response, error; |
|||
bool success = google_breakpad::HTTPUpload::SendRequest( |
|||
url, |
|||
arguments, |
|||
files, |
|||
std::string(), |
|||
std::string(), |
|||
std::string(), |
|||
&response, |
|||
NULL, |
|||
&error); |
|||
|
|||
return success; |
|||
} |
|||
} |
|||
|
|||
#endif
|
|||
|
|||
IMPLEMENT_APP(CrashReportApp); |
|||
namespace |
|||
{ |
|||
std::map<std::string, std::string> parseArguments(const std::string& str) |
|||
{ |
|||
int TOKEN_IDENTIFIER{ 0 }; |
|||
constexpr int TOKEN_EQ{ 1 }; |
|||
constexpr int TOKEN_COMMA{ 2 }; |
|||
constexpr int TOKEN_VALUE{ 3 }; |
|||
|
|||
int i = 0; |
|||
|
|||
std::string key; |
|||
int state = TOKEN_COMMA; |
|||
std::map<std::string, std::string> result; |
|||
while (true) |
|||
{ |
|||
if (str[i] == 0) |
|||
break; |
|||
else if (isspace(str[i])) |
|||
++i; |
|||
else if (isalpha(str[i])) |
|||
{ |
|||
if (state != TOKEN_COMMA) |
|||
throw std::logic_error("malformed parameters string: unexpected identifier"); |
|||
|
|||
int begin = i; |
|||
while (isalnum(str[i])) |
|||
++i; |
|||
|
|||
key = str.substr(begin, i - begin); |
|||
state = TOKEN_IDENTIFIER; |
|||
} |
|||
else if (str[i] == '=') |
|||
{ |
|||
if (state != TOKEN_IDENTIFIER) |
|||
throw std::logic_error("malformed parameters string: unexpected '=' symbol"); |
|||
++i; |
|||
state = TOKEN_EQ; |
|||
} |
|||
else if (str[i] == '\"') |
|||
{ |
|||
if (state != TOKEN_EQ) |
|||
throw std::logic_error("malformed parameters string: unexpected '\"' symbol"); |
|||
|
|||
int begin = ++i; |
|||
while (true) |
|||
{ |
|||
if (str[i] == 0) |
|||
throw std::logic_error("unterminated string literal"); |
|||
else if (str[i] == '\"') |
|||
{ |
|||
if (i > begin) |
|||
result[key] = str.substr(begin, i - begin); |
|||
else |
|||
result[key] = std::string(); |
|||
++i; |
|||
state = TOKEN_VALUE; |
|||
break; |
|||
} |
|||
++i; |
|||
} |
|||
} |
|||
else if (str[i] == ',') |
|||
{ |
|||
if (state != TOKEN_VALUE) |
|||
throw std::logic_error("malformed parameters string: unexpected ',' symbol"); |
|||
state = TOKEN_COMMA; |
|||
++i; |
|||
} |
|||
else |
|||
throw std::logic_error("malformed parameters string"); |
|||
} |
|||
if (state != TOKEN_VALUE) |
|||
throw std::logic_error("malformed parameters string"); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void PrintMinidump(google_breakpad::Minidump& minidump) |
|||
{ |
|||
google_breakpad::BasicSourceLineResolver resolver; |
|||
google_breakpad::MinidumpProcessor minidumpProcessor(nullptr, &resolver); |
|||
google_breakpad::MinidumpThreadList::set_max_threads(std::numeric_limits<uint32_t>::max()); |
|||
google_breakpad::MinidumpMemoryList::set_max_regions(std::numeric_limits<uint32_t>::max()); |
|||
|
|||
google_breakpad::ProcessState processState; |
|||
|
|||
if (minidumpProcessor.Process(&minidump, &processState) != google_breakpad::PROCESS_OK) |
|||
{ |
|||
printf("Failed to process minidump"); |
|||
} |
|||
else |
|||
{ |
|||
google_breakpad::PrintProcessState(processState, true, &resolver); |
|||
} |
|||
} |
|||
|
|||
wxString MakeDumpString(google_breakpad::Minidump& minidump, const wxString& temp) |
|||
{ |
|||
#if _WIN32
|
|||
auto stream = _wfreopen(temp.wc_str(), L"w+", stdout); |
|||
#else
|
|||
auto stream = freopen(temp.utf8_str().data(), "w+", stdout); |
|||
#endif
|
|||
if (stream == NULL) |
|||
throw std::runtime_error("Failed to print minidump: cannot open temp file"); |
|||
PrintMinidump(minidump); |
|||
fflush(stdout); |
|||
|
|||
auto length = ftell(stream); |
|||
std::vector<char> bytes(length); |
|||
fseek(stream, 0, SEEK_SET); |
|||
fread(&bytes[0], 1, length, stream); |
|||
fclose(stream); |
|||
|
|||
#if _WIN32
|
|||
_wremove(temp.wc_str()); |
|||
#else
|
|||
remove(temp.utf8_str().data()); |
|||
#endif
|
|||
|
|||
return wxString::From8BitData(&bytes[0], bytes.size()); |
|||
} |
|||
|
|||
wxString MakeHeaderString(google_breakpad::Minidump& minidump) |
|||
{ |
|||
if (auto exception = minidump.GetException()) |
|||
{ |
|||
if (auto rawException = exception->exception()) |
|||
{ |
|||
// i18n-hint C++ programming assertion
|
|||
return wxString::Format(_("Exception code 0x%x"), rawException->exception_record.exception_code); |
|||
} |
|||
else |
|||
{ |
|||
// i18n-hint C++ programming assertion
|
|||
return _("Unknown exception"); |
|||
} |
|||
} |
|||
else if (auto assertion = minidump.GetAssertion()) |
|||
{ |
|||
auto expression = assertion->expression(); |
|||
if (!expression.empty()) |
|||
{ |
|||
return expression; |
|||
} |
|||
} |
|||
return _("Unknown error"); |
|||
} |
|||
|
|||
void DoShowCrashReportFrame(const wxString& header, const wxString& dump, const std::function<bool(const wxString& comment)>& onSend) |
|||
{ |
|||
static constexpr int MaxUserCommentLength = 2000; |
|||
|
|||
auto frame = new wxFrame( |
|||
nullptr, |
|||
wxID_ANY, |
|||
_("Problem Report for Audacity"), |
|||
wxDefaultPosition, |
|||
wxDefaultSize, |
|||
wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)//disable frame resize
|
|||
); |
|||
frame->SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK)); |
|||
|
|||
auto mainLayout = new wxBoxSizer(wxVERTICAL); |
|||
|
|||
auto headerText = new wxStaticText(frame, wxID_ANY, header); |
|||
headerText->SetFont(wxFont(wxFontInfo().Bold())); |
|||
|
|||
auto headerLayout = new wxBoxSizer(wxHORIZONTAL); |
|||
headerLayout->Add(new wxStaticBitmap(frame, wxID_ANY, wxIcon(warning))); |
|||
headerLayout->AddSpacer(5); |
|||
headerLayout->Add(headerText, wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL)); |
|||
|
|||
auto buttonsLayout = new wxBoxSizer(wxHORIZONTAL); |
|||
|
|||
wxTextCtrl* commentCtrl = nullptr; |
|||
if (onSend != nullptr) |
|||
{ |
|||
commentCtrl = new wxTextCtrl(frame, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(500, 100), wxTE_MULTILINE); |
|||
commentCtrl->SetMaxLength(MaxUserCommentLength); |
|||
} |
|||
|
|||
if (onSend != nullptr) |
|||
{ |
|||
auto okButton = new wxButton(frame, wxID_ANY, XC("&Don't send", "crash reporter button")); |
|||
auto sendButton = new wxButton(frame, wxID_ANY, XC("&Send", "crash reporter button")); |
|||
|
|||
okButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) |
|||
{ |
|||
frame->Close(true); |
|||
}); |
|||
sendButton->Bind(wxEVT_BUTTON, [frame, commentCtrl, onSend](wxCommandEvent&) |
|||
{ |
|||
if (onSend(commentCtrl->GetValue())) |
|||
{ |
|||
frame->Close(true); |
|||
} |
|||
}); |
|||
|
|||
buttonsLayout->Add(okButton); |
|||
buttonsLayout->AddSpacer(5); |
|||
buttonsLayout->Add(sendButton); |
|||
} |
|||
else |
|||
{ |
|||
auto okButton = new wxButton(frame, wxID_OK, wxT("OK")); |
|||
okButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) |
|||
{ |
|||
frame->Close(true); |
|||
}); |
|||
buttonsLayout->Add(okButton); |
|||
} |
|||
|
|||
mainLayout->Add(headerLayout, wxSizerFlags().Border(wxALL)); |
|||
if (onSend != nullptr) |
|||
{ |
|||
mainLayout->AddSpacer(5); |
|||
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Click \"Send\" to submit the report to Audacity. This information is collected anonymously.")), wxSizerFlags().Border(wxALL)); |
|||
} |
|||
mainLayout->AddSpacer(10); |
|||
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Problem details")), wxSizerFlags().Border(wxALL)); |
|||
|
|||
auto dumpTextCtrl = new wxTextCtrl(frame, wxID_ANY, dump, wxDefaultPosition, wxSize(500, 300), wxTE_RICH | wxTE_READONLY | wxTE_MULTILINE | wxTE_DONTWRAP); |
|||
dumpTextCtrl->SetFont(wxFont(wxFontInfo().Family(wxFONTFAMILY_TELETYPE))); |
|||
dumpTextCtrl->ShowPosition(0);//scroll to top
|
|||
mainLayout->Add(dumpTextCtrl, wxSizerFlags().Border(wxALL).Expand()); |
|||
|
|||
if (onSend != nullptr) |
|||
{ |
|||
mainLayout->AddSpacer(10); |
|||
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Comments")), wxSizerFlags().Border(wxALL)); |
|||
mainLayout->Add(commentCtrl, wxSizerFlags().Border(wxALL).Expand()); |
|||
} |
|||
|
|||
mainLayout->Add(buttonsLayout, wxSizerFlags().Border(wxALL).Align(wxALIGN_RIGHT)); |
|||
frame->SetSizerAndFit(mainLayout); |
|||
|
|||
frame->Show(true); |
|||
} |
|||
} |
|||
|
|||
|
|||
bool CrashReportApp::OnInit() |
|||
{ |
|||
if (!wxApp::OnInit()) |
|||
return false; |
|||
|
|||
if (mSilent) |
|||
{ |
|||
if (!mURL.empty()) |
|||
SendMinidump(mURL, mMinidumpPath, mArguments, wxEmptyString); |
|||
} |
|||
else |
|||
{ |
|||
static std::unique_ptr<wxLocale> sLocale(new wxLocale(wxLANGUAGE_DEFAULT)); |
|||
#if defined(__WXOSX__)
|
|||
sLocale->AddCatalogLookupPathPrefix(wxT("../Resources")); |
|||
#elif defined(__WXMSW__)
|
|||
sLocale->AddCatalogLookupPathPrefix(wxT("Languages")); |
|||
#elif defined(__WXGTK__)
|
|||
sLocale->AddCatalogLookupPathPrefix(wxT("./locale")); |
|||
sLocale->AddCatalogLookupPathPrefix(wxString::Format(wxT("%s/share/locale"), wxT(INSTALL_PREFIX))); |
|||
#endif
|
|||
sLocale->AddCatalog("audacity"); |
|||
sLocale->AddCatalog("wxstd"); |
|||
|
|||
google_breakpad::Minidump minidump(mMinidumpPath.ToStdString(), false); |
|||
if (minidump.Read()) |
|||
{ |
|||
SetExitOnFrameDelete(true); |
|||
|
|||
wxFileName temp(mMinidumpPath); |
|||
temp.SetExt("tmp"); |
|||
|
|||
try |
|||
{ |
|||
ShowCrashReport(MakeHeaderString(minidump), MakeDumpString(minidump, temp.GetFullPath())); |
|||
} |
|||
catch (std::exception& e) |
|||
{ |
|||
wxMessageBox(e.what()); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
void CrashReportApp::OnInitCmdLine(wxCmdLineParser& parser) |
|||
{ |
|||
static const wxCmdLineEntryDesc cmdLineEntryDesc[] = |
|||
{ |
|||
{ wxCMD_LINE_SWITCH, "h", "help", "Display help on the command line parameters", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, |
|||
{ wxCMD_LINE_SWITCH, "s", "silent", "Send without displaying the confirmation dialog" }, |
|||
{ wxCMD_LINE_OPTION, "u", "url", "Crash report server URL", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, |
|||
{ wxCMD_LINE_OPTION, "a", "args", "A set of arguments to send", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, |
|||
{ wxCMD_LINE_PARAM, NULL, NULL, "path to minidump file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, |
|||
{ wxCMD_LINE_NONE } |
|||
}; |
|||
|
|||
parser.SetDesc(cmdLineEntryDesc); |
|||
|
|||
wxApp::OnInitCmdLine(parser); |
|||
} |
|||
|
|||
bool CrashReportApp::OnCmdLineParsed(wxCmdLineParser& parser) |
|||
{ |
|||
wxString url; |
|||
wxString arguments; |
|||
if (parser.Found("u", &url)) |
|||
{ |
|||
mURL = url.ToStdString(); |
|||
} |
|||
if (parser.Found("a", &arguments)) |
|||
{ |
|||
try |
|||
{ |
|||
mArguments = parseArguments(arguments.ToStdString()); |
|||
} |
|||
catch (std::exception& e) |
|||
{ |
|||
wxMessageBox(e.what()); |
|||
return false; |
|||
} |
|||
} |
|||
mMinidumpPath = parser.GetParam(0); |
|||
mSilent = parser.Found("s"); |
|||
|
|||
return wxApp::OnCmdLineParsed(parser); |
|||
} |
|||
|
|||
void CrashReportApp::ShowCrashReport(const wxString& header, const wxString& text) |
|||
{ |
|||
if (mURL.empty()) |
|||
{ |
|||
DoShowCrashReportFrame(header, text, nullptr); |
|||
} |
|||
else |
|||
{ |
|||
DoShowCrashReportFrame(header, text, [this](const wxString& comments) |
|||
{ |
|||
wxString commentsFilePath; |
|||
if (!comments.empty()) |
|||
{ |
|||
wxFileName temp(mMinidumpPath); |
|||
temp.SetName(temp.GetName() + "-comments"); |
|||
temp.SetExt("txt"); |
|||
commentsFilePath = temp.GetFullPath(); |
|||
wxFile file; |
|||
if (file.Open(commentsFilePath, wxFile::write)) |
|||
{ |
|||
file.Write(comments); |
|||
file.Close(); |
|||
} |
|||
} |
|||
|
|||
auto result = SendMinidump(mURL, mMinidumpPath, mArguments, commentsFilePath); |
|||
if (!commentsFilePath.empty()) |
|||
wxRemoveFile(commentsFilePath); |
|||
|
|||
if (!result) |
|||
{ |
|||
wxMessageBox(_("Failed to send crash report")); |
|||
} |
|||
return result; |
|||
}); |
|||
} |
|||
} |
@ -1,36 +0,0 @@ |
|||
/*!******************************************************************** |
|||
* |
|||
Audacity: A Digital Audio Editor |
|||
|
|||
CrashReportApp.h |
|||
|
|||
Vitaly Sverchinsky |
|||
|
|||
**********************************************************************/ |
|||
|
|||
#include <wx/wx.h> |
|||
#include <map> |
|||
#include <string> |
|||
|
|||
//! Crash reporter GUI application |
|||
/*! Used to send crash reports to a remote server, or view them. |
|||
* Shows brief report content, and allows user to send report to developers. |
|||
* Reporting URL and other parameters are specified as a command line arguments. |
|||
*/ |
|||
class CrashReportApp final : public wxApp |
|||
{ |
|||
std::string mURL; |
|||
wxString mMinidumpPath; |
|||
std::map<std::string, std::string> mArguments; |
|||
|
|||
bool mSilent{ false }; |
|||
public: |
|||
bool OnInit() override; |
|||
void OnInitCmdLine(wxCmdLineParser& parser) override; |
|||
bool OnCmdLineParsed(wxCmdLineParser& parser) override; |
|||
|
|||
private: |
|||
void ShowCrashReport(const wxString& header, const wxString& text); |
|||
}; |
|||
|
|||
DECLARE_APP(CrashReportApp); |
@ -1,138 +0,0 @@ |
|||
/* XPM */ |
|||
static const char *warning[] = { |
|||
/* columns rows colors chars-per-pixel */ |
|||
"24 24 108 2 ", |
|||
" c None", |
|||
". c black", |
|||
"X c #010100", |
|||
"o c #020200", |
|||
"O c #020201", |
|||
"+ c #070601", |
|||
"@ c #070701", |
|||
"# c #0E0C02", |
|||
"$ c #151204", |
|||
"% c #1C1804", |
|||
"& c #1F1A05", |
|||
"* c #261F00", |
|||
"= c #262000", |
|||
"- c #262005", |
|||
"; c #292305", |
|||
": c #2D2705", |
|||
"> c #312A06", |
|||
", c #403705", |
|||
"< c #413806", |
|||
"1 c #8F7300", |
|||
"2 c #957700", |
|||
"3 c #BA9500", |
|||
"4 c #B99600", |
|||
"5 c #E3B800", |
|||
"6 c #E5BA00", |
|||
"7 c #FEBB0B", |
|||
"8 c #FFBC08", |
|||
"9 c #FFBA0C", |
|||
"0 c #FFBF10", |
|||
"q c #FFBF11", |
|||
"w c #FFC000", |
|||
"e c #FFC100", |
|||
"r c #FFC202", |
|||
"t c #FFC400", |
|||
"y c #FFC500", |
|||
"u c #FFC700", |
|||
"i c #FFC307", |
|||
"p c #FFC800", |
|||
"a c #FFC900", |
|||
"s c #FECA00", |
|||
"d c #FFCB00", |
|||
"f c #FFCC00", |
|||
"g c #FFCD00", |
|||
"h c #FFCA04", |
|||
"j c #FFCF04", |
|||
"k c #FFC20B", |
|||
"l c #FFC00D", |
|||
"z c #FFC20D", |
|||
"x c #FFC00E", |
|||
"c c #FFCF0D", |
|||
"v c #FED004", |
|||
"b c #FFD104", |
|||
"n c #FFD00D", |
|||
"m c #FFD10D", |
|||
"M c #FFD20D", |
|||
"N c #FEC116", |
|||
"B c #FFCB14", |
|||
"V c #FFC61C", |
|||
"C c #FFCA1F", |
|||
"Z c #FFD215", |
|||
"A c #FFD11C", |
|||
"S c #FFD11D", |
|||
"D c #FFD31D", |
|||
"F c #FFD41D", |
|||
"G c #E6C327", |
|||
"H c #E7C527", |
|||
"J c #FFC621", |
|||
"K c #FFC525", |
|||
"L c #FFC624", |
|||
"P c #FFCC21", |
|||
"I c #FFCA25", |
|||
"U c #FFC927", |
|||
"Y c #FFCB26", |
|||
"T c #FFCC27", |
|||
"R c #FFCE27", |
|||
"E c #FFC22B", |
|||
"W c #FFC52A", |
|||
"Q c #FFC62C", |
|||
"! c #F2CE29", |
|||
"~ c #F3CF29", |
|||
"^ c #FFC828", |
|||
"/ c #FFCE28", |
|||
"( c #FFCC2A", |
|||
") c #FFCC2C", |
|||
"_ c #FFD423", |
|||
"` c #FFD623", |
|||
"' c #FFD226", |
|||
"] c #FFD527", |
|||
"[ c #F6D129", |
|||
"{ c #FFD129", |
|||
"} c #FFD229", |
|||
"| c #FFD22A", |
|||
" . c #FFD32A", |
|||
".. c #FDD42A", |
|||
"X. c #FCD52B", |
|||
"o. c #FFD42A", |
|||
"O. c #FFD52A", |
|||
"+. c #FFD52B", |
|||
"@. c #FFD62A", |
|||
"#. c #FFD62B", |
|||
"$. c #FFD72B", |
|||
"%. c #FFD828", |
|||
"&. c #FFD92B", |
|||
"*. c #FFDA2B", |
|||
"=. c #FFDA2C", |
|||
"-. c #FFC633", |
|||
";. c #FFC830", |
|||
":. c #FFCA31", |
|||
/* pixels */ |
|||
" ", |
|||
" -.E ", |
|||
" / R ", |
|||
" U +.+.) ", |
|||
" ;.| +.+.| W ", |
|||
" U +.[ [ +.R ", |
|||
" ;.+.H X X G | J ", |
|||
" R +.! X X ! +.R ", |
|||
" L +.+.+.@ @ +.+.+.^ ", |
|||
" | +.+.=.# # *.+.+.| ", |
|||
" / +.+.+.*.$ $ *.+.+.+.U ", |
|||
" L ' ] ] ] *.% % *.] ] ] ' Q ", |
|||
" C ` ` ` ` ` - ; ` ` ` ` ` P ", |
|||
" J D D D D D D : > F D D D D D V ", |
|||
" B Z Z Z Z Z Z < , Z Z Z Z Z Z B ", |
|||
" k c n n n n n n n n n n n n n n c x ", |
|||
" q h j j j j j j j b b j j j j j j j h x ", |
|||
" i f f f f f f f 6 = * 5 f f f f f f f w ", |
|||
" 8 p p p p p p p p 3 X X 3 p p p f f p p p q ", |
|||
" w p p p p p p p p p 2 1 p p p p p p p p p w ", |
|||
"9 u u u u u u u u u u u u u u u u u u u u u u 7 ", |
|||
"N u u u u u u u u u u u u u u u u u u u u u u x ", |
|||
" ", |
|||
" " |
|||
}; |
@ -1,155 +0,0 @@ |
|||
/*!********************************************************************
|
|||
* |
|||
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
|
|||
} |
@ -1,43 +0,0 @@ |
|||
/*!******************************************************************** |
|||
* |
|||
Audacity: A Digital Audio Editor |
|||
|
|||
CrashReportContext.h |
|||
|
|||
Vitaly Sverchinsky |
|||
|
|||
**********************************************************************/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <map> |
|||
|
|||
//!This object is for internal usage. |
|||
/*! Simple POD type, holds user data required to start handler. |
|||
* Fields are initialized with Set* methods, |
|||
* which may return false if internal buffer isn't large enough |
|||
* to store value passed as an argument. |
|||
* After initialization call StartHandler providing path to the |
|||
* database, where minidumps will be stored. |
|||
*/ |
|||
class CrashReportContext |
|||
{ |
|||
static constexpr size_t MaxBufferLength{ 2048 }; |
|||
|
|||
char mSenderPath[MaxBufferLength]{}; |
|||
char mReportURL[MaxBufferLength]{}; |
|||
char mParameters[MaxBufferLength]{}; |
|||
|
|||
public: |
|||
|
|||
bool SetSenderPathUTF8(const std::string& path); |
|||
bool SetReportURL(const std::string& url); |
|||
bool SetParameters(const std::map<std::string, std::string>& p); |
|||
|
|||
void StartHandler(const std::string& databasePath); |
|||
|
|||
private: |
|||
//helper function which need access to a private data, but should not be exposed to a public class interface |
|||
friend bool SendReport(CrashReportContext* ctx, const char* minidumpPath); |
|||
}; |
@ -1,165 +0,0 @@ |
|||
/*!********************************************************************
|
|||
* |
|||
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 <locale>
|
|||
#include <codecvt>
|
|||
#include <sstream>
|
|||
#include "client/windows/handler/exception_handler.h"
|
|||
|
|||
namespace |
|||
{ |
|||
//copy src(null-terminated) to dst,
|
|||
//returns false if dest is not large enough
|
|||
bool StrcpyChecked(wchar_t* dest, size_t destsz, const wchar_t* src) |
|||
{ |
|||
auto len = wcslen(src); |
|||
if (len < destsz) |
|||
{ |
|||
memcpy(dest, src, sizeof(wchar_t) * len); |
|||
dest[len] = 0; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
//appends src(null-terminated) to dest, destsz is the total dest buffer size, not remaining
|
|||
//returns false if dest is not large enough
|
|||
bool StrcatChecked(wchar_t* dest, size_t destsz, const wchar_t* src) |
|||
{ |
|||
auto srclen = wcslen(src); |
|||
auto dstlen = wcslen(dest); |
|||
if (srclen + dstlen < destsz) |
|||
{ |
|||
memcpy(dest + dstlen, src, sizeof(wchar_t) * srclen); |
|||
dest[srclen + dstlen] = 0; |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
//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(); |
|||
} |
|||
} |
|||
|
|||
bool MakeCommand(CrashReportContext* c, const wchar_t* path, const wchar_t* id) |
|||
{ |
|||
//utility path
|
|||
auto ok = StrcpyChecked(c->mCommand, CrashReportContext::MaxCommandLength, L"\""); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, c->mSenderPath); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, L"\""); |
|||
|
|||
//parameters: /p "..."
|
|||
if (ok && c->mParameters[0] != 0) |
|||
{ |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, L" /a \""); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, c->mParameters); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, L"\""); |
|||
} |
|||
//crash report URL: /u https://...
|
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxBufferLength, L" /u \""); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxBufferLength, c->mReportURL); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxBufferLength, L"\" "); |
|||
//minidump path: path/to/minidump.dmp
|
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, L" \""); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, path); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, L"\\"); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, id); |
|||
ok = ok && StrcatChecked(c->mCommand, CrashReportContext::MaxCommandLength, L".dmp\""); |
|||
return ok; |
|||
} |
|||
|
|||
bool SendReport(CrashReportContext* c, const wchar_t* path, const wchar_t* id) |
|||
{ |
|||
if (!MakeCommand(c, path, id)) |
|||
return false; |
|||
|
|||
STARTUPINFOW si; |
|||
ZeroMemory(&si, sizeof(si)); |
|||
si.cb = sizeof(si); |
|||
si.dwFlags = STARTF_USESHOWWINDOW; |
|||
si.wShowWindow = SW_SHOW; |
|||
|
|||
PROCESS_INFORMATION pi; |
|||
ZeroMemory(&pi, sizeof(pi)); |
|||
|
|||
if (CreateProcessW(NULL, c->mCommand, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) |
|||
{ |
|||
CloseHandle(pi.hProcess); |
|||
CloseHandle(pi.hThread); |
|||
return true; |
|||
} |
|||
else |
|||
return false; |
|||
} |
|||
|
|||
bool UploadReport( |
|||
const wchar_t* dump_path, |
|||
const wchar_t* minidump_id, |
|||
void* context, |
|||
EXCEPTION_POINTERS* /*exinfo*/, |
|||
MDRawAssertionInfo* /*assertion*/, |
|||
bool succeeded) |
|||
{ |
|||
CrashReportContext* crashReportContext = static_cast<CrashReportContext*>(context); |
|||
if (!SendReport(crashReportContext, dump_path, minidump_id)) |
|||
return false; |
|||
return succeeded; |
|||
} |
|||
|
|||
bool CrashReportContext::SetSenderPathUTF8(const std::string& path) |
|||
{ |
|||
auto fullpath = path + "\\" + CRASHREPORTER_PROGRAM_NAME; |
|||
return StrcpyChecked(mSenderPath, MaxBufferLength, std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>().from_bytes(fullpath).c_str()); |
|||
} |
|||
|
|||
bool CrashReportContext::SetReportURL(const std::string& url) |
|||
{ |
|||
return StrcpyChecked(mReportURL, MaxBufferLength, std::wstring(url.begin(), url.end()).c_str()); |
|||
} |
|||
|
|||
bool CrashReportContext::SetParameters(const std::map<std::string, std::string>& p) |
|||
{ |
|||
auto str = StringifyParameters(p); |
|||
return StrcpyChecked(mParameters, MaxBufferLength, std::wstring(str.begin(), str.end()).c_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...
|
|||
static auto handler = new google_breakpad::ExceptionHandler( |
|||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>().from_bytes(databasePath), |
|||
NULL, |
|||
UploadReport, |
|||
this, |
|||
google_breakpad::ExceptionHandler::HANDLER_ALL); |
|||
} |
|||
|
@ -1,47 +0,0 @@ |
|||
/*!******************************************************************** |
|||
* |
|||
Audacity: A Digital Audio Editor |
|||
|
|||
CrashReportContext.h |
|||
|
|||
Vitaly Sverchinsky |
|||
|
|||
**********************************************************************/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <map> |
|||
|
|||
//!This object is for internal usage. |
|||
/*! Simple POD type, holds user data required to start handler. |
|||
* Fields are initialized with Set* methods, |
|||
* which may return false if internal buffer isn't large enough |
|||
* to store value passed as an argument. |
|||
* After initialization call StartHandler providing path to the |
|||
* database, where minidumps will be stored. |
|||
*/ |
|||
class CrashReportContext final |
|||
{ |
|||
static constexpr size_t MaxBufferLength{ 2048 }; |
|||
static constexpr size_t MaxCommandLength{ 8192 }; |
|||
|
|||
wchar_t mSenderPath[MaxBufferLength]{}; |
|||
wchar_t mReportURL[MaxBufferLength]{}; |
|||
wchar_t mParameters[MaxBufferLength]{}; |
|||
|
|||
//this is a buffer where the command will be built at runtime |
|||
wchar_t mCommand[MaxCommandLength]{}; |
|||
|
|||
public: |
|||
bool SetSenderPathUTF8(const std::string& path); |
|||
bool SetReportURL(const std::string& path); |
|||
bool SetParameters(const std::map<std::string, std::string>& p); |
|||
|
|||
void StartHandler(const std::string& databasePath); |
|||
|
|||
private: |
|||
//helper functions which need access to a private data, but should not be exposed to a public class interface |
|||
friend bool MakeCommand(CrashReportContext* ctx, const wchar_t* path, const wchar_t* id); |
|||
friend bool SendReport(CrashReportContext* ctx, const wchar_t* path, const wchar_t* id); |
|||
}; |
@ -1,119 +0,0 @@ |
|||
/**********************************************************************
|
|||
|
|||
Audacity: A Digital Audio Editor |
|||
|
|||
CrashReport.cpp |
|||
|
|||
*//*******************************************************************/ |
|||
|
|||
|
|||
#include "CrashReport.h"
|
|||
|
|||
#if defined(HAS_CRASH_REPORT)
|
|||
#include <atomic>
|
|||
#include <thread>
|
|||
|
|||
#include <wx/progdlg.h>
|
|||
|
|||
#if defined(__WXMSW__)
|
|||
#include <wx/evtloop.h>
|
|||
#endif
|
|||
|
|||
#include "wxFileNameWrapper.h"
|
|||
#include "AudacityLogger.h"
|
|||
#include "AudioIOBase.h"
|
|||
#include "FileNames.h"
|
|||
#include "Internat.h"
|
|||
#include "Languages.h"
|
|||
#include "Project.h"
|
|||
#include "ProjectFileIO.h"
|
|||
#include "prefs/GUIPrefs.h"
|
|||
#include "widgets/ErrorDialog.h"
|
|||
|
|||
namespace CrashReport { |
|||
|
|||
void Generate(wxDebugReport::Context ctx) |
|||
{ |
|||
wxDebugReportCompress rpt; |
|||
|
|||
// Bug 1927: Seems there problems with wxStackWalker, so don't even include
|
|||
// the stack trace or memory dump. The former is pretty much useless in Release
|
|||
// builds anyway and none of use have the skill/time/desire to fiddle with the
|
|||
// latter.
|
|||
// rpt.AddAll(ctx);
|
|||
|
|||
{ |
|||
// Provides a progress dialog with indeterminate mode
|
|||
wxGenericProgressDialog pd(XO("Audacity Support Data").Translation(), |
|||
XO("This may take several seconds").Translation(), |
|||
300000, // range
|
|||
nullptr, // parent
|
|||
wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH); |
|||
|
|||
std::atomic_bool done = {false}; |
|||
auto thread = std::thread([&] |
|||
{ |
|||
wxFileNameWrapper fn{ FileNames::DataDir(), wxT("audacity.cfg") }; |
|||
rpt.AddFile(fn.GetFullPath(), _TS("Audacity Configuration")); |
|||
rpt.AddFile(FileNames::PluginRegistry(), wxT("Plugin Registry")); |
|||
rpt.AddFile(FileNames::PluginSettings(), wxT("Plugin Settings")); |
|||
|
|||
if (ctx == wxDebugReport::Context_Current) |
|||
{ |
|||
auto saveLang = Languages::GetLangShort(); |
|||
GUIPrefs::SetLang( wxT("en") ); |
|||
auto cleanup = finally( [&]{ GUIPrefs::SetLang( saveLang ); } ); |
|||
|
|||
auto gAudioIO = AudioIOBase::Get(); |
|||
rpt.AddText(wxT("audiodev.txt"), gAudioIO->GetDeviceInfo(), wxT("Audio Device Info")); |
|||
#ifdef EXPERIMENTAL_MIDI_OUT
|
|||
rpt.AddText(wxT("mididev.txt"), gAudioIO->GetMidiDeviceInfo(), wxT("MIDI Device Info")); |
|||