aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormaksim-kita <maksim-kita@yandex-team.com>2023-11-02 15:15:26 +0300
committermaksim-kita <maksim-kita@yandex-team.com>2023-11-02 16:26:16 +0300
commitd4ec9ad0ad93850fa81d9e78298066d138aba60f (patch)
tree70255a78488d9abdac8cbac0f447356e40249cd2
parent7bb2ef5057a017f193e0c790e16dac7e78891c26 (diff)
downloadydb-d4ec9ad0ad93850fa81d9e78298066d138aba60f.tar.gz
Stacktraces add line numbers
-rw-r--r--.mapping.json8
-rw-r--r--contrib/libs/CMakeLists.darwin-x86_64.txt1
-rw-r--r--contrib/libs/CMakeLists.linux-aarch64.txt1
-rw-r--r--contrib/libs/CMakeLists.linux-x86_64.txt1
-rw-r--r--contrib/libs/backtrace/CMakeLists.darwin-x86_64.txt31
-rw-r--r--contrib/libs/backtrace/CMakeLists.linux-aarch64.txt34
-rw-r--r--contrib/libs/backtrace/CMakeLists.linux-x86_64.txt34
-rw-r--r--contrib/libs/backtrace/CMakeLists.txt15
-rw-r--r--contrib/libs/backtrace/macho.c1355
-rw-r--r--library/cpp/CMakeLists.darwin-x86_64.txt1
-rw-r--r--library/cpp/CMakeLists.linux-aarch64.txt1
-rw-r--r--library/cpp/CMakeLists.linux-x86_64.txt1
-rw-r--r--library/cpp/dwarf_backtrace/CMakeLists.darwin-x86_64.txt18
-rw-r--r--library/cpp/dwarf_backtrace/CMakeLists.linux-aarch64.txt19
-rw-r--r--library/cpp/dwarf_backtrace/CMakeLists.linux-x86_64.txt19
-rw-r--r--library/cpp/dwarf_backtrace/CMakeLists.txt15
-rw-r--r--library/cpp/dwarf_backtrace/registry/set_format_backtrace.cpp18
-rw-r--r--library/cpp/dwarf_backtrace/registry/ya.make15
-rw-r--r--library/cpp/dwarf_backtrace/ut/backtrace_ut.cpp55
-rw-r--r--library/cpp/dwarf_backtrace/ut/ya.make12
-rw-r--r--ydb/core/base/CMakeLists.darwin-x86_64.txt2
-rw-r--r--ydb/core/base/CMakeLists.linux-aarch64.txt2
-rw-r--r--ydb/core/base/CMakeLists.linux-x86_64.txt2
-rw-r--r--ydb/core/base/CMakeLists.windows-x86_64.txt1
-rw-r--r--ydb/core/base/backtrace.cpp53
-rw-r--r--ydb/core/base/backtrace.h7
-rw-r--r--ydb/core/base/ya.make8
-rw-r--r--ydb/core/driver_lib/run/main.cpp5
-rw-r--r--ydb/core/kqp/ut/common/kqp_ut_common.cpp3
29 files changed, 1736 insertions, 1 deletions
diff --git a/.mapping.json b/.mapping.json
index 537f8d29e3..16eed80203 100644
--- a/.mapping.json
+++ b/.mapping.json
@@ -131,6 +131,10 @@
"contrib/libs/aws-sdk-cpp/aws-cpp-sdk-s3/CMakeLists.linux-x86_64.txt":"",
"contrib/libs/aws-sdk-cpp/aws-cpp-sdk-s3/CMakeLists.txt":"",
"contrib/libs/aws-sdk-cpp/aws-cpp-sdk-s3/CMakeLists.windows-x86_64.txt":"",
+ "contrib/libs/backtrace/CMakeLists.darwin-x86_64.txt":"",
+ "contrib/libs/backtrace/CMakeLists.linux-aarch64.txt":"",
+ "contrib/libs/backtrace/CMakeLists.linux-x86_64.txt":"",
+ "contrib/libs/backtrace/CMakeLists.txt":"",
"contrib/libs/base64/CMakeLists.txt":"",
"contrib/libs/base64/avx2/CMakeLists.darwin-x86_64.txt":"",
"contrib/libs/base64/avx2/CMakeLists.linux-aarch64.txt":"",
@@ -2201,6 +2205,10 @@
"library/cpp/dns/CMakeLists.linux-x86_64.txt":"",
"library/cpp/dns/CMakeLists.txt":"",
"library/cpp/dns/CMakeLists.windows-x86_64.txt":"",
+ "library/cpp/dwarf_backtrace/CMakeLists.darwin-x86_64.txt":"",
+ "library/cpp/dwarf_backtrace/CMakeLists.linux-aarch64.txt":"",
+ "library/cpp/dwarf_backtrace/CMakeLists.linux-x86_64.txt":"",
+ "library/cpp/dwarf_backtrace/CMakeLists.txt":"",
"library/cpp/enumbitset/CMakeLists.darwin-x86_64.txt":"",
"library/cpp/enumbitset/CMakeLists.linux-aarch64.txt":"",
"library/cpp/enumbitset/CMakeLists.linux-x86_64.txt":"",
diff --git a/contrib/libs/CMakeLists.darwin-x86_64.txt b/contrib/libs/CMakeLists.darwin-x86_64.txt
index c62e34c5ff..883bdccf09 100644
--- a/contrib/libs/CMakeLists.darwin-x86_64.txt
+++ b/contrib/libs/CMakeLists.darwin-x86_64.txt
@@ -9,6 +9,7 @@
add_subdirectory(antlr3_cpp_runtime)
add_subdirectory(apache)
add_subdirectory(aws-sdk-cpp)
+add_subdirectory(backtrace)
add_subdirectory(base64)
add_subdirectory(brotli)
add_subdirectory(c-ares)
diff --git a/contrib/libs/CMakeLists.linux-aarch64.txt b/contrib/libs/CMakeLists.linux-aarch64.txt
index 39f8e9a55c..9baeaba9de 100644
--- a/contrib/libs/CMakeLists.linux-aarch64.txt
+++ b/contrib/libs/CMakeLists.linux-aarch64.txt
@@ -9,6 +9,7 @@
add_subdirectory(antlr3_cpp_runtime)
add_subdirectory(apache)
add_subdirectory(aws-sdk-cpp)
+add_subdirectory(backtrace)
add_subdirectory(base64)
add_subdirectory(brotli)
add_subdirectory(c-ares)
diff --git a/contrib/libs/CMakeLists.linux-x86_64.txt b/contrib/libs/CMakeLists.linux-x86_64.txt
index 56ff664a72..5a5c430a16 100644
--- a/contrib/libs/CMakeLists.linux-x86_64.txt
+++ b/contrib/libs/CMakeLists.linux-x86_64.txt
@@ -9,6 +9,7 @@
add_subdirectory(antlr3_cpp_runtime)
add_subdirectory(apache)
add_subdirectory(aws-sdk-cpp)
+add_subdirectory(backtrace)
add_subdirectory(base64)
add_subdirectory(brotli)
add_subdirectory(c-ares)
diff --git a/contrib/libs/backtrace/CMakeLists.darwin-x86_64.txt b/contrib/libs/backtrace/CMakeLists.darwin-x86_64.txt
new file mode 100644
index 0000000000..fe260798da
--- /dev/null
+++ b/contrib/libs/backtrace/CMakeLists.darwin-x86_64.txt
@@ -0,0 +1,31 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(contrib-libs-backtrace)
+target_compile_options(contrib-libs-backtrace PRIVATE
+ -DHAVE_CONFIG_H
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(contrib-libs-backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace
+)
+target_sources(contrib-libs-backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/atomic.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/backtrace.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/dwarf.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/fileline.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/mmap.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/mmapio.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/posix.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/print.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/simple.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/sort.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/state.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/macho.c
+)
diff --git a/contrib/libs/backtrace/CMakeLists.linux-aarch64.txt b/contrib/libs/backtrace/CMakeLists.linux-aarch64.txt
new file mode 100644
index 0000000000..fa7fd4f6df
--- /dev/null
+++ b/contrib/libs/backtrace/CMakeLists.linux-aarch64.txt
@@ -0,0 +1,34 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(contrib-libs-backtrace)
+target_compile_options(contrib-libs-backtrace PRIVATE
+ -DHAVE_CONFIG_H
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(contrib-libs-backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace
+)
+target_link_libraries(contrib-libs-backtrace PUBLIC
+ contrib-libs-linux-headers
+)
+target_sources(contrib-libs-backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/atomic.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/backtrace.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/dwarf.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/fileline.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/mmap.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/mmapio.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/posix.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/print.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/simple.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/sort.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/state.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/elf.c
+)
diff --git a/contrib/libs/backtrace/CMakeLists.linux-x86_64.txt b/contrib/libs/backtrace/CMakeLists.linux-x86_64.txt
new file mode 100644
index 0000000000..fa7fd4f6df
--- /dev/null
+++ b/contrib/libs/backtrace/CMakeLists.linux-x86_64.txt
@@ -0,0 +1,34 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(contrib-libs-backtrace)
+target_compile_options(contrib-libs-backtrace PRIVATE
+ -DHAVE_CONFIG_H
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(contrib-libs-backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace
+)
+target_link_libraries(contrib-libs-backtrace PUBLIC
+ contrib-libs-linux-headers
+)
+target_sources(contrib-libs-backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/atomic.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/backtrace.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/dwarf.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/fileline.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/mmap.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/mmapio.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/posix.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/print.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/simple.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/sort.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/state.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/backtrace/elf.c
+)
diff --git a/contrib/libs/backtrace/CMakeLists.txt b/contrib/libs/backtrace/CMakeLists.txt
new file mode 100644
index 0000000000..606ff46b4b
--- /dev/null
+++ b/contrib/libs/backtrace/CMakeLists.txt
@@ -0,0 +1,15 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA)
+ include(CMakeLists.linux-aarch64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ include(CMakeLists.darwin-x86_64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA)
+ include(CMakeLists.linux-x86_64.txt)
+endif()
diff --git a/contrib/libs/backtrace/macho.c b/contrib/libs/backtrace/macho.c
new file mode 100644
index 0000000000..d00aea9bc8
--- /dev/null
+++ b/contrib/libs/backtrace/macho.c
@@ -0,0 +1,1355 @@
+/* elf.c -- Get debug data from a Mach-O file for backtraces.
+ Copyright (C) 2020-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 <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_MACH_O_DYLD_H
+#include <mach-o/dyld.h>
+#endif
+
+#include "backtrace.h"
+#include "internal.h"
+
+/* Mach-O file header for a 32-bit executable. */
+
+struct macho_header_32
+{
+ uint32_t magic; /* Magic number (MACH_O_MAGIC_32) */
+ uint32_t cputype; /* CPU type */
+ uint32_t cpusubtype; /* CPU subtype */
+ uint32_t filetype; /* Type of file (object, executable) */
+ uint32_t ncmds; /* Number of load commands */
+ uint32_t sizeofcmds; /* Total size of load commands */
+ uint32_t flags; /* Flags for special features */
+};
+
+/* Mach-O file header for a 64-bit executable. */
+
+struct macho_header_64
+{
+ uint32_t magic; /* Magic number (MACH_O_MAGIC_64) */
+ uint32_t cputype; /* CPU type */
+ uint32_t cpusubtype; /* CPU subtype */
+ uint32_t filetype; /* Type of file (object, executable) */
+ uint32_t ncmds; /* Number of load commands */
+ uint32_t sizeofcmds; /* Total size of load commands */
+ uint32_t flags; /* Flags for special features */
+ uint32_t reserved; /* Reserved */
+};
+
+/* Mach-O file header for a fat executable. */
+
+struct macho_header_fat
+{
+ uint32_t magic; /* Magic number (MACH_O_MH_(MAGIC|CIGAM)_FAT(_64)?) */
+ uint32_t nfat_arch; /* Number of components */
+};
+
+/* Values for the header magic field. */
+
+#define MACH_O_MH_MAGIC_32 0xfeedface
+#define MACH_O_MH_MAGIC_64 0xfeedfacf
+#define MACH_O_MH_MAGIC_FAT 0xcafebabe
+#define MACH_O_MH_CIGAM_FAT 0xbebafeca
+#define MACH_O_MH_MAGIC_FAT_64 0xcafebabf
+#define MACH_O_MH_CIGAM_FAT_64 0xbfbafeca
+
+/* Value for the header filetype field. */
+
+#define MACH_O_MH_EXECUTE 0x02
+#define MACH_O_MH_DYLIB 0x06
+#define MACH_O_MH_DSYM 0x0a
+
+/* A component of a fat file. A fat file starts with a
+ macho_header_fat followed by nfat_arch instances of this
+ struct. */
+
+struct macho_fat_arch
+{
+ uint32_t cputype; /* CPU type */
+ uint32_t cpusubtype; /* CPU subtype */
+ uint32_t offset; /* File offset of this entry */
+ uint32_t size; /* Size of this entry */
+ uint32_t align; /* Alignment of this entry */
+};
+
+/* A component of a 64-bit fat file. This is used if the magic field
+ is MAGIC_FAT_64. This is only used when some file size or file
+ offset is too large to represent in the 32-bit format. */
+
+struct macho_fat_arch_64
+{
+ uint32_t cputype; /* CPU type */
+ uint32_t cpusubtype; /* CPU subtype */
+ uint64_t offset; /* File offset of this entry */
+ uint64_t size; /* Size of this entry */
+ uint32_t align; /* Alignment of this entry */
+ uint32_t reserved; /* Reserved */
+};
+
+/* Values for the fat_arch cputype field (and the header cputype
+ field). */
+
+#define MACH_O_CPU_ARCH_ABI64 0x01000000
+
+#define MACH_O_CPU_TYPE_X86 7
+#define MACH_O_CPU_TYPE_ARM 12
+#define MACH_O_CPU_TYPE_PPC 18
+
+#define MACH_O_CPU_TYPE_X86_64 (MACH_O_CPU_TYPE_X86 | MACH_O_CPU_ARCH_ABI64)
+#define MACH_O_CPU_TYPE_ARM64 (MACH_O_CPU_TYPE_ARM | MACH_O_CPU_ARCH_ABI64)
+#define MACH_O_CPU_TYPE_PPC64 (MACH_O_CPU_TYPE_PPC | MACH_O_CPU_ARCH_ABI64)
+
+/* The header of a load command. */
+
+struct macho_load_command
+{
+ uint32_t cmd; /* The type of load command */
+ uint32_t cmdsize; /* Size in bytes of the entire command */
+};
+
+/* Values for the load_command cmd field. */
+
+#define MACH_O_LC_SEGMENT 0x01
+#define MACH_O_LC_SYMTAB 0x02
+#define MACH_O_LC_SEGMENT_64 0x19
+#define MACH_O_LC_UUID 0x1b
+
+/* The length of a section of segment name. */
+
+#define MACH_O_NAMELEN (16)
+
+/* LC_SEGMENT load command. */
+
+struct macho_segment_command
+{
+ uint32_t cmd; /* The type of load command (LC_SEGMENT) */
+ uint32_t cmdsize; /* Size in bytes of the entire command */
+ char segname[MACH_O_NAMELEN]; /* Segment name */
+ uint32_t vmaddr; /* Virtual memory address */
+ uint32_t vmsize; /* Virtual memory size */
+ uint32_t fileoff; /* Offset of data to be mapped */
+ uint32_t filesize; /* Size of data in file */
+ uint32_t maxprot; /* Maximum permitted virtual protection */
+ uint32_t initprot; /* Initial virtual memory protection */
+ uint32_t nsects; /* Number of sections in this segment */
+ uint32_t flags; /* Flags */
+};
+
+/* LC_SEGMENT_64 load command. */
+
+struct macho_segment_64_command
+{
+ uint32_t cmd; /* The type of load command (LC_SEGMENT) */
+ uint32_t cmdsize; /* Size in bytes of the entire command */
+ char segname[MACH_O_NAMELEN]; /* Segment name */
+ uint64_t vmaddr; /* Virtual memory address */
+ uint64_t vmsize; /* Virtual memory size */
+ uint64_t fileoff; /* Offset of data to be mapped */
+ uint64_t filesize; /* Size of data in file */
+ uint32_t maxprot; /* Maximum permitted virtual protection */
+ uint32_t initprot; /* Initial virtual memory protection */
+ uint32_t nsects; /* Number of sections in this segment */
+ uint32_t flags; /* Flags */
+};
+
+/* LC_SYMTAB load command. */
+
+struct macho_symtab_command
+{
+ uint32_t cmd; /* The type of load command (LC_SEGMENT) */
+ uint32_t cmdsize; /* Size in bytes of the entire command */
+ uint32_t symoff; /* File offset of symbol table */
+ uint32_t nsyms; /* Number of symbols */
+ uint32_t stroff; /* File offset of string table */
+ uint32_t strsize; /* String table size */
+};
+
+/* The length of a Mach-O uuid. */
+
+#define MACH_O_UUID_LEN (16)
+
+/* LC_UUID load command. */
+
+struct macho_uuid_command
+{
+ uint32_t cmd; /* Type of load command (LC_UUID) */
+ uint32_t cmdsize; /* Size in bytes of command */
+ unsigned char uuid[MACH_O_UUID_LEN]; /* UUID */
+};
+
+/* 32-bit section header within a LC_SEGMENT segment. */
+
+struct macho_section
+{
+ char sectname[MACH_O_NAMELEN]; /* Section name */
+ char segment[MACH_O_NAMELEN]; /* Segment of this section */
+ uint32_t addr; /* Address in memory */
+ uint32_t size; /* Section size */
+ uint32_t offset; /* File offset */
+ uint32_t align; /* Log2 of section alignment */
+ uint32_t reloff; /* File offset of relocations */
+ uint32_t nreloc; /* Number of relocs for this section */
+ uint32_t flags; /* Flags */
+ uint32_t reserved1;
+ uint32_t reserved2;
+};
+
+/* 64-bit section header within a LC_SEGMENT_64 segment. */
+
+struct macho_section_64
+{
+ char sectname[MACH_O_NAMELEN]; /* Section name */
+ char segment[MACH_O_NAMELEN]; /* Segment of this section */
+ uint64_t addr; /* Address in memory */
+ uint64_t size; /* Section size */
+ uint32_t offset; /* File offset */
+ uint32_t align; /* Log2 of section alignment */
+ uint32_t reloff; /* File offset of section relocations */
+ uint32_t nreloc; /* Number of relocs for this section */
+ uint32_t flags; /* Flags */
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+};
+
+/* 32-bit symbol data. */
+
+struct macho_nlist
+{
+ uint32_t n_strx; /* Index of name in string table */
+ uint8_t n_type; /* Type flag */
+ uint8_t n_sect; /* Section number */
+ uint16_t n_desc; /* Stabs description field */
+ uint32_t n_value; /* Value */
+};
+
+/* 64-bit symbol data. */
+
+struct macho_nlist_64
+{
+ uint32_t n_strx; /* Index of name in string table */
+ uint8_t n_type; /* Type flag */
+ uint8_t n_sect; /* Section number */
+ uint16_t n_desc; /* Stabs description field */
+ uint64_t n_value; /* Value */
+};
+
+/* Value found in nlist n_type field. */
+
+#define MACH_O_N_EXT 0x01 /* Extern symbol */
+#define MACH_O_N_ABS 0x02 /* Absolute symbol */
+#define MACH_O_N_SECT 0x0e /* Defined in section */
+
+#define MACH_O_N_TYPE 0x0e /* Mask for type bits */
+#define MACH_O_N_STAB 0xe0 /* Stabs debugging symbol */
+
+/* Information we keep for a Mach-O symbol. */
+
+struct macho_symbol
+{
+ const char *name; /* Symbol name */
+ uintptr_t address; /* Symbol address */
+};
+
+/* Information to pass to macho_syminfo. */
+
+struct macho_syminfo_data
+{
+ struct macho_syminfo_data *next; /* Next module */
+ struct macho_symbol *symbols; /* Symbols sorted by address */
+ size_t count; /* Number of symbols */
+};
+
+/* Names of sections, indexed by enum dwarf_section in internal.h. */
+
+static const char * const dwarf_section_names[DEBUG_MAX] =
+{
+ "__debug_info",
+ "__debug_line",
+ "__debug_abbrev",
+ "__debug_ranges",
+ "__debug_str",
+ "", /* DEBUG_ADDR */
+ "__debug_str_offs",
+ "", /* DEBUG_LINE_STR */
+ "__debug_rnglists"
+};
+
+/* Forward declaration. */
+
+static int macho_add (struct backtrace_state *, const char *, int, off_t,
+ const unsigned char *, uintptr_t, int,
+ backtrace_error_callback, void *, fileline *, int *);
+
+/* A dummy callback function used when we can't find any debug info. */
+
+static int
+macho_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 Mach-O executable", -1);
+ return 0;
+}
+
+/* A dummy callback function used when we can't find a symbol
+ table. */
+
+static void
+macho_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 Mach-O executable", -1);
+}
+
+/* Add a single DWARF section to DWARF_SECTIONS, if we need the
+ section. Returns 1 on success, 0 on failure. */
+
+static int
+macho_add_dwarf_section (struct backtrace_state *state, int descriptor,
+ const char *sectname, uint32_t offset, uint64_t size,
+ backtrace_error_callback error_callback, void *data,
+ struct dwarf_sections *dwarf_sections)
+{
+ int i;
+
+ for (i = 0; i < (int) DEBUG_MAX; ++i)
+ {
+ if (dwarf_section_names[i][0] != '\0'
+ && strncmp (sectname, dwarf_section_names[i], MACH_O_NAMELEN) == 0)
+ {
+ struct backtrace_view section_view;
+
+ /* FIXME: Perhaps it would be better to try to use a single
+ view to read all the DWARF data, as we try to do for
+ ELF. */
+
+ if (!backtrace_get_view (state, descriptor, offset, size,
+ error_callback, data, &section_view))
+ return 0;
+ dwarf_sections->data[i] = (const unsigned char *) section_view.data;
+ dwarf_sections->size[i] = size;
+ break;
+ }
+ }
+ return 1;
+}
+
+/* Collect DWARF sections from a DWARF segment. Returns 1 on success,
+ 0 on failure. */
+
+static int
+macho_add_dwarf_segment (struct backtrace_state *state, int descriptor,
+ off_t offset, unsigned int cmd, const char *psecs,
+ size_t sizesecs, unsigned int nsects,
+ backtrace_error_callback error_callback, void *data,
+ struct dwarf_sections *dwarf_sections)
+{
+ size_t sec_header_size;
+ size_t secoffset;
+ unsigned int i;
+
+ switch (cmd)
+ {
+ case MACH_O_LC_SEGMENT:
+ sec_header_size = sizeof (struct macho_section);
+ break;
+ case MACH_O_LC_SEGMENT_64:
+ sec_header_size = sizeof (struct macho_section_64);
+ break;
+ default:
+ abort ();
+ }
+
+ secoffset = 0;
+ for (i = 0; i < nsects; ++i)
+ {
+ if (secoffset + sec_header_size > sizesecs)
+ {
+ error_callback (data, "section overflow withing segment", 0);
+ return 0;
+ }
+
+ switch (cmd)
+ {
+ case MACH_O_LC_SEGMENT:
+ {
+ struct macho_section section;
+
+ memcpy (&section, psecs + secoffset, sizeof section);
+ macho_add_dwarf_section (state, descriptor, section.sectname,
+ offset + section.offset, section.size,
+ error_callback, data, dwarf_sections);
+ }
+ break;
+
+ case MACH_O_LC_SEGMENT_64:
+ {
+ struct macho_section_64 section;
+
+ memcpy (&section, psecs + secoffset, sizeof section);
+ macho_add_dwarf_section (state, descriptor, section.sectname,
+ offset + section.offset, section.size,
+ error_callback, data, dwarf_sections);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ secoffset += sec_header_size;
+ }
+
+ return 1;
+}
+
+/* Compare struct macho_symbol for qsort. */
+
+static int
+macho_symbol_compare (const void *v1, const void *v2)
+{
+ const struct macho_symbol *m1 = (const struct macho_symbol *) v1;
+ const struct macho_symbol *m2 = (const struct macho_symbol *) v2;
+
+ if (m1->address < m2->address)
+ return -1;
+ else if (m1->address > m2->address)
+ return 1;
+ else
+ return 0;
+}
+
+/* Compare an address against a macho_symbol for bsearch. We allocate
+ one extra entry in the array so that this can safely look at the
+ next entry. */
+
+static int
+macho_symbol_search (const void *vkey, const void *ventry)
+{
+ const uintptr_t *key = (const uintptr_t *) vkey;
+ const struct macho_symbol *entry = (const struct macho_symbol *) ventry;
+ uintptr_t addr;
+
+ addr = *key;
+ if (addr < entry->address)
+ return -1;
+ else if (entry->name[0] == '\0'
+ && entry->address == ~(uintptr_t) 0)
+ return -1;
+ else if ((entry + 1)->name[0] == '\0'
+ && (entry + 1)->address == ~(uintptr_t) 0)
+ return -1;
+ else if (addr >= (entry + 1)->address)
+ return 1;
+ else
+ return 0;
+}
+
+/* Return whether the symbol type field indicates a symbol table entry
+ that we care about: a function or data symbol. */
+
+static int
+macho_defined_symbol (uint8_t type)
+{
+ if ((type & MACH_O_N_STAB) != 0)
+ return 0;
+ if ((type & MACH_O_N_EXT) != 0)
+ return 0;
+ switch (type & MACH_O_N_TYPE)
+ {
+ case MACH_O_N_ABS:
+ return 1;
+ case MACH_O_N_SECT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Add symbol table information for a Mach-O file. */
+
+static int
+macho_add_symtab (struct backtrace_state *state, int descriptor,
+ uintptr_t base_address, int is_64,
+ off_t symoff, unsigned int nsyms, off_t stroff,
+ unsigned int strsize,
+ backtrace_error_callback error_callback, void *data)
+{
+ size_t symsize;
+ struct backtrace_view sym_view;
+ int sym_view_valid;
+ struct backtrace_view str_view;
+ int str_view_valid;
+ size_t ndefs;
+ size_t symtaboff;
+ unsigned int i;
+ size_t macho_symbol_size;
+ struct macho_symbol *macho_symbols;
+ unsigned int j;
+ struct macho_syminfo_data *sdata;
+
+ sym_view_valid = 0;
+ str_view_valid = 0;
+ macho_symbol_size = 0;
+ macho_symbols = NULL;
+
+ if (is_64)
+ symsize = sizeof (struct macho_nlist_64);
+ else
+ symsize = sizeof (struct macho_nlist);
+
+ if (!backtrace_get_view (state, descriptor, symoff, nsyms * symsize,
+ error_callback, data, &sym_view))
+ goto fail;
+ sym_view_valid = 1;
+
+ if (!backtrace_get_view (state, descriptor, stroff, strsize,
+ error_callback, data, &str_view))
+ return 0;
+ str_view_valid = 1;
+
+ ndefs = 0;
+ symtaboff = 0;
+ for (i = 0; i < nsyms; ++i, symtaboff += symsize)
+ {
+ if (is_64)
+ {
+ struct macho_nlist_64 nlist;
+
+ memcpy (&nlist, (const char *) sym_view.data + symtaboff,
+ sizeof nlist);
+ if (macho_defined_symbol (nlist.n_type))
+ ++ndefs;
+ }
+ else
+ {
+ struct macho_nlist nlist;
+
+ memcpy (&nlist, (const char *) sym_view.data + symtaboff,
+ sizeof nlist);
+ if (macho_defined_symbol (nlist.n_type))
+ ++ndefs;
+ }
+ }
+
+ /* Add 1 to ndefs to make room for a sentinel. */
+ macho_symbol_size = (ndefs + 1) * sizeof (struct macho_symbol);
+ macho_symbols = ((struct macho_symbol *)
+ backtrace_alloc (state, macho_symbol_size, error_callback,
+ data));
+ if (macho_symbols == NULL)
+ goto fail;
+
+ j = 0;
+ symtaboff = 0;
+ for (i = 0; i < nsyms; ++i, symtaboff += symsize)
+ {
+ uint32_t strx;
+ uint64_t value;
+ const char *name;
+
+ strx = 0;
+ value = 0;
+ if (is_64)
+ {
+ struct macho_nlist_64 nlist;
+
+ memcpy (&nlist, (const char *) sym_view.data + symtaboff,
+ sizeof nlist);
+ if (!macho_defined_symbol (nlist.n_type))
+ continue;
+
+ strx = nlist.n_strx;
+ value = nlist.n_value;
+ }
+ else
+ {
+ struct macho_nlist nlist;
+
+ memcpy (&nlist, (const char *) sym_view.data + symtaboff,
+ sizeof nlist);
+ if (!macho_defined_symbol (nlist.n_type))
+ continue;
+
+ strx = nlist.n_strx;
+ value = nlist.n_value;
+ }
+
+ if (strx >= strsize)
+ {
+ error_callback (data, "symbol string index out of range", 0);
+ goto fail;
+ }
+
+ name = (const char *) str_view.data + strx;
+ if (name[0] == '_')
+ ++name;
+ macho_symbols[j].name = name;
+ macho_symbols[j].address = value + base_address;
+ ++j;
+ }
+
+ sdata = ((struct macho_syminfo_data *)
+ backtrace_alloc (state, sizeof *sdata, error_callback, data));
+ if (sdata == NULL)
+ goto fail;
+
+ /* We need to keep the string table since it holds the names, but we
+ can release the symbol table. */
+
+ backtrace_release_view (state, &sym_view, error_callback, data);
+ sym_view_valid = 0;
+ str_view_valid = 0;
+
+ /* Add a trailing sentinel symbol. */
+ macho_symbols[j].name = "";
+ macho_symbols[j].address = ~(uintptr_t) 0;
+
+ backtrace_qsort (macho_symbols, ndefs + 1, sizeof (struct macho_symbol),
+ macho_symbol_compare);
+
+ sdata->next = NULL;
+ sdata->symbols = macho_symbols;
+ sdata->count = ndefs;
+
+ if (!state->threaded)
+ {
+ struct macho_syminfo_data **pp;
+
+ for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
+ *pp != NULL;
+ pp = &(*pp)->next)
+ ;
+ *pp = sdata;
+ }
+ else
+ {
+ while (1)
+ {
+ struct macho_syminfo_data **pp;
+
+ pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
+
+ while (1)
+ {
+ struct macho_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;
+ }
+ }
+
+ return 1;
+
+ fail:
+ if (macho_symbols != NULL)
+ backtrace_free (state, macho_symbols, macho_symbol_size,
+ error_callback, data);
+ if (sym_view_valid)
+ backtrace_release_view (state, &sym_view, error_callback, data);
+ if (str_view_valid)
+ backtrace_release_view (state, &str_view, error_callback, data);
+ return 0;
+}
+
+/* Return the symbol name and value for an ADDR. */
+
+static void
+macho_syminfo (struct backtrace_state *state, uintptr_t addr,
+ backtrace_syminfo_callback callback,
+ backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+ void *data)
+{
+ struct macho_syminfo_data *sdata;
+ struct macho_symbol *sym;
+
+ sym = NULL;
+ if (!state->threaded)
+ {
+ for (sdata = (struct macho_syminfo_data *) state->syminfo_data;
+ sdata != NULL;
+ sdata = sdata->next)
+ {
+ sym = ((struct macho_symbol *)
+ bsearch (&addr, sdata->symbols, sdata->count,
+ sizeof (struct macho_symbol), macho_symbol_search));
+ if (sym != NULL)
+ break;
+ }
+ }
+ else
+ {
+ struct macho_syminfo_data **pp;
+
+ pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
+ while (1)
+ {
+ sdata = backtrace_atomic_load_pointer (pp);
+ if (sdata == NULL)
+ break;
+
+ sym = ((struct macho_symbol *)
+ bsearch (&addr, sdata->symbols, sdata->count,
+ sizeof (struct macho_symbol), macho_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);
+}
+
+/* Look through a fat file to find the relevant executable. Returns 1
+ on success, 0 on failure (in both cases descriptor is closed). */
+
+static int
+macho_add_fat (struct backtrace_state *state, const char *filename,
+ int descriptor, int swapped, off_t offset,
+ const unsigned char *match_uuid, uintptr_t base_address,
+ int skip_symtab, uint32_t nfat_arch, int is_64,
+ backtrace_error_callback error_callback, void *data,
+ fileline *fileline_fn, int *found_sym)
+{
+ int arch_view_valid;
+ unsigned int cputype;
+ size_t arch_size;
+ struct backtrace_view arch_view;
+ unsigned int i;
+
+ arch_view_valid = 0;
+
+#if defined (__x86_64__)
+ cputype = MACH_O_CPU_TYPE_X86_64;
+#elif defined (__i386__)
+ cputype = MACH_O_CPU_TYPE_X86;
+#elif defined (__aarch64__)
+ cputype = MACH_O_CPU_TYPE_ARM64;
+#elif defined (__arm__)
+ cputype = MACH_O_CPU_TYPE_ARM;
+#elif defined (__ppc__)
+ cputype = MACH_O_CPU_TYPE_PPC;
+#elif defined (__ppc64__)
+ cputype = MACH_O_CPU_TYPE_PPC64;
+#else
+ error_callback (data, "unknown Mach-O architecture", 0);
+ goto fail;
+#endif
+
+ if (is_64)
+ arch_size = sizeof (struct macho_fat_arch_64);
+ else
+ arch_size = sizeof (struct macho_fat_arch);
+
+ if (!backtrace_get_view (state, descriptor, offset,
+ nfat_arch * arch_size,
+ error_callback, data, &arch_view))
+ goto fail;
+
+ for (i = 0; i < nfat_arch; ++i)
+ {
+ uint32_t fcputype;
+ uint64_t foffset;
+
+ if (is_64)
+ {
+ struct macho_fat_arch_64 fat_arch_64;
+
+ memcpy (&fat_arch_64,
+ (const char *) arch_view.data + i * arch_size,
+ arch_size);
+ fcputype = fat_arch_64.cputype;
+ foffset = fat_arch_64.offset;
+ if (swapped)
+ {
+ fcputype = __builtin_bswap32 (fcputype);
+ foffset = __builtin_bswap64 (foffset);
+ }
+ }
+ else
+ {
+ struct macho_fat_arch fat_arch_32;
+
+ memcpy (&fat_arch_32,
+ (const char *) arch_view.data + i * arch_size,
+ arch_size);
+ fcputype = fat_arch_32.cputype;
+ foffset = (uint64_t) fat_arch_32.offset;
+ if (swapped)
+ {
+ fcputype = __builtin_bswap32 (fcputype);
+ foffset = (uint64_t) __builtin_bswap32 ((uint32_t) foffset);
+ }
+ }
+
+ if (fcputype == cputype)
+ {
+ /* FIXME: What about cpusubtype? */
+ backtrace_release_view (state, &arch_view, error_callback, data);
+ return macho_add (state, filename, descriptor, foffset, match_uuid,
+ base_address, skip_symtab, error_callback, data,
+ fileline_fn, found_sym);
+ }
+ }
+
+ error_callback (data, "could not find executable in fat file", 0);
+
+ fail:
+ if (arch_view_valid)
+ backtrace_release_view (state, &arch_view, error_callback, data);
+ if (descriptor != -1)
+ backtrace_close (descriptor, error_callback, data);
+ return 0;
+}
+
+/* Look for the dsym file for FILENAME. This is called if FILENAME
+ does not have debug info or a symbol table. Returns 1 on success,
+ 0 on failure. */
+
+static int
+macho_add_dsym (struct backtrace_state *state, const char *filename,
+ uintptr_t base_address, const unsigned char *uuid,
+ backtrace_error_callback error_callback, void *data,
+ fileline* fileline_fn)
+{
+ const char *p;
+ const char *dirname;
+ char *diralc;
+ size_t dirnamelen;
+ const char *basename;
+ size_t basenamelen;
+ const char *dsymsuffixdir;
+ size_t dsymsuffixdirlen;
+ size_t dsymlen;
+ char *dsym;
+ char *ps;
+ int d;
+ int does_not_exist;
+ int dummy_found_sym;
+
+ diralc = NULL;
+ dirnamelen = 0;
+ dsym = NULL;
+ dsymlen = 0;
+
+ p = strrchr (filename, '/');
+ if (p == NULL)
+ {
+ dirname = ".";
+ dirnamelen = 1;
+ basename = filename;
+ basenamelen = strlen (basename);
+ diralc = NULL;
+ }
+ else
+ {
+ dirnamelen = p - filename;
+ diralc = backtrace_alloc (state, dirnamelen + 1, error_callback, data);
+ if (diralc == NULL)
+ goto fail;
+ memcpy (diralc, filename, dirnamelen);
+ diralc[dirnamelen] = '\0';
+ dirname = diralc;
+ basename = p + 1;
+ basenamelen = strlen (basename);
+ }
+
+ dsymsuffixdir = ".dSYM/Contents/Resources/DWARF/";
+ dsymsuffixdirlen = strlen (dsymsuffixdir);
+
+ dsymlen = (dirnamelen
+ + 1
+ + basenamelen
+ + dsymsuffixdirlen
+ + basenamelen
+ + 1);
+ dsym = backtrace_alloc (state, dsymlen, error_callback, data);
+ if (dsym == NULL)
+ goto fail;
+
+ ps = dsym;
+ memcpy (ps, dirname, dirnamelen);
+ ps += dirnamelen;
+ *ps++ = '/';
+ memcpy (ps, basename, basenamelen);
+ ps += basenamelen;
+ memcpy (ps, dsymsuffixdir, dsymsuffixdirlen);
+ ps += dsymsuffixdirlen;
+ memcpy (ps, basename, basenamelen);
+ ps += basenamelen;
+ *ps = '\0';
+
+ if (diralc != NULL)
+ {
+ backtrace_free (state, diralc, dirnamelen + 1, error_callback, data);
+ diralc = NULL;
+ }
+
+ d = backtrace_open (dsym, error_callback, data, &does_not_exist);
+ if (d < 0)
+ {
+ /* The file does not exist, so we can't read the debug info.
+ Just return success. */
+ backtrace_free (state, dsym, dsymlen, error_callback, data);
+ return 1;
+ }
+
+ if (!macho_add (state, dsym, d, 0, uuid, base_address, 1,
+ error_callback, data, fileline_fn, &dummy_found_sym))
+ goto fail;
+
+ backtrace_free (state, dsym, dsymlen, error_callback, data);
+
+ return 1;
+
+ fail:
+ if (dsym != NULL)
+ backtrace_free (state, dsym, dsymlen, error_callback, data);
+ if (diralc != NULL)
+ backtrace_free (state, diralc, dirnamelen, error_callback, data);
+ return 0;
+}
+
+/* Add the backtrace data for a Macho-O file. Returns 1 on success, 0
+ on failure (in both cases descriptor is closed).
+
+ FILENAME: the name of the executable.
+ DESCRIPTOR: an open descriptor for the executable, closed here.
+ OFFSET: the offset within the file of this executable, for fat files.
+ MATCH_UUID: if not NULL, UUID that must match.
+ BASE_ADDRESS: the load address of the executable.
+ SKIP_SYMTAB: if non-zero, ignore the symbol table; used for dSYM files.
+ FILELINE_FN: set to the fileline function, by backtrace_dwarf_add.
+ FOUND_SYM: set to non-zero if we found the symbol table.
+*/
+
+static int
+macho_add (struct backtrace_state *state, const char *filename, int descriptor,
+ off_t offset, const unsigned char *match_uuid,
+ uintptr_t base_address, int skip_symtab,
+ backtrace_error_callback error_callback, void *data,
+ fileline *fileline_fn, int *found_sym)
+{
+ struct backtrace_view header_view;
+ struct macho_header_32 header;
+ off_t hdroffset;
+ int is_64;
+ struct backtrace_view cmds_view;
+ int cmds_view_valid;
+ struct dwarf_sections dwarf_sections;
+ int have_dwarf;
+ unsigned char uuid[MACH_O_UUID_LEN];
+ int have_uuid;
+ size_t cmdoffset;
+ unsigned int i;
+
+ *found_sym = 0;
+
+ cmds_view_valid = 0;
+
+ /* The 32-bit and 64-bit file headers start out the same, so we can
+ just always read the 32-bit version. A fat header is shorter but
+ it will always be followed by data, so it's OK to read extra. */
+
+ if (!backtrace_get_view (state, descriptor, offset,
+ sizeof (struct macho_header_32),
+ error_callback, data, &header_view))
+ goto fail;
+
+ memcpy (&header, header_view.data, sizeof header);
+
+ backtrace_release_view (state, &header_view, error_callback, data);
+
+ switch (header.magic)
+ {
+ case MACH_O_MH_MAGIC_32:
+ is_64 = 0;
+ hdroffset = offset + sizeof (struct macho_header_32);
+ break;
+ case MACH_O_MH_MAGIC_64:
+ is_64 = 1;
+ hdroffset = offset + sizeof (struct macho_header_64);
+ break;
+ case MACH_O_MH_MAGIC_FAT:
+ case MACH_O_MH_MAGIC_FAT_64:
+ {
+ struct macho_header_fat fat_header;
+
+ hdroffset = offset + sizeof (struct macho_header_fat);
+ memcpy (&fat_header, &header, sizeof fat_header);
+ return macho_add_fat (state, filename, descriptor, 0, hdroffset,
+ match_uuid, base_address, skip_symtab,
+ fat_header.nfat_arch,
+ header.magic == MACH_O_MH_MAGIC_FAT_64,
+ error_callback, data, fileline_fn, found_sym);
+ }
+ case MACH_O_MH_CIGAM_FAT:
+ case MACH_O_MH_CIGAM_FAT_64:
+ {
+ struct macho_header_fat fat_header;
+ uint32_t nfat_arch;
+
+ hdroffset = offset + sizeof (struct macho_header_fat);
+ memcpy (&fat_header, &header, sizeof fat_header);
+ nfat_arch = __builtin_bswap32 (fat_header.nfat_arch);
+ return macho_add_fat (state, filename, descriptor, 1, hdroffset,
+ match_uuid, base_address, skip_symtab,
+ nfat_arch,
+ header.magic == MACH_O_MH_CIGAM_FAT_64,
+ error_callback, data, fileline_fn, found_sym);
+ }
+ default:
+ error_callback (data, "executable file is not in Mach-O format", 0);
+ goto fail;
+ }
+
+ switch (header.filetype)
+ {
+ case MACH_O_MH_EXECUTE:
+ case MACH_O_MH_DYLIB:
+ case MACH_O_MH_DSYM:
+ break;
+ default:
+ error_callback (data, "executable file is not an executable", 0);
+ goto fail;
+ }
+
+ if (!backtrace_get_view (state, descriptor, hdroffset, header.sizeofcmds,
+ error_callback, data, &cmds_view))
+ goto fail;
+ cmds_view_valid = 1;
+
+ memset (&dwarf_sections, 0, sizeof dwarf_sections);
+ have_dwarf = 0;
+ memset (&uuid, 0, sizeof uuid);
+ have_uuid = 0;
+
+ cmdoffset = 0;
+ for (i = 0; i < header.ncmds; ++i)
+ {
+ const char *pcmd;
+ struct macho_load_command load_command;
+
+ if (cmdoffset + sizeof load_command > header.sizeofcmds)
+ break;
+
+ pcmd = (const char *) cmds_view.data + cmdoffset;
+ memcpy (&load_command, pcmd, sizeof load_command);
+
+ switch (load_command.cmd)
+ {
+ case MACH_O_LC_SEGMENT:
+ {
+ struct macho_segment_command segcmd;
+
+ memcpy (&segcmd, pcmd, sizeof segcmd);
+ if (memcmp (segcmd.segname,
+ "__DWARF\0\0\0\0\0\0\0\0\0",
+ MACH_O_NAMELEN) == 0)
+ {
+ if (!macho_add_dwarf_segment (state, descriptor, offset,
+ load_command.cmd,
+ pcmd + sizeof segcmd,
+ (load_command.cmdsize
+ - sizeof segcmd),
+ segcmd.nsects, error_callback,
+ data, &dwarf_sections))
+ goto fail;
+ have_dwarf = 1;
+ }
+ }
+ break;
+
+ case MACH_O_LC_SEGMENT_64:
+ {
+ struct macho_segment_64_command segcmd;
+
+ memcpy (&segcmd, pcmd, sizeof segcmd);
+ if (memcmp (segcmd.segname,
+ "__DWARF\0\0\0\0\0\0\0\0\0",
+ MACH_O_NAMELEN) == 0)
+ {
+ if (!macho_add_dwarf_segment (state, descriptor, offset,
+ load_command.cmd,
+ pcmd + sizeof segcmd,
+ (load_command.cmdsize
+ - sizeof segcmd),
+ segcmd.nsects, error_callback,
+ data, &dwarf_sections))
+ goto fail;
+ have_dwarf = 1;
+ }
+ }
+ break;
+
+ case MACH_O_LC_SYMTAB:
+ if (!skip_symtab)
+ {
+ struct macho_symtab_command symcmd;
+
+ memcpy (&symcmd, pcmd, sizeof symcmd);
+ if (!macho_add_symtab (state, descriptor, base_address, is_64,
+ offset + symcmd.symoff, symcmd.nsyms,
+ offset + symcmd.stroff, symcmd.strsize,
+ error_callback, data))
+ goto fail;
+
+ *found_sym = 1;
+ }
+ break;
+
+ case MACH_O_LC_UUID:
+ {
+ struct macho_uuid_command uuidcmd;
+
+ memcpy (&uuidcmd, pcmd, sizeof uuidcmd);
+ memcpy (&uuid[0], &uuidcmd.uuid[0], MACH_O_UUID_LEN);
+ have_uuid = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ cmdoffset += load_command.cmdsize;
+ }
+
+ if (!backtrace_close (descriptor, error_callback, data))
+ goto fail;
+ descriptor = -1;
+
+ backtrace_release_view (state, &cmds_view, error_callback, data);
+ cmds_view_valid = 0;
+
+ if (match_uuid != NULL)
+ {
+ /* If we don't have a UUID, or it doesn't match, just ignore
+ this file. */
+ if (!have_uuid
+ || memcmp (match_uuid, &uuid[0], MACH_O_UUID_LEN) != 0)
+ return 1;
+ }
+
+ if (have_dwarf)
+ {
+ int is_big_endian;
+
+ is_big_endian = 0;
+#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ is_big_endian = 1;
+#endif
+#endif
+
+ if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
+ is_big_endian, NULL, error_callback, data,
+ fileline_fn, NULL))
+ goto fail;
+ }
+
+ if (!have_dwarf && have_uuid)
+ {
+ if (!macho_add_dsym (state, filename, base_address, &uuid[0],
+ error_callback, data, fileline_fn))
+ goto fail;
+ }
+
+ return 1;
+
+ fail:
+ if (cmds_view_valid)
+ backtrace_release_view (state, &cmds_view, error_callback, data);
+ if (descriptor != -1)
+ backtrace_close (descriptor, error_callback, data);
+ return 0;
+}
+
+#ifdef HAVE_MACH_O_DYLD_H
+
+/* Initialize the backtrace data we need from a Mach-O executable
+ using the dyld support functions. This closes descriptor. */
+
+int
+backtrace_initialize (struct backtrace_state *state, const char *filename,
+ int descriptor, backtrace_error_callback error_callback,
+ void *data, fileline *fileline_fn)
+{
+ uint32_t c;
+ uint32_t i;
+ int closed_descriptor;
+ int found_sym;
+ fileline macho_fileline_fn;
+
+ closed_descriptor = 0;
+ found_sym = 0;
+ macho_fileline_fn = macho_nodebug;
+
+ c = _dyld_image_count ();
+ for (i = 0; i < c; ++i)
+ {
+ uintptr_t base_address;
+ const char *name;
+ int d;
+ fileline mff;
+ int mfs;
+
+ name = _dyld_get_image_name (i);
+ if (name == NULL)
+ continue;
+
+ if (strcmp (name, filename) == 0 && !closed_descriptor)
+ {
+ d = descriptor;
+ closed_descriptor = 1;
+ }
+ else
+ {
+ int does_not_exist;
+
+ d = backtrace_open (name, error_callback, data, &does_not_exist);
+ if (d < 0)
+ continue;
+ }
+
+ base_address = _dyld_get_image_vmaddr_slide (i);
+
+ mff = macho_nodebug;
+ if (!macho_add (state, name, d, 0, NULL, base_address, 0,
+ error_callback, data, &mff, &mfs))
+ continue;
+
+ if (mff != macho_nodebug)
+ macho_fileline_fn = mff;
+ if (mfs)
+ found_sym = 1;
+ }
+
+ if (!closed_descriptor)
+ backtrace_close (descriptor, error_callback, data);
+
+ if (!state->threaded)
+ {
+ if (found_sym)
+ state->syminfo_fn = macho_syminfo;
+ else if (state->syminfo_fn == NULL)
+ state->syminfo_fn = macho_nosyms;
+ }
+ else
+ {
+ if (found_sym)
+ backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo);
+ else
+ (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
+ macho_nosyms);
+ }
+
+ if (!state->threaded)
+ *fileline_fn = state->fileline_fn;
+ else
+ *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
+
+ if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)
+ *fileline_fn = macho_fileline_fn;
+
+ return 1;
+}
+
+#else /* !defined (HAVE_MACH_O_DYLD_H) */
+
+/* Initialize the backtrace data we need from a Mach-O executable
+ without using the dyld support functions. This closes
+ descriptor. */
+
+int
+backtrace_initialize (struct backtrace_state *state, const char *filename,
+ int descriptor, backtrace_error_callback error_callback,
+ void *data, fileline *fileline_fn)
+{
+ fileline macho_fileline_fn;
+ int found_sym;
+
+ macho_fileline_fn = macho_nodebug;
+ if (!macho_add (state, filename, descriptor, 0, NULL, 0, 0,
+ error_callback, data, &macho_fileline_fn, &found_sym))
+ return 0;
+
+ if (!state->threaded)
+ {
+ if (found_sym)
+ state->syminfo_fn = macho_syminfo;
+ else if (state->syminfo_fn == NULL)
+ state->syminfo_fn = macho_nosyms;
+ }
+ else
+ {
+ if (found_sym)
+ backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo);
+ else
+ (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
+ macho_nosyms);
+ }
+
+ if (!state->threaded)
+ *fileline_fn = state->fileline_fn;
+ else
+ *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
+
+ if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)
+ *fileline_fn = macho_fileline_fn;
+
+ return 1;
+}
+
+#endif /* !defined (HAVE_MACH_O_DYLD_H) */
diff --git a/library/cpp/CMakeLists.darwin-x86_64.txt b/library/cpp/CMakeLists.darwin-x86_64.txt
index 772027a342..0f393b2039 100644
--- a/library/cpp/CMakeLists.darwin-x86_64.txt
+++ b/library/cpp/CMakeLists.darwin-x86_64.txt
@@ -34,6 +34,7 @@ add_subdirectory(diff)
add_subdirectory(digest)
add_subdirectory(disjoint_sets)
add_subdirectory(dns)
+add_subdirectory(dwarf_backtrace)
add_subdirectory(enumbitset)
add_subdirectory(execprofile)
add_subdirectory(getopt)
diff --git a/library/cpp/CMakeLists.linux-aarch64.txt b/library/cpp/CMakeLists.linux-aarch64.txt
index cd50b0e3a4..cf47314f07 100644
--- a/library/cpp/CMakeLists.linux-aarch64.txt
+++ b/library/cpp/CMakeLists.linux-aarch64.txt
@@ -33,6 +33,7 @@ add_subdirectory(diff)
add_subdirectory(digest)
add_subdirectory(disjoint_sets)
add_subdirectory(dns)
+add_subdirectory(dwarf_backtrace)
add_subdirectory(enumbitset)
add_subdirectory(execprofile)
add_subdirectory(getopt)
diff --git a/library/cpp/CMakeLists.linux-x86_64.txt b/library/cpp/CMakeLists.linux-x86_64.txt
index 772027a342..0f393b2039 100644
--- a/library/cpp/CMakeLists.linux-x86_64.txt
+++ b/library/cpp/CMakeLists.linux-x86_64.txt
@@ -34,6 +34,7 @@ add_subdirectory(diff)
add_subdirectory(digest)
add_subdirectory(disjoint_sets)
add_subdirectory(dns)
+add_subdirectory(dwarf_backtrace)
add_subdirectory(enumbitset)
add_subdirectory(execprofile)
add_subdirectory(getopt)
diff --git a/library/cpp/dwarf_backtrace/CMakeLists.darwin-x86_64.txt b/library/cpp/dwarf_backtrace/CMakeLists.darwin-x86_64.txt
new file mode 100644
index 0000000000..3fb6a8f4b9
--- /dev/null
+++ b/library/cpp/dwarf_backtrace/CMakeLists.darwin-x86_64.txt
@@ -0,0 +1,18 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(library-cpp-dwarf_backtrace)
+target_link_libraries(library-cpp-dwarf_backtrace PUBLIC
+ contrib-libs-cxxsupp
+ yutil
+ contrib-libs-backtrace
+)
+target_sources(library-cpp-dwarf_backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/library/cpp/dwarf_backtrace/backtrace.cpp
+)
diff --git a/library/cpp/dwarf_backtrace/CMakeLists.linux-aarch64.txt b/library/cpp/dwarf_backtrace/CMakeLists.linux-aarch64.txt
new file mode 100644
index 0000000000..fc0672a08c
--- /dev/null
+++ b/library/cpp/dwarf_backtrace/CMakeLists.linux-aarch64.txt
@@ -0,0 +1,19 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(library-cpp-dwarf_backtrace)
+target_link_libraries(library-cpp-dwarf_backtrace PUBLIC
+ contrib-libs-linux-headers
+ contrib-libs-cxxsupp
+ yutil
+ contrib-libs-backtrace
+)
+target_sources(library-cpp-dwarf_backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/library/cpp/dwarf_backtrace/backtrace.cpp
+)
diff --git a/library/cpp/dwarf_backtrace/CMakeLists.linux-x86_64.txt b/library/cpp/dwarf_backtrace/CMakeLists.linux-x86_64.txt
new file mode 100644
index 0000000000..fc0672a08c
--- /dev/null
+++ b/library/cpp/dwarf_backtrace/CMakeLists.linux-x86_64.txt
@@ -0,0 +1,19 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(library-cpp-dwarf_backtrace)
+target_link_libraries(library-cpp-dwarf_backtrace PUBLIC
+ contrib-libs-linux-headers
+ contrib-libs-cxxsupp
+ yutil
+ contrib-libs-backtrace
+)
+target_sources(library-cpp-dwarf_backtrace PRIVATE
+ ${CMAKE_SOURCE_DIR}/library/cpp/dwarf_backtrace/backtrace.cpp
+)
diff --git a/library/cpp/dwarf_backtrace/CMakeLists.txt b/library/cpp/dwarf_backtrace/CMakeLists.txt
new file mode 100644
index 0000000000..606ff46b4b
--- /dev/null
+++ b/library/cpp/dwarf_backtrace/CMakeLists.txt
@@ -0,0 +1,15 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA)
+ include(CMakeLists.linux-aarch64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ include(CMakeLists.darwin-x86_64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA)
+ include(CMakeLists.linux-x86_64.txt)
+endif()
diff --git a/library/cpp/dwarf_backtrace/registry/set_format_backtrace.cpp b/library/cpp/dwarf_backtrace/registry/set_format_backtrace.cpp
new file mode 100644
index 0000000000..b3e6c3f8d8
--- /dev/null
+++ b/library/cpp/dwarf_backtrace/registry/set_format_backtrace.cpp
@@ -0,0 +1,18 @@
+#include <library/cpp/dwarf_backtrace/backtrace.h>
+#include <util/stream/format.h>
+#include <util/system/backtrace.h>
+
+namespace {
+ void PrintDwarfBacktrace(IOutputStream* out, void* const* backtrace, size_t size) {
+ auto error = NDwarf::ResolveBacktrace({backtrace, size}, [out](const NDwarf::TLineInfo& info) {
+ *out << info.FileName << ":" << info.Line << ":" << info.Col
+ << " in " << info.FunctionName << " (" << Hex(info.Address, HF_ADDX) << ')' << Endl;
+ return NDwarf::EResolving::Continue;
+ });
+ if (error) {
+ *out << "***Cannot get backtrace: " << error->Message << " (" << error->Code << ")***" << Endl;
+ }
+ }
+
+ [[maybe_unused]] auto _ = SetFormatBackTraceFn(&PrintDwarfBacktrace);
+}
diff --git a/library/cpp/dwarf_backtrace/registry/ya.make b/library/cpp/dwarf_backtrace/registry/ya.make
new file mode 100644
index 0000000000..6770671b13
--- /dev/null
+++ b/library/cpp/dwarf_backtrace/registry/ya.make
@@ -0,0 +1,15 @@
+LIBRARY()
+
+IF(OS_LINUX)
+
+ PEERDIR(
+ library/cpp/dwarf_backtrace
+ )
+
+ SRCS(
+ GLOBAL set_format_backtrace.cpp
+ )
+
+ENDIF()
+
+END()
diff --git a/library/cpp/dwarf_backtrace/ut/backtrace_ut.cpp b/library/cpp/dwarf_backtrace/ut/backtrace_ut.cpp
new file mode 100644
index 0000000000..dc271ad513
--- /dev/null
+++ b/library/cpp/dwarf_backtrace/ut/backtrace_ut.cpp
@@ -0,0 +1,55 @@
+#include <library/cpp/testing/gtest/gtest.h>
+#include <util/system/compiler.h>
+#include <util/system/backtrace.h>
+#include <util/stream/str.h>
+
+Y_FORCE_INLINE
+TString InlinedFunction_866a4407b28483588033f95add111d() {
+ TStringStream out;
+ FormatBackTrace(&out);
+ return out.Str();
+}
+
+Y_NO_INLINE
+TString Function_3e15a2d04c8613ae64833c5407dd98() {
+ return InlinedFunction_866a4407b28483588033f95add111d();
+}
+
+Y_NO_INLINE
+TString NotInlinedFunction_3c7dbf1e3b2b71819241cb5ad2b142() {
+ return Function_3e15a2d04c8613ae64833c5407dd98();
+}
+
+namespace NTestNamespace {
+ Y_NO_INLINE
+ TString NamespacedFunction() {
+ return InlinedFunction_866a4407b28483588033f95add111d();
+ }
+}
+
+using namespace ::testing;
+TEST(dwarf_backtrace_should, handle_inlines) {
+ const TString backtrace = NotInlinedFunction_3c7dbf1e3b2b71819241cb5ad2b142();
+
+ EXPECT_THAT(
+ backtrace,
+ HasSubstr("InlinedFunction_866a4407b28483588033f95add111d")
+ );
+
+ EXPECT_THAT(
+ backtrace,
+ HasSubstr("backtrace_ut.cpp:9:0 in InlinedFunction")
+ );
+
+ EXPECT_THAT(
+ backtrace,
+ HasSubstr("Function_3e15a2d04c8613ae64833c5407dd98")
+ );
+}
+
+TEST(dwarf_backtrace_should, handle_namespaces) {
+ EXPECT_THAT(
+ NTestNamespace::NamespacedFunction(),
+ HasSubstr("NTestNamespace::NamespacedFunction")
+ );
+}
diff --git a/library/cpp/dwarf_backtrace/ut/ya.make b/library/cpp/dwarf_backtrace/ut/ya.make
new file mode 100644
index 0000000000..9f23256483
--- /dev/null
+++ b/library/cpp/dwarf_backtrace/ut/ya.make
@@ -0,0 +1,12 @@
+GTEST()
+
+PEERDIR(
+ library/cpp/dwarf_backtrace
+ library/cpp/dwarf_backtrace/registry
+)
+
+SRCS(
+ backtrace_ut.cpp
+)
+
+END()
diff --git a/ydb/core/base/CMakeLists.darwin-x86_64.txt b/ydb/core/base/CMakeLists.darwin-x86_64.txt
index d9cc205a3c..680bf15851 100644
--- a/ydb/core/base/CMakeLists.darwin-x86_64.txt
+++ b/ydb/core/base/CMakeLists.darwin-x86_64.txt
@@ -39,10 +39,12 @@ target_link_libraries(ydb-core-base PUBLIC
api-protos-out
library-yql-minikql
cpp-deprecated-atomic
+ library-cpp-dwarf_backtrace
)
target_sources(ydb-core-base PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/base/actor_activity_names.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/appdata.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/base/backtrace.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_lookup.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_publish.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_replica.cpp
diff --git a/ydb/core/base/CMakeLists.linux-aarch64.txt b/ydb/core/base/CMakeLists.linux-aarch64.txt
index 7f8a6c28b8..c4665d5a9d 100644
--- a/ydb/core/base/CMakeLists.linux-aarch64.txt
+++ b/ydb/core/base/CMakeLists.linux-aarch64.txt
@@ -40,10 +40,12 @@ target_link_libraries(ydb-core-base PUBLIC
api-protos-out
library-yql-minikql
cpp-deprecated-atomic
+ library-cpp-dwarf_backtrace
)
target_sources(ydb-core-base PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/base/actor_activity_names.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/appdata.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/base/backtrace.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_lookup.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_publish.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_replica.cpp
diff --git a/ydb/core/base/CMakeLists.linux-x86_64.txt b/ydb/core/base/CMakeLists.linux-x86_64.txt
index 7f8a6c28b8..c4665d5a9d 100644
--- a/ydb/core/base/CMakeLists.linux-x86_64.txt
+++ b/ydb/core/base/CMakeLists.linux-x86_64.txt
@@ -40,10 +40,12 @@ target_link_libraries(ydb-core-base PUBLIC
api-protos-out
library-yql-minikql
cpp-deprecated-atomic
+ library-cpp-dwarf_backtrace
)
target_sources(ydb-core-base PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/base/actor_activity_names.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/appdata.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/base/backtrace.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_lookup.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_publish.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_replica.cpp
diff --git a/ydb/core/base/CMakeLists.windows-x86_64.txt b/ydb/core/base/CMakeLists.windows-x86_64.txt
index d9cc205a3c..85d791fe9f 100644
--- a/ydb/core/base/CMakeLists.windows-x86_64.txt
+++ b/ydb/core/base/CMakeLists.windows-x86_64.txt
@@ -43,6 +43,7 @@ target_link_libraries(ydb-core-base PUBLIC
target_sources(ydb-core-base PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/base/actor_activity_names.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/appdata.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/base/backtrace.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_lookup.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_publish.cpp
${CMAKE_SOURCE_DIR}/ydb/core/base/board_replica.cpp
diff --git a/ydb/core/base/backtrace.cpp b/ydb/core/base/backtrace.cpp
new file mode 100644
index 0000000000..906400d54d
--- /dev/null
+++ b/ydb/core/base/backtrace.cpp
@@ -0,0 +1,53 @@
+#include "backtrace.h"
+
+#include <util/system/backtrace.h>
+
+#if defined(__linux__) || defined(__APPLE__)
+#include <library/cpp/dwarf_backtrace/backtrace.h>
+#include <util/stream/format.h>
+#endif
+
+namespace NKikimr {
+
+#if defined(__linux__) || defined(__APPLE__)
+
+namespace {
+
+void FormatBacktraceDwarf(IOutputStream* out, void* const* backtrace, size_t backtraceSize) {
+ size_t frameIndex = 0;
+ bool allFramesUnknown = true;
+
+ auto error = NDwarf::ResolveBacktrace({backtrace, backtraceSize}, [out, &frameIndex, &allFramesUnknown](const NDwarf::TLineInfo& info) {
+ const TString & fileName = info.FileName == "???" ? "??" : info.FileName;
+ if (fileName != "??") {
+ allFramesUnknown = false;
+ }
+
+ const TString & functionName = info.FunctionName == "???" ? "??" : info.FunctionName;
+ *out << frameIndex << ". " << fileName << ":" << info.Line << ": " << functionName << " @ " << Hex(info.Address, HF_ADDX) << Endl;
+ ++frameIndex;
+
+ return NDwarf::EResolving::Continue;
+ });
+
+ /// Fallback to default backtrace format
+ if (error || allFramesUnknown) {
+ FormatBackTrace(out, backtrace, backtraceSize);
+ }
+}
+
+}
+
+void EnableYDBBacktraceFormat() {
+ SetFormatBackTraceFn(FormatBacktraceDwarf);
+}
+
+#else
+
+void EnableYDBBacktraceFormat() {
+ SetFormatBackTraceFn(FormatBackTrace);
+}
+
+#endif
+
+}
diff --git a/ydb/core/base/backtrace.h b/ydb/core/base/backtrace.h
new file mode 100644
index 0000000000..e1ebdc0631
--- /dev/null
+++ b/ydb/core/base/backtrace.h
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace NKikimr {
+
+void EnableYDBBacktraceFormat();
+
+}
diff --git a/ydb/core/base/ya.make b/ydb/core/base/ya.make
index a9c5c9934f..f96c27d0a3 100644
--- a/ydb/core/base/ya.make
+++ b/ydb/core/base/ya.make
@@ -4,6 +4,8 @@ SRCS(
actor_activity_names.cpp
appdata.h
appdata.cpp
+ backtrace.h
+ backtrace.cpp
board_lookup.cpp
board_publish.cpp
board_replica.cpp
@@ -99,6 +101,12 @@ PEERDIR(
library/cpp/deprecated/atomic
)
+IF (NOT OS_WINDOWS)
+PEERDIR(
+ library/cpp/dwarf_backtrace
+)
+ENDIF()
+
END()
RECURSE_FOR_TESTS(
diff --git a/ydb/core/driver_lib/run/main.cpp b/ydb/core/driver_lib/run/main.cpp
index e0d093c901..e7a6066739 100644
--- a/ydb/core/driver_lib/run/main.cpp
+++ b/ydb/core/driver_lib/run/main.cpp
@@ -20,6 +20,9 @@
// compatibility info
#include <ydb/core/driver_lib/version/version.h>
+// backtrace formatting
+#include <ydb/core/base/backtrace.h>
+
#ifndef _win_
#include <sys/mman.h>
#endif
@@ -72,6 +75,8 @@ int MainRun(const TKikimrRunConfig& runConfig, std::shared_ptr<TModuleFactories>
using namespace NLastGetopt;
using TDriverModeParser = TCliCommands<EDriverMode>;
+ EnableYDBBacktraceFormat();
+
NKikimrConfig::TAppConfig appConfig;
TCommandConfig cmdConf;
TKikimrRunConfig runConfig(appConfig);
diff --git a/ydb/core/kqp/ut/common/kqp_ut_common.cpp b/ydb/core/kqp/ut/common/kqp_ut_common.cpp
index e880587900..ae5a996481 100644
--- a/ydb/core/kqp/ut/common/kqp_ut_common.cpp
+++ b/ydb/core/kqp/ut/common/kqp_ut_common.cpp
@@ -1,5 +1,6 @@
#include "kqp_ut_common.h"
+#include <ydb/core/base/backtrace.h>
#include <ydb/core/tx/schemeshard/schemeshard.h>
#include <ydb/core/kqp/counters/kqp_counters.h>
#include <ydb/core/kqp/provider/yql_kikimr_results.h>
@@ -87,7 +88,7 @@ TVector<NKikimrKqp::TKqpSetting> SyntaxV1Settings() {
}
TKikimrRunner::TKikimrRunner(const TKikimrSettings& settings) {
- // EnableKikimrBacktraceFormat(); // Very slow, enable only when required locally
+ EnableYDBBacktraceFormat();
auto mbusPort = PortManager.GetPort();
auto grpcPort = PortManager.GetPort();