19 Commits

Author SHA1 Message Date
Alastair Houghton 80746bdd0a Disable this library for Swift 5.9 and above. (#68) 2023-09-05 06:47:22 -07:00
Yim Lee 2cfddd6892 Update CI (#66)
- Add docker-compose file for Swift 5.8 and 5.9
- Update docker image for Swift 5.7
- Update `main` to Ubuntu 22.04
2023-04-04 14:31:55 -07:00
Yim Lee e9cffd432c Add .spi.yml for Swift Package Index DocC support (#63) 2022-12-05 11:35:05 -08:00
Yim Lee 9f43812fb5 Merge pull request #62 from yim-lee/docc
DocC setup
2022-08-11 10:43:55 -07:00
Yim Lee 9cc8c17785 Fix formatting 2022-08-10 21:56:25 -07:00
Yim Lee a0bfe70c1b Add manifest for Swift 5.0 2022-08-10 21:55:36 -07:00
Yim Lee 1809e7963b DocC setup 2022-08-10 21:53:01 -07:00
Johannes Weiss f25620d5d0 Merge pull request #60 from tomerd/fix/flush
flush stderr after printing backtraces
2022-06-14 20:32:13 +01:00
tom doron 3bd448574b flush stderr after printing back traces
motivation: make sure stderr buffered is printed out before program exits

changes: explicitly call fflush after writing the backtraces
2022-06-13 21:05:40 -07:00
tomer doron c085164685 update vendored copy of libbacktrace (#59)
motivation: catch up to fixes and improvments in underlying library

changes:
* vendor latest version of libbacktrace
* update vendoring script to exclude some new files that are not needed
2022-06-09 11:16:22 -07:00
tomer doron baf9597d12 trap SIGSEGV, SIGBUS and SIGFPE by default, in addition to SIGILL (#58)
motivation: print crash trace on segmentation faults and other common failures beyond illegal instructions

changes:
* include SIGSEGV, SIGBUS and SIGFPE in the default signals trapped
* update and improve tests
2022-06-08 09:06:33 -07:00
Konrad `ktoso` Malawski 7ba397e50d Merge pull request #57 from Fabio1988/patch-1
exit after printing stacktrace #51
2022-04-06 10:45:57 +09:00
Fabio1988 ad485ae151 exit after printing stacktrace #51 2022-03-17 12:17:02 +01:00
tomer doron 662e436989 ci update (#56)
motivation: 5.6 is out

changes:
* use release version of 5.6
* add docker setup for 5.7 (using nightly for now)
2022-03-16 21:15:06 -07:00
Konrad `ktoso` Malawski 923624a26e Merge pull request #53 from swift-server/tomerd-patch-2
update CI setup with new versions of swift
2021-09-23 06:03:22 +09:00
tomer doron e2621e2fa1 Create docker-compose.2004.main.yaml
* add ci setup for nightly toolchain
2021-09-22 12:02:54 -07:00
tomer doron ea4824d488 Update Dockerfile
address jazzy install issues on older ubuntu versions
2021-09-22 12:00:46 -07:00
tomer doron f1db8bf93d update CI setup with new versions of swift
motivation: 5.5 release is available

changes: 
* add docker CI setup to for 5.5
2021-09-22 11:56:43 -07:00
tomer doron 99a6c79fc5 Update README.md (#50)
motivation: highlight the background for this library and incourage use via service-lifecycle 

changes: update readme to reflect these ideas
2021-07-28 16:13:56 -07:00
42 changed files with 4546 additions and 972 deletions
+4
View File
@@ -0,0 +1,4 @@
version: 1
builder:
configs:
- documentation_targets: [Backtrace]
+6 -4
View File
@@ -1,4 +1,4 @@
// swift-tools-version:5.0
// swift-tools-version:5.6
import PackageDescription
@@ -10,14 +10,16 @@ let package = Package(
targets: ["Backtrace"]
),
],
dependencies: [],
dependencies: [
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
],
targets: [
.target(name: "Backtrace",
dependencies: ["CBacktrace"]),
.target(name: "CBacktrace",
dependencies: []),
.target(name: "Sample",
dependencies: ["Backtrace"]),
.executableTarget(name: "Sample",
dependencies: ["Backtrace"]),
.testTarget(name: "BacktraceTests",
dependencies: ["Backtrace"]),
]
+24
View File
@@ -0,0 +1,24 @@
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "swift-backtrace",
products: [
.library(
name: "Backtrace",
targets: ["Backtrace"]
),
],
dependencies: [],
targets: [
.target(name: "Backtrace",
dependencies: ["CBacktrace"]),
.target(name: "CBacktrace",
dependencies: []),
.target(name: "Sample",
dependencies: ["Backtrace"]),
.testTarget(name: "BacktraceTests",
dependencies: ["Backtrace"]),
]
)
+24
View File
@@ -0,0 +1,24 @@
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "swift-backtrace",
products: [
.library(
name: "Backtrace",
targets: ["Backtrace"]
),
],
dependencies: [],
targets: [
.target(name: "Backtrace",
dependencies: ["CBacktrace"]),
.target(name: "CBacktrace",
dependencies: []),
.target(name: "Sample",
dependencies: ["Backtrace"]),
.testTarget(name: "BacktraceTests",
dependencies: ["Backtrace"]),
]
)
+24
View File
@@ -0,0 +1,24 @@
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "swift-backtrace",
products: [
.library(
name: "Backtrace",
targets: ["Backtrace"]
),
],
dependencies: [],
targets: [
.target(name: "Backtrace",
dependencies: ["CBacktrace"]),
.target(name: "CBacktrace",
dependencies: []),
.target(name: "Sample",
dependencies: ["Backtrace"]),
.testTarget(name: "BacktraceTests",
dependencies: ["Backtrace"]),
]
)
+24
View File
@@ -0,0 +1,24 @@
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "swift-backtrace",
products: [
.library(
name: "Backtrace",
targets: ["Backtrace"]
),
],
dependencies: [],
targets: [
.target(name: "Backtrace",
dependencies: ["CBacktrace"]),
.target(name: "CBacktrace",
dependencies: []),
.target(name: "Sample",
dependencies: ["Backtrace"]),
.testTarget(name: "BacktraceTests",
dependencies: ["Backtrace"]),
]
)
+24
View File
@@ -0,0 +1,24 @@
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "swift-backtrace",
products: [
.library(
name: "Backtrace",
targets: ["Backtrace"]
),
],
dependencies: [],
targets: [
.target(name: "Backtrace",
dependencies: ["CBacktrace"]),
.target(name: "CBacktrace",
dependencies: []),
.target(name: "Sample",
dependencies: ["Backtrace"]),
.testTarget(name: "BacktraceTests",
dependencies: ["Backtrace"]),
]
)
+24
View File
@@ -0,0 +1,24 @@
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "swift-backtrace",
products: [
.library(
name: "Backtrace",
targets: ["Backtrace"]
),
],
dependencies: [],
targets: [
.target(name: "Backtrace",
dependencies: ["CBacktrace"]),
.target(name: "CBacktrace",
dependencies: []),
.target(name: "Sample",
dependencies: ["Backtrace"]),
.testTarget(name: "BacktraceTests",
dependencies: ["Backtrace"]),
]
)
+6
View File
@@ -2,8 +2,14 @@
This Swift package provides support for automatically printing crash backtraces of Swift programs.
The library is designed to fill a gap in backtraces support for Swift on non-Darwin platforms.
When this gap is closed at the language runtime level, this library will become redundant and be deprecated.
## Usage
**Note**: You do not need this library on Linux as of Swift 5.9, which has
built-in backtracing support.
Add `https://github.com/swift-server/swift-backtrace.git` as a dependency in your `Package.swift`.
### Crash backtraces
+24 -4
View File
@@ -2,7 +2,7 @@
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) 2019-2020 Apple Inc. and the SwiftLinuxBacktrace project authors
// Copyright (c) 2019-2022 Apple Inc. and the SwiftLinuxBacktrace project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
@@ -12,7 +12,21 @@
//
//===----------------------------------------------------------------------===//
#if os(Linux)
// Swift 5.9 has its own built-in backtracing support in the runtime;
// we don't want to activate this library if we're using 5.9 or above.
#if swift(>=5.9) && !os(Windows)
public enum Backtrace {
@available(*, deprecated, message: "This is no longer needed in Swift 5.9")
public static func install() {}
@available(*, deprecated, message: "This is no longer needed in Swift 5.9")
public static func install(signals: [CInt]) {}
@available(*, deprecated, message: "This method will be removed in the next major version.")
public static func print() {}
}
#elseif os(Linux)
import CBacktrace
import Glibc
@@ -64,12 +78,13 @@ private let errorCallback: CBacktraceErrorCallback? = {
private func printBacktrace(signal: CInt) {
_ = fputs("Received signal \(signal). Backtrace:\n", stderr)
backtrace_full(state, /* skip */ 0, fullCallback, errorCallback, nil)
fflush(stderr)
}
public enum Backtrace {
/// Install the backtrace handler on `SIGILL`.
/// Install the backtrace handler on default signals: `SIGILL`, `SIGSEGV`, `SIGBUS`, `SIGFPE`.
public static func install() {
Backtrace.install(signals: [SIGILL])
Backtrace.install(signals: [SIGILL, SIGSEGV, SIGBUS, SIGFPE])
}
/// Install the backtrace handler when any of `signals` happen.
@@ -77,6 +92,7 @@ public enum Backtrace {
for signal in signals {
self.setupHandler(signal: signal) { signal in
printBacktrace(signal: signal)
raise(signal)
}
}
}
@@ -122,11 +138,13 @@ public enum Backtrace {
#endif
}
/// Signal selection unavailable on Windows. Use ``install()-484jy``.
@available(*, deprecated, message: "signal selection unavailable on Windows")
public static func install(signals: [CInt]) {
Backtrace.install()
}
/// Install the backtrace handler on default signals.
public static func install() {
// Install a last-chance vectored exception handler to capture the error
// before the termination and report the stack trace. It is unlikely
@@ -262,8 +280,10 @@ public enum Backtrace {
#else
public enum Backtrace {
/// Install the backtrace handler on default signals. Available on Windows and Linux only.
public static func install() {}
/// Install the backtrace handler on specific signals. Available on Linux only.
public static func install(signals: [CInt]) {}
@available(*, deprecated, message: "This method will be removed in the next major version.")
+34
View File
@@ -0,0 +1,34 @@
# ``Backtrace``
Provides support for automatically printing crash backtraces of Swift programs.
## Overview
The Backtrace library is designed to fill a gap in backtraces support for Swift on non-Darwin platforms.
When this gap is closed at the language runtime level, this library will become redundant and be deprecated.
## Getting started
When building web-services and daemons, direct usage of this library is discouraged.
Instead, use [swift-service-lifecycle](https://github.com/swift-server/swift-service-lifecycle) which helps manage the application lifecycle including setting up backtraces hooks when needed.
Add `https://github.com/swift-server/swift-backtrace.git` as a dependency in your `Package.swift`.
### Crash backtraces
In your `main.swift`, do:
```swift
import Backtrace
// Do this first
Backtrace.install()
```
Finally, for Swift < 5.2, make sure you build your application with debug symbols enabled. Debug symbols are automatically included for Swift 5.2 and above.
```
$ swift build -c release -Xswiftc -g
```
When your app crashes, a stacktrace will be printed to `stderr`.
+1 -1
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* atomic.c -- Support for atomic functions if not present.
Copyright (C) 2013-2018 Free Software Foundation, Inc.
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
+1 -1
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* backtrace-supported.h.in -- Whether stack backtrace is supported.
Copyright (C) 2012-2016 Free Software Foundation, Inc.
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
+2 -2
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* backtrace.c -- Entry point for stack backtrace library.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -99,7 +99,7 @@ unwind (struct _Unwind_Context *context, void *vdata)
/* Get a stack backtrace. */
int
int __attribute__((noinline))
backtrace_full (struct backtrace_state *state, int skip,
backtrace_full_callback callback,
backtrace_error_callback error_callback, void *data)
+23 -3
View File
@@ -14,6 +14,10 @@
/* 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 1
/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
don't. */
#define HAVE_DECL_STRNLEN 1
@@ -36,8 +40,16 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `z' library (-lz). */
/* #undef HAVE_LIBZ */
/* 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. */
/* #undef HAVE_LIBLZMA */
/* Define to 1 if you have the <link.h> header file. */
#define HAVE_LINK_H 1
@@ -48,6 +60,9 @@
/* Define to 1 if you have the `lstat' function. */
#define HAVE_LSTAT 1
/* 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
@@ -85,7 +100,7 @@
#define HAVE_UNISTD_H 1
/* Define if -lz is available. */
/* #undef HAVE_ZLIB */
#define HAVE_ZLIB 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
@@ -134,6 +149,11 @@
#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. */
/* #undef _FILE_OFFSET_BITS */
+1953 -677
View File
File diff suppressed because it is too large Load Diff
+1792 -213
View File
File diff suppressed because it is too large Load Diff
+150 -5
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* fileline.c -- Get file and line number information in a backtrace.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -40,6 +40,14 @@ POSSIBILITY OF SUCH DAMAGE. */
#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 "include/backtrace.h"
#include "internal.h"
@@ -47,6 +55,107 @@ POSSIBILITY OF SUCH DAMAGE. */
#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. */
@@ -84,7 +193,7 @@ fileline_initialize (struct backtrace_state *state,
descriptor = -1;
called_error_callback = 0;
for (pass = 0; pass < 5; ++pass)
for (pass = 0; pass < 8; ++pass)
{
int does_not_exist;
@@ -94,19 +203,28 @@ fileline_initialize (struct backtrace_state *state,
filename = state->filename;
break;
case 1:
filename = "/proc/self/exe";
filename = getexecname ();
break;
case 2:
filename = "/proc/curproc/file";
filename = "/proc/self/exe";
break;
case 3:
filename = getexecname ();
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 ();
}
@@ -200,4 +318,31 @@ backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
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);
}
#endif
+3
View File
@@ -45,7 +45,10 @@ POSSIBILITY OF SUCH DAMAGE. */
#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
#endif
+16 -9
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* backtrace.h -- Public header file for stack backtrace library.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -55,13 +55,14 @@ struct backtrace_state;
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, 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. */
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);
@@ -76,7 +77,13 @@ typedef void (*backtrace_error_callback) (void *data, const char *msg,
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. */
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,
+89 -13
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* internal.h -- Internal header file for stack backtrace library.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -57,6 +57,14 @@ POSSIBILITY OF SUCH DAMAGE. */
# 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
@@ -180,7 +188,7 @@ struct backtrace_view
/* 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, size_t size,
off_t offset, uint64_t size,
backtrace_error_callback error_callback,
void *data, struct backtrace_view *view);
@@ -258,6 +266,18 @@ extern int backtrace_vector_release (struct backtrace_state *state,
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
@@ -275,23 +295,70 @@ extern int backtrace_initialize (struct backtrace_state *state,
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 unsigned char* dwarf_info,
size_t dwarf_info_size,
const unsigned char *dwarf_line,
size_t dwarf_line_size,
const unsigned char *dwarf_abbrev,
size_t dwarf_abbrev_size,
const unsigned char *dwarf_ranges,
size_t dwarf_range_size,
const unsigned char *dwarf_str,
size_t dwarf_str_size,
const struct dwarf_sections *dwarf_sections,
int is_bigendian,
struct dwarf_data *fileline_altlink,
backtrace_error_callback error_callback,
void *data, fileline *fileline_fn);
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. */
@@ -302,5 +369,14 @@ extern int backtrace_uncompress_zdebug (struct backtrace_state *,
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
#endif
+8 -2
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* mmap.c -- Memory allocation with mmap.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -43,6 +43,10 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "include/backtrace.h"
#include "internal.h"
#ifndef HAVE_DECL_GETPAGESIZE
extern int getpagesize (void);
#endif
/* Memory allocation on systems that provide anonymous mmap. This
permits the backtrace functions to be invoked from a signal
handler, assuming that mmap is async-signal safe. */
@@ -170,7 +174,7 @@ backtrace_alloc (struct backtrace_state *state,
if (page == MAP_FAILED)
{
if (error_callback)
error_callback (data, "mmap for alloc", errno);
error_callback (data, "mmap", errno);
}
else
{
@@ -322,6 +326,8 @@ backtrace_vector_release (struct backtrace_state *state,
backtrace_free (state, (char *) vec->base + aligned, alc,
error_callback, data);
vec->alc = 0;
if (vec->size == 0)
vec->base = NULL;
return 1;
}
#endif
+13 -3
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* mmapio.c -- File views using mmap.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -41,6 +41,10 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "include/backtrace.h"
#include "internal.h"
#ifndef HAVE_DECL_GETPAGESIZE
extern int getpagesize (void);
#endif
#ifndef MAP_FAILED
#define MAP_FAILED ((void *)-1)
#endif
@@ -52,7 +56,7 @@ POSSIBILITY OF SUCH DAMAGE. */
int
backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
int descriptor, off_t offset, size_t size,
int descriptor, off_t offset, uint64_t size,
backtrace_error_callback error_callback,
void *data, struct backtrace_view *view)
{
@@ -61,6 +65,12 @@ backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
off_t pageoff;
void *map;
if ((uint64_t) (size_t) size != size)
{
error_callback (data, "file size too large", 0);
return 0;
}
pagesize = getpagesize ();
inpage = offset % pagesize;
pageoff = offset - inpage;
@@ -71,7 +81,7 @@ backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff);
if (map == MAP_FAILED)
{
error_callback (data, "mmap file i/o", errno);
error_callback (data, "mmap", errno);
return 0;
}
+6 -2
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* posix.c -- POSIX file I/O routines for the backtrace library.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -68,7 +68,11 @@ backtrace_open (const char *filename, backtrace_error_callback error_callback,
descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC));
if (descriptor < 0)
{
if (does_not_exist != NULL && errno == ENOENT)
/* 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);
+2 -2
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* print.c -- Print the current backtrace.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -81,7 +81,7 @@ error_callback (void *data, const char *msg, int errnum)
/* Print a backtrace. */
void
void __attribute__((noinline))
backtrace_print (struct backtrace_state *state, int skip, FILE *f)
{
struct print_data data;
+3 -3
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* simple.c -- The backtrace_simple function.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
@@ -56,7 +56,7 @@ struct backtrace_simple_data
int ret;
};
/* Unwind library callback routine. This is passd to
/* Unwind library callback routine. This is passed to
_Unwind_Backtrace. */
static _Unwind_Reason_Code
@@ -91,7 +91,7 @@ simple_unwind (struct _Unwind_Context *context, void *vdata)
/* Get a simple stack backtrace. */
int
int __attribute__((noinline))
backtrace_simple (struct backtrace_state *state, int skip,
backtrace_simple_callback callback,
backtrace_error_callback error_callback, void *data)
+1 -1
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* sort.c -- Sort without allocating memory
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
+1 -1
View File
@@ -1,6 +1,6 @@
#ifdef __linux__
/* state.c -- Create the backtrace state.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
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
+25 -2
View File
@@ -13,7 +13,30 @@
//===----------------------------------------------------------------------===//
import Backtrace
#if canImport(Darwin)
import Darwin
#elseif os(Linux)
import Glibc
#endif
#if swift(<5.9) || os(Windows)
Backtrace.install()
#endif
func raiseSignal(_ signal: Int32) {
raise(signal)
}
let reason = CommandLine.arguments.count == 2 ? CommandLine.arguments[1] : "unknown"
Backtrace.install()
fatalError(reason)
switch reason.uppercased() {
case "SIGILL":
raiseSignal(SIGILL)
case "SIGSEGV":
raiseSignal(SIGSEGV)
case "SIGBUS":
raiseSignal(SIGBUS)
case "SIGFPE":
raiseSignal(SIGFPE)
default:
fatalError(reason)
}
@@ -25,7 +25,11 @@ import XCTest
extension BacktraceTests {
public static var allTests: [(String, (BacktraceTests) -> () throws -> Void)] {
return [
("testBacktrace", testBacktrace),
("testFatalError", testFatalError),
("testSIGILL", testSIGILL),
("testSIGSEGV", testSIGSEGV),
("testSIGBUS", testSIGBUS),
("testSIGFPE", testSIGFPE),
]
}
}
+86 -12
View File
@@ -15,22 +15,96 @@
import XCTest
public final class BacktraceTests: XCTestCase {
func testBacktrace() {
#if os(Linux)
func testFatalError() throws {
#if !os(Linux)
try XCTSkipIf(true, "test is only supported on Linux")
#endif
#if swift(>=5.9)
try XCTSkipIf(true, "test is not supported on Swift 5.9")
#endif
let expectedError = UUID().uuidString
let stderr = try runSample(reason: expectedError)
print(stderr)
XCTAssert(stderr.contains("Received signal 4. Backtrace:"))
XCTAssert(stderr.contains("Current stack trace:"), "expected stanard error to include backtrace")
XCTAssert(stderr.contains("Fatal error: \(expectedError)"), "expected stanard error to include error information")
}
func testSIGILL() throws {
#if !os(Linux)
try XCTSkipIf(true, "test is only supported on Linux")
#endif
#if swift(>=5.9)
try XCTSkipIf(true, "test is not supported on Swift 5.9")
#endif
let stderr = try runSample(reason: "SIGILL")
print(stderr)
XCTAssert(stderr.contains("Received signal \(SIGILL). Backtrace:"))
XCTAssert(stderr.contains("Sample.raiseSignal"))
}
func testSIGSEGV() throws {
#if !os(Linux)
try XCTSkipIf(true, "test is only supported on Linux")
#endif
#if swift(>=5.9)
try XCTSkipIf(true, "test is not supported on Swift 5.9")
#endif
let stderr = try runSample(reason: "SIGSEGV")
print(stderr)
XCTAssert(stderr.contains("Received signal \(SIGSEGV). Backtrace:"))
XCTAssert(stderr.contains("Sample.raiseSignal"))
}
func testSIGBUS() throws {
#if !os(Linux)
try XCTSkipIf(true, "test is only supported on Linux")
#endif
#if swift(>=5.9)
try XCTSkipIf(true, "test is not supported on Swift 5.9")
#endif
let stderr = try runSample(reason: "SIGBUS")
print(stderr)
XCTAssert(stderr.contains("Received signal \(SIGBUS). Backtrace:"))
XCTAssert(stderr.contains("Sample.raiseSignal"))
}
func testSIGFPE() throws {
#if !os(Linux)
try XCTSkipIf(true, "test is only supported on Linux")
#endif
#if swift(>=5.9)
try XCTSkipIf(true, "test is not supported on Swift 5.9")
#endif
let stderr = try runSample(reason: "SIGFPE")
print(stderr)
XCTAssert(stderr.contains("Received signal \(SIGFPE). Backtrace:"))
XCTAssert(stderr.contains("Sample.raiseSignal"))
}
func runSample(reason: String) throws -> String {
let pipe = Pipe()
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/swift")
process.arguments = ["run", "Sample", expectedError]
process.arguments = ["run", "Sample", reason]
process.standardError = pipe
XCTAssertNoThrow(try process.run())
if process.isRunning {
process.waitUntilExit()
}
let stderr = String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
print(stderr)
XCTAssert(stderr.contains("Current stack trace:"), "expected stanard error to include backtrace")
XCTAssert(stderr.contains("Fatal error: \(expectedError)"), "expected stanard error to include error information")
#endif
try process.run()
process.waitUntilExit()
return String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
}
}
+3 -3
View File
@@ -18,9 +18,9 @@ RUN apt-get update && apt-get install -y lsof dnsutils netcat-openbsd net-tools
# ruby and jazzy for docs generation
RUN apt-get update && apt-get install -y ruby ruby-dev libsqlite3-dev build-essential
# switch of gem docs building
RUN echo "gem: --no-document" > ~/.gemrc
RUN if [ "${ubuntu_version}" != "xenial" ] ; then gem install jazzy ; fi
# jazzy no longer works on older version of ubuntu as ruby is too old.
RUN if [ "${ubuntu_version}" = "focal" ] ; then echo "gem: --no-document" > ~/.gemrc ; fi
RUN if [ "${ubuntu_version}" = "focal" ] ; then gem install jazzy ; fi
# tools
RUN mkdir -p $HOME/.tools
+16
View File
@@ -0,0 +1,16 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:20.04-5.5
build:
args:
ubuntu_version: "focal"
swift_version: "5.5"
test:
image: swift-linux-backtrace:20.04-5.5
shell:
image: swift-linux-backtrace:20.04-5.5
+18
View File
@@ -0,0 +1,18 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:20.04-5.6
build:
args:
ubuntu_version: "focal"
swift_version: "5.6"
test:
image: swift-linux-backtrace:20.04-5.6
environment:
- FORCE_TEST_DISCOVERY=--enable-test-discovery
shell:
image: swift-linux-backtrace:20.04-5.6
+18
View File
@@ -0,0 +1,18 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:20.04-5.7
build:
args:
ubuntu_version: "focal"
swift_version: "5.7"
test:
image: swift-linux-backtrace:20.04-5.7
environment:
- FORCE_TEST_DISCOVERY=--enable-test-discovery
shell:
image: swift-linux-backtrace:20.04-5.7
+18
View File
@@ -0,0 +1,18 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:22.04-5.8
build:
args:
ubuntu_version: "jammy"
swift_version: "5.8"
test:
image: swift-linux-backtrace:22.04-5.8
environment:
- FORCE_TEST_DISCOVERY=--enable-test-discovery
shell:
image: swift-linux-backtrace:22.04-5.8
+17
View File
@@ -0,0 +1,17 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:22.04-5.9
build:
args:
base_image: "swiftlang/swift:nightly-5.9-jammy"
test:
image: swift-linux-backtrace:22.04-5.9
environment:
- FORCE_TEST_DISCOVERY=--enable-test-discovery
shell:
image: swift-linux-backtrace:22.04-5.9
+17
View File
@@ -0,0 +1,17 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:22.04-main
build:
args:
base_image: "swiftlang/swift:nightly-main-jammy"
test:
image: swift-linux-backtrace:22.04-main
environment:
- FORCE_TEST_DISCOVERY=--enable-test-discovery
shell:
image: swift-linux-backtrace:22.04-main
+4 -4
View File
@@ -22,16 +22,16 @@ services:
- CAP_NET_RAW
- CAP_NET_BIND_SERVICE
sanity:
soundness:
<<: *common
command: /bin/bash -cl "./scripts/sanity.sh"
command: /bin/bash -cl "./scripts/soundness.sh"
test:
<<: *common
command: /bin/bash -cl "swift test -c release -Xswiftc -g -Xswiftc -warnings-as-errors $${SANITIZER_ARG-}"
command: /bin/bash -cl "swift test -c release -Xswiftc -g -Xswiftc -warnings-as-errors $${FORCE_TEST_DISCOVERY-} $${SANITIZER_ARG-}"
# util
shell:
<<: *common
entrypoint: /bin/bash
entrypoint: /bin/bash -l
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftLinuxBacktrace open source project
##
## Copyright (c) 2022 Apple Inc. and the SwiftLinuxBacktrace project authors
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.txt for the list of SwiftLinuxBacktrace project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
##===----------------------------------------------------------------------===##
##
## This source file is part of the Swift Distributed Actors open source project
##
## Copyright (c) 2018-2019 Apple Inc. and the Swift Distributed Actors project authors
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
## See CONTRIBUTORS.md for the list of Swift Distributed Actors project authors
##
## SPDX-License-Identifier: Apache-2.0
##
##===----------------------------------------------------------------------===##
swift package --disable-sandbox preview-documentation --target $1
+3 -3
View File
@@ -3,7 +3,7 @@
##
## This source file is part of the SwiftLinuxBacktrace open source project
##
## Copyright (c) 2017-2018 Apple Inc. and the SwiftLinuxBacktrace project authors
## Copyright (c) 2017-2022 Apple Inc. and the SwiftLinuxBacktrace project authors
## Licensed under Apache License v2.0
##
## See LICENSE.txt for license information
@@ -19,7 +19,7 @@ here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
function replace_acceptable_years() {
# this needs to replace all acceptable forms with 'YEARS'
sed -e 's/2017-2018/YEARS/' -e 's/2019-2020/YEARS/' -e 's/2019/YEARS/' -e 's/2020/YEARS/'
sed -e 's/20[12][78901]-20[12][89012]/YEARS/' -e 's/2019/YEARS/' -e 's/202[012]/YEARS/'
}
printf "=> Checking linux tests... "
@@ -57,7 +57,7 @@ for language in swift-or-c bash dtrace; do
matching_files=( -name '*' )
case "$language" in
swift-or-c)
exceptions=( -name Package.swift -o -path './Sources/CBacktrace/*' )
exceptions=( -name Package.swift -o -name 'Package@*.swift' -o -path './Sources/CBacktrace/*' )
matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' )
cat > "$tmp" <<"EOF"
//===----------------------------------------------------------------------===//
+4 -1
View File
@@ -63,12 +63,15 @@ done
EXCLUDES=(
'*test*'
'alloc.c'
'nounwind.c'
'pecoff.c'
'read.c'
'unknown.c'
'xcoff.c'
'macho.c'
'alloc.c'
'allocfail.c'
'instrumented_alloc.c'
)
for exclude in "${EXCLUDES[@]}"