1
0
mirror of https://github.com/godotengine/godot synced 2024-07-01 08:59:19 +00:00

[Windows] Enable crash reporter on MinGW builds, use libbacktrace to generate stack trace from DWARF symbols.

This commit is contained in:
bruvzg 2022-05-13 15:42:07 +03:00
parent 7529c0bec5
commit c1b34672f9
No known key found for this signature in database
GPG Key ID: 7960FCF39844EC38
28 changed files with 7854 additions and 4 deletions

View File

@ -293,6 +293,11 @@ Comment: jpeg-compressor
Copyright: 2012, Rich Geldreich
License: public-domain or Apache-2.0
Files: ./thirdparty/libbacktrace/
Comment: libbacktrace
Copyright: 2012-2021, Free Software Foundation, Inc.
License: BSD-3-clause
Files: ./thirdparty/libktx/
Comment: KTX
Copyright: 2013-2020, Mark Callow

View File

@ -14,6 +14,8 @@ SConscript("coreaudio/SCsub")
SConscript("pulseaudio/SCsub")
if env["platform"] == "windows":
SConscript("wasapi/SCsub")
if not env.msvc:
SConscript("backtrace/SCsub")
if env["xaudio2"]:
SConscript("xaudio2/SCsub")

44
drivers/backtrace/SCsub Normal file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env python
Import("env")
env_backtrace = env.Clone()
# Thirdparty source files
thirdparty_obj = []
thirdparty_dir = "#thirdparty/libbacktrace/"
thirdparty_sources = [
"atomic.c",
"dwarf.c",
"fileline.c",
"posix.c",
"print.c",
"sort.c",
"state.c",
"backtrace.c",
"simple.c",
"pecoff.c",
"read.c",
"alloc.c",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_backtrace.Prepend(CPPPATH=[thirdparty_dir])
env_thirdparty = env_backtrace.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env.drivers_sources += thirdparty_obj
# Godot source files
driver_obj = []
env_backtrace.add_source_files(driver_obj, "*.cpp")
env.drivers_sources += driver_obj
# Needed to force rebuilding the driver files when the thirdparty library is updated.
env.Depends(driver_obj, thirdparty_obj)

View File

@ -10,7 +10,6 @@ sources = []
common_win = [
"godot_windows.cpp",
"crash_handler_windows.cpp",
"os_windows.cpp",
"display_server_windows.cpp",
"key_mapping_windows.cpp",
@ -25,6 +24,11 @@ common_win = [
"rendering_context_driver_vulkan_windows.cpp",
]
if env.msvc:
common_win += ["crash_handler_windows_seh.cpp"]
else:
common_win += ["crash_handler_windows_signal.cpp"]
common_win_wrap = [
"console_wrapper_windows.cpp",
]

View File

@ -35,12 +35,15 @@
#include <windows.h>
// Crash handler exception only enabled with MSVC
#if defined(DEBUG_ENABLED) && defined(_MSC_VER)
#if defined(DEBUG_ENABLED)
#define CRASH_HANDLER_EXCEPTION 1
#ifdef _MSC_VER
extern DWORD CrashHandlerException(EXCEPTION_POINTERS *ep);
#endif
#endif
class CrashHandler {
bool disabled;

View File

@ -1,5 +1,5 @@
/**************************************************************************/
/* crash_handler_windows.cpp */
/* crash_handler_windows_seh.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */

View File

@ -0,0 +1,205 @@
/**************************************************************************/
/* crash_handler_windows_signal.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "crash_handler_windows.h"
#include "core/config/project_settings.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/version.h"
#include "main/main.h"
#ifdef CRASH_HANDLER_EXCEPTION
#include <cxxabi.h>
#include <signal.h>
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>
#include <psapi.h>
#include "thirdparty/libbacktrace/backtrace.h"
struct CrashHandlerData {
int64_t index = 0;
backtrace_state *state = nullptr;
int64_t offset = 0;
};
int symbol_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function) {
CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);
if (!function) {
return 0;
}
char fname[1024];
snprintf(fname, 1024, "%s", function);
if (function[0] == '_') {
int status;
char *demangled = abi::__cxa_demangle(function, nullptr, nullptr, &status);
if (status == 0 && demangled) {
snprintf(fname, 1024, "%s", demangled);
}
if (demangled) {
free(demangled);
}
}
print_error(vformat("[%d] %s (%s:%d)", ch_data->index++, String::utf8(fname), String::utf8(filename), lineno));
return 0;
}
void error_callback(void *data, const char *msg, int errnum) {
CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);
if (ch_data->index == 0) {
print_error(vformat("Error(%d): %s", errnum, String::utf8(msg)));
} else {
print_error(vformat("[%d] error(%d): %s", ch_data->index++, errnum, String::utf8(msg)));
}
}
int trace_callback(void *data, uintptr_t pc) {
CrashHandlerData *ch_data = reinterpret_cast<CrashHandlerData *>(data);
backtrace_pcinfo(ch_data->state, pc - ch_data->offset, &symbol_callback, &error_callback, data);
return 0;
}
int64_t get_image_base(const String &p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
if (f.is_null()) {
return 0;
}
{
f->seek(0x3c);
uint32_t pe_pos = f->get_32();
f->seek(pe_pos);
uint32_t magic = f->get_32();
if (magic != 0x00004550) {
return 0;
}
}
int64_t opt_header_pos = f->get_position() + 0x14;
f->seek(opt_header_pos);
uint16_t opt_header_magic = f->get_16();
if (opt_header_magic == 0x10B) {
f->seek(opt_header_pos + 0x1C);
return f->get_32();
} else if (opt_header_magic == 0x20B) {
f->seek(opt_header_pos + 0x18);
return f->get_64();
} else {
return 0;
}
}
extern void CrashHandlerException(int signal) {
CrashHandlerData data;
if (OS::get_singleton() == nullptr || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) {
return;
}
String msg;
const ProjectSettings *proj_settings = ProjectSettings::get_singleton();
if (proj_settings) {
msg = proj_settings->get("debug/settings/crash_handler/message");
}
// Tell MainLoop about the crash. This can be handled by users too in Node.
if (OS::get_singleton()->get_main_loop()) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
}
print_error("\n================================================================");
print_error(vformat("%s: Program crashed with signal %d", __FUNCTION__, signal));
// Print the engine version just before, so that people are reminded to include the version in backtrace reports.
if (String(VERSION_HASH).is_empty()) {
print_error(vformat("Engine version: %s", VERSION_FULL_NAME));
} else {
print_error(vformat("Engine version: %s (%s)", VERSION_FULL_NAME, VERSION_HASH));
}
print_error(vformat("Dumping the backtrace. %s", msg));
String _execpath = OS::get_singleton()->get_executable_path();
// Load process and image info to determine ASLR addresses offset.
MODULEINFO mi;
GetModuleInformation(GetCurrentProcess(), GetModuleHandle(NULL), &mi, sizeof(mi));
int64_t image_mem_base = reinterpret_cast<int64_t>(mi.lpBaseOfDll);
int64_t image_file_base = get_image_base(_execpath);
data.offset = image_mem_base - image_file_base;
data.state = backtrace_create_state(_execpath.utf8().get_data(), 0, &error_callback, reinterpret_cast<void *>(&data));
if (data.state != nullptr) {
data.index = 1;
backtrace_simple(data.state, 1, &trace_callback, &error_callback, reinterpret_cast<void *>(&data));
}
print_error("-- END OF BACKTRACE --");
print_error("================================================================");
}
#endif
CrashHandler::CrashHandler() {
disabled = false;
}
CrashHandler::~CrashHandler() {
}
void CrashHandler::disable() {
if (disabled) {
return;
}
#if defined(CRASH_HANDLER_EXCEPTION)
signal(SIGSEGV, nullptr);
signal(SIGFPE, nullptr);
signal(SIGILL, nullptr);
#endif
disabled = true;
}
void CrashHandler::initialize() {
#if defined(CRASH_HANDLER_EXCEPTION)
signal(SIGSEGV, CrashHandlerException);
signal(SIGFPE, CrashHandlerException);
signal(SIGILL, CrashHandlerException);
#endif
}

View File

@ -557,6 +557,9 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
LIBS += ["dxgi", "d3d9", "d3d11"]
env.Prepend(CPPPATH=["#thirdparty/angle/include"])
if env["target"] in ["editor", "template_debug"]:
LIBS += ["psapi", "dbghelp"]
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
if vcvars_msvc_config:

View File

@ -215,7 +215,7 @@ int main(int argc, char **argv) {
// _argc and _argv are ignored
// we are going to use the WideChar version of them instead
#ifdef CRASH_HANDLER_EXCEPTION
#if defined(CRASH_HANDLER_EXCEPTION) && defined(_MSC_VER)
__try {
return _main();
} __except (CrashHandlerException(GetExceptionInformation())) {

12
thirdparty/README.md vendored
View File

@ -428,6 +428,18 @@ Files extracted from upstream source:
- `jpge*.{c,h}`
## libbacktrace
- Upstream: https://github.com/ianlancetaylor/libbacktrace
- Version: git (4d2dd0b172f2c9192f83ba93425f868f2a13c553, 2022)
- License: BSD-3-Clause
Files extracted from upstream source:
- `*.{c,h}` files for Windows platform
- `LICENSE`
## libktx
- Upstream: https://github.com/KhronosGroup/KTX-Software

29
thirdparty/libbacktrace/LICENSE vendored Normal file
View File

@ -0,0 +1,29 @@
# Copyright (C) 2012-2016 Free Software Foundation, Inc.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# (1) Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# (2) Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# (3) The name of the author may not be used to
# endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

167
thirdparty/libbacktrace/alloc.c vendored Normal file
View File

@ -0,0 +1,167 @@
/* alloc.c -- Memory allocation without mmap.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include "backtrace.h"
#include "internal.h"
/* Allocation routines to use on systems that do not support anonymous
mmap. This implementation just uses malloc, which means that the
backtrace functions may not be safely invoked from a signal
handler. */
/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't
report an error. */
void *
backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED,
size_t size, backtrace_error_callback error_callback,
void *data)
{
void *ret;
ret = malloc (size);
if (ret == NULL)
{
if (error_callback)
error_callback (data, "malloc", errno);
}
return ret;
}
/* Free memory. */
void
backtrace_free (struct backtrace_state *state ATTRIBUTE_UNUSED,
void *p, size_t size ATTRIBUTE_UNUSED,
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
free (p);
}
/* Grow VEC by SIZE bytes. */
void *
backtrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED,
size_t size, backtrace_error_callback error_callback,
void *data, struct backtrace_vector *vec)
{
void *ret;
if (size > vec->alc)
{
size_t alc;
void *base;
if (vec->size == 0)
alc = 32 * size;
else if (vec->size >= 4096)
alc = vec->size + 4096;
else
alc = 2 * vec->size;
if (alc < vec->size + size)
alc = vec->size + size;
base = realloc (vec->base, alc);
if (base == NULL)
{
error_callback (data, "realloc", errno);
return NULL;
}
vec->base = base;
vec->alc = alc - vec->size;
}
ret = (char *) vec->base + vec->size;
vec->size += size;
vec->alc -= size;
return ret;
}
/* Finish the current allocation on VEC. */
void *
backtrace_vector_finish (struct backtrace_state *state,
struct backtrace_vector *vec,
backtrace_error_callback error_callback,
void *data)
{
void *ret;
/* With this allocator we call realloc in backtrace_vector_grow,
which means we can't easily reuse the memory here. So just
release it. */
if (!backtrace_vector_release (state, vec, error_callback, data))
return NULL;
ret = vec->base;
vec->base = NULL;
vec->size = 0;
vec->alc = 0;
return ret;
}
/* Release any extra space allocated for VEC. */
int
backtrace_vector_release (struct backtrace_state *state ATTRIBUTE_UNUSED,
struct backtrace_vector *vec,
backtrace_error_callback error_callback,
void *data)
{
vec->alc = 0;
if (vec->size == 0)
{
/* As of C17, realloc with size 0 is marked as an obsolescent feature, use
free instead. */
free (vec->base);
vec->base = NULL;
return 1;
}
vec->base = realloc (vec->base, vec->size);
if (vec->base == NULL)
{
error_callback (data, "realloc", errno);
return 0;
}
return 1;
}

113
thirdparty/libbacktrace/atomic.c vendored Normal file
View File

@ -0,0 +1,113 @@
/* atomic.c -- Support for atomic functions if not present.
Copyright (C) 2013-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <sys/types.h>
#include "backtrace.h"
#include "backtrace-supported.h"
#include "internal.h"
/* This file holds implementations of the atomic functions that are
used if the host compiler has the sync functions but not the atomic
functions, as is true of versions of GCC before 4.7. */
#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS)
/* Do an atomic load of a pointer. */
void *
backtrace_atomic_load_pointer (void *arg)
{
void **pp;
void *p;
pp = (void **) arg;
p = *pp;
while (!__sync_bool_compare_and_swap (pp, p, p))
p = *pp;
return p;
}
/* Do an atomic load of an int. */
int
backtrace_atomic_load_int (int *p)
{
int i;
i = *p;
while (!__sync_bool_compare_and_swap (p, i, i))
i = *p;
return i;
}
/* Do an atomic store of a pointer. */
void
backtrace_atomic_store_pointer (void *arg, void *p)
{
void **pp;
void *old;
pp = (void **) arg;
old = *pp;
while (!__sync_bool_compare_and_swap (pp, old, p))
old = *pp;
}
/* Do an atomic store of a size_t value. */
void
backtrace_atomic_store_size_t (size_t *p, size_t v)
{
size_t old;
old = *p;
while (!__sync_bool_compare_and_swap (p, old, v))
old = *p;
}
/* Do an atomic store of a int value. */
void
backtrace_atomic_store_int (int *p, int v)
{
size_t old;
old = *p;
while (!__sync_bool_compare_and_swap (p, old, v))
old = *p;
}
#endif

View File

@ -0,0 +1,66 @@
/* backtrace-supported.h.in -- Whether stack backtrace is supported.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
/* The file backtrace-supported.h.in is used by configure to generate
the file backtrace-supported.h. The file backtrace-supported.h may
be #include'd to see whether the backtrace library will be able to
get a backtrace and produce symbolic information. */
/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library
should work, 0 if it will not. Libraries may #include this to make
other arrangements. */
#define BACKTRACE_SUPPORTED 1
/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace
library will call malloc as it works, 0 if it will call mmap
instead. This may be used to determine whether it is safe to call
the backtrace functions from a signal handler. In general this
only applies to calls like backtrace and backtrace_pcinfo. It does
not apply to backtrace_simple, which never calls malloc. It does
not apply to backtrace_print, which always calls fprintf and
therefore malloc. */
#define BACKTRACE_USES_MALLOC 1
/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace
library is configured with threading support, 0 if not. If this is
0, the threaded parameter to backtrace_create_state must be passed
as 0. */
#define BACKTRACE_SUPPORTS_THREADS 1
/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo
will work for variables. It will always work for functions. */
#define BACKTRACE_SUPPORTS_DATA 0

129
thirdparty/libbacktrace/backtrace.c vendored Normal file
View File

@ -0,0 +1,129 @@
/* backtrace.c -- Entry point for stack backtrace library.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <sys/types.h>
#include "unwind.h"
#include "backtrace.h"
#include "internal.h"
/* The main backtrace_full routine. */
/* Data passed through _Unwind_Backtrace. */
struct backtrace_data
{
/* Number of frames to skip. */
int skip;
/* Library state. */
struct backtrace_state *state;
/* Callback routine. */
backtrace_full_callback callback;
/* Error callback routine. */
backtrace_error_callback error_callback;
/* Data to pass to callback routines. */
void *data;
/* Value to return from backtrace_full. */
int ret;
/* Whether there is any memory available. */
int can_alloc;
};
/* Unwind library callback routine. This is passed to
_Unwind_Backtrace. */
static _Unwind_Reason_Code
unwind (struct _Unwind_Context *context, void *vdata)
{
struct backtrace_data *bdata = (struct backtrace_data *) vdata;
uintptr_t pc;
int ip_before_insn = 0;
#ifdef HAVE_GETIPINFO
pc = _Unwind_GetIPInfo (context, &ip_before_insn);
#else
pc = _Unwind_GetIP (context);
#endif
if (bdata->skip > 0)
{
--bdata->skip;
return _URC_NO_REASON;
}
if (!ip_before_insn)
--pc;
if (!bdata->can_alloc)
bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL);
else
bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback,
bdata->error_callback, bdata->data);
if (bdata->ret != 0)
return _URC_END_OF_STACK;
return _URC_NO_REASON;
}
/* Get a stack backtrace. */
int __attribute__((noinline))
backtrace_full (struct backtrace_state *state, int skip,
backtrace_full_callback callback,
backtrace_error_callback error_callback, void *data)
{
struct backtrace_data bdata;
void *p;
bdata.skip = skip + 1;
bdata.state = state;
bdata.callback = callback;
bdata.error_callback = error_callback;
bdata.data = data;
bdata.ret = 0;
/* If we can't allocate any memory at all, don't try to produce
file/line information. */
p = backtrace_alloc (state, 4096, NULL, NULL);
if (p == NULL)
bdata.can_alloc = 0;
else
{
backtrace_free (state, p, 4096, NULL, NULL);
bdata.can_alloc = 1;
}
_Unwind_Backtrace (unwind, &bdata);
return bdata.ret;
}

