mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-29 23:29:41 +02:00
💩 Remove Breakpad Crash Reports
This commit is contained in:
parent
5728dd542f
commit
2a37cd19a0
2
.github/workflows/cmake_build.yml
vendored
2
.github/workflows/cmake_build.yml
vendored
@ -80,8 +80,6 @@ jobs:
|
||||
|
||||
- name: Configure
|
||||
env:
|
||||
# Error reporing
|
||||
CRASH_REPORT_URL: ${{ secrets.CRASH_REPORT_URL }}
|
||||
# Apple code signing
|
||||
APPLE_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
|
||||
APPLE_NOTARIZATION_USER_NAME: ${{ secrets.APPLE_NOTARIZATION_USER_NAME }}
|
||||
|
@ -204,10 +204,6 @@ elseif( CMAKE_SYSTEM_NAME MATCHES "Darwin" )
|
||||
message( STATUS " MacOS SDK: ${CMAKE_OSX_SYSROOT}" )
|
||||
message( STATUS )
|
||||
|
||||
if(${_OPT}has_crashreports)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
# Try to get the current commit information
|
||||
@ -476,9 +472,6 @@ add_subdirectory( "cmake-proxies" )
|
||||
resolve_conan_dependencies()
|
||||
|
||||
add_subdirectory( "help" )
|
||||
if(${_OPT}has_crashreports)
|
||||
add_subdirectory( "crashreports" )
|
||||
endif()
|
||||
add_subdirectory( "images" )
|
||||
add_subdirectory( "libraries" )
|
||||
add_subdirectory( "locale" )
|
||||
|
@ -18,10 +18,6 @@ add_conan_lib(
|
||||
expat:shared=True
|
||||
)
|
||||
|
||||
if(${_OPT}has_crashreports)
|
||||
add_conan_lib(breakpad breakpad/0.1 REQUIRED)
|
||||
endif()
|
||||
|
||||
set( wx_zlib "zlib" )
|
||||
|
||||
set( wx_png "libpng" )
|
||||
|
@ -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);
|
||||
};
|
@ -77,7 +77,6 @@ It handles initialization and termination by subclassing wxApp.
|
||||
#include "AudioIO.h"
|
||||
#include "Benchmark.h"
|
||||
#include "Clipboard.h"
|
||||
#include "CrashReport.h" // for HAS_CRASH_REPORT
|
||||
#include "commands/CommandHandler.h"
|
||||
#include "commands/AppCommandEvent.h"
|
||||
#include "widgets/ASlider.h"
|
||||
@ -123,10 +122,6 @@ It handles initialization and termination by subclassing wxApp.
|
||||
|
||||
#include "import/Import.h"
|
||||
|
||||
#if defined(USE_BREAKPAD)
|
||||
#include "BreakpadConfigurer.h"
|
||||
#endif
|
||||
|
||||
#ifdef EXPERIMENTAL_SCOREALIGN
|
||||
#include "effects/ScoreAlignDialog.h"
|
||||
#endif
|
||||
@ -382,29 +377,6 @@ void PopulatePreferences()
|
||||
gPrefs->Flush();
|
||||
}
|
||||
|
||||
#if defined(USE_BREAKPAD)
|
||||
void InitBreakpad()
|
||||
{
|
||||
wxFileName databasePath;
|
||||
databasePath.SetPath(wxStandardPaths::Get().GetUserLocalDataDir());
|
||||
databasePath.AppendDir("crashreports");
|
||||
databasePath.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
|
||||
|
||||
if(databasePath.DirExists())
|
||||
{
|
||||
BreakpadConfigurer configurer;
|
||||
configurer.SetDatabasePathUTF8(databasePath.GetPath().ToUTF8().data())
|
||||
.SetSenderPathUTF8(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath().ToUTF8().data())
|
||||
#if defined(CRASH_REPORT_URL)
|
||||
.SetReportURL(CRASH_REPORT_URL)
|
||||
#endif
|
||||
.SetParameters({
|
||||
{ "version", wxString(AUDACITY_VERSION_STRING).ToUTF8().data() }
|
||||
})
|
||||
.Start();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool gInited = false;
|
||||
@ -952,10 +924,6 @@ wxLanguageInfo userLangs[] =
|
||||
|
||||
void AudacityApp::OnFatalException()
|
||||
{
|
||||
#if defined(HAS_CRASH_REPORT)
|
||||
CrashReport::Generate(wxDebugReport::Context_Exception);
|
||||
#endif
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -1020,15 +988,12 @@ bool AudacityApp::OnExceptionInMainLoop()
|
||||
AudacityApp::AudacityApp()
|
||||
{
|
||||
#if defined(USE_BREAKPAD)
|
||||
InitBreakpad();
|
||||
// Do not capture crashes in debug builds
|
||||
#elif !defined(_DEBUG)
|
||||
#if defined(HAS_CRASH_REPORT)
|
||||
#if defined(wxUSE_ON_FATAL_EXCEPTION) && wxUSE_ON_FATAL_EXCEPTION
|
||||
wxHandleFatalExceptions();
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
AudacityApp::~AudacityApp()
|
||||
|
@ -120,8 +120,6 @@ list( APPEND SOURCES
|
||||
Clipboard.h
|
||||
CommonCommandFlags.cpp
|
||||
CommonCommandFlags.h
|
||||
CrashReport.cpp
|
||||
CrashReport.h
|
||||
DarkThemeAsCeeCode.h
|
||||
DBConnection.cpp
|
||||
DBConnection.h
|
||||
@ -1071,7 +1069,6 @@ list( APPEND LIBRARIES
|
||||
libsoxr
|
||||
portaudio-v19
|
||||
sqlite
|
||||
$<$<BOOL:${${_OPT}has_crashreports}>:crashreports>
|
||||
$<$<BOOL:${USE_FFMPEG}>:ffmpeg>
|
||||
$<$<BOOL:${USE_LIBID3TAG}>:libid3tag::libid3tag>
|
||||
$<$<BOOL:${USE_LIBFLAC}>:libflac>
|
||||
@ -1294,10 +1291,6 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CRASH_REPORT_URL)
|
||||
list(APPEND DEFINES PRIVATE -DCRASH_REPORT_URL="${CRASH_REPORT_URL}")
|
||||
endif()
|
||||
|
||||
set_target_property_all( ${TARGET} RUNTIME_OUTPUT_NAME ${AUDACITY_NAME} )
|
||||
|
||||
organize_source( "${TARGET_ROOT}/.." "include" "${HEADERS}" )
|
||||
|
@ -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"));
|
||||
#endif
|
||||
auto project = GetActiveProject();
|
||||
auto &projectFileIO = ProjectFileIO::Get( *project );
|
||||
rpt.AddText(wxT("project.txt"), projectFileIO.GenerateDoc(), wxT("Active project doc"));
|
||||
}
|
||||
|
||||
auto logger = AudacityLogger::Get();
|
||||
if (logger)
|
||||
{
|
||||
rpt.AddText(wxT("log.txt"), logger->GetLog(), _TS("Audacity Log"));
|
||||
}
|
||||
|
||||
done = true;
|
||||
});
|
||||
|
||||
// Wait for information to be gathered
|
||||
while (!done)
|
||||
{
|
||||
wxMilliSleep(50);
|
||||
pd.Pulse();
|
||||
}
|
||||
thread.join();
|
||||
}
|
||||
|
||||
bool ok = wxDebugReportPreviewStd().Show(rpt);
|
||||
|
||||
#if defined(__WXMSW__)
|
||||
wxEventLoop::SetCriticalWindow(NULL);
|
||||
#endif
|
||||
|
||||
if (ok && rpt.Process())
|
||||
{
|
||||
AudacityTextEntryDialog dlg(nullptr,
|
||||
XO("Report generated to:"),
|
||||
XO("Audacity Support Data"),
|
||||
rpt.GetCompressedFileName(),
|
||||
wxOK | wxCENTER);
|
||||
dlg.SetName(dlg.GetTitle());
|
||||
dlg.ShowModal();
|
||||
|
||||
wxLogMessage(wxT("Report generated to: %s"),
|
||||
rpt.GetCompressedFileName());
|
||||
|
||||
rpt.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -1,36 +0,0 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
CrashReport.h
|
||||
|
||||
Paul Licameli
|
||||
split from AudacityApp.h
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_CRASH_REPORT__
|
||||
#define __AUDACITY_CRASH_REPORT__
|
||||
|
||||
#undef HAS_CRASH_REPORT
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(EXPERIMENTAL_CRASH_REPORT)
|
||||
|
||||
#include <wx/setup.h> // for wxUSE* macros
|
||||
#if defined(wxUSE_DEBUGREPORT) && wxUSE_DEBUGREPORT
|
||||
#define HAS_CRASH_REPORT
|
||||
#include <wx/debugrpt.h>
|
||||
|
||||
namespace CrashReport
|
||||
{
|
||||
AUDACITY_DLL_API
|
||||
void Generate(wxDebugReport::Context ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -175,10 +175,6 @@ set( EXPERIMENTAL_OPTIONS_LIST
|
||||
# scrolling past zero is enabled. Perhaps that lessens confusion.
|
||||
TWO_TONE_TIME_RULER
|
||||
|
||||
#Define to include crash reporting, if available in wxWidgets build
|
||||
#This flag is used only in CrashReport.h; elsewhere use HAS_CRASH_REPORT
|
||||
CRASH_REPORT
|
||||
|
||||
# Paul Licameli (PRL) 31 May 2015
|
||||
# Zero-padding factor for spectrograms can smooth the display of spectrograms by
|
||||
# interpolating in frequency domain.
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "../AudacityLogger.h"
|
||||
#include "../AudioIOBase.h"
|
||||
#include "../CommonCommandFlags.h"
|
||||
#include "../CrashReport.h" // for HAS_CRASH_REPORT
|
||||
#include "../FileNames.h"
|
||||
#include "../HelpText.h"
|
||||
#include "../Menus.h"
|
||||
@ -348,18 +347,6 @@ void OnShowLog( const CommandContext &context )
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAS_CRASH_REPORT)
|
||||
void OnCrashReport(const CommandContext &WXUNUSED(context) )
|
||||
{
|
||||
// Change to "1" to test a real crash
|
||||
#if 0
|
||||
char *p = 0;
|
||||
*p = 1234;
|
||||
#endif
|
||||
CrashReport::Generate(wxDebugReport::Context_Current);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IS_ALPHA
|
||||
void OnSegfault(const CommandContext &)
|
||||
{
|
||||
@ -543,9 +530,6 @@ BaseItemSharedPtr HelpMenu()
|
||||
#endif
|
||||
Command( wxT("Log"), XXO("Show &Log..."), FN(OnShowLog),
|
||||
AlwaysEnabledFlag ),
|
||||
#if defined(HAS_CRASH_REPORT)
|
||||
Command( wxT("CrashReport"), XXO("&Generate Support Data..."),
|
||||
FN(OnCrashReport), AlwaysEnabledFlag )
|
||||
#endif
|
||||
|
||||
#ifdef IS_ALPHA
|
||||
|
Loading…
x
Reference in New Issue
Block a user