47 Commits

Author SHA1 Message Date
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
Johannes Weiss d3e04a9d4b Merge pull request #49 from weissi/jw-other-platforms
forgot other platforms
2021-07-16 19:50:16 +01:00
Johannes Weiss b3b195e0e6 forgot other platforms 2021-07-16 19:34:47 +01:00
Johannes Weiss e434780428 Merge pull request #48 from weissi/jw-signals
allow other signals
2021-07-15 21:24:11 +01:00
Johannes Weiss ceaaf36f0f allow other signals 2021-07-15 19:40:14 +01:00
Konrad `ktoso` Malawski bb3bd2357e Merge pull request #45 from swift-server/tomerd-patch-1
adopt SSWG security guidelines
2021-06-21 11:24:12 +09:00
tomer doron 5f7686a18b Merge branch 'main' into tomerd-patch-1 2021-06-11 09:13:34 -07:00
tomer doron d9655c7867 add 5.4 CI (#46)
motivation: 5.4 was released, add 5.4 CI

changes: add docker-compose setup for 5.4
2021-06-11 09:13:24 -07:00
tomer doron 84bcaad52f Update README.md 2021-06-08 10:38:03 -07:00
tomer doron 7152ac0033 adopt SSWG security guidelines
add SECURITY.md detailing the security process
2021-06-08 10:37:16 -07:00
tomer doron 54a65d6391 recent changes to support windows broke macos (#44)
motivation: unbreak macos

changes: make _stdlib_demangleName only available on macOS and Windows where it is fully supported
2021-04-20 11:04:11 -07:00
Saleem Abdulrasool 1ca1dbd9ff README: add acknowledgement for Windows port (#43) 2021-04-20 10:10:33 -07:00
Johannes Weiss 182caea1a4 Merge pull request #42 from compnerd/windows
Backtrace: enable support for Windows
2021-04-20 14:04:13 +01:00
Saleem Abdulrasool 5b47490c74 Backtrace: adjust style (NFC)
Adjust the style for the linter.
2021-04-19 13:13:09 -07:00
Saleem Abdulrasool b097912943 Backtrace: enable support for Windows
Add an implementation across all architectures supported by Windows:
- x86
- x86_64
- ARM
- ARM64

This relies on DbgHlp32.dll which makes this unfriendly to store
applications.  We can investigate improvements to that in the future.
This sketches out an implementation which allows building and using the
interface for providing backtraces.  This requires that the programs be
built with debug information in CodeView format.  Without the additional
debug information, the stack traces will be limited to symbolication and
resolution to export only symbols.

Resolves: #34
2021-04-18 11:16:45 -07:00
Saleem Abdulrasool a4f7b4204e Backtrace: make _stdlib_demangleName part of all platforms (#41) 2021-04-17 21:45:37 -07:00
Saleem Abdulrasool 9a2ef536ee git: ignore vim swap files (#39) 2021-04-17 19:54:24 -07:00
Johannes Weiss c859218177 Merge pull request #37 from mpdifran/patch-1
Update build flags with Swift version info
2021-03-03 10:24:02 +00:00
Mark DiFranco 1d5fbd8c42 Update build flags with Swift version info
As of Swift 5.2, this build flag is no longer necessary.
2021-03-01 09:11:11 -05:00
Johannes Weiss 93b3d9a764 Merge pull request #35 from weissi/jw-error
better distinguish mmap errors & print errno
2021-02-22 11:10:40 +00:00
Johannes Weiss 4353fd38d5 Merge branch 'main' into jw-error 2021-02-22 11:09:50 +00:00
Johannes Weiss 97a034c8a4 Merge pull request #36 from weissi/jw-exe-name
determine the executable path automatically
2021-02-22 11:09:38 +00:00
Johannes Weiss 566d2454b2 determine the executable path automatically
Motivation:

Previously, we would use
`CommandLine.arguments[0]`/`argv[0]`/`getexecname()` as the preferred
ways to find the main binary. That sounds sensible, especially given
the fact that we'd fall back onto other methods (such as
`/proc/self/exe`) when the previous ones don't work.

There is however an unfortunate edge case. If you for example have your
app binary at `/app/app` and you start it with a relative path `./app`
from within `/app`, then `CommandLine.arguments[0]` will only contain
`./app`. If now the app changes its working directory to `/`, `./app`
would mean `/app` which is the directory. This would mean we will find
the target but instead of the binary we'd find the directory `/app`.
From then on, everything else fails.

A similar problem is if `argv[0]` was actually set incorrectly when
`exec*`ing the process. This has happened at least in one instance.

Modification:

Given that we only target Linux here, we can actually here, we can
change the order in which we try to find the main binary. We can start
by using `/proc/self/exe` which is a very high quality and almost
guaranteed to work way to find the main binary, nevermind the
information in `argv`.

Result:

More robust symbolications, especially in environments like Heroku/Dokku
where we've seen `argv` not being set correctly.
2021-02-21 18:28:38 +00:00
Johannes Weiss c8d8ddd88b better distinguish mmap errors & print errno
Motivation:

In case SwiftBacktrace fails, we get only very little output.
Unfortunately, some crucial information (like the errno) is missing and
in case `mmap` fails, we don't know if the problem is file I/O or
allocating memory.

Modification:

- print errnos
- distinguish the two mmaps

Result:

Easier debugging
2021-02-20 23:12:33 +00:00
tomer doron 4915cdd24e remove symbolicate-linux-fatal from Docker (#33)
motivation: we are not actually using symbolicate-linux-fatal in any meaningful way in CI and it's pinned to the master branch which has been removed

changes: remove symbolicate-linux-fatal fetching from Docker
2020-10-07 17:29:02 -07:00
tomer doron 7a48ec7baa Swift 5.3 was released, use if for CI (#32)
motivation: Swift 5.3 was released, use if for CI

changes: update docker setup to use the release version of 5.3
2020-09-18 12:59:21 -07:00
tomer doron c6559c866c stabilize ci (#31)
motivation: update swift-server ci

changes: 
* remove travis ci definition
* dont install jazzy on 16.04 - its broken on that version and not in use  (stabilize ci)
* using 5.3 nightlies (stabilize ci)
2020-08-19 11:33:07 -07:00
tomer doron 232bd5bdbc update ci setup (#27)
motivation: 5.2 adoption, prepare for 5.3

changes:
* add 5.2 docker-compose setup
* add 5.3 docker-compose setup (placeholder)
2020-04-04 00:20:09 -07:00
tomer doron f2fd8c4845 add testing (#26)
motivation: make sure library works as expected

changes:
* add a Sample target we can use for testing
* add a test to make sure backtraces are printed as expected
* make docker tests use a release version for a more realistic tests
* update linux test generation script to work with release builds
2020-03-25 12:29:57 -07:00
tomer doron 7faa1c401b remove print from public API (#25)
motivation: reduce public API surface area given the plan is to abosrb this library in the language runtime eventually

changes:
* make print function private
* remove explicit swift-server file
2020-03-25 12:06:04 -07:00
tomer doron 1afd60a0bb ci setup (#23)
motivation: setup ci for the project

changes:
* add docker setup for testing 5.0, 5.1 and 5.2
* fix license headers
* add sanity script
* format
* regenerate tests to match convention
2020-03-20 16:20:00 -07:00
Ian Partridge 5074f997bf Fix package url in README.md (#21) 2020-03-05 12:48:10 +00:00
Tanner f5462810b8 Update README.md 2020-02-18 10:48:35 -05:00
Tanner e735696872 Update README.md 2020-02-18 10:48:24 -05:00
Ian Partridge 383950b36a ci: Swift 5.1 testing (#20) 2019-11-01 13:54:05 +01:00
Ian Partridge feaee74aa6 Update README.md 2019-09-11 08:59:31 -04:00
Ian Partridge eaf2cef011 feat: cross-compilation (#17) 2019-09-03 14:28:12 +01:00
Ian Partridge f244ad1074 feat: add Backtrace.print() function (#15) 2019-07-22 08:19:56 +01:00
Ian Partridge 39bf306f55 chore: add Xcode 11 testing (#12) 2019-07-18 14:05:15 +01:00
49 changed files with 1219 additions and 148 deletions
+2
View File
@@ -2,3 +2,5 @@
/.build
/Packages
/*.xcodeproj
.swiftpm
.*.sw[nop]
+3
View File
@@ -0,0 +1,3 @@
Tomer Doron <tomer@apple.com> <tomer@apple.com>
Tomer Doron <tomer@apple.com> <tomerd@apple.com>
Tomer Doron <tomer@apple.com> <tomer.doron@gmail.com>
-1
View File
@@ -1 +0,0 @@
5.0.1
+13
View File
@@ -0,0 +1,13 @@
# file options
--swiftversion 5.0
--exclude .build
# format options
--self insert
--patternlet inline
--stripunusedargs unnamed-only
--ifdef no-indent
# rules
-37
View File
@@ -1,37 +0,0 @@
branches:
only:
- master
# The matrix of builds should cover each combination of Swift version
# and platform that is supported. The version of Swift used is specified
# by .swift-version, unless SWIFT_SNAPSHOT is specified.
matrix:
include:
- os: linux
dist: xenial
sudo: required
services: docker
env: DOCKER_IMAGE=swift:4.2.4 SWIFT_SNAPSHOT=4.2.4
- os: linux
dist: xenial
sudo: required
services: docker
env: DOCKER_IMAGE=swift:5.0-xenial
- os: linux
dist: xenial
sudo: required
services: docker
env: DOCKER_IMAGE=swift:5.0-bionic
- os: osx
osx_image: xcode10.1
sudo: required
env: SWIFT_SNAPSHOT=4.2.1
- os: osx
osx_image: xcode10.2
sudo: required
before_install:
- git clone https://github.com/IBM-Swift/Package-Builder.git
script:
- ./Package-Builder/build-package.sh -projectDir $TRAVIS_BUILD_DIR
+21
View File
@@ -0,0 +1,21 @@
For the purpose of tracking copyright, this is the list of individuals and
organizations who have contributed source code to SwiftLinuxBacktrace.
For employees of an organization/company where the copyright of work done
by employees of that company is held by the company itself, only the company
needs to be listed here.
## COPYRIGHT HOLDERS
- Apple Inc. (all contributors with '@apple.com')
### Contributors
- Ian Partridge <i.partridge@uk.ibm.com>
- Tanner <me@tanner.xyz>
- Tomer Doron <tomer@apple.com>
- Zsolt Váradi <vzsg@users.noreply.github.com>
**Updating this list**
Please do not edit this file manually. It is generated using `./scripts/generate_contributors_list.sh`. If a name is misspelled or appearing multiple times: add an entry in `./.mailmap`
+12 -26
View File
@@ -2,37 +2,23 @@
import PackageDescription
var backtraceDependencies: [Target.Dependency] = []
#if os(Linux)
backtraceDependencies.append(.target(name: "CBacktrace"))
#endif
var targets: [Target] = [
.target(
name: "Backtrace",
dependencies: backtraceDependencies),
.testTarget(
name: "BacktraceTests",
dependencies: ["Backtrace"])
]
#if os(Linux)
targets.append(
.target(
name: "CBacktrace",
dependencies: [])
)
#endif
let package = Package(
name: "swift-backtrace",
products: [
.library(
name: "Backtrace",
targets: ["Backtrace"]),
targets: ["Backtrace"]
),
],
dependencies: [],
targets: targets
targets: [
.target(name: "Backtrace",
dependencies: ["CBacktrace"]),
.target(name: "CBacktrace",
dependencies: []),
.target(name: "Sample",
dependencies: ["Backtrace"]),
.testTarget(name: "BacktraceTests",
dependencies: ["Backtrace"]),
]
)
-38
View File
@@ -1,38 +0,0 @@
// swift-tools-version:4.2
import PackageDescription
var backtraceDependencies: [Target.Dependency] = []
#if os(Linux)
backtraceDependencies.append(.target(name: "CBacktrace"))
#endif
var targets: [Target] = [
.target(
name: "Backtrace",
dependencies: backtraceDependencies),
.testTarget(
name: "BacktraceTests",
dependencies: ["Backtrace"])
]
#if os(Linux)
targets.append(
.target(
name: "CBacktrace",
dependencies: [])
)
#endif
let package = Package(
name: "swift-backtrace",
products: [
.library(
name: "Backtrace",
targets: ["Backtrace"]),
],
dependencies: [],
targets: targets
)
+20 -4
View File
@@ -2,11 +2,19 @@
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
Add `https://github.com/ianpartridge/swift-backtrace.git` as a dependency in your `Package.swift`.
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.
Then, in your `main.swift`, do:
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
@@ -15,7 +23,7 @@ import Backtrace
Backtrace.install()
```
Finally, make sure you build your application with debug symbols enabled:
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
@@ -23,6 +31,14 @@ $ swift build -c release -Xswiftc -g
When your app crashes, a stacktrace will be printed to `stderr`.
## Security
Please see [SECURITY.md](SECURITY.md) for details on the security process.
## Acknowledgements
@weissi, for the signal handling code!
Ian Partridge ([GitHub](https://github.com/ianpartridge/), [Twitter](https://twitter.com/alfa)) the original author of this package.
Johannes Weiss ([GitHub](https://github.com/weissi), [Twitter](https://twitter.com/johannesweiss)) for the signal handling code.
Saleem Abdulrasool ([GitHub](https://github.com/compnerd), [Twitter](https://twitter.com/compnerd)) for the Windows port.
+43
View File
@@ -0,0 +1,43 @@
# Security
This document specifies the security process for the Backtrace project.
## Disclosures
### Private Disclosure Process
The Backtrace maintainers ask that known and suspected vulnerabilities be
privately and responsibly disclosed by emailing
[sswg-security-reports@forums.swift.org](mailto:sswg-security-reports@forums.swift.org)
with the all the required detail.
**Do not file a public issue.**
#### When to report a vulnerability
* You think you have discovered a potential security vulnerability in Backtrace.
* You are unsure how a vulnerability affects Backtrace.
#### What happens next?
* A member of the team will acknowledge receipt of the report within 3
working days (United States). This may include a request for additional
information about reproducing the vulnerability.
* We will privately inform the Swift Server Work Group ([SSWG][sswg]) of the
vulnerability within 10 days of the report as per their [security
guidelines][sswg-security].
* Once we have identified a fix we may ask you to validate it. We aim to do this
within 30 days. In some cases this may not be possible, for example when the
vulnerability exists at the protocol level and the industry must coordinate on
the disclosure process.
* If a CVE number is required, one will be requested from [MITRE][mitre]
providing you with full credit for the discovery.
* We will decide on a planned release date and let you know when it is.
* Prior to release, we will inform major dependents that a security-related
patch is impending.
* Once the fix has been released we will publish a security advisory on GitHub
and in the Server → Security Updates category on the [Swift forums][swift-forums-sec].
[sswg]: https://github.com/swift-server/sswg
[sswg-security]: https://github.com/swift-server/sswg/blob/main/security/README.md
[swift-forums-sec]: https://forums.swift.org/c/server/security-updates/
[mitre]: https://cveform.mitre.org/
+208 -9
View File
@@ -1,16 +1,30 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) 2019-2020 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
//
//===----------------------------------------------------------------------===//
#if os(Linux)
import Glibc
import CBacktrace
import Glibc
typealias CBacktraceErrorCallback = @convention(c) (_ data: UnsafeMutableRawPointer?, _ msg: UnsafePointer<CChar>?, _ errnum: CInt) -> Void
typealias CBacktraceFullCallback = @convention(c) (_ data: UnsafeMutableRawPointer?, _ pc: UInt, _ filename: UnsafePointer<CChar>?, _ lineno: CInt, _ function: UnsafePointer<CChar>?) -> CInt
typealias CBacktraceSimpleCallback = @convention(c) (_ data: UnsafeMutableRawPointer?, _ pc: UInt) -> CInt
typealias CBacktraceSyminfoCallback = @convention(c) (_ data: UnsafeMutableRawPointer?, _ pc: UInt, _ filename: UnsafePointer<CChar>?, _ symval: UInt, _ symsize: UInt) -> Void
private let state = backtrace_create_state(CommandLine.arguments[0], /* BACKTRACE_SUPPORTS_THREADS */ 1, nil, nil)
private let state = backtrace_create_state(nil, /* BACKTRACE_SUPPORTS_THREADS */ 1, nil, nil)
private let fullCallback: CBacktraceFullCallback? = {
data, pc, filename, lineno, function in
_, pc, filename, lineno, function in
var str = "0x"
str.append(String(pc, radix: 16))
@@ -39,21 +53,40 @@ private let fullCallback: CBacktraceFullCallback? = {
}
private let errorCallback: CBacktraceErrorCallback? = {
data, msg, errnum in
_, msg, errNo in
if let msg = msg {
_ = withVaList([msg]) { vaList in
vfprintf(stderr, "%s\n", vaList)
_ = withVaList([msg, errNo]) { vaList in
vfprintf(stderr, "SwiftBacktrace ERROR: %s (errno: %d)\n", vaList)
}
}
}
private func printBacktrace(signal: CInt) {
_ = fputs("Received signal \(signal). Backtrace:\n", stderr)
backtrace_full(state, /* skip */ 0, fullCallback, errorCallback, nil)
}
public enum Backtrace {
/// Install the backtrace handler on default signals: `SIGILL`, `SIGSEGV`, `SIGBUS`, `SIGFPE`.
public static func install() {
setupHandler(signal: SIGILL) { _ in
backtrace_full(state, /* skip */ 0, fullCallback, errorCallback, nil)
Backtrace.install(signals: [SIGILL, SIGSEGV, SIGBUS, SIGFPE])
}
/// Install the backtrace handler when any of `signals` happen.
public static func install(signals: [CInt]) {
for signal in signals {
self.setupHandler(signal: signal) { signal in
printBacktrace(signal: signal)
raise(signal)
}
}
}
@available(*, deprecated, message: "This method will be removed in the next major version.")
public static func print() {
backtrace_full(state, /* skip */ 0, fullCallback, errorCallback, nil)
}
private static func setupHandler(signal: Int32, handler: @escaping @convention(c) (CInt) -> Void) {
typealias sigaction_t = sigaction
let sa_flags = CInt(SA_NODEFER) | CInt(bitPattern: CUnsignedInt(SA_RESETHAND))
@@ -66,9 +99,175 @@ public enum Backtrace {
}
}
}
#elseif os(Windows)
#if swift(<5.4)
#error("unsupported Swift version")
#else
@_implementationOnly import CRT
@_implementationOnly import WinSDK
#endif
public enum Backtrace {
public static func install() {
private static var MachineType: DWORD {
#if arch(arm)
DWORD(IMAGE_FILE_MACHINE_ARMNT)
#elseif arch(arm64)
DWORD(IMAGE_FILE_MACHINE_ARM64)
#elseif arch(i386)
DWORD(IMAGE_FILE_MACHINE_I386)
#elseif arch(x86_64)
DWORD(IMAGE_FILE_MACHINE_AMD64)
#else
#error("unsupported architecture")
#endif
}
@available(*, deprecated, message: "signal selection unavailable on Windows")
public static func install(signals: [CInt]) {
Backtrace.install()
}
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
// that this will be recovered at this point by a SEH handler.
_ = AddVectoredExceptionHandler(0) { _ in
// NOTE: GetCurrentProcess does not increment the reference count on
// the process. This handle should _not_ be closed upon completion.
let hProcess: HANDLE = GetCurrentProcess()
var cxr: CONTEXT = CONTEXT()
cxr.ContextFlags =
DWORD(CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
RtlCaptureContext(&cxr)
_ = SymInitializeW(hProcess, nil, true)
_ = SymSetOptions(DWORD(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME))
var Frame: STACKFRAME64 = STACKFRAME64()
#if arch(arm)
Frame.AddrPC.Offset = cxr.Pc
Frame.AddrFrame.Offset = cxr.R11
Frame.AddrStack.Offset = cxr.Sp
#elseif arch(arm64)
Frame.AddrPC.Offset = cxr.Pc
Frame.AddrFrame.Offset = cxr.Fp
Frame.AddrStack.Offset = cxr.Sp
#elseif arch(i386)
Frame.AddrPC.Offset = cxr.Eip
Frame.AddrFrame.Offset = cxr.Ebp
Frame.AddrStack.Offset = cxr.Esp
#elseif arch(x86_64)
Frame.AddrPC.Offset = cxr.Rip
Frame.AddrFrame.Offset = cxr.Rbp
Frame.AddrStack.Offset = cxr.Rsp
#else
#error("unsupported architecture")
#endif
Frame.AddrPC.Mode = AddrModeFlat
Frame.AddrFrame.Mode = AddrModeFlat
Frame.AddrStack.Mode = AddrModeFlat
// Constant indicating the maximum symbol length that we expect
// during symbolication of the stack trace.
let kMaxSymbolLength: Int = 255
// Heap allocate the buffer as we need to account for the trailing
// storage that we need to provide.
let pSymbolBuffer: UnsafeMutableRawPointer =
UnsafeMutableRawPointer.allocate(byteCount: MemoryLayout<IMAGEHLP_SYMBOL64>.size + kMaxSymbolLength,
alignment: 1)
defer { pSymbolBuffer.deallocate() }
let pSymbol: UnsafeMutablePointer<IMAGEHLP_SYMBOL64> =
pSymbolBuffer.bindMemory(to: IMAGEHLP_SYMBOL64.self,
capacity: 1)
let hThread: HANDLE = GetCurrentThread()
while StackWalk64(Backtrace.MachineType, hProcess, hThread,
&Frame, &cxr, nil, SymFunctionTableAccess64,
SymGetModuleBase64, nil) {
var qwModuleBase: DWORD64 =
SymGetModuleBase64(hProcess, Frame.AddrPC.Offset)
let module: String = withUnsafeMutablePointer(to: &qwModuleBase) {
$0.withMemoryRebound(to: HINSTANCE.self, capacity: 1) { hInstance in
String(decoding: [WCHAR](unsafeUninitializedCapacity: Int(MAX_PATH + 1)) {
$1 = Int(GetModuleFileNameW(hInstance.pointee,
$0.baseAddress,
DWORD($0.count)))
}, as: UTF16.self)
}
}
pSymbol.pointee.SizeOfStruct =
DWORD(MemoryLayout<IMAGEHLP_SYMBOL64>.size)
pSymbol.pointee.MaxNameLength = DWORD(kMaxSymbolLength)
_ = SymGetSymFromAddr64(hProcess, Frame.AddrPC.Offset, nil,
pSymbol)
var symbol: String =
withUnsafePointer(to: &pSymbol.pointee.Name) {
String(cString: $0)
}
// Undecorate Swift 3+ names only. Earlier Swift decorations
// are unsupported. Any MSVC name decoration has been
// unperformed during the DbgHelp operation through the use of
// the `SYMOPT_UNDNAME` option.
if symbol.hasPrefix("$s") || symbol.hasPrefix("$S") {
symbol = _stdlib_demangleName(symbol)
}
var Displacement: DWORD = 0
var Line: IMAGEHLP_LINE64 = IMAGEHLP_LINE64()
Line.SizeOfStruct = DWORD(MemoryLayout<IMAGEHLP_LINE64>.size)
_ = SymGetLineFromAddr64(hProcess, Frame.AddrPC.Offset,
&Displacement, &Line)
var details: String = ""
if !symbol.isEmpty {
// Truncate the module path to the filename. The
// `PathFindFileNameW` call will return the beginning of the
// string if a path separator character is not found.
if let pszModule = module.withCString(encodedAs: UTF16.self,
PathFindFileNameW) {
details.append(", \(String(decodingCString: pszModule, as: UTF16.self))!\(symbol)")
}
}
if let szFileName = Line.FileName {
details.append(" at \(String(cString: szFileName)):\(Line.LineNumber)")
}
_ = details.withCString { pszDetails in
withVaList([Frame.AddrPC.Offset, pszDetails]) {
#if arch(arm64) || arch(x86_64)
vfprintf(stderr, "%#016x%s\n", $0)
#else
vfprintf(stderr, "%#08x%s\n", $0)
#endif
}
}
}
_ = SymCleanup(hProcess)
// We have not handled the exception, continue the search.
return EXCEPTION_CONTINUE_SEARCH
}
}
}
#else
public enum Backtrace {
public static func install() {}
public static func install(signals: [CInt]) {}
@available(*, deprecated, message: "This method will be removed in the next major version.")
public static func print() {}
}
#endif
+26 -4
View File
@@ -1,9 +1,29 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) 2019-2020 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
//
//===----------------------------------------------------------------------===//
#if os(Linux)
import Glibc
#elseif os(Windows)
#if swift(<5.4)
#error("unsupported Swift version")
#else
import Darwin
@_implementationOnly
import ucrt
#endif
#endif
#if os(Linux) || os(Windows)
@_silgen_name("swift_demangle")
public
func _stdlib_demangleImpl(
@@ -12,18 +32,19 @@ func _stdlib_demangleImpl(
outputBuffer: UnsafeMutablePointer<CChar>?,
outputBufferSize: UnsafeMutablePointer<UInt>?,
flags: UInt32
) -> UnsafeMutablePointer<CChar>?
) -> UnsafeMutablePointer<CChar>?
internal func _stdlib_demangleName(_ mangledName: String) -> String {
return mangledName.utf8CString.withUnsafeBufferPointer {
(mangledNameUTF8CStr) in
mangledNameUTF8CStr in
let demangledNamePtr = _stdlib_demangleImpl(
mangledName: mangledNameUTF8CStr.baseAddress,
mangledNameLength: UInt(mangledNameUTF8CStr.count - 1),
outputBuffer: nil,
outputBufferSize: nil,
flags: 0)
flags: 0
)
if let demangledNamePtr = demangledNamePtr {
let demangledName = String(cString: demangledNamePtr)
@@ -33,3 +54,4 @@ internal func _stdlib_demangleName(_ mangledName: String) -> String {
return mangledName
}
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* atomic.c -- Support for atomic functions if not present.
Copyright (C) 2013-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -111,3 +112,4 @@ backtrace_atomic_store_int (int *p, int v)
}
#endif
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* backtrace-supported.h.in -- Whether stack backtrace is supported.
Copyright (C) 2012-2016 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -64,3 +65,4 @@ POSSIBILITY OF SUCH DAMAGE. */
will work for variables. It will always work for functions. */
#define BACKTRACE_SUPPORTS_DATA 1
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* backtrace.c -- Entry point for stack backtrace library.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -127,3 +128,4 @@ backtrace_full (struct backtrace_state *state, int skip,
_Unwind_Backtrace (unwind, &bdata);
return bdata.ret;
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
@@ -148,3 +149,4 @@
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* dwarf.c -- Get file/line information from DWARF for backtraces.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -3124,3 +3125,4 @@ backtrace_dwarf_add (struct backtrace_state *state,
return 1;
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* elf.c -- Get debug data from an ELF file for backtraces.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -3338,3 +3339,4 @@ backtrace_initialize (struct backtrace_state *state, const char *filename,
return 1;
}
#endif
+6 -4
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* fileline.c -- Get file and line number information in a backtrace.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -93,14 +94,14 @@ fileline_initialize (struct backtrace_state *state,
filename = state->filename;
break;
case 1:
filename = getexecname ();
break;
case 2:
filename = "/proc/self/exe";
break;
case 3:
case 2:
filename = "/proc/curproc/file";
break;
case 3:
filename = getexecname ();
break;
case 4:
snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out",
(long) getpid ());
@@ -199,3 +200,4 @@ backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
state->syminfo_fn (state, pc, callback, error_callback, data);
return 1;
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* btest.c -- Filename header for libbacktrace library
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -47,3 +48,4 @@ POSSIBILITY OF SUCH DAMAGE. */
#else
# define IS_DIR_SEPARATOR(c) ((c) == '/')
#endif
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* backtrace.h -- Public header file for stack backtrace library.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -180,3 +181,4 @@ extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr,
#endif
#endif
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* internal.h -- Internal header file for stack backtrace library.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -302,3 +303,4 @@ extern int backtrace_uncompress_zdebug (struct backtrace_state *,
size_t *uncompressed_size);
#endif
#endif
+3 -1
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* mmap.c -- Memory allocation with mmap.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -169,7 +170,7 @@ backtrace_alloc (struct backtrace_state *state,
if (page == MAP_FAILED)
{
if (error_callback)
error_callback (data, "mmap", errno);
error_callback (data, "mmap for alloc", errno);
}
else
{
@@ -323,3 +324,4 @@ backtrace_vector_release (struct backtrace_state *state,
vec->alc = 0;
return 1;
}
#endif
+3 -1
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* mmapio.c -- File views using mmap.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -70,7 +71,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", errno);
error_callback (data, "mmap file i/o", errno);
return 0;
}
@@ -98,3 +99,4 @@ backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
if (munmap (const_cast.v, view->len) < 0)
error_callback (data, "munmap", errno);
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* posix.c -- POSIX file I/O routines for the backtrace library.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -98,3 +99,4 @@ backtrace_close (int descriptor, backtrace_error_callback error_callback,
}
return 1;
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* print.c -- Print the current backtrace.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -90,3 +91,4 @@ backtrace_print (struct backtrace_state *state, int skip, FILE *f)
backtrace_full (state, skip + 1, print_callback, error_callback,
(void *) &data);
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* simple.c -- The backtrace_simple function.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -106,3 +107,4 @@ backtrace_simple (struct backtrace_state *state, int skip,
_Unwind_Backtrace (simple_unwind, &bdata);
return bdata.ret;
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* sort.c -- Sort without allocating memory
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -106,3 +107,4 @@ backtrace_qsort (void *basearg, size_t count, size_t size,
goto tail_recurse;
}
}
#endif
+2
View File
@@ -1,3 +1,4 @@
#ifdef __linux__
/* state.c -- Create the backtrace state.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
@@ -70,3 +71,4 @@ backtrace_create_state (const char *filename, int threaded,
return state;
}
#endif
+40
View File
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) 2019-2020 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
//
//===----------------------------------------------------------------------===//
import Backtrace
#if canImport(Darwin)
import Darwin
#elseif os(Linux)
import Glibc
#endif
Backtrace.install()
func raiseSignal(_ signal: Int32) {
raise(signal)
}
let reason = CommandLine.arguments.count == 2 ? CommandLine.arguments[1] : "unknown"
switch reason.uppercased() {
case "SIGILL":
raiseSignal(SIGILL)
case "SIGSEGV":
raiseSignal(SIGSEGV)
case "SIGBUS":
raiseSignal(SIGBUS)
case "SIGFPE":
raiseSignal(SIGFPE)
default:
fatalError(reason)
}
@@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) 2019-2020 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
//
//===----------------------------------------------------------------------===//
//
// BacktraceTests+XCTest.swift
//
import XCTest
///
/// NOTE: This file was generated by generate_linux_tests.rb
///
/// Do NOT edit this file directly as it will be regenerated automatically when needed.
///
extension BacktraceTests {
public static var allTests: [(String, (BacktraceTests) -> () throws -> Void)] {
return [
("testFatalError", testFatalError),
("testSIGILL", testSIGILL),
("testSIGSEGV", testSIGSEGV),
("testSIGBUS", testSIGBUS),
("testSIGFPE", testSIGFPE),
]
}
}
+86 -11
View File
@@ -1,15 +1,90 @@
import XCTest
@testable import Backtrace
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) 2019-2020 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
//
//===----------------------------------------------------------------------===//
final class BacktraceTests: XCTestCase {
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssert(true)
import XCTest
public final class BacktraceTests: XCTestCase {
func testFatalError() throws {
#if !os(Linux)
try XCTSkipIf(true, "test is only supported on Linux")
#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")
}
static var allTests = [
("testExample", testExample),
]
func testSIGILL() throws {
#if !os(Linux)
try XCTSkipIf(true, "test is only supported on Linux")
#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
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
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
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", reason]
process.standardError = pipe
try process.run()
process.waitUntilExit()
return String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) ?? ""
}
}
@@ -1,9 +0,0 @@
import XCTest
#if !canImport(ObjectiveC)
public func allTests() -> [XCTestCaseEntry] {
return [
testCase(BacktraceTests.allTests),
]
}
#endif
+27 -3
View File
@@ -1,7 +1,31 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) 2019-2020 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
//
//===----------------------------------------------------------------------===//
//
// LinuxMain.swift
//
import XCTest
///
/// NOTE: This file was generated by generate_linux_tests.rb
///
/// Do NOT edit this file directly as it will be regenerated automatically when needed.
///
#if os(Linux) || os(FreeBSD)
import BacktraceTests
var tests = [XCTestCaseEntry]()
tests += BacktraceTests.allTests()
XCTMain(tests)
XCTMain([
testCase(BacktraceTests.allTests),
])
#endif
+34
View File
@@ -0,0 +1,34 @@
ARG swift_version=5.0
ARG ubuntu_version=bionic
ARG base_image=swift:$swift_version-$ubuntu_version
FROM $base_image
# needed to do again after FROM due to docker limitation
ARG swift_version
ARG ubuntu_version
# set as UTF-8
RUN apt-get update && apt-get install -y locales locales-all
ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8
# dependencies
RUN apt-get update && apt-get install -y wget
RUN apt-get update && apt-get install -y lsof dnsutils netcat-openbsd net-tools curl jq # used by integration tests
# ruby and jazzy for docs generation
RUN apt-get update && apt-get install -y ruby ruby-dev libsqlite3-dev build-essential
# 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
RUN echo 'export PATH="$HOME/.tools:$PATH"' >> $HOME/.profile
# swiftformat (until part of the toolchain)
ARG swiftformat_version=0.44.6
RUN git clone --branch $swiftformat_version --depth 1 https://github.com/nicklockwood/SwiftFormat $HOME/.tools/swift-format
RUN cd $HOME/.tools/swift-format && swift build -c release
RUN ln -s $HOME/.tools/swift-format/.build/release/swiftformat $HOME/.tools/swiftformat
+18
View File
@@ -0,0 +1,18 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:16.04-5.1
build:
args:
ubuntu_version: "xenial"
swift_version: "5.1"
test:
image: swift-linux-backtrace:16.04-5.1
environment:
- SANITIZER_ARG=--sanitize=thread
shell:
image: swift-linux-backtrace:16.04-5.1
+16
View File
@@ -0,0 +1,16 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:18.04-5.0
build:
args:
ubuntu_version: "bionic"
swift_version: "5.0"
test:
image: swift-linux-backtrace:18.04-5.0
shell:
image: swift-linux-backtrace:18.04-5.0
+16
View File
@@ -0,0 +1,16 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:18.04-5.2
build:
args:
ubuntu_version: "bionic"
swift_version: "5.2"
test:
image: swift-linux-backtrace:18.04-5.2
shell:
image: swift-linux-backtrace:18.04-5.2
+16
View File
@@ -0,0 +1,16 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:18.04-5.3
build:
args:
ubuntu_version: "bionic"
swift_version: "5.3"
test:
image: swift-linux-backtrace:18.04-5.3
shell:
image: swift-linux-backtrace:18.04-5.3
+16
View File
@@ -0,0 +1,16 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:20.04-5.4
build:
args:
ubuntu_version: "focal"
swift_version: "5.4"
test:
image: swift-linux-backtrace:20.04-5.4
shell:
image: swift-linux-backtrace:20.04-5.4
+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
+16
View File
@@ -0,0 +1,16 @@
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
shell:
image: swift-linux-backtrace:20.04-5.6
+15
View File
@@ -0,0 +1,15 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:20.04-5.7
build:
args:
base_image: "swiftlang/swift:nightly-main-focal"
test:
image: swift-linux-backtrace:20.04-5.7
shell:
image: swift-linux-backtrace:20.04-5.7
+15
View File
@@ -0,0 +1,15 @@
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:20.04-main
build:
args:
base_image: "swiftlang/swift:nightly-main-focal"
test:
image: swift-linux-backtrace:20.04-main
shell:
image: swift-linux-backtrace:20.04-main
+37
View File
@@ -0,0 +1,37 @@
# this file is not designed to be run directly
# instead, use the docker-compose.<os>.<swift> files
# eg docker-compose -f docker/docker-compose.yaml -f docker/docker-compose.1804.50.yaml run test
version: "3"
services:
runtime-setup:
image: swift-linux-backtrace:default
build:
context: .
dockerfile: Dockerfile
common: &common
image: swift-linux-backtrace:default
depends_on: [runtime-setup]
volumes:
- ~/.ssh:/root/.ssh
- ..:/code:z
working_dir: /code
cap_drop:
- CAP_NET_RAW
- CAP_NET_BIND_SERVICE
sanity:
<<: *common
command: /bin/bash -cl "./scripts/sanity.sh"
test:
<<: *common
command: /bin/bash -cl "swift test -c release -Xswiftc -g -Xswiftc -warnings-as-errors $${SANITIZER_ARG-}"
# util
shell:
<<: *common
entrypoint: /bin/bash -l
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftLinuxBacktrace open source project
##
## Copyright (c) 2019-2020 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
##
##===----------------------------------------------------------------------===##
set -eu
here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
contributors=$( cd "$here"/.. && git shortlog -es | cut -f2 | sed 's/^/- /' )
cat > "$here/../CONTRIBUTORS.txt" <<- EOF
For the purpose of tracking copyright, this is the list of individuals and
organizations who have contributed source code to SwiftLinuxBacktrace.
For employees of an organization/company where the copyright of work done
by employees of that company is held by the company itself, only the company
needs to be listed here.
## COPYRIGHT HOLDERS
- Apple Inc. (all contributors with '@apple.com')
### Contributors
$contributors
**Updating this list**
Please do not edit this file manually. It is generated using \`./scripts/generate_contributors_list.sh\`. If a name is misspelled or appearing multiple times: add an entry in \`./.mailmap\`
EOF
+231
View File
@@ -0,0 +1,231 @@
#!/usr/bin/env ruby
#
# process_test_files.rb
#
# Copyright 2016 Tony Stone
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Created by Tony Stone on 5/4/16.
#
require 'getoptlong'
require 'fileutils'
require 'pathname'
include FileUtils
#
# This ruby script will auto generate LinuxMain.swift and the +XCTest.swift extension files for Swift Package Manager on Linux platforms.
#
# See https://github.com/apple/swift-corelibs-xctest/blob/master/Documentation/Linux.md
#
def header(fileName)
string = <<-eos
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) 2019-2020 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
//
//===----------------------------------------------------------------------===//
//
// <FileName>
//
import XCTest
///
/// NOTE: This file was generated by generate_linux_tests.rb
///
/// Do NOT edit this file directly as it will be regenerated automatically when needed.
///
eos
string
.sub('<FileName>', File.basename(fileName))
.sub('<Date>', Time.now.to_s)
end
def createExtensionFile(fileName, classes)
extensionFile = fileName.sub! '.swift', '+XCTest.swift'
print 'Creating file: ' + extensionFile + "\n"
File.open(extensionFile, 'w') do |file|
file.write header(extensionFile)
file.write "\n"
for classArray in classes
file.write 'extension ' + classArray[0] + " {\n"
file.write ' public static var allTests: [(String, (' + classArray[0] + ") -> () throws -> Void)] {\n"
file.write " return [\n"
for funcName in classArray[1]
file.write ' ("' + funcName + '", ' + funcName + "),\n"
end
file.write " ]\n"
file.write " }\n"
file.write "}\n"
end
end
end
def createLinuxMain(testsDirectory, allTestSubDirectories, files)
fileName = testsDirectory + '/LinuxMain.swift'
print 'Creating file: ' + fileName + "\n"
File.open(fileName, 'w') do |file|
file.write header(fileName)
file.write "\n"
file.write "#if os(Linux) || os(FreeBSD)\n"
for testSubDirectory in allTestSubDirectories.sort { |x, y| x <=> y }
file.write 'import ' + testSubDirectory + "\n"
end
file.write "\n"
file.write "XCTMain([\n"
testCases = []
for classes in files
for classArray in classes
testCases << classArray[0]
end
end
for testCase in testCases.sort { |x, y| x <=> y }
file.write ' testCase(' + testCase + ".allTests),\n"
end
file.write "])\n"
file.write "#endif\n"
end
end
def parseSourceFile(fileName)
puts 'Parsing file: ' + fileName + "\n"
classes = []
currentClass = nil
inIfLinux = false
inElse = false
ignore = false
#
# Read the file line by line
# and parse to find the class
# names and func names
#
File.readlines(fileName).each do |line|
if inIfLinux
if /\#else/.match(line)
inElse = true
ignore = true
else
if /\#end/.match(line)
inElse = false
inIfLinux = false
ignore = false
end
end
else
if /\#if[ \t]+os\(Linux\)/.match(line)
inIfLinux = true
ignore = false
end
end
next if ignore
# Match class or func
match = line[/class[ \t]+[a-zA-Z0-9_]*(?=[ \t]*:[ \t]*XCTestCase)|func[ \t]+test[a-zA-Z0-9_]*(?=[ \t]*\(\))/, 0]
if match
if match[/class/, 0] == 'class'
className = match.sub(/^class[ \t]+/, '')
#
# Create a new class / func structure
# and add it to the classes array.
#
currentClass = [className, []]
classes << currentClass
else # Must be a func
funcName = match.sub(/^func[ \t]+/, '')
#
# Add each func name the the class / func
# structure created above.
#
currentClass[1] << funcName
end
end
end
classes
end
#
# Main routine
#
#
testsDirectory = 'Tests'
options = GetoptLong.new(['--tests-dir', GetoptLong::OPTIONAL_ARGUMENT])
options.quiet = true
begin
options.each do |option, value|
case option
when '--tests-dir'
testsDirectory = value
end
end
rescue GetoptLong::InvalidOption
end
allTestSubDirectories = []
allFiles = []
Dir[testsDirectory + '/*'].each do |subDirectory|
next unless File.directory?(subDirectory)
directoryHasClasses = false
Dir[subDirectory + '/*Test{s,}.swift'].each do |fileName|
next unless File.file? fileName
fileClasses = parseSourceFile(fileName)
#
# If there are classes in the
# test source file, create an extension
# file for it.
#
next unless fileClasses.count > 0
createExtensionFile(fileName, fileClasses)
directoryHasClasses = true
allFiles << fileClasses
end
if directoryHasClasses
allTestSubDirectories << Pathname.new(subDirectory).split.last.to_s
end
end
#
# Last step is the create a LinuxMain.swift file that
# references all the classes and funcs in the source files.
#
if allFiles.count > 0
createLinuxMain(testsDirectory, allTestSubDirectories, allFiles)
end
# eof
+140
View File
@@ -0,0 +1,140 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftLinuxBacktrace open source project
##
## Copyright (c) 2017-2018 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
##
##===----------------------------------------------------------------------===##
set -eu
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/'
}
printf "=> Checking linux tests... "
FIRST_OUT="$(git status --porcelain)"
ruby "$here/../scripts/generate_linux_tests.rb" > /dev/null
SECOND_OUT="$(git status --porcelain)"
if [[ "$FIRST_OUT" != "$SECOND_OUT" ]]; then
printf "\033[0;31mmissing changes!\033[0m\n"
git --no-pager diff
exit 1
else
printf "\033[0;32mokay.\033[0m\n"
fi
printf "=> Checking format... "
FIRST_OUT="$(git status --porcelain)"
swiftformat . > /dev/null 2>&1
SECOND_OUT="$(git status --porcelain)"
if [[ "$FIRST_OUT" != "$SECOND_OUT" ]]; then
printf "\033[0;31mformatting issues!\033[0m\n"
git --no-pager diff
exit 1
else
printf "\033[0;32mokay.\033[0m\n"
fi
printf "=> Checking license headers\n"
tmp=$(mktemp /tmp/.swift-aws-lambda-sanity_XXXXXX)
for language in swift-or-c bash dtrace; do
printf " * $language... "
declare -a matching_files
declare -a exceptions
expections=( )
matching_files=( -name '*' )
case "$language" in
swift-or-c)
exceptions=( -name Package.swift -o -path './Sources/CBacktrace/*' )
matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' )
cat > "$tmp" <<"EOF"
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLinuxBacktrace open source project
//
// Copyright (c) YEARS 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
//
//===----------------------------------------------------------------------===//
EOF
;;
bash)
matching_files=( -name '*.sh' )
cat > "$tmp" <<"EOF"
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftLinuxBacktrace open source project
##
## Copyright (c) YEARS 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
##
##===----------------------------------------------------------------------===##
EOF
;;
dtrace)
matching_files=( -name '*.d' )
cat > "$tmp" <<"EOF"
#!/usr/sbin/dtrace -q -s
/*===----------------------------------------------------------------------===*
*
* This source file is part of the SwiftLinuxBacktrace open source project
*
* Copyright (c) YEARS 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
*
*===----------------------------------------------------------------------===*/
EOF
;;
*)
echo >&2 "ERROR: unknown language '$language'"
;;
esac
expected_lines=$(cat "$tmp" | wc -l)
expected_sha=$(cat "$tmp" | shasum)
(
cd "$here/.."
find . \
\( \! -path './.build/*' -a \
\( "${matching_files[@]}" \) -a \
\( \! \( "${exceptions[@]}" \) \) \) | while read line; do
if [[ "$(cat "$line" | replace_acceptable_years | head -n $expected_lines | shasum)" != "$expected_sha" ]]; then
printf "\033[0;31mmissing headers in file '$line'!\033[0m\n"
diff -u <(cat "$line" | replace_acceptable_years | head -n $expected_lines) "$tmp"
exit 1
fi
done
printf "\033[0;32mokay.\033[0m\n"
)
done
rm "$tmp"
+18
View File
@@ -1,3 +1,18 @@
#!/bin/bash
##===----------------------------------------------------------------------===##
##
## This source file is part of the SwiftLinuxBacktrace open source project
##
## Copyright (c) 2019-2020 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
##
##===----------------------------------------------------------------------===##
#!/bin/bash
# This script creates a vendored copy of libbacktrace that is
@@ -69,4 +84,7 @@ mv "$DSTROOT/backtrace.h" "$DSTROOT/include"
echo "REPLACING references to \"backtrace.h\" with \"include/backtrace.h\""
find $DSTROOT -name "*.[ch]" -print0 | xargs -0 sed -i -e 's#"backtrace.h"#"include/backtrace.h"#g'
echo "ADDING preprocessor conditionals"
find $DSTROOT -name "*.[ch]" -print0 | xargs -0 sed -i -e '1i#ifdef __linux__' -e '$a#endif'
echo "DONE"