189
thirdparty/libbacktrace/backtrace.h vendored Normal file
View File

@ -0,0 +1,189 @@
/* backtrace.h -- Public header file for stack backtrace library.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#ifndef BACKTRACE_H
#define BACKTRACE_H
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/* The backtrace state. This struct is intentionally not defined in
the public interface. */
struct backtrace_state;
/* The type of the error callback argument to backtrace functions.
This function, if not NULL, will be called for certain error cases.
The DATA argument is passed to the function that calls this one.
The MSG argument is an error message. The ERRNUM argument, if
greater than 0, holds an errno value. The MSG buffer may become
invalid after this function returns.
As a special case, the ERRNUM argument will be passed as -1 if no
debug info can be found for the executable, or if the debug info
exists but has an unsupported version, but the function requires
debug info (e.g., backtrace_full, backtrace_pcinfo). The MSG in
this case will be something along the lines of "no debug info".
Similarly, ERRNUM will be passed as -1 if there is no symbol table,
but the function requires a symbol table (e.g., backtrace_syminfo).
This may be used as a signal that some other approach should be
tried. */
typedef void (*backtrace_error_callback) (void *data, const char *msg,
int errnum);
/* Create state information for the backtrace routines. This must be
called before any of the other routines, and its return value must
be passed to all of the other routines. FILENAME is the path name
of the executable file; if it is NULL the library will try
system-specific path names. If not NULL, FILENAME must point to a
permanent buffer. If THREADED is non-zero the state may be
accessed by multiple threads simultaneously, and the library will
use appropriate atomic operations. If THREADED is zero the state
may only be accessed by one thread at a time. This returns a state
pointer on success, NULL on error. If an error occurs, this will
call the ERROR_CALLBACK routine.
Calling this function allocates resources that cannot be freed.
There is no backtrace_free_state function. The state is used to
cache information that is expensive to recompute. Programs are
expected to call this function at most once and to save the return
value for all later calls to backtrace functions. */
extern struct backtrace_state *backtrace_create_state (
const char *filename, int threaded,
backtrace_error_callback error_callback, void *data);
/* The type of the callback argument to the backtrace_full function.
DATA is the argument passed to backtrace_full. PC is the program
counter. FILENAME is the name of the file containing PC, or NULL
if not available. LINENO is the line number in FILENAME containing
PC, or 0 if not available. FUNCTION is the name of the function
containing PC, or NULL if not available. This should return 0 to
continuing tracing. The FILENAME and FUNCTION buffers may become
invalid after this function returns. */
typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
const char *filename, int lineno,
const char *function);
/* Get a full stack backtrace. SKIP is the number of frames to skip;
passing 0 will start the trace with the function calling
backtrace_full. DATA is passed to the callback routine. If any
call to CALLBACK returns a non-zero value, the stack backtrace
stops, and backtrace returns that value; this may be used to limit
the number of stack frames desired. If all calls to CALLBACK
return 0, backtrace returns 0. The backtrace_full function will
make at least one call to either CALLBACK or ERROR_CALLBACK. This
function requires debug info for the executable. */
extern int backtrace_full (struct backtrace_state *state, int skip,
backtrace_full_callback callback,
backtrace_error_callback error_callback,
void *data);
/* The type of the callback argument to the backtrace_simple function.
DATA is the argument passed to simple_backtrace. PC is the program
counter. This should return 0 to continue tracing. */
typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc);
/* Get a simple backtrace. SKIP is the number of frames to skip, as
in backtrace. DATA is passed to the callback routine. If any call
to CALLBACK returns a non-zero value, the stack backtrace stops,
and backtrace_simple returns that value. Otherwise
backtrace_simple returns 0. The backtrace_simple function will
make at least one call to either CALLBACK or ERROR_CALLBACK. This
function does not require any debug info for the executable. */
extern int backtrace_simple (struct backtrace_state *state, int skip,
backtrace_simple_callback callback,
backtrace_error_callback error_callback,
void *data);
/* Print the current backtrace in a user readable format to a FILE.
SKIP is the number of frames to skip, as in backtrace_full. Any
error messages are printed to stderr. This function requires debug
info for the executable. */
extern void backtrace_print (struct backtrace_state *state, int skip, FILE *);
/* Given PC, a program counter in the current program, call the
callback function with filename, line number, and function name
information. This will normally call the callback function exactly
once. However, if the PC happens to describe an inlined call, and
the debugging information contains the necessary information, then
this may call the callback function multiple times. This will make
at least one call to either CALLBACK or ERROR_CALLBACK. This
returns the first non-zero value returned by CALLBACK, or 0. */
extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
backtrace_full_callback callback,
backtrace_error_callback error_callback,
void *data);
/* The type of the callback argument to backtrace_syminfo. DATA and
PC are the arguments passed to backtrace_syminfo. SYMNAME is the
name of the symbol for the corresponding code. SYMVAL is the
value and SYMSIZE is the size of the symbol. SYMNAME will be NULL
if no error occurred but the symbol could not be found. */
typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc,
const char *symname,
uintptr_t symval,
uintptr_t symsize);
/* Given ADDR, an address or program counter in the current program,
call the callback information with the symbol name and value
describing the function or variable in which ADDR may be found.
This will call either CALLBACK or ERROR_CALLBACK exactly once.
This returns 1 on success, 0 on failure. This function requires
the symbol table but does not require the debug info. Note that if
the symbol table is present but ADDR could not be found in the
table, CALLBACK will be called with a NULL SYMNAME argument.
Returns 1 on success, 0 on error. */
extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr,
backtrace_syminfo_callback callback,
backtrace_error_callback error_callback,
void *data);
#ifdef __cplusplus
} /* End extern "C". */
#endif
#endif

