Merge branch 'master' into jgrpp

# Conflicts:
#	cmake/CompileFlags.cmake
#	src/crashlog.cpp
#	src/crashlog.h
#	src/date_type.h
#	src/depot_type.h
#	src/landscape.cpp
#	src/openttd.cpp
#	src/order_cmd.cpp
#	src/order_gui.cpp
#	src/os/macosx/crashlog_osx.cpp
#	src/os/unix/crashlog_unix.cpp
#	src/os/windows/crashlog_win.cpp
#	src/pathfinder/npf/npf.cpp
#	src/road_cmd.cpp
#	src/script/api/script_infrastructure.cpp
#	src/stdafx.h
#	src/table/settings/gui_settings.ini
#	src/table/settings/pathfinding_settings.ini
#	src/tests/CMakeLists.txt
This commit is contained in:
Jonathan G Rennison
2023-11-13 19:08:22 +00:00
154 changed files with 1004 additions and 1007 deletions

View File

@@ -26,6 +26,7 @@
#include <dlfcn.h>
#include <cxxabi.h>
#include <sys/mman.h>
#include <execinfo.h>
#ifdef WITH_UCONTEXT
#include <sys/ucontext.h>
#endif
@@ -186,77 +187,16 @@ class CrashLogOSX : public CrashLog {
char *LogStacktrace(char *buffer, const char *last) const override
{
/* As backtrace() is only implemented in 10.5 or later,
* we're rolling our own here. Mostly based on
* http://stackoverflow.com/questions/289820/getting-the-current-stack-trace-on-mac-os-x
* and some details looked up in the Darwin sources. */
buffer += seprintf(buffer, last, "\nStacktrace:\n");
void **frame;
int i = 0;
void *trace[64];
int trace_size = backtrace(trace, lengthof(trace));
auto print_frame = [&](void *ip) {
/* Print running index. */
buffer += seprintf(buffer, last, " [%02d]", i);
Dl_info dli;
bool dl_valid = dladdr(ip, &dli) != 0;
const char *fname = "???";
if (dl_valid && dli.dli_fname) {
/* Valid image name? Extract filename from the complete path. */
const char *s = strrchr(dli.dli_fname, '/');
if (s != nullptr) {
fname = s + 1;
} else {
fname = dli.dli_fname;
}
}
/* Print image name and IP. */
buffer += seprintf(buffer, last, " %-20s " PRINTF_PTR, fname, (uintptr_t)ip);
/* Print function offset if information is available. */
if (dl_valid && dli.dli_sname != nullptr && dli.dli_saddr != nullptr) {
/* Try to demangle a possible C++ symbol. */
int status = -1;
char *func_name = abi::__cxa_demangle(dli.dli_sname, nullptr, 0, &status);
long int offset = (intptr_t)ip - (intptr_t)dli.dli_saddr;
buffer += seprintf(buffer, last, " (%s + %ld)", func_name != nullptr ? func_name : dli.dli_sname, offset);
free(func_name);
}
buffer += seprintf(buffer, last, "\n");
};
#if defined(__ppc__) || defined(__ppc64__)
/* Apple says __builtin_frame_address can be broken on PPC. */
__asm__ volatile("mr %0, r1" : "=r" (frame));
#else
frame = (void **)__builtin_frame_address(0);
#endif
for (; frame != nullptr && i < MAX_STACK_FRAMES; i++) {
auto guard = scope_guard([&]() {
this->CrashLogFaultSectionCheckpoint(buffer);
});
/* Get IP for current stack frame. */
#if defined(__ppc__) || defined(__ppc64__)
void *ip = frame[2];
#else
void *ip = frame[1];
#endif
if (ip == nullptr) break;
print_frame(ip);
/* Get address of next stack frame. */
void **next = (void **)frame[0];
/* Frame address not increasing or not aligned? Broken stack, exit! */
if (next <= frame || !IS_ALIGNED(next)) break;
frame = next;
char **messages = backtrace_symbols(trace, trace_size);
for (int i = 0; i < trace_size; i++) {
buffer += seprintf(buffer, last, "%s\n", messages[i]);
}
free(messages);
return buffer + seprintf(buffer, last, "\n");
}

View File

@@ -48,10 +48,7 @@
#if defined(WITH_BFD)
# include <bfd.h>
#endif
#elif defined(SUNOS)
# include <ucontext.h>
# include <dlfcn.h>
#endif
#endif /* __GLIBC__ */
#if defined(__NetBSD__)
#include <unistd.h>
@@ -363,39 +360,6 @@ class CrashLogUnix : public CrashLog {
return buffer;
}
#if defined(SUNOS)
/** Data needed while walking up the stack */
struct StackWalkerParams {
char **bufptr; ///< Buffer
const char *last; ///< End of buffer
int counter; ///< We are at counter-th stack level
};
/**
* Callback used while walking up the stack.
* @param pc program counter
* @param sig 'active' signal (unused)
* @param params parameters
* @return always 0, continue walking up the stack
*/
static int SunOSStackWalker(uintptr_t pc, int sig, void *params)
{
StackWalkerParams *wp = (StackWalkerParams *)params;
/* Resolve program counter to file and nearest symbol (if possible) */
Dl_info dli;
if (dladdr((void *)pc, &dli) != 0) {
*wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] %s(%s+0x%x) [0x%x]\n",
wp->counter, dli.dli_fname, dli.dli_sname, (int)((byte *)pc - (byte *)dli.dli_saddr), (uint)pc);
} else {
*wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] [0x%x]\n", wp->counter, (uint)pc);
}
wp->counter++;
return 0;
}
#endif
/**
* Log GDB information if available
*/
@@ -663,17 +627,6 @@ class CrashLogUnix : public CrashLog {
free(messages);
/* end of __GLIBC__ */
#elif defined(SUNOS)
ucontext_t uc;
if (getcontext(&uc) != 0) {
buffer += seprintf(buffer, last, " getcontext() failed\n\n");
return buffer;
}
StackWalkerParams wp = { &buffer, last, 0 };
walkcontext(&uc, &CrashLogUnix::SunOSStackWalker, &wp);
/* end of SUNOS */
#else
buffer += seprintf(buffer, last, " Not supported.\n");
#endif

View File

@@ -71,9 +71,10 @@ class CrashLogWindows : public CrashLog {
char *LogOSVersion(char *buffer, const char *last) const override;
char *LogError(char *buffer, const char *last, const char *message) const override;
#if defined(_MSC_VER) || defined(WITH_DBGHELP)
char *LogStacktrace(char *buffer, const char *last) const override;
#endif /* _MSC_VER || WITH_DBGHELP */
char *LogRegisters(char *buffer, const char *last) const override;
char *LogModules(char *buffer, const char *last) const override;
protected:
char *TryCrashLogFaultSection(char *buffer, const char *last, const char *section_name, CrashLogSectionWriter writer) override;
@@ -83,19 +84,9 @@ public:
#if defined(_MSC_VER)
int WriteCrashDump(char *filename, const char *filename_last) const override;
#endif /* _MSC_VER */
#if defined(_MSC_VER) || defined(WITH_DBGHELP)
char *AppendDecodedStacktrace(char *buffer, const char *last) const;
#endif /* _MSC_VER || WITH_DBGHELP */
/** Buffer for the generated crash log */
char crashlog[65536 * 4];
/** Buffer for the filename of the crash log */
char crashlog_filename[MAX_PATH];
/** Buffer for the filename of the crash dump */
char crashdump_filename[MAX_PATH];
/** Buffer for the filename of the crash screenshot */
char screenshot_filename[MAX_PATH];
/**
* A crash log is always generated when it's generated.
@@ -220,114 +211,6 @@ static const char *GetAccessViolationTypeString(uint type)
return buffer;
}
struct DebugFileInfo {
uint32 size;
uint32 crc32;
SYSTEMTIME file_time;
};
static uint32 *_crc_table;
static void MakeCRCTable(uint32 *table)
{
uint32 crc, poly = 0xEDB88320L;
int i;
int j;
_crc_table = table;
for (i = 0; i != 256; i++) {
crc = i;
for (j = 8; j != 0; j--) {
crc = (crc & 1 ? (crc >> 1) ^ poly : crc >> 1);
}
table[i] = crc;
}
}
static uint32 CalcCRC(byte *data, uint size, uint32 crc)
{
for (; size > 0; size--) {
crc = ((crc >> 8) & 0x00FFFFFF) ^ _crc_table[(crc ^ *data++) & 0xFF];
}
return crc;
}
static void GetFileInfo(DebugFileInfo *dfi, const wchar_t *filename)
{
HANDLE file;
memset(dfi, 0, sizeof(*dfi));
file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0);
if (file != INVALID_HANDLE_VALUE) {
byte buffer[1024];
DWORD numread;
uint32 filesize = 0;
FILETIME write_time;
uint32 crc = (uint32)-1;
for (;;) {
if (ReadFile(file, buffer, sizeof(buffer), &numread, nullptr) == 0 || numread == 0) {
break;
}
filesize += numread;
crc = CalcCRC(buffer, numread, crc);
}
dfi->size = filesize;
dfi->crc32 = crc ^ (uint32)-1;
if (GetFileTime(file, nullptr, nullptr, &write_time)) {
FileTimeToSystemTime(&write_time, &dfi->file_time);
}
CloseHandle(file);
}
}
static char *PrintModuleInfo(char *output, const char *last, HMODULE mod)
{
wchar_t buffer[MAX_PATH];
DebugFileInfo dfi;
GetModuleFileName(mod, buffer, MAX_PATH);
GetFileInfo(&dfi, buffer);
output += seprintf(output, last, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
FS2OTTD(buffer).c_str(),
mod,
dfi.size,
dfi.crc32,
dfi.file_time.wYear,
dfi.file_time.wMonth,
dfi.file_time.wDay,
dfi.file_time.wHour,
dfi.file_time.wMinute,
dfi.file_time.wSecond
);
return output;
}
/* virtual */ char *CrashLogWindows::LogModules(char *output, const char *last) const
{
MakeCRCTable(AllocaM(uint32, 256));
output += seprintf(output, last, "Module information:\n");
HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
if (proc != nullptr) {
HMODULE modules[100];
DWORD needed;
BOOL res = EnumProcessModules(proc, modules, sizeof(modules), &needed);
CloseHandle(proc);
if (res) {
size_t count = std::min<DWORD>(needed / sizeof(HMODULE), lengthof(modules));
for (size_t i = 0; i != count; i++) output = PrintModuleInfo(output, last, modules[i]);
return output + seprintf(output, last, "\n");
}
}
output = PrintModuleInfo(output, last, nullptr);
return output + seprintf(output, last, "\n");
}
/* virtual */ char *CrashLogWindows::LogRegisters(char *buffer, const char *last) const
{
buffer += seprintf(buffer, last, "Registers:\n");
@@ -438,40 +321,6 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod)
return buffer + seprintf(buffer, last, "\n\n");
}
/* virtual */ char *CrashLogWindows::LogStacktrace(char *buffer, const char *last) const
{
#if defined(_MSC_VER) || defined(WITH_DBGHELP)
char *stacktrace_end = this->AppendDecodedStacktrace(buffer, last);
if (stacktrace_end - buffer >= 32) {
/* If AppendDecodedStacktrace managed to write out anything more than just the section title,
* consider that a success and don't bother writing out the raw stack trace values as well.
* The raw values are useless in almost all cases. */
return stacktrace_end;
}
#endif
buffer += seprintf(buffer, last, "Stack trace:\n");
#ifdef _M_AMD64
uint32 *b = (uint32*)ep->ContextRecord->Rsp;
#elif defined(_M_IX86)
uint32 *b = (uint32*)ep->ContextRecord->Esp;
#elif defined(_M_ARM64)
uint32 *b = (uint32*)ep->ContextRecord->Sp;
#endif
for (int j = 0; j != 24; j++) {
for (int i = 0; i != 8; i++) {
if (IsBadReadPtr(b, sizeof(uint32))) {
buffer += seprintf(buffer, last, " ????????"); // OCR: WAS - , 0);
} else {
buffer += seprintf(buffer, last, " %.8X", *b);
}
b++;
}
buffer += seprintf(buffer, last, "\n");
}
return buffer + seprintf(buffer, last, "\n");
}
#if defined(_MSC_VER) || defined(WITH_DBGHELP)
static const uint MAX_SYMBOL_LEN = 512;
static const uint MAX_FRAMES = 64;
@@ -483,7 +332,7 @@ static const uint MAX_FRAMES = 64;
#pragma warning(default:4091)
#endif
char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) const
/* virtual */ char *CrashLogWindows::LogStacktrace(char *buffer, const char *last) const
{
#define M(x) x "\0"
static const char dbg_import[] =
@@ -796,8 +645,6 @@ thread_local void *_safe_esp = nullptr;
static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
{
CrashLog::RegisterCrashed();
/* Restore system timer resolution. */
timeEndPeriod(1);
@@ -818,22 +665,9 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
ImmediateExitProcess(3);
}
VideoDriver::EmergencyAcquireGameLock(1000, 5);
CrashLogWindows *log = new CrashLogWindows(ep);
CrashLogWindows::current = log;
char *name_buffer_date = log->name_buffer + seprintf(log->name_buffer, lastof(log->name_buffer), "crash-");
UTCTime::Format(name_buffer_date, lastof(log->name_buffer), "%Y%m%dT%H%M%SZ");
log->WriteCrashLog("", log->crashlog_filename, lastof(log->crashlog_filename), log->name_buffer, &(log->crash_file));
log->crash_buffer_write = log->crashlog;
log->FillCrashLog(log->crashlog, lastof(log->crashlog));
log->CloseCrashLogFile();
log->WriteCrashDump(log->crashdump_filename, lastof(log->crashdump_filename));
SetScreenshotAuxiliaryText("Crash Log", log->crashlog);
log->WriteScreenshot(log->screenshot_filename, lastof(log->screenshot_filename), log->name_buffer);
log->SendSurvey();
log->MakeCrashLog(log->crashlog, lastof(log->crashlog));
/* Close any possible log files */
CloseConsoleLogIfActive();
@@ -973,13 +807,7 @@ static const TCHAR _crash_desc[] =
L"Please send the crash information (log files and crash saves, if any) to the patchpack developer.\n"
L"This will greatly help debugging. The correct place to do this is https://www.tt-forums.net/viewtopic.php?f=33&t=73469"
L" or https://github.com/JGRennison/OpenTTD-patches\n"
L"The information contained in the report is displayed below.\n"
L"Press \"Emergency save\" to attempt saving the game. Generated file(s):\n";
static const wchar_t _save_succeeded[] =
L"Emergency save succeeded.\nIts location is '%s'.\n"
L"Be aware that critical parts of the internal game state may have become "
L"corrupted. The saved game is not guaranteed to work.";
L"The information contained in the report is displayed below.\n";
static const wchar_t * const _expand_texts[] = {L"S&how report >>", L"&Hide report <<" };
@@ -1041,7 +869,7 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
}
*p = '\0';
/* Add path to crash.log and crash.dmp (if any) to the crash window text */
/* Add path to all files to the crash window text */
const wchar_t * const crash_desc_buf_last = crash_desc_buf + crash_desc_buf_length - 1;
wcsncpy_s(crash_desc_buf, crash_desc_buf_length, _crash_desc, _TRUNCATE);
wchar_t *desc = crash_desc_buf + wcslen(crash_desc_buf);
@@ -1063,6 +891,10 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
append_newline();
append_str(CrashLogWindows::current->crashdump_filename);
}
if (CrashLogWindows::current->savegame_filename[0] != 0) {
append_newline();
append_str(CrashLogWindows::current->savegame_filename);
}
if (CrashLogWindows::current->screenshot_filename[0] != 0) {
append_newline();
append_str(CrashLogWindows::current->screenshot_filename);
@@ -1078,23 +910,6 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
case 12: // Close
CrashLog::AfterCrashLogCleanup();
ImmediateExitProcess(2);
case 13: // Emergency save
_savegame_DBGL_data = CrashLogWindows::current->crashlog;
_save_DBGC_data = true;
wchar_t filenamebuf[MAX_PATH * 2];
char filename[MAX_PATH];
if (CrashLogWindows::current->WriteSavegame(filename, lastof(filename), CrashLogWindows::current->name_buffer)) {
convert_to_fs(filename, filenamebuf, lengthof(filenamebuf));
size_t len = lengthof(_save_succeeded) + wcslen(filenamebuf) + 1;
wchar_t *text = AllocaM(wchar_t, len);
_snwprintf(text, len, _save_succeeded, filenamebuf);
MessageBox(wnd, text, L"Save successful", MB_ICONINFORMATION);
} else {
MessageBox(wnd, L"Save failed", L"Save failed", MB_ICONINFORMATION);
}
_savegame_DBGL_data = nullptr;
_save_DBGC_data = false;
break;
case 15: // Expand window to show crash-message
_expanded = !_expanded;
SetWndSize(wnd, _expanded);

View File

@@ -50,7 +50,6 @@ CAPTION "Fatal Application Failure"
FONT 8, "MS Sans Serif"
BEGIN
PUSHBUTTON "&Close",12,7,82,60,14
PUSHBUTTON "&Emergency save",13,158,82,60,14
PUSHBUTTON "",15,238,82,60,14
EDITTEXT 11,7,103,291,118,ES_MULTILINE | ES_READONLY | WS_VSCROLL |
WS_HSCROLL | NOT WS_TABSTOP