mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 06:15:04 +00:00
Add: use breakpad to create crash.dmp on MacOS / Linux too (#11202)
Normally only the Windows platform could create a crash.dmp, making analysing crash-reports from MacOS / Linux rather tricky.
This commit is contained in:
parent
8f6df242c4
commit
f120d2beb8
8
.github/workflows/ci-build.yml
vendored
8
.github/workflows/ci-build.yml
vendored
@ -121,6 +121,10 @@ jobs:
|
||||
${{ matrix.libraries }} \
|
||||
zlib1g-dev \
|
||||
# EOF
|
||||
|
||||
sudo vcpkg install \
|
||||
breakpad \
|
||||
# EOF
|
||||
echo "::endgroup::"
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
@ -149,7 +153,7 @@ jobs:
|
||||
cd build
|
||||
|
||||
echo "::group::CMake"
|
||||
cmake .. ${{ matrix.extra-cmake-parameters }}
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake ${{ matrix.extra-cmake-parameters }}
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build"
|
||||
@ -205,6 +209,7 @@ jobs:
|
||||
- name: Prepare vcpkg
|
||||
run: |
|
||||
vcpkg install --triplet=${{ matrix.arch }}-osx \
|
||||
breakpad \
|
||||
curl \
|
||||
liblzma \
|
||||
libpng \
|
||||
@ -290,6 +295,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
vcpkg install --triplet=${{ matrix.arch }}-windows-static \
|
||||
breakpad \
|
||||
liblzma \
|
||||
libpng \
|
||||
lzo \
|
||||
|
1
.github/workflows/release-linux.yml
vendored
1
.github/workflows/release-linux.yml
vendored
@ -108,6 +108,7 @@ jobs:
|
||||
ln -sf $(pwd)/installed/x64-linux/tools/python3/python3.[0-9][0-9] /usr/bin/python3
|
||||
|
||||
./vcpkg install \
|
||||
breakpad \
|
||||
curl[http2] \
|
||||
fontconfig \
|
||||
freetype \
|
||||
|
2
.github/workflows/release-macos.yml
vendored
2
.github/workflows/release-macos.yml
vendored
@ -53,6 +53,8 @@ jobs:
|
||||
- name: Prepare vcpkg
|
||||
run: |
|
||||
vcpkg install \
|
||||
breakpad:x64-osx \
|
||||
breakpad:arm64-osx \
|
||||
curl:x64-osx \
|
||||
curl:arm64-osx \
|
||||
liblzma:x64-osx \
|
||||
|
1
.github/workflows/release-windows.yml
vendored
1
.github/workflows/release-windows.yml
vendored
@ -65,6 +65,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
vcpkg install --triplet=${{ matrix.arch }}-windows-static \
|
||||
breakpad \
|
||||
liblzma \
|
||||
libpng \
|
||||
lzo \
|
||||
|
@ -134,6 +134,11 @@ else()
|
||||
find_package(CURL)
|
||||
endif()
|
||||
|
||||
# Breakpad doesn't support emscripten.
|
||||
if(NOT EMSCRIPTEN)
|
||||
find_package(unofficial-breakpad)
|
||||
endif()
|
||||
|
||||
if(NOT OPTION_DEDICATED)
|
||||
if(NOT WIN32)
|
||||
find_package(Allegro)
|
||||
@ -310,6 +315,10 @@ if(NOT WIN32 AND NOT EMSCRIPTEN)
|
||||
link_package(CURL ENCOURAGED)
|
||||
endif()
|
||||
|
||||
if(NOT EMSCRIPTEN)
|
||||
link_package(unofficial-breakpad TARGET unofficial::breakpad::libbreakpad_client ENCOURAGED)
|
||||
endif()
|
||||
|
||||
if(NOT OPTION_DEDICATED)
|
||||
link_package(Fluidsynth)
|
||||
link_package(SDL)
|
||||
|
@ -5,6 +5,7 @@
|
||||
OpenTTD makes use of the following external libraries:
|
||||
|
||||
- (encouraged) nlohmann-json: JSON handling
|
||||
- (encouraged) breakpad: creates minidumps on crash
|
||||
- (encouraged) zlib: (de)compressing of old (0.3.0-1.0.5) savegames, content downloads,
|
||||
heightmaps
|
||||
- (encouraged) liblzma: (de)compressing of savegames (1.1.0 and later)
|
||||
@ -50,6 +51,7 @@ by following the `Quick Start` instructions of their
|
||||
After this, you can install the dependencies OpenTTD needs. We advise to use
|
||||
the `static` versions, and OpenTTD currently needs the following dependencies:
|
||||
|
||||
- breakpad
|
||||
- liblzma
|
||||
- libpng
|
||||
- lzo
|
||||
@ -59,8 +61,8 @@ the `static` versions, and OpenTTD currently needs the following dependencies:
|
||||
To install both the x64 (64bit) and x86 (32bit) variants (though only one is necessary), you can use:
|
||||
|
||||
```ps
|
||||
.\vcpkg install liblzma:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static nlohmann-json:x64-windows-static zlib:x64-windows-static
|
||||
.\vcpkg install liblzma:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static nlohmann-json:x86-windows-static zlib:x86-windows-static
|
||||
.\vcpkg install breakpad:x64-windows-static liblzma:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static nlohmann-json:x64-windows-static zlib:x64-windows-static
|
||||
.\vcpkg install breakpad:x86-windows-static liblzma:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static nlohmann-json:x86-windows-static zlib:x86-windows-static
|
||||
```
|
||||
|
||||
You can open the folder (as a CMake project). CMake will be detected, and you can compile from there.
|
||||
|
@ -55,7 +55,7 @@ find_library(LZO_LIBRARY
|
||||
# name as the optimized file. This is not always the case, but so far
|
||||
# experiences has shown that in those case vcpkg CMake files do the right
|
||||
# thing.
|
||||
if(VCPKG_TOOLCHAIN AND LZO_LIBRARY)
|
||||
if(VCPKG_TOOLCHAIN AND LZO_LIBRARY AND LZO_LIBRARY MATCHES "${VCPKG_INSTALLED_DIR}")
|
||||
if(LZO_LIBRARY MATCHES "/debug/")
|
||||
set(LZO_LIBRARY_DEBUG ${LZO_LIBRARY})
|
||||
string(REPLACE "/debug/lib/" "/lib/" LZO_LIBRARY_RELEASE ${LZO_LIBRARY})
|
||||
|
@ -3,6 +3,9 @@ function(link_package NAME)
|
||||
|
||||
if(${NAME}_FOUND)
|
||||
string(TOUPPER "${NAME}" UCNAME)
|
||||
# Some libraries have a dash, which is not allowed in a preprocessor macro.
|
||||
string(REPLACE "-" "_" UCNAME "${UCNAME}")
|
||||
|
||||
add_definitions(-DWITH_${UCNAME})
|
||||
# Some libraries' cmake packages (looking at you, SDL2) leave trailing whitespace in the link commands,
|
||||
# which (later) cmake considers to be an error. Work around this with by stripping the incoming string.
|
||||
|
@ -369,9 +369,14 @@ bool CrashLog::WriteCrashLog()
|
||||
return len == written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the (crash) dump to a file.
|
||||
*
|
||||
* @note Sets \c crashdump_filename when there is a successful return.
|
||||
* @return 1 iff the crashdump was successfully created, -1 if it failed, 0 if not implemented.
|
||||
*/
|
||||
/* virtual */ int CrashLog::WriteCrashDump()
|
||||
{
|
||||
/* Stub implementation; not all OSes support this. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -452,13 +457,15 @@ bool CrashLog::MakeCrashLog()
|
||||
ret = false;
|
||||
}
|
||||
|
||||
/* Don't mention writing crash dumps because not all platforms support it. */
|
||||
fmt::print("Writing crash dump to disk...\n");
|
||||
int dret = this->WriteCrashDump();
|
||||
if (dret < 0) {
|
||||
fmt::print("Writing crash dump failed.\n\n");
|
||||
ret = false;
|
||||
} else if (dret > 0) {
|
||||
fmt::print("Crash dump written to {}. Please add this file to any bug reports.\n\n", this->crashdump_filename);
|
||||
} else {
|
||||
fmt::print("Skipped; missing dependency to create crash dump.\n");
|
||||
}
|
||||
|
||||
fmt::print("Writing crash savegame...\n");
|
||||
|
@ -73,12 +73,6 @@ public:
|
||||
void FillCrashLog(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
bool WriteCrashLog();
|
||||
|
||||
/**
|
||||
* Write the (crash) dump to a file.
|
||||
* @note Sets \c crashdump_filename when there is a successful return.
|
||||
* @return if less than 0, error. If 0 no dump is made, otherwise the dump
|
||||
* was successful (not all OSes support dumping files).
|
||||
*/
|
||||
virtual int WriteCrashDump();
|
||||
bool WriteSavegame();
|
||||
bool WriteScreenshot();
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../crashlog.h"
|
||||
#include "../../fileio_func.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../gamelog.h"
|
||||
#include "../../saveload/saveload.h"
|
||||
@ -20,6 +21,10 @@
|
||||
#include <dlfcn.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
# include <client/mac/handler/exception_handler.h>
|
||||
#endif
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
|
||||
@ -139,6 +144,22 @@ class CrashLogOSX : public CrashLog {
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
static bool MinidumpCallback(const char* dump_dir, const char* minidump_id, void* context, bool succeeded)
|
||||
{
|
||||
CrashLogOSX *crashlog = reinterpret_cast<CrashLogOSX *>(context);
|
||||
|
||||
crashlog->crashdump_filename = crashlog->CreateFileName(".dmp");
|
||||
std::rename(fmt::format("{}/{}.dmp", dump_dir, minidump_id).c_str(), crashlog->crashdump_filename.c_str());
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
int WriteCrashDump() override
|
||||
{
|
||||
return google_breakpad::ExceptionHandler::WriteMinidump(_personal_dir, MinidumpCallback, this) ? 1 : -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* A crash log is always generated by signal.
|
||||
@ -155,8 +176,8 @@ public:
|
||||
std::string message = fmt::format(
|
||||
"Please send the generated crash information and the last (auto)save to the developers. "
|
||||
"This will greatly help debugging. The correct place to do this is https://github.com/OpenTTD/OpenTTD/issues.\n\n"
|
||||
"Generated file(s):\n{}\n{}\n{}",
|
||||
this->crashlog_filename, this->savegame_filename, this->screenshot_filename);
|
||||
"Generated file(s):\n{}\n{}\n{}\n{}",
|
||||
this->crashlog_filename, this->crashdump_filename, this->savegame_filename, this->screenshot_filename);
|
||||
|
||||
ShowMacDialog(crash_title, message.c_str(), "Quit");
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../crashlog.h"
|
||||
#include "../../fileio_func.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../gamelog.h"
|
||||
#include "../../saveload/saveload.h"
|
||||
@ -25,6 +26,10 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
# include <client/linux/handler/exception_handler.h>
|
||||
#endif
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/**
|
||||
@ -84,6 +89,23 @@ class CrashLogUnix : public CrashLog {
|
||||
#endif
|
||||
fmt::format_to(output_iterator, "\n");
|
||||
}
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
static bool MinidumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
|
||||
{
|
||||
CrashLogUnix *crashlog = reinterpret_cast<CrashLogUnix *>(context);
|
||||
|
||||
crashlog->crashdump_filename = crashlog->CreateFileName(".dmp");
|
||||
std::rename(descriptor.path(), crashlog->crashdump_filename.c_str());
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
int WriteCrashDump() override
|
||||
{
|
||||
return google_breakpad::ExceptionHandler::WriteMinidump(_personal_dir, MinidumpCallback, this) ? 1 : -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* A crash log is always generated by signal.
|
||||
|
@ -23,6 +23,14 @@
|
||||
#include <signal.h>
|
||||
#include <psapi.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include <dbghelp.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
# include <client/windows/handler/exception_handler.h>
|
||||
#endif
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/**
|
||||
@ -37,8 +45,24 @@ class CrashLogWindows : public CrashLog {
|
||||
void LogStacktrace(std::back_insert_iterator<std::string> &output_iterator) const override;
|
||||
void LogModules(std::back_insert_iterator<std::string> &output_iterator) const override;
|
||||
public:
|
||||
|
||||
#ifdef WITH_UNOFFICIAL_BREAKPAD
|
||||
static bool MinidumpCallback(const wchar_t *dump_dir, const wchar_t *minidump_id, void *context, EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion, bool succeeded)
|
||||
{
|
||||
CrashLogWindows *crashlog = reinterpret_cast<CrashLogWindows *>(context);
|
||||
|
||||
crashlog->crashdump_filename = crashlog->CreateFileName(".dmp");
|
||||
std::rename(fmt::format("{}/{}.dmp", FS2OTTD(dump_dir), FS2OTTD(minidump_id)).c_str(), crashlog->crashdump_filename.c_str());
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
int WriteCrashDump() override
|
||||
{
|
||||
return google_breakpad::ExceptionHandler::WriteMinidump(OTTD2FS(_personal_dir), MinidumpCallback, this) ? 1 : -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
int WriteCrashDump() override;
|
||||
void AppendDecodedStacktrace(std::back_insert_iterator<std::string> &output_iterator) const;
|
||||
#else
|
||||
void AppendDecodedStacktrace(std::back_insert_iterator<std::string> &output_iterator) const {}
|
||||
@ -205,10 +229,6 @@ static void PrintModuleInfo(std::back_insert_iterator<std::string> &output_itera
|
||||
static const uint MAX_SYMBOL_LEN = 512;
|
||||
static const uint MAX_FRAMES = 64;
|
||||
|
||||
#pragma warning(disable:4091)
|
||||
#include <dbghelp.h>
|
||||
#pragma warning(default:4091)
|
||||
|
||||
void CrashLogWindows::AppendDecodedStacktrace(std::back_insert_iterator<std::string> &output_iterator) const
|
||||
{
|
||||
DllLoader dbghelp(L"dbghelp.dll");
|
||||
@ -321,46 +341,6 @@ void CrashLogWindows::AppendDecodedStacktrace(std::back_insert_iterator<std::str
|
||||
|
||||
fmt::format_to(output_iterator, "\n*** End of additional info ***\n");
|
||||
}
|
||||
|
||||
/* virtual */ int CrashLogWindows::WriteCrashDump()
|
||||
{
|
||||
int ret = 0;
|
||||
DllLoader dbghelp(L"dbghelp.dll");
|
||||
if (dbghelp.Success()) {
|
||||
typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE,
|
||||
MINIDUMP_TYPE,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION);
|
||||
MiniDumpWriteDump_t funcMiniDumpWriteDump = dbghelp.GetProcAddress("MiniDumpWriteDump");
|
||||
if (funcMiniDumpWriteDump != nullptr) {
|
||||
this->crashdump_filename = this->CreateFileName(".dmp");
|
||||
HANDLE file = CreateFile(OTTD2FS(this->crashdump_filename).c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0);
|
||||
HANDLE proc = GetCurrentProcess();
|
||||
DWORD procid = GetCurrentProcessId();
|
||||
MINIDUMP_EXCEPTION_INFORMATION mdei;
|
||||
MINIDUMP_USER_STREAM userstream;
|
||||
MINIDUMP_USER_STREAM_INFORMATION musi;
|
||||
|
||||
userstream.Type = LastReservedStream + 1;
|
||||
userstream.Buffer = (void*)this->crashlog.data();
|
||||
userstream.BufferSize = (ULONG)this->crashlog.size() + 1;
|
||||
|
||||
musi.UserStreamCount = 1;
|
||||
musi.UserStreamArray = &userstream;
|
||||
|
||||
mdei.ThreadId = GetCurrentThreadId();
|
||||
mdei.ExceptionPointers = ep;
|
||||
mdei.ClientPointers = false;
|
||||
|
||||
funcMiniDumpWriteDump(proc, procid, file, MiniDumpWithDataSegs, &mdei, &musi, nullptr);
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
extern bool CloseConsoleLogIfActive();
|
||||
|
Loading…
Reference in New Issue
Block a user