170
thirdparty/libbacktrace/config.h vendored Normal file
View File

@ -0,0 +1,170 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* ELF size: 32 or 64 */
#define BACKTRACE_ELF_SIZE unused
/* XCOFF size: 32 or 64 */
#define BACKTRACE_XCOFF_SIZE unused
/* Define to 1 if you have the __atomic functions */
#define HAVE_ATOMIC_FUNCTIONS 1
/* Define to 1 if you have the `clock_gettime' function. */
#define HAVE_CLOCK_GETTIME 1
/* Define to 1 if you have the declaration of `getpagesize', and to 0 if you
don't. */
#define HAVE_DECL_GETPAGESIZE 0
/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
don't. */
#define HAVE_DECL_STRNLEN 1
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
/* Define if dl_iterate_phdr is available. */
/* #undef HAVE_DL_ITERATE_PHDR */
/* Define to 1 if you have the fcntl function */
/* #undef HAVE_FCNTL */
/* Define if getexecname is available. */
/* #undef HAVE_GETEXECNAME */
/* Define if _Unwind_GetIPInfo is available. */
#define HAVE_GETIPINFO 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have KERN_PROC and KERN_PROC_PATHNAME in <sys/sysctl.h>.
*/
/* #undef HAVE_KERN_PROC */
/* Define to 1 if you have KERN_PROCARGS and KERN_PROC_PATHNAME in
<sys/sysctl.h>. */
/* #undef HAVE_KERN_PROC_ARGS */
/* Define if -llzma is available. */
#define HAVE_LIBLZMA 1
/* Define to 1 if you have the <link.h> header file. */
/* #undef HAVE_LINK_H */
/* Define if AIX loadquery is available. */
/* #undef HAVE_LOADQUERY */
/* Define to 1 if you have the `lstat' function. */
/* #undef HAVE_LSTAT */
/* Define to 1 if you have the <mach-o/dyld.h> header file. */
/* #undef HAVE_MACH_O_DYLD_H */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `readlink' function. */
/* #undef HAVE_READLINK */
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the __sync functions */
#define HAVE_SYNC_FUNCTIONS 1
/* Define to 1 if you have the <sys/ldr.h> header file. */
/* #undef HAVE_SYS_LDR_H */
/* Define to 1 if you have the <sys/mman.h> header file. */
/* #undef HAVE_SYS_MMAN_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if -lz is available. */
#define HAVE_ZLIB 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME "package-unused"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "package-unused version-unused"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libbacktrace"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "version-unused"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# define _ALL_SOURCE 1
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#define _FILE_OFFSET_BITS 64
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */

4402
thirdparty/libbacktrace/dwarf.c vendored Normal file

File diff suppressed because it is too large Load Diff

346
thirdparty/libbacktrace/fileline.c vendored Normal file
View File

@ -0,0 +1,346 @@
/* fileline.c -- Get file and line number information in a backtrace.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#if defined (HAVE_KERN_PROC_ARGS) || defined (HAVE_KERN_PROC)
#include <sys/sysctl.h>
#endif
#ifdef HAVE_MACH_O_DYLD_H
#include <mach-o/dyld.h>
#endif
#include "backtrace.h"
#include "internal.h"
#ifndef HAVE_GETEXECNAME
#define getexecname() NULL
#endif
#if !defined (HAVE_KERN_PROC_ARGS) && !defined (HAVE_KERN_PROC)
#define sysctl_exec_name1(state, error_callback, data) NULL
#define sysctl_exec_name2(state, error_callback, data) NULL
#else /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
static char *
sysctl_exec_name (struct backtrace_state *state,
int mib0, int mib1, int mib2, int mib3,
backtrace_error_callback error_callback, void *data)
{
int mib[4];
size_t len;
char *name;
size_t rlen;
mib[0] = mib0;
mib[1] = mib1;
mib[2] = mib2;
mib[3] = mib3;
if (sysctl (mib, 4, NULL, &len, NULL, 0) < 0)
return NULL;
name = (char *) backtrace_alloc (state, len, error_callback, data);
if (name == NULL)
return NULL;
rlen = len;
if (sysctl (mib, 4, name, &rlen, NULL, 0) < 0)
{
backtrace_free (state, name, len, error_callback, data);
return NULL;
}
return name;
}
#ifdef HAVE_KERN_PROC_ARGS
static char *
sysctl_exec_name1 (struct backtrace_state *state,
backtrace_error_callback error_callback, void *data)
{
/* This variant is used on NetBSD. */
return sysctl_exec_name (state, CTL_KERN, KERN_PROC_ARGS, -1,
KERN_PROC_PATHNAME, error_callback, data);
}
#else
#define sysctl_exec_name1(state, error_callback, data) NULL
#endif
#ifdef HAVE_KERN_PROC
static char *
sysctl_exec_name2 (struct backtrace_state *state,
backtrace_error_callback error_callback, void *data)
{
/* This variant is used on FreeBSD. */
return sysctl_exec_name (state, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1,
error_callback, data);
}
#else
#define sysctl_exec_name2(state, error_callback, data) NULL
#endif
#endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
#ifdef HAVE_MACH_O_DYLD_H
static char *
macho_get_executable_path (struct backtrace_state *state,
backtrace_error_callback error_callback, void *data)
{
uint32_t len;
char *name;
len = 0;
if (_NSGetExecutablePath (NULL, &len) == 0)
return NULL;
name = (char *) backtrace_alloc (state, len, error_callback, data);
if (name == NULL)
return NULL;
if (_NSGetExecutablePath (name, &len) != 0)
{
backtrace_free (state, name, len, error_callback, data);
return NULL;
}
return name;
}
#else /* !defined (HAVE_MACH_O_DYLD_H) */
#define macho_get_executable_path(state, error_callback, data) NULL
#endif /* !defined (HAVE_MACH_O_DYLD_H) */
/* Initialize the fileline information from the executable. Returns 1
on success, 0 on failure. */
static int
fileline_initialize (struct backtrace_state *state,
backtrace_error_callback error_callback, void *data)
{
int failed;
fileline fileline_fn;
int pass;
int called_error_callback;
int descriptor;
const char *filename;
char buf[64];
if (!state->threaded)
failed = state->fileline_initialization_failed;
else
failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
if (failed)
{
error_callback (data, "failed to read executable information", -1);
return 0;
}
if (!state->threaded)
fileline_fn = state->fileline_fn;
else
fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
if (fileline_fn != NULL)
return 1;
/* We have not initialized the information. Do it now. */
descriptor = -1;
called_error_callback = 0;
for (pass = 0; pass < 8; ++pass)
{
int does_not_exist;
switch (pass)
{
case 0:
filename = state->filename;
break;
case 1:
filename = getexecname ();
break;
case 2:
filename = "/proc/self/exe";
break;
case 3:
filename = "/proc/curproc/file";
break;
case 4:
snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out",
(long) getpid ());
filename = buf;
break;
case 5:
filename = sysctl_exec_name1 (state, error_callback, data);
break;
case 6:
filename = sysctl_exec_name2 (state, error_callback, data);
break;
case 7:
filename = macho_get_executable_path (state, error_callback, data);
break;
default:
abort ();
}
if (filename == NULL)
continue;
descriptor = backtrace_open (filename, error_callback, data,
&does_not_exist);
if (descriptor < 0 && !does_not_exist)
{
called_error_callback = 1;
break;
}
if (descriptor >= 0)
break;
}
if (descriptor < 0)
{
if (!called_error_callback)
{
if (state->filename != NULL)
error_callback (data, state->filename, ENOENT);
else
error_callback (data,
"libbacktrace could not find executable to open",
0);
}
failed = 1;
}
if (!failed)
{
if (!backtrace_initialize (state, filename, descriptor, error_callback,
data, &fileline_fn))
failed = 1;
}
if (failed)
{
if (!state->threaded)
state->fileline_initialization_failed = 1;
else
backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
return 0;
}
if (!state->threaded)
state->fileline_fn = fileline_fn;
else
{
backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
/* Note that if two threads initialize at once, one of the data
sets may be leaked. */
}
return 1;
}
/* Given a PC, find the file name, line number, and function name. */
int
backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
backtrace_full_callback callback,
backtrace_error_callback error_callback, void *data)
{
if (!fileline_initialize (state, error_callback, data))
return 0;
if (state->fileline_initialization_failed)
return 0;
return state->fileline_fn (state, pc, callback, error_callback, data);
}
/* Given a PC, find the symbol for it, and its value. */
int
backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
backtrace_syminfo_callback callback,
backtrace_error_callback error_callback, void *data)
{
if (!fileline_initialize (state, error_callback, data))
return 0;
if (state->fileline_initialization_failed)
return 0;
state->syminfo_fn (state, pc, callback, error_callback, data);
return 1;
}
/* A backtrace_syminfo_callback that can call into a
backtrace_full_callback, used when we have a symbol table but no
debug info. */
void
backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
const char *symname,
uintptr_t symval ATTRIBUTE_UNUSED,
uintptr_t symsize ATTRIBUTE_UNUSED)
{
struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, symname);
}
/* An error callback that corresponds to
backtrace_syminfo_to_full_callback. */
void
backtrace_syminfo_to_full_error_callback (void *data, const char *msg,
int errnum)
{
struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
bdata->full_error_callback (bdata->full_data, msg, errnum);
}

52
thirdparty/libbacktrace/filenames.h vendored Normal file
View File

@ -0,0 +1,52 @@
/* btest.c -- Filename header for libbacktrace library
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#ifndef GCC_VERSION
# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
#endif
#if (GCC_VERSION < 2007)
# define __attribute__(x)
#endif
#ifndef ATTRIBUTE_UNUSED
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif
#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__)
# define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\')
# define HAS_DRIVE_SPEC(f) ((f)[0] != '\0' && (f)[1] == ':')
# define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || HAS_DRIVE_SPEC(f))
#else
# define IS_DIR_SEPARATOR(c) ((c) == '/')
# define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]))
#endif

380
thirdparty/libbacktrace/internal.h vendored Normal file
View File

@ -0,0 +1,380 @@
/* internal.h -- Internal header file for stack backtrace library.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#ifndef BACKTRACE_INTERNAL_H
#define BACKTRACE_INTERNAL_H
/* We assume that <sys/types.h> and "backtrace.h" have already been
included. */
#ifndef GCC_VERSION
# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
#endif
#if (GCC_VERSION < 2007)
# define __attribute__(x)
#endif
#ifndef ATTRIBUTE_UNUSED
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif
#ifndef ATTRIBUTE_MALLOC
# if (GCC_VERSION >= 2096)
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
# else
# define ATTRIBUTE_MALLOC
# endif
#endif
#ifndef ATTRIBUTE_FALLTHROUGH
# if (GCC_VERSION >= 7000)
# define ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__))
# else
# define ATTRIBUTE_FALLTHROUGH
# endif
#endif
#ifndef HAVE_SYNC_FUNCTIONS
/* Define out the sync functions. These should never be called if
they are not available. */
#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1)
#define __sync_lock_test_and_set(A, B) (abort(), 0)
#define __sync_lock_release(A) abort()
#endif /* !defined (HAVE_SYNC_FUNCTIONS) */
#ifdef HAVE_ATOMIC_FUNCTIONS
/* We have the atomic builtin functions. */
#define backtrace_atomic_load_pointer(p) \
__atomic_load_n ((p), __ATOMIC_ACQUIRE)
#define backtrace_atomic_load_int(p) \
__atomic_load_n ((p), __ATOMIC_ACQUIRE)
#define backtrace_atomic_store_pointer(p, v) \
__atomic_store_n ((p), (v), __ATOMIC_RELEASE)
#define backtrace_atomic_store_size_t(p, v) \
__atomic_store_n ((p), (v), __ATOMIC_RELEASE)
#define backtrace_atomic_store_int(p, v) \
__atomic_store_n ((p), (v), __ATOMIC_RELEASE)
#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */
#ifdef HAVE_SYNC_FUNCTIONS
/* We have the sync functions but not the atomic functions. Define
the atomic ones in terms of the sync ones. */
extern void *backtrace_atomic_load_pointer (void *);
extern int backtrace_atomic_load_int (int *);
extern void backtrace_atomic_store_pointer (void *, void *);
extern void backtrace_atomic_store_size_t (size_t *, size_t);
extern void backtrace_atomic_store_int (int *, int);
#else /* !defined (HAVE_SYNC_FUNCTIONS) */
/* We have neither the sync nor the atomic functions. These will
never be called. */
#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL)
#define backtrace_atomic_load_int(p) (abort(), 0)
#define backtrace_atomic_store_pointer(p, v) abort()
#define backtrace_atomic_store_size_t(p, v) abort()
#define backtrace_atomic_store_int(p, v) abort()
#endif /* !defined (HAVE_SYNC_FUNCTIONS) */
#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */
/* The type of the function that collects file/line information. This
is like backtrace_pcinfo. */
typedef int (*fileline) (struct backtrace_state *state, uintptr_t pc,
backtrace_full_callback callback,
backtrace_error_callback error_callback, void *data);
/* The type of the function that collects symbol information. This is
like backtrace_syminfo. */
typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc,
backtrace_syminfo_callback callback,
backtrace_error_callback error_callback, void *data);
/* What the backtrace state pointer points to. */
struct backtrace_state
{
/* The name of the executable. */
const char *filename;
/* Non-zero if threaded. */
int threaded;
/* The master lock for fileline_fn, fileline_data, syminfo_fn,
syminfo_data, fileline_initialization_failed and everything the
data pointers point to. */
void *lock;
/* The function that returns file/line information. */
fileline fileline_fn;
/* The data to pass to FILELINE_FN. */
void *fileline_data;
/* The function that returns symbol information. */
syminfo syminfo_fn;
/* The data to pass to SYMINFO_FN. */
void *syminfo_data;
/* Whether initializing the file/line information failed. */
int fileline_initialization_failed;
/* The lock for the freelist. */
int lock_alloc;
/* The freelist when using mmap. */
struct backtrace_freelist_struct *freelist;
};
/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST
is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1
if the file does not exist. If the file does not exist and
DOES_NOT_EXIST is not NULL, the function will return -1 and will
not call ERROR_CALLBACK. On other errors, or if DOES_NOT_EXIST is
NULL, the function will call ERROR_CALLBACK before returning. */
extern int backtrace_open (const char *filename,
backtrace_error_callback error_callback,
void *data,
int *does_not_exist);
/* A view of the contents of a file. This supports mmap when
available. A view will remain in memory even after backtrace_close
is called on the file descriptor from which the view was
obtained. */
struct backtrace_view
{
/* The data that the caller requested. */
const void *data;
/* The base of the view. */
void *base;
/* The total length of the view. */
size_t len;
};
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the
result in *VIEW. Returns 1 on success, 0 on error. */
extern int backtrace_get_view (struct backtrace_state *state, int descriptor,
off_t offset, uint64_t size,
backtrace_error_callback error_callback,
void *data, struct backtrace_view *view);
/* Release a view created by backtrace_get_view. */
extern void backtrace_release_view (struct backtrace_state *state,
struct backtrace_view *view,
backtrace_error_callback error_callback,
void *data);
/* Close a file opened by backtrace_open. Returns 1 on success, 0 on
error. */
extern int backtrace_close (int descriptor,
backtrace_error_callback error_callback,
void *data);
/* Sort without using memory. */
extern void backtrace_qsort (void *base, size_t count, size_t size,
int (*compar) (const void *, const void *));
/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL,
this does not report an error, it just returns NULL. */
extern void *backtrace_alloc (struct backtrace_state *state, size_t size,
backtrace_error_callback error_callback,
void *data) ATTRIBUTE_MALLOC;
/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is
NULL, this does not report an error. */
extern void backtrace_free (struct backtrace_state *state, void *mem,
size_t size,
backtrace_error_callback error_callback,
void *data);
/* A growable vector of some struct. This is used for more efficient
allocation when we don't know the final size of some group of data
that we want to represent as an array. */
struct backtrace_vector
{
/* The base of the vector. */
void *base;
/* The number of bytes in the vector. */
size_t size;
/* The number of bytes available at the current allocation. */
size_t alc;
};
/* Grow VEC by SIZE bytes. Return a pointer to the newly allocated
bytes. Note that this may move the entire vector to a new memory
location. Returns NULL on failure. */
extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size,
backtrace_error_callback error_callback,
void *data,
struct backtrace_vector *vec);
/* Finish the current allocation on VEC. Prepare to start a new
allocation. The finished allocation will never be freed. Returns
a pointer to the base of the finished entries, or NULL on
failure. */
extern void* backtrace_vector_finish (struct backtrace_state *state,
struct backtrace_vector *vec,
backtrace_error_callback error_callback,
void *data);
/* Release any extra space allocated for VEC. This may change
VEC->base. Returns 1 on success, 0 on failure. */
extern int backtrace_vector_release (struct backtrace_state *state,
struct backtrace_vector *vec,
backtrace_error_callback error_callback,
void *data);
/* Free the space managed by VEC. This will reset VEC. */
static inline void
backtrace_vector_free (struct backtrace_state *state,
struct backtrace_vector *vec,
backtrace_error_callback error_callback, void *data)
{
vec->alc += vec->size;
vec->size = 0;
backtrace_vector_release (state, vec, error_callback, data);
}
/* Read initial debug data from a descriptor, and set the
fileline_data, syminfo_fn, and syminfo_data fields of STATE.
Return the fileln_fn field in *FILELN_FN--this is done this way so
that the synchronization code is only implemented once. This is
called after the descriptor has first been opened. It will close
the descriptor if it is no longer needed. Returns 1 on success, 0
on error. There will be multiple implementations of this function,
for different file formats. Each system will compile the
appropriate one. */
extern int backtrace_initialize (struct backtrace_state *state,
const char *filename,
int descriptor,
backtrace_error_callback error_callback,
void *data,
fileline *fileline_fn);
/* An enum for the DWARF sections we care about. */
enum dwarf_section
{
DEBUG_INFO,
DEBUG_LINE,
DEBUG_ABBREV,
DEBUG_RANGES,
DEBUG_STR,
DEBUG_ADDR,
DEBUG_STR_OFFSETS,
DEBUG_LINE_STR,
DEBUG_RNGLISTS,
DEBUG_MAX
};
/* Data for the DWARF sections we care about. */
struct dwarf_sections
{
const unsigned char *data[DEBUG_MAX];
size_t size[DEBUG_MAX];
};
/* DWARF data read from a file, used for .gnu_debugaltlink. */
struct dwarf_data;
/* Add file/line information for a DWARF module. */
extern int backtrace_dwarf_add (struct backtrace_state *state,
uintptr_t base_address,
const struct dwarf_sections *dwarf_sections,
int is_bigendian,
struct dwarf_data *fileline_altlink,
backtrace_error_callback error_callback,
void *data, fileline *fileline_fn,
struct dwarf_data **fileline_entry);
/* A data structure to pass to backtrace_syminfo_to_full. */
struct backtrace_call_full
{
backtrace_full_callback full_callback;
backtrace_error_callback full_error_callback;
void *full_data;
int ret;
};
/* A backtrace_syminfo_callback that can call into a
backtrace_full_callback, used when we have a symbol table but no
debug info. */
extern void backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
const char *symname,
uintptr_t symval,
uintptr_t symsize);
/* An error callback that corresponds to
backtrace_syminfo_to_full_callback. */
extern void backtrace_syminfo_to_full_error_callback (void *, const char *,
int);
/* A test-only hook for elf_uncompress_zdebug. */
extern int backtrace_uncompress_zdebug (struct backtrace_state *,
const unsigned char *compressed,
size_t compressed_size,
backtrace_error_callback, void *data,
unsigned char **uncompressed,
size_t *uncompressed_size);
/* A test-only hook for elf_uncompress_lzma. */
extern int backtrace_uncompress_lzma (struct backtrace_state *,
const unsigned char *compressed,
size_t compressed_size,
backtrace_error_callback, void *data,
unsigned char **uncompressed,
size_t *uncompressed_size);
#endif

935
thirdparty/libbacktrace/pecoff.c vendored Normal file
View File

@ -0,0 +1,935 @@
/* pecoff.c -- Get debug data from a PE/COFFF file for backtraces.
Copyright (C) 2015-2021 Free Software Foundation, Inc.
Adapted from elf.c by Tristan Gingold, AdaCore.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "backtrace.h"
#include "internal.h"
/* Coff file header. */
typedef struct {
uint16_t machine;
uint16_t number_of_sections;
uint32_t time_date_stamp;
uint32_t pointer_to_symbol_table;
uint32_t number_of_symbols;
uint16_t size_of_optional_header;
uint16_t characteristics;
} b_coff_file_header;
/* Coff optional header. */
typedef struct {
uint16_t magic;
uint8_t major_linker_version;
uint8_t minor_linker_version;
uint32_t size_of_code;
uint32_t size_of_initialized_data;
uint32_t size_of_uninitialized_data;
uint32_t address_of_entry_point;
uint32_t base_of_code;
union {
struct {
uint32_t base_of_data;
uint32_t image_base;
} pe;
struct {
uint64_t image_base;
} pep;
} u;
} b_coff_optional_header;
/* Values of magic in optional header. */
#define PE_MAGIC 0x10b /* PE32 executable. */
#define PEP_MAGIC 0x20b /* PE32+ executable (for 64bit targets). */
/* Coff section header. */
typedef struct {
char name[8];
uint32_t virtual_size;
uint32_t virtual_address;
uint32_t size_of_raw_data;
uint32_t pointer_to_raw_data;
uint32_t pointer_to_relocations;
uint32_t pointer_to_line_numbers;
uint16_t number_of_relocations;
uint16_t number_of_line_numbers;
uint32_t characteristics;
} b_coff_section_header;
/* Coff symbol name. */
typedef union {
char short_name[8];
struct {
unsigned char zeroes[4];
unsigned char off[4];
} long_name;
} b_coff_name;
/* Coff symbol (external representation which is unaligned). */
typedef struct {
b_coff_name name;
unsigned char value[4];
unsigned char section_number[2];
unsigned char type[2];
unsigned char storage_class;
unsigned char number_of_aux_symbols;
} b_coff_external_symbol;
/* Symbol types. */
#define N_TBSHFT 4 /* Shift for the derived type. */
#define IMAGE_SYM_DTYPE_FUNCTION 2 /* Function derived type. */
/* Size of a coff symbol. */
#define SYM_SZ 18
/* Coff symbol, internal representation (aligned). */
typedef struct {
const char *name;
uint32_t value;
int16_t sec;
uint16_t type;
uint16_t sc;
} b_coff_internal_symbol;
/* Names of sections, indexed by enum dwarf_section in internal.h. */
static const char * const debug_section_names[DEBUG_MAX] =
{
".debug_info",
".debug_line",
".debug_abbrev",
".debug_ranges",
".debug_str",
".debug_addr",
".debug_str_offsets",
".debug_line_str",
".debug_rnglists"
};
/* Information we gather for the sections we care about. */
struct debug_section_info
{
/* Section file offset. */
off_t offset;
/* Section size. */
size_t size;
};
/* Information we keep for an coff symbol. */
struct coff_symbol
{
/* The name of the symbol. */
const char *name;
/* The address of the symbol. */
uintptr_t address;
};
/* Information to pass to coff_syminfo. */
struct coff_syminfo_data
{
/* Symbols for the next module. */
struct coff_syminfo_data *next;
/* The COFF symbols, sorted by address. */
struct coff_symbol *symbols;
/* The number of symbols. */
size_t count;
};
/* A dummy callback function used when we can't find any debug info. */
static int
coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
uintptr_t pc ATTRIBUTE_UNUSED,
backtrace_full_callback callback ATTRIBUTE_UNUSED,
backtrace_error_callback error_callback, void *data)
{
error_callback (data, "no debug info in PE/COFF executable", -1);
return 0;
}
/* A dummy callback function used when we can't find a symbol
table. */
static void
coff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
uintptr_t addr ATTRIBUTE_UNUSED,
backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
backtrace_error_callback error_callback, void *data)
{
error_callback (data, "no symbol table in PE/COFF executable", -1);
}
/* Read a potentially unaligned 4 byte word at P, using native endianness. */
static uint32_t
coff_read4 (const unsigned char *p)
{
uint32_t res;
memcpy (&res, p, 4);
return res;
}
/* Read a potentially unaligned 2 byte word at P, using native endianness.
All 2 byte word in symbols are always aligned, but for coherency all
fields are declared as char arrays. */
static uint16_t
coff_read2 (const unsigned char *p)
{
uint16_t res;
memcpy (&res, p, sizeof (res));
return res;
}
/* Return the length (without the trailing 0) of a COFF short name. */
static size_t
coff_short_name_len (const char *name)
{
int i;
for (i = 0; i < 8; i++)
if (name[i] == 0)
return i;
return 8;
}
/* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated
string). */
static int
coff_short_name_eq (const char *name, const char *cname)
{
int i;
for (i = 0; i < 8; i++)
{
if (name[i] != cname[i])
return 0;
if (name[i] == 0)
return 1;
}
return name[8] == 0;
}
/* Return true iff NAME is the same as string at offset OFF. */
static int
coff_long_name_eq (const char *name, unsigned int off,
struct backtrace_view *str_view)
{
if (off >= str_view->len)
return 0;
return strcmp (name, (const char *)str_view->data + off) == 0;
}
/* Compare struct coff_symbol for qsort. */
static int
coff_symbol_compare (const void *v1, const void *v2)
{
const struct coff_symbol *e1 = (const struct coff_symbol *) v1;
const struct coff_symbol *e2 = (const struct coff_symbol *) v2;
if (e1->address < e2->address)
return -1;
else if (e1->address > e2->address)
return 1;
else
return 0;
}
/* Convert SYM to internal (and aligned) format ISYM, using string table
from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM.
Return -1 in case of error (invalid section number or string index). */
static int
coff_expand_symbol (b_coff_internal_symbol *isym,
const b_coff_external_symbol *sym,
uint16_t sects_num,
const unsigned char *strtab, size_t strtab_size)
{
isym->type = coff_read2 (sym->type);
isym->sec = coff_read2 (sym->section_number);
isym->sc = sym->storage_class;
if (isym->sec > 0 && (uint16_t) isym->sec > sects_num)
return -1;
if (sym->name.short_name[0] != 0)
isym->name = sym->name.short_name;
else
{
uint32_t off = coff_read4 (sym->name.long_name.off);
if (off >= strtab_size)
return -1;
isym->name = (const char *) strtab + off;
}
return 0;
}
/* Return true iff SYM is a defined symbol for a function. Data symbols
aren't considered because they aren't easily identified (same type as
section names, presence of symbols defined by the linker script). */
static int
coff_is_function_symbol (const b_coff_internal_symbol *isym)
{
return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION
&& isym->sec > 0;
}
/* Initialize the symbol table info for coff_syminfo. */
static int
coff_initialize_syminfo (struct backtrace_state *state,
uintptr_t base_address, int is_64,
const b_coff_section_header *sects, size_t sects_num,
const b_coff_external_symbol *syms, size_t syms_size,
const unsigned char *strtab, size_t strtab_size,
backtrace_error_callback error_callback,
void *data, struct coff_syminfo_data *sdata)
{
size_t syms_count;
char *coff_symstr;
size_t coff_symstr_len;
size_t coff_symbol_count;
size_t coff_symbol_size;
struct coff_symbol *coff_symbols;
struct coff_symbol *coff_sym;
char *coff_str;
size_t i;
syms_count = syms_size / SYM_SZ;
/* We only care about function symbols. Count them. Also count size of
strings for in-symbol names. */
coff_symbol_count = 0;
coff_symstr_len = 0;
for (i = 0; i < syms_count; ++i)
{
const b_coff_external_symbol *asym = &syms[i];
b_coff_internal_symbol isym;
if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size) < 0)
{
error_callback (data, "invalid section or offset in coff symbol", 0);
return 0;
}
if (coff_is_function_symbol (&isym))
{
++coff_symbol_count;
if (asym->name.short_name[0] != 0)
coff_symstr_len += coff_short_name_len (asym->name.short_name) + 1;
}
i += asym->number_of_aux_symbols;
}
coff_symbol_size = (coff_symbol_count + 1) * sizeof (struct coff_symbol);
coff_symbols = ((struct coff_symbol *)
backtrace_alloc (state, coff_symbol_size, error_callback,
data));
if (coff_symbols == NULL)
return 0;
/* Allocate memory for symbols strings. */
if (coff_symstr_len > 0)
{
coff_symstr = ((char *)
backtrace_alloc (state, coff_symstr_len, error_callback,
data));
if (coff_symstr == NULL)
{
backtrace_free (state, coff_symbols, coff_symbol_size,
error_callback, data);
return 0;
}
}
else
coff_symstr = NULL;
/* Copy symbols. */
coff_sym = coff_symbols;
coff_str = coff_symstr;
for (i = 0; i < syms_count; ++i)
{
const b_coff_external_symbol *asym = &syms[i];
b_coff_internal_symbol isym;
if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size))
{
/* Should not fail, as it was already tested in the previous
loop. */
abort ();
}
if (coff_is_function_symbol (&isym))
{
const char *name;
int16_t secnum;
if (asym->name.short_name[0] != 0)
{
size_t len = coff_short_name_len (isym.name);
name = coff_str;
memcpy (coff_str, isym.name, len);
coff_str[len] = 0;
coff_str += len + 1;
}
else
name = isym.name;
if (!is_64)
{
/* Strip leading '_'. */
if (name[0] == '_')
name++;
}
/* Symbol value is section relative, so we need to read the address
of its section. */
secnum = coff_read2 (asym->section_number);
coff_sym->name = name;
coff_sym->address = (coff_read4 (asym->value)
+ sects[secnum - 1].virtual_address
+ base_address);
coff_sym++;
}
i += asym->number_of_aux_symbols;
}
/* End of symbols marker. */
coff_sym->name = NULL;
coff_sym->address = -1;
backtrace_qsort (coff_symbols, coff_symbol_count,
sizeof (struct coff_symbol), coff_symbol_compare);
sdata->next = NULL;
sdata->symbols = coff_symbols;
sdata->count = coff_symbol_count;
return 1;
}
/* Add EDATA to the list in STATE. */
static void
coff_add_syminfo_data (struct backtrace_state *state,
struct coff_syminfo_data *sdata)
{
if (!state->threaded)
{
struct coff_syminfo_data **pp;
for (pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
*pp != NULL;
pp = &(*pp)->next)
;
*pp = sdata;
}
else
{
while (1)
{
struct coff_syminfo_data **pp;
pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
while (1)
{
struct coff_syminfo_data *p;
p = backtrace_atomic_load_pointer (pp);
if (p == NULL)
break;
pp = &p->next;
}
if (__sync_bool_compare_and_swap (pp, NULL, sdata))
break;
}
}
}
/* Compare an ADDR against an elf_symbol for bsearch. We allocate one
extra entry in the array so that this can look safely at the next
entry. */
static int
coff_symbol_search (const void *vkey, const void *ventry)
{
const uintptr_t *key = (const uintptr_t *) vkey;
const struct coff_symbol *entry = (const struct coff_symbol *) ventry;
uintptr_t addr;
addr = *key;
if (addr < entry->address)
return -1;
else if (addr >= entry[1].address)
return 1;
else
return 0;
}
/* Return the symbol name and value for an ADDR. */
static void
coff_syminfo (struct backtrace_state *state, uintptr_t addr,
backtrace_syminfo_callback callback,
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
void *data)
{
struct coff_syminfo_data *sdata;
struct coff_symbol *sym = NULL;
if (!state->threaded)
{
for (sdata = (struct coff_syminfo_data *) state->syminfo_data;
sdata != NULL;
sdata = sdata->next)
{
sym = ((struct coff_symbol *)
bsearch (&addr, sdata->symbols, sdata->count,
sizeof (struct coff_symbol), coff_symbol_search));
if (sym != NULL)
break;
}
}
else
{
struct coff_syminfo_data **pp;
pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data;
while (1)
{
sdata = backtrace_atomic_load_pointer (pp);
if (sdata == NULL)
break;
sym = ((struct coff_symbol *)
bsearch (&addr, sdata->symbols, sdata->count,
sizeof (struct coff_symbol), coff_symbol_search));
if (sym != NULL)
break;
pp = &sdata->next;
}
}
if (sym == NULL)
callback (data, addr, NULL, 0, 0);
else
callback (data, addr, sym->name, sym->address, 0);
}
/* Add the backtrace data for one PE/COFF file. Returns 1 on success,
0 on failure (in both cases descriptor is closed). */
static int
coff_add (struct backtrace_state *state, int descriptor,
backtrace_error_callback error_callback, void *data,
fileline *fileline_fn, int *found_sym, int *found_dwarf)
{
struct backtrace_view fhdr_view;
off_t fhdr_off;
int magic_ok;
b_coff_file_header fhdr;
off_t opt_sects_off;
size_t opt_sects_size;
unsigned int sects_num;
struct backtrace_view sects_view;
int sects_view_valid;
const b_coff_optional_header *opt_hdr;
const b_coff_section_header *sects;
struct backtrace_view str_view;
int str_view_valid;
size_t str_size;
off_t str_off;
struct backtrace_view syms_view;
off_t syms_off;
size_t syms_size;
int syms_view_valid;
unsigned int syms_num;
unsigned int i;
struct debug_section_info sections[DEBUG_MAX];
off_t min_offset;
off_t max_offset;
struct backtrace_view debug_view;
int debug_view_valid;
int is_64;
uintptr_t image_base;
struct dwarf_sections dwarf_sections;
*found_sym = 0;
*found_dwarf = 0;
sects_view_valid = 0;
syms_view_valid = 0;
str_view_valid = 0;
debug_view_valid = 0;
/* Map the MS-DOS stub (if any) and extract file header offset. */
if (!backtrace_get_view (state, descriptor, 0, 0x40, error_callback,
data, &fhdr_view))
goto fail;
{
const unsigned char *vptr = fhdr_view.data;
if (vptr[0] == 'M' && vptr[1] == 'Z')
fhdr_off = coff_read4 (vptr + 0x3c);
else
fhdr_off = 0;
}
backtrace_release_view (state, &fhdr_view, error_callback, data);
/* Map the coff file header. */
if (!backtrace_get_view (state, descriptor, fhdr_off,
sizeof (b_coff_file_header) + 4,
error_callback, data, &fhdr_view))
goto fail;
if (fhdr_off != 0)
{
const char *magic = (const char *) fhdr_view.data;
magic_ok = memcmp (magic, "PE\0", 4) == 0;
fhdr_off += 4;
memcpy (&fhdr, fhdr_view.data + 4, sizeof fhdr);
}
else
{
memcpy (&fhdr, fhdr_view.data, sizeof fhdr);
/* TODO: test fhdr.machine for coff but non-PE platforms. */
magic_ok = 0;
}
backtrace_release_view (state, &fhdr_view, error_callback, data);
if (!magic_ok)
{
error_callback (data, "executable file is not COFF", 0);
goto fail;
}
sects_num = fhdr.number_of_sections;
syms_num = fhdr.number_of_symbols;
opt_sects_off = fhdr_off + sizeof (fhdr);
opt_sects_size = (fhdr.size_of_optional_header
+ sects_num * sizeof (b_coff_section_header));
/* To translate PC to file/line when using DWARF, we need to find
the .debug_info and .debug_line sections. */
/* Read the optional header and the section headers. */
if (!backtrace_get_view (state, descriptor, opt_sects_off, opt_sects_size,
error_callback, data, &sects_view))
goto fail;
sects_view_valid = 1;
opt_hdr = (const b_coff_optional_header *) sects_view.data;
sects = (const b_coff_section_header *)
(sects_view.data + fhdr.size_of_optional_header);
is_64 = 0;
if (fhdr.size_of_optional_header > sizeof (*opt_hdr))
{
if (opt_hdr->magic == PE_MAGIC)
image_base = opt_hdr->u.pe.image_base;
else if (opt_hdr->magic == PEP_MAGIC)
{
image_base = opt_hdr->u.pep.image_base;
is_64 = 1;
}
else
{
error_callback (data, "bad magic in PE optional header", 0);
goto fail;
}
}
else
image_base = 0;
/* Read the symbol table and the string table. */
if (fhdr.pointer_to_symbol_table == 0)
{
/* No symbol table, no string table. */
str_off = 0;
str_size = 0;
syms_num = 0;
syms_size = 0;
}
else
{
/* Symbol table is followed by the string table. The string table
starts with its length (on 4 bytes).
Map the symbol table and the length of the string table. */
syms_off = fhdr.pointer_to_symbol_table;
syms_size = syms_num * SYM_SZ;
if (!backtrace_get_view (state, descriptor, syms_off, syms_size + 4,
error_callback, data, &syms_view))
goto fail;
syms_view_valid = 1;
str_size = coff_read4 (syms_view.data + syms_size);
str_off = syms_off + syms_size;
if (str_size > 4)
{
/* Map string table (including the length word). */
if (!backtrace_get_view (state, descriptor, str_off, str_size,
error_callback, data, &str_view))
goto fail;
str_view_valid = 1;
}
}
memset (sections, 0, sizeof sections);
/* Look for the symbol table. */
for (i = 0; i < sects_num; ++i)
{
const b_coff_section_header *s = sects + i;
unsigned int str_off;
int j;
if (s->name[0] == '/')
{
/* Extended section name. */
str_off = atoi (s->name + 1);
}
else
str_off = 0;
for (j = 0; j < (int) DEBUG_MAX; ++j)
{
const char *dbg_name = debug_section_names[j];
int match;
if (str_off != 0)
match = coff_long_name_eq (dbg_name, str_off, &str_view);
else
match = coff_short_name_eq (dbg_name, s->name);
if (match)
{
sections[j].offset = s->pointer_to_raw_data;
sections[j].size = s->virtual_size <= s->size_of_raw_data ?
s->virtual_size : s->size_of_raw_data;
break;
}
}
}
if (syms_num != 0)
{
struct coff_syminfo_data *sdata;
sdata = ((struct coff_syminfo_data *)
backtrace_alloc (state, sizeof *sdata, error_callback, data));
if (sdata == NULL)
goto fail;
if (!coff_initialize_syminfo (state, image_base, is_64,
sects, sects_num,
syms_view.data, syms_size,
str_view.data, str_size,
error_callback, data, sdata))
{
backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
goto fail;
}
*found_sym = 1;
coff_add_syminfo_data (state, sdata);
}
backtrace_release_view (state, &sects_view, error_callback, data);
sects_view_valid = 0;
if (syms_view_valid)
{
backtrace_release_view (state, &syms_view, error_callback, data);
syms_view_valid = 0;
}
/* Read all the debug sections in a single view, since they are
probably adjacent in the file. We never release this view. */
min_offset = 0;
max_offset = 0;
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
off_t end;
if (sections[i].size == 0)
continue;
if (min_offset == 0 || sections[i].offset < min_offset)
min_offset = sections[i].offset;
end = sections[i].offset + sections[i].size;
if (end > max_offset)
max_offset = end;
}
if (min_offset == 0 || max_offset == 0)
{
if (!backtrace_close (descriptor, error_callback, data))
goto fail;
*fileline_fn = coff_nodebug;
return 1;
}
if (!backtrace_get_view (state, descriptor, min_offset,
max_offset - min_offset,
error_callback, data, &debug_view))
goto fail;
debug_view_valid = 1;
/* We've read all we need from the executable. */
if (!backtrace_close (descriptor, error_callback, data))
goto fail;
descriptor = -1;
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
size_t size = sections[i].size;
dwarf_sections.size[i] = size;
if (size == 0)
dwarf_sections.data[i] = NULL;
else
dwarf_sections.data[i] = ((const unsigned char *) debug_view.data
+ (sections[i].offset - min_offset));
}
if (!backtrace_dwarf_add (state, /* base_address */ 0, &dwarf_sections,
0, /* FIXME: is_bigendian */
NULL, /* altlink */
error_callback, data, fileline_fn,
NULL /* returned fileline_entry */))
goto fail;
*found_dwarf = 1;
return 1;
fail:
if (sects_view_valid)
backtrace_release_view (state, &sects_view, error_callback, data);
if (str_view_valid)
backtrace_release_view (state, &str_view, error_callback, data);
if (syms_view_valid)
backtrace_release_view (state, &syms_view, error_callback, data);
if (debug_view_valid)
backtrace_release_view (state, &debug_view, error_callback, data);
if (descriptor != -1)
backtrace_close (descriptor, error_callback, data);
return 0;
}
/* Initialize the backtrace data we need from an ELF executable. At
the ELF level, all we need to do is find the debug info
sections. */
int
backtrace_initialize (struct backtrace_state *state,
const char *filename ATTRIBUTE_UNUSED, int descriptor,
backtrace_error_callback error_callback,
void *data, fileline *fileline_fn)
{
int ret;
int found_sym;
int found_dwarf;
fileline coff_fileline_fn;
ret = coff_add (state, descriptor, error_callback, data,
&coff_fileline_fn, &found_sym, &found_dwarf);
if (!ret)
return 0;
if (!state->threaded)
{
if (found_sym)
state->syminfo_fn = coff_syminfo;
else if (state->syminfo_fn == NULL)
state->syminfo_fn = coff_nosyms;
}
else
{
if (found_sym)
backtrace_atomic_store_pointer (&state->syminfo_fn, coff_syminfo);
else
(void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
coff_nosyms);
}
if (!state->threaded)
{
if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug)
*fileline_fn = coff_fileline_fn;
}
else
{
fileline current_fn;
current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
if (current_fn == NULL || current_fn == coff_nodebug)
*fileline_fn = coff_fileline_fn;
}
return 1;
}

104
thirdparty/libbacktrace/posix.c vendored Normal file
View File

@ -0,0 +1,104 @@
/* posix.c -- POSIX file I/O routines for the backtrace library.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "backtrace.h"
#include "internal.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#ifndef FD_CLOEXEC
#define FD_CLOEXEC 1
#endif
/* Open a file for reading. */
int
backtrace_open (const char *filename, backtrace_error_callback error_callback,
void *data, int *does_not_exist)
{
int descriptor;
if (does_not_exist != NULL)
*does_not_exist = 0;
descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC));
if (descriptor < 0)
{
/* If DOES_NOT_EXIST is not NULL, then don't call ERROR_CALLBACK
if the file does not exist. We treat lacking permission to
open the file as the file not existing; this case arises when
running the libgo syscall package tests as root. */
if (does_not_exist != NULL && (errno == ENOENT || errno == EACCES))
*does_not_exist = 1;
else
error_callback (data, filename, errno);
return -1;
}
#ifdef HAVE_FCNTL
/* Set FD_CLOEXEC just in case the kernel does not support
O_CLOEXEC. It doesn't matter if this fails for some reason.
FIXME: At some point it should be safe to only do this if
O_CLOEXEC == 0. */
fcntl (descriptor, F_SETFD, FD_CLOEXEC);
#endif
return descriptor;
}
/* Close DESCRIPTOR. */
int
backtrace_close (int descriptor, backtrace_error_callback error_callback,
void *data)
{
if (close (descriptor) < 0)
{
error_callback (data, "close", errno);
return 0;
}
return 1;
}

92
thirdparty/libbacktrace/print.c vendored Normal file
View File

@ -0,0 +1,92 @@
/* print.c -- Print the current backtrace.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "backtrace.h"
#include "internal.h"
/* Passed to callbacks. */
struct print_data
{
struct backtrace_state *state;
FILE *f;
};
/* Print one level of a backtrace. */
static int
print_callback (void *data, uintptr_t pc, const char *filename, int lineno,
const char *function)
{
struct print_data *pdata = (struct print_data *) data;
fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n",
(unsigned long) pc,
function == NULL ? "???" : function,
filename == NULL ? "???" : filename,
lineno);
return 0;
}
/* Print errors to stderr. */
static void
error_callback (void *data, const char *msg, int errnum)
{
struct print_data *pdata = (struct print_data *) data;
if (pdata->state->filename != NULL)
fprintf (stderr, "%s: ", pdata->state->filename);
fprintf (stderr, "libbacktrace: %s", msg);
if (errnum > 0)
fprintf (stderr, ": %s", strerror (errnum));
fputc ('\n', stderr);
}
/* Print a backtrace. */
void __attribute__((noinline))
backtrace_print (struct backtrace_state *state, int skip, FILE *f)
{
struct print_data data;
data.state = state;
data.f = f;
backtrace_full (state, skip + 1, print_callback, error_callback,
(void *) &data);
}

110
thirdparty/libbacktrace/read.c vendored Normal file
View File

@ -0,0 +1,110 @@
/* read.c -- File views without mmap.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "backtrace.h"
#include "internal.h"
/* This file implements file views when mmap is not available. */
/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */
int
backtrace_get_view (struct backtrace_state *state, int descriptor,
off_t offset, uint64_t size,
backtrace_error_callback error_callback,
void *data, struct backtrace_view *view)
{
uint64_t got;
ssize_t r;
if ((uint64_t) (size_t) size != size)
{
error_callback (data, "file size too large", 0);
return 0;
}
if (lseek (descriptor, offset, SEEK_SET) < 0)
{
error_callback (data, "lseek", errno);
return 0;
}
view->base = backtrace_alloc (state, size, error_callback, data);
if (view->base == NULL)
return 0;
view->data = view->base;
view->len = size;
got = 0;
while (got < size)
{
r = read (descriptor, view->base, size - got);
if (r < 0)
{
error_callback (data, "read", errno);
free (view->base);
return 0;
}
if (r == 0)
break;
got += (uint64_t) r;
}
if (got < size)
{
error_callback (data, "file too short", 0);
free (view->base);
return 0;
}
return 1;
}
/* Release a view read by backtrace_get_view. */
void
backtrace_release_view (struct backtrace_state *state,
struct backtrace_view *view,
backtrace_error_callback error_callback,
void *data)
{
backtrace_free (state, view->base, view->len, error_callback, data);
view->data = NULL;
view->base = NULL;
}

108
thirdparty/libbacktrace/simple.c vendored Normal file
View File

@ -0,0 +1,108 @@
/* simple.c -- The backtrace_simple function.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include "unwind.h"
#include "backtrace.h"
/* The simple_backtrace routine. */
/* Data passed through _Unwind_Backtrace. */
struct backtrace_simple_data
{
/* Number of frames to skip. */
int skip;
/* Library state. */
struct backtrace_state *state;
/* Callback routine. */
backtrace_simple_callback callback;
/* Error callback routine. */
backtrace_error_callback error_callback;
/* Data to pass to callback routine. */
void *data;
/* Value to return from backtrace. */
int ret;
};
/* Unwind library callback routine. This is passed to
_Unwind_Backtrace. */
static _Unwind_Reason_Code
simple_unwind (struct _Unwind_Context *context, void *vdata)
{
struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata;
uintptr_t pc;
int ip_before_insn = 0;
#ifdef HAVE_GETIPINFO
pc = _Unwind_GetIPInfo (context, &ip_before_insn);
#else
pc = _Unwind_GetIP (context);
#endif
if (bdata->skip > 0)
{
--bdata->skip;
return _URC_NO_REASON;
}
if (!ip_before_insn)
--pc;
bdata->ret = bdata->callback (bdata->data, pc);
if (bdata->ret != 0)
return _URC_END_OF_STACK;
return _URC_NO_REASON;
}
/* Get a simple stack backtrace. */
int __attribute__((noinline))
backtrace_simple (struct backtrace_state *state, int skip,
backtrace_simple_callback callback,
backtrace_error_callback error_callback, void *data)
{
struct backtrace_simple_data bdata;
bdata.skip = skip + 1;
bdata.state = state;
bdata.callback = callback;
bdata.error_callback = error_callback;
bdata.data = data;
bdata.ret = 0;
_Unwind_Backtrace (simple_unwind, &bdata);
return bdata.ret;
}

108
thirdparty/libbacktrace/sort.c vendored Normal file
View File

@ -0,0 +1,108 @@
/* sort.c -- Sort without allocating memory
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <stddef.h>
#include <sys/types.h>
#include "backtrace.h"
#include "internal.h"
/* The GNU glibc version of qsort allocates memory, which we must not
do if we are invoked by a signal handler. So provide our own
sort. */
static void
swap (char *a, char *b, size_t size)
{
size_t i;
for (i = 0; i < size; i++, a++, b++)
{
char t;
t = *a;
*a = *b;
*b = t;
}
}
void
backtrace_qsort (void *basearg, size_t count, size_t size,
int (*compar) (const void *, const void *))
{
char *base = (char *) basearg;
size_t i;
size_t mid;
tail_recurse:
if (count < 2)
return;
/* The symbol table and DWARF tables, which is all we use this
routine for, tend to be roughly sorted. Pick the middle element
in the array as our pivot point, so that we are more likely to
cut the array in half for each recursion step. */
swap (base, base + (count / 2) * size, size);
mid = 0;
for (i = 1; i < count; i++)
{
if ((*compar) (base, base + i * size) > 0)
{
++mid;
if (i != mid)
swap (base + mid * size, base + i * size, size);
}
}
if (mid > 0)
swap (base, base + mid * size, size);
/* Recurse with the smaller array, loop with the larger one. That
ensures that our maximum stack depth is log count. */
if (2 * mid < count)
{
backtrace_qsort (base, mid, size, compar);
base += (mid + 1) * size;
count -= mid + 1;
goto tail_recurse;
}
else
{
backtrace_qsort (base + (mid + 1) * size, count - (mid + 1),
size, compar);
count = mid;
goto tail_recurse;
}
}

72
thirdparty/libbacktrace/state.c vendored Normal file
View File

@ -0,0 +1,72 @@
/* state.c -- Create the backtrace state.
Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
(1) Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
#include <string.h>
#include <sys/types.h>
#include "backtrace.h"
#include "backtrace-supported.h"
#include "internal.h"
/* Create the backtrace state. This will then be passed to all the
other routines. */
struct backtrace_state *
backtrace_create_state (const char *filename, int threaded,
backtrace_error_callback error_callback,
void *data)
{
struct backtrace_state init_state;
struct backtrace_state *state;
#ifndef HAVE_SYNC_FUNCTIONS
if (threaded)
{
error_callback (data, "backtrace library does not support threads", 0);
return NULL;
}
#endif
memset (&init_state, 0, sizeof init_state);
init_state.filename = filename;
init_state.threaded = threaded;
state = ((struct backtrace_state *)
backtrace_alloc (&init_state, sizeof *state, error_callback, data));
if (state == NULL)
return NULL;
*state = init_state;
return state;
}