mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Backtracing] Add an indication that we're working on a backtrace.
When we crash, emit a message straight away that says we're working on a backtrace. If starting the backtracer fails, report that also. Finally, add a duration to the messages output by the backtracer, so that we can see how long it took. rdar://118055527
This commit is contained in:
@@ -31,114 +31,17 @@
|
|||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
// For DWORD
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#define NOMINMAX
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// For wchar_t
|
|
||||||
#include <cwchar>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
namespace swift {
|
namespace swift {
|
||||||
namespace runtime {
|
namespace runtime {
|
||||||
namespace backtrace {
|
namespace backtrace {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
// Test if a given function is a Swift thunk of some sort.
|
||||||
typedef wchar_t ArgChar;
|
//
|
||||||
typedef DWORD ErrorCode;
|
// @param mangledName is the name of the symbol to test.
|
||||||
#else
|
//
|
||||||
typedef char ArgChar;
|
// @returns true if the function is a thunk.
|
||||||
typedef int ErrorCode;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SWIFT_RUNTIME_STDLIB_INTERNAL ErrorCode _swift_installCrashHandler();
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
SWIFT_RUNTIME_STDLIB_INTERNAL bool _swift_spawnBacktracer(const ArgChar * const *argv, int memserver_fd);
|
|
||||||
#else
|
|
||||||
SWIFT_RUNTIME_STDLIB_INTERNAL bool _swift_spawnBacktracer(const ArgChar * const *argv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum class UnwindAlgorithm {
|
|
||||||
Auto = 0,
|
|
||||||
Fast = 1,
|
|
||||||
Precise = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class OnOffTty {
|
|
||||||
Off = 0,
|
|
||||||
On = 1,
|
|
||||||
TTY = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Preset {
|
|
||||||
Auto = -1,
|
|
||||||
Friendly = 0,
|
|
||||||
Medium = 1,
|
|
||||||
Full = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ThreadsToShow {
|
|
||||||
Preset = -1,
|
|
||||||
All = 0,
|
|
||||||
Crashed = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class RegistersToShow {
|
|
||||||
Preset = -1,
|
|
||||||
None = 0,
|
|
||||||
All = 1,
|
|
||||||
Crashed = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ImagesToShow {
|
|
||||||
Preset = -1,
|
|
||||||
None = 0,
|
|
||||||
All = 1,
|
|
||||||
Mentioned = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SanitizePaths {
|
|
||||||
Preset = -1,
|
|
||||||
Off = 0,
|
|
||||||
On = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class OutputTo {
|
|
||||||
Auto = -1,
|
|
||||||
Stdout = 0,
|
|
||||||
Stderr = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BacktraceSettings {
|
|
||||||
UnwindAlgorithm algorithm;
|
|
||||||
OnOffTty enabled;
|
|
||||||
bool demangle;
|
|
||||||
OnOffTty interactive;
|
|
||||||
OnOffTty color;
|
|
||||||
unsigned timeout;
|
|
||||||
ThreadsToShow threads;
|
|
||||||
RegistersToShow registers;
|
|
||||||
ImagesToShow images;
|
|
||||||
unsigned limit;
|
|
||||||
unsigned top;
|
|
||||||
SanitizePaths sanitize;
|
|
||||||
Preset preset;
|
|
||||||
bool cache;
|
|
||||||
OutputTo outputTo;
|
|
||||||
const char *swiftBacktracePath;
|
|
||||||
};
|
|
||||||
|
|
||||||
SWIFT_RUNTIME_STDLIB_INTERNAL BacktraceSettings _swift_backtraceSettings;
|
|
||||||
|
|
||||||
inline bool _swift_backtrace_isEnabled() {
|
|
||||||
return _swift_backtraceSettings.enabled == OnOffTty::On;
|
|
||||||
}
|
|
||||||
|
|
||||||
SWIFT_RUNTIME_STDLIB_SPI
|
SWIFT_RUNTIME_STDLIB_SPI
|
||||||
bool _swift_backtrace_isThunkFunction(const char *mangledName);
|
bool _swift_backtrace_isThunkFunction(const char *mangledName);
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,38 @@ internal struct SwiftBacktrace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func subtract(timespec ts: timespec, from: timespec) -> timespec {
|
||||||
|
var sec = from.tv_sec - ts.tv_sec
|
||||||
|
var nsec = from.tv_nsec - ts.tv_nsec
|
||||||
|
if nsec < 0 {
|
||||||
|
sec -= 1
|
||||||
|
nsec += 1000000000
|
||||||
|
}
|
||||||
|
return timespec(tv_sec: sec, tv_nsec: nsec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't use Foundation here, so there's no String(format:, ...)
|
||||||
|
static func format(duration: timespec) -> String {
|
||||||
|
let centisRounded = (duration.tv_nsec + 5000000) / 10000000
|
||||||
|
let centis = centisRounded % 100
|
||||||
|
let secs = duration.tv_sec + (centisRounded / 100)
|
||||||
|
let d1 = centis / 10
|
||||||
|
let d2 = centis % 10
|
||||||
|
|
||||||
|
return "\(secs).\(d1)\(d2)"
|
||||||
|
}
|
||||||
|
|
||||||
|
static func measureDuration(_ body: () -> ()) -> timespec {
|
||||||
|
var startTime = timespec()
|
||||||
|
var endTime = timespec()
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &startTime)
|
||||||
|
body()
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &endTime)
|
||||||
|
|
||||||
|
return subtract(timespec: startTime, from: endTime)
|
||||||
|
}
|
||||||
|
|
||||||
static func usage() {
|
static func usage() {
|
||||||
print("""
|
print("""
|
||||||
usage: swift-backtrace [--unwind <algorithm>] [--demangle [<bool>]] [--interactive [<bool>]] [--color [<bool>]] [--timeout <seconds>] [--preset <preset>] [--threads [<bool>]] [--registers <registers>] [--images <images>] [--cache [<bool>]] [--output-to <stream>] --crashinfo <addr>
|
usage: swift-backtrace [--unwind <algorithm>] [--demangle [<bool>]] [--interactive [<bool>]] [--color [<bool>]] [--timeout <seconds>] [--preset <preset>] [--threads [<bool>]] [--registers <registers>] [--images <images>] [--cache [<bool>]] [--output-to <stream>] --crashinfo <addr>
|
||||||
@@ -460,16 +492,25 @@ Generate a backtrace for the parent process.
|
|||||||
// want to do it *once* for all the backtraces we showed.
|
// want to do it *once* for all the backtraces we showed.
|
||||||
formattingOptions = formattingOptions.showImages(.none)
|
formattingOptions = formattingOptions.showImages(.none)
|
||||||
|
|
||||||
target = Target(crashInfoAddr: crashInfoAddr,
|
// Target's initializer fetches and symbolicates backtraces, so
|
||||||
limit: args.limit, top: args.top,
|
// we want to time that part here.
|
||||||
cache: args.cache)
|
let duration = measureDuration {
|
||||||
|
target = Target(crashInfoAddr: crashInfoAddr,
|
||||||
|
limit: args.limit, top: args.top,
|
||||||
|
cache: args.cache)
|
||||||
|
|
||||||
currentThread = target!.crashingThreadNdx
|
currentThread = target!.crashingThreadNdx
|
||||||
|
}
|
||||||
|
|
||||||
printCrashLog()
|
printCrashLog()
|
||||||
|
|
||||||
writeln("")
|
writeln("")
|
||||||
|
|
||||||
|
let formattedDuration = format(duration: duration)
|
||||||
|
|
||||||
|
writeln("Backtrace took \(formattedDuration)s")
|
||||||
|
writeln("")
|
||||||
|
|
||||||
if args.interactive {
|
if args.interactive {
|
||||||
// Make sure we're line buffered
|
// Make sure we're line buffered
|
||||||
setvbuf(stdout, nil, _IOLBF, 0)
|
setvbuf(stdout, nil, _IOLBF, 0)
|
||||||
@@ -611,7 +652,13 @@ Generate a backtrace for the parent process.
|
|||||||
description = "Program crashed: \(target.signalDescription) at \(hex(target.faultAddress))"
|
description = "Program crashed: \(target.signalDescription) at \(hex(target.faultAddress))"
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln("")
|
// Clear the message written by the crash handler
|
||||||
|
if args.color {
|
||||||
|
write("\r\u{1b}[0K")
|
||||||
|
} else {
|
||||||
|
write("\r" + String(repeating:" ", count: 80) + "\r")
|
||||||
|
}
|
||||||
|
|
||||||
writeln(theme.crashReason(description))
|
writeln(theme.crashReason(description))
|
||||||
|
|
||||||
var mentionedImages = Set<Int>()
|
var mentionedImages = Set<Int>()
|
||||||
|
|||||||
@@ -58,6 +58,8 @@
|
|||||||
#include <cxxabi.h>
|
#include <cxxabi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "BacktracePrivate.h"
|
||||||
|
|
||||||
#define DEBUG_BACKTRACING_SETTINGS 0
|
#define DEBUG_BACKTRACING_SETTINGS 0
|
||||||
|
|
||||||
#ifndef lengthof
|
#ifndef lengthof
|
||||||
@@ -987,6 +989,57 @@ _swift_spawnBacktracer(const ArgChar * const *argv)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// N.B. THIS FUNCTION MUST BE SAFE TO USE FROM A CRASH HANDLER. On Linux
|
||||||
|
// and macOS, that means it must be async-signal-safe. On Windows, there
|
||||||
|
// isn't an equivalent notion but a similar restriction applies.
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL void
|
||||||
|
_swift_displayCrashMessage(int signum, const void *pc)
|
||||||
|
{
|
||||||
|
#if !SWIFT_BACKTRACE_ON_CRASH_SUPPORTED
|
||||||
|
return;
|
||||||
|
#else
|
||||||
|
int fd = STDOUT_FILENO;
|
||||||
|
|
||||||
|
if (_swift_backtraceSettings.outputTo == OutputTo::Stderr)
|
||||||
|
fd = STDERR_FILENO;
|
||||||
|
|
||||||
|
const char *intro;
|
||||||
|
if (_swift_backtraceSettings.color == OnOffTty::On) {
|
||||||
|
intro = "\n💣 \033[91mProgram crashed: ";
|
||||||
|
} else {
|
||||||
|
intro = "\n*** Program crashed: ";
|
||||||
|
}
|
||||||
|
write(fd, intro, strlen(intro));
|
||||||
|
|
||||||
|
char sigbuf[30];
|
||||||
|
strcpy(sigbuf, "Signal ");
|
||||||
|
_swift_formatUnsigned((unsigned)signum, sigbuf + 7);
|
||||||
|
write(fd, sigbuf, strlen(sigbuf));
|
||||||
|
|
||||||
|
const char *message;
|
||||||
|
if (!pc) {
|
||||||
|
message = ": Backtracing";
|
||||||
|
} else {
|
||||||
|
message = ": Backtracing from 0x";
|
||||||
|
}
|
||||||
|
write(fd, message, strlen(message));
|
||||||
|
|
||||||
|
if (pc) {
|
||||||
|
char pcbuf[18];
|
||||||
|
_swift_formatAddress(pc, pcbuf);
|
||||||
|
write(fd, pcbuf, strlen(pcbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *outro;
|
||||||
|
if (_swift_backtraceSettings.color == OnOffTty::On) {
|
||||||
|
outro = "...\033[0m";
|
||||||
|
} else {
|
||||||
|
outro = "...";
|
||||||
|
}
|
||||||
|
write(fd, outro, strlen(outro));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace backtrace
|
} // namespace backtrace
|
||||||
} // namespace runtime
|
} // namespace runtime
|
||||||
} // namespace swift
|
} // namespace swift
|
||||||
|
|||||||
147
stdlib/public/runtime/BacktracePrivate.h
Normal file
147
stdlib/public/runtime/BacktracePrivate.h
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
//===--- BacktraceUtils.h - Private backtracing utilities -------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Swift.org open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
||||||
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||||
|
//
|
||||||
|
// See https://swift.org/LICENSE.txt for license information
|
||||||
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Private declarations of the Swift runtime's backtracing code.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef SWIFT_RUNTIME_BACKTRACE_UTILS_H
|
||||||
|
#define SWIFT_RUNTIME_BACKTRACE_UTILS_H
|
||||||
|
|
||||||
|
#include "swift/Runtime/Config.h"
|
||||||
|
#include "swift/shims/Visibility.h"
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// For DWORD
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// For wchar_t
|
||||||
|
#include <cwchar>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace swift {
|
||||||
|
namespace runtime {
|
||||||
|
namespace backtrace {
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef wchar_t ArgChar;
|
||||||
|
typedef DWORD ErrorCode;
|
||||||
|
#else
|
||||||
|
typedef char ArgChar;
|
||||||
|
typedef int ErrorCode;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum class UnwindAlgorithm {
|
||||||
|
Auto = 0,
|
||||||
|
Fast = 1,
|
||||||
|
Precise = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OnOffTty {
|
||||||
|
Off = 0,
|
||||||
|
On = 1,
|
||||||
|
TTY = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Preset {
|
||||||
|
Auto = -1,
|
||||||
|
Friendly = 0,
|
||||||
|
Medium = 1,
|
||||||
|
Full = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ThreadsToShow {
|
||||||
|
Preset = -1,
|
||||||
|
All = 0,
|
||||||
|
Crashed = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class RegistersToShow {
|
||||||
|
Preset = -1,
|
||||||
|
None = 0,
|
||||||
|
All = 1,
|
||||||
|
Crashed = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ImagesToShow {
|
||||||
|
Preset = -1,
|
||||||
|
None = 0,
|
||||||
|
All = 1,
|
||||||
|
Mentioned = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SanitizePaths {
|
||||||
|
Preset = -1,
|
||||||
|
Off = 0,
|
||||||
|
On = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OutputTo {
|
||||||
|
Auto = -1,
|
||||||
|
Stdout = 0,
|
||||||
|
Stderr = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BacktraceSettings {
|
||||||
|
UnwindAlgorithm algorithm;
|
||||||
|
OnOffTty enabled;
|
||||||
|
bool demangle;
|
||||||
|
OnOffTty interactive;
|
||||||
|
OnOffTty color;
|
||||||
|
unsigned timeout;
|
||||||
|
ThreadsToShow threads;
|
||||||
|
RegistersToShow registers;
|
||||||
|
ImagesToShow images;
|
||||||
|
unsigned limit;
|
||||||
|
unsigned top;
|
||||||
|
SanitizePaths sanitize;
|
||||||
|
Preset preset;
|
||||||
|
bool cache;
|
||||||
|
OutputTo outputTo;
|
||||||
|
const char *swiftBacktracePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL BacktraceSettings _swift_backtraceSettings;
|
||||||
|
|
||||||
|
inline bool _swift_backtrace_isEnabled() {
|
||||||
|
return _swift_backtraceSettings.enabled == OnOffTty::On;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL ErrorCode _swift_installCrashHandler();
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL bool _swift_spawnBacktracer(const ArgChar * const *argv, int memserver_fd);
|
||||||
|
#else
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL bool _swift_spawnBacktracer(const ArgChar * const *argv);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL void _swift_displayCrashMessage(int signum, const void *pc);
|
||||||
|
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||||
|
void _swift_formatAddress(uintptr_t addr, char buffer[18]);
|
||||||
|
|
||||||
|
inline void _swift_formatAddress(const void *ptr, char buffer[18]) {
|
||||||
|
_swift_formatAddress(reinterpret_cast<uintptr_t>(ptr), buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||||
|
void _swift_formatUnsigned(unsigned u, char buffer[22]);
|
||||||
|
|
||||||
|
} // namespace backtrace
|
||||||
|
} // namespace runtime
|
||||||
|
} // namespace swift
|
||||||
|
|
||||||
|
#endif // SWIFT_RUNTIME_BACKTRACE_UTILS_H
|
||||||
74
stdlib/public/runtime/BacktraceUtils.cpp
Normal file
74
stdlib/public/runtime/BacktraceUtils.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
//===--- BacktraceUtils.cpp - Private backtracing utilities -----*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// This source file is part of the Swift.org open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
||||||
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||||
|
//
|
||||||
|
// See https://swift.org/LICENSE.txt for license information
|
||||||
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Defines some async-signal-safe formatting functions.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "BacktracePrivate.h"
|
||||||
|
|
||||||
|
namespace swift {
|
||||||
|
namespace runtime {
|
||||||
|
namespace backtracing {
|
||||||
|
|
||||||
|
// We can't call sprintf() here because we're in a signal handler,
|
||||||
|
// so we need to be async-signal-safe.
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL void
|
||||||
|
_swift_formatAddress(uintptr_t addr, char buffer[18])
|
||||||
|
{
|
||||||
|
char *ptr = buffer + 18;
|
||||||
|
*--ptr = '\0';
|
||||||
|
while (ptr > buffer) {
|
||||||
|
char digit = '0' + (addr & 0xf);
|
||||||
|
if (digit > '9')
|
||||||
|
digit += 'a' - '0' - 10;
|
||||||
|
*--ptr = digit;
|
||||||
|
addr >>= 4;
|
||||||
|
if (!addr)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left-justify in the buffer
|
||||||
|
if (ptr > buffer) {
|
||||||
|
char *pt2 = buffer;
|
||||||
|
while (*ptr)
|
||||||
|
*pt2++ = *ptr++;
|
||||||
|
*pt2++ = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See above; we can't use sprintf() here.
|
||||||
|
SWIFT_RUNTIME_STDLIB_INTERNAL void
|
||||||
|
_swift_formatUnsigned(unsigned u, char buffer[22])
|
||||||
|
{
|
||||||
|
char *ptr = buffer + 22;
|
||||||
|
*--ptr = '\0';
|
||||||
|
while (ptr > buffer) {
|
||||||
|
char digit = '0' + (u % 10);
|
||||||
|
*--ptr = digit;
|
||||||
|
u /= 10;
|
||||||
|
if (!u)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left-justify in the buffer
|
||||||
|
if (ptr > buffer) {
|
||||||
|
char *pt2 = buffer;
|
||||||
|
while (*ptr)
|
||||||
|
*pt2++ = *ptr++;
|
||||||
|
*pt2++ = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace backtracing
|
||||||
|
} // namespace runtime
|
||||||
|
} // namespace swift
|
||||||
@@ -88,6 +88,7 @@ set(swift_runtime_threading_sources
|
|||||||
|
|
||||||
set(swift_runtime_backtracing_sources
|
set(swift_runtime_backtracing_sources
|
||||||
Backtrace.cpp
|
Backtrace.cpp
|
||||||
|
BacktraceUtils.cpp
|
||||||
CrashHandlerMacOS.cpp
|
CrashHandlerMacOS.cpp
|
||||||
CrashHandlerLinux.cpp)
|
CrashHandlerLinux.cpp)
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "BacktracePrivate.h"
|
||||||
|
|
||||||
// Run the memserver in a thread (0) or separate process (1)
|
// Run the memserver in a thread (0) or separate process (1)
|
||||||
#define MEMSERVER_USE_PROCESS 0
|
#define MEMSERVER_USE_PROCESS 0
|
||||||
|
|
||||||
@@ -67,7 +69,6 @@ void wait_paused(uint32_t expected, const struct timespec *timeout);
|
|||||||
int memserver_start();
|
int memserver_start();
|
||||||
int memserver_entry(void *);
|
int memserver_entry(void *);
|
||||||
bool run_backtracer(int fd);
|
bool run_backtracer(int fd);
|
||||||
void format_unsigned(unsigned u, char buffer[22]);
|
|
||||||
|
|
||||||
ssize_t safe_read(int fd, void *buf, size_t len) {
|
ssize_t safe_read(int fd, void *buf, size_t len) {
|
||||||
uint8_t *ptr = (uint8_t *)buf;
|
uint8_t *ptr = (uint8_t *)buf;
|
||||||
@@ -231,8 +232,30 @@ handle_fatal_signal(int signum,
|
|||||||
// Start the memory server
|
// Start the memory server
|
||||||
int fd = memserver_start();
|
int fd = memserver_start();
|
||||||
|
|
||||||
|
// Display a progress message
|
||||||
|
void *pc = 0;
|
||||||
|
ucontext_t *ctx = (ucontext_t *)uctx;
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
pc = (void *)(ctx->uc_mcontext.gregs[REG_RIP]);
|
||||||
|
#elif defined(__i386__)
|
||||||
|
pc = (void *)(ctx->uc_mcontext.gregs[REG_EIP]);
|
||||||
|
#elif defined(__arm64__)
|
||||||
|
pc = (void *)(ctx->uc_mcontext.pc);
|
||||||
|
#elif defined(__arm__)
|
||||||
|
pc = (void *)(ctx->uc_mcontext.gprs[15]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_swift_displayCrashMessage(signum, pc);
|
||||||
|
|
||||||
// Actually start the backtracer
|
// Actually start the backtracer
|
||||||
run_backtracer(fd);
|
if (!run_backtracer(fd)) {
|
||||||
|
const char *message = "\n\nBacktracing failed\n";
|
||||||
|
if (_swift_backtraceSettings.outputTo == OutputTo::Stderr)
|
||||||
|
write(STDERR_FILENO, message, strlen(message));
|
||||||
|
else
|
||||||
|
write(STDOUT_FILENO, message, strlen(message));
|
||||||
|
}
|
||||||
|
|
||||||
#if !MEMSERVER_USE_PROCESS
|
#if !MEMSERVER_USE_PROCESS
|
||||||
/* If the memserver is in-process, it may have set signal handlers,
|
/* If the memserver is in-process, it may have set signal handlers,
|
||||||
@@ -327,8 +350,8 @@ signal_for_suspend(int pid, int tid)
|
|||||||
char pid_buffer[22];
|
char pid_buffer[22];
|
||||||
char tid_buffer[22];
|
char tid_buffer[22];
|
||||||
|
|
||||||
format_unsigned((unsigned)pid, pid_buffer);
|
_swift_formatUnsigned((unsigned)pid, pid_buffer);
|
||||||
format_unsigned((unsigned)tid, tid_buffer);
|
_swift_formatUnsigned((unsigned)tid, tid_buffer);
|
||||||
|
|
||||||
char status_file[6 + 22 + 6 + 22 + 7 + 1];
|
char status_file[6 + 22 + 6 + 22 + 7 + 1];
|
||||||
|
|
||||||
@@ -788,60 +811,6 @@ const char *backtracer_argv[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// We can't call sprintf() here because we're in a signal handler,
|
|
||||||
// so we need to be async-signal-safe.
|
|
||||||
void
|
|
||||||
format_address(uintptr_t addr, char buffer[18])
|
|
||||||
{
|
|
||||||
char *ptr = buffer + 18;
|
|
||||||
*--ptr = '\0';
|
|
||||||
while (ptr > buffer) {
|
|
||||||
char digit = '0' + (addr & 0xf);
|
|
||||||
if (digit > '9')
|
|
||||||
digit += 'a' - '0' - 10;
|
|
||||||
*--ptr = digit;
|
|
||||||
addr >>= 4;
|
|
||||||
if (!addr)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left-justify in the buffer
|
|
||||||
if (ptr > buffer) {
|
|
||||||
char *pt2 = buffer;
|
|
||||||
while (*ptr)
|
|
||||||
*pt2++ = *ptr++;
|
|
||||||
*pt2++ = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void
|
|
||||||
format_address(const void *ptr, char buffer[18])
|
|
||||||
{
|
|
||||||
format_address(reinterpret_cast<uintptr_t>(ptr), buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// See above; we can't use sprintf() here.
|
|
||||||
void
|
|
||||||
format_unsigned(unsigned u, char buffer[22])
|
|
||||||
{
|
|
||||||
char *ptr = buffer + 22;
|
|
||||||
*--ptr = '\0';
|
|
||||||
while (ptr > buffer) {
|
|
||||||
char digit = '0' + (u % 10);
|
|
||||||
*--ptr = digit;
|
|
||||||
u /= 10;
|
|
||||||
if (!u)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left-justify in the buffer
|
|
||||||
if (ptr > buffer) {
|
|
||||||
char *pt2 = buffer;
|
|
||||||
while (*ptr)
|
|
||||||
*pt2++ = *ptr++;
|
|
||||||
*pt2++ = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
trueOrFalse(bool b) {
|
trueOrFalse(bool b) {
|
||||||
return b ? "true" : "false";
|
return b ? "true" : "false";
|
||||||
@@ -949,15 +918,15 @@ run_backtracer(int memserver_fd)
|
|||||||
|
|
||||||
backtracer_argv[28] = trueOrFalse(_swift_backtraceSettings.cache);
|
backtracer_argv[28] = trueOrFalse(_swift_backtraceSettings.cache);
|
||||||
|
|
||||||
format_unsigned(_swift_backtraceSettings.timeout, timeout_buf);
|
_swift_formatUnsigned(_swift_backtraceSettings.timeout, timeout_buf);
|
||||||
|
|
||||||
if (_swift_backtraceSettings.limit < 0)
|
if (_swift_backtraceSettings.limit < 0)
|
||||||
std::strcpy(limit_buf, "none");
|
std::strcpy(limit_buf, "none");
|
||||||
else
|
else
|
||||||
format_unsigned(_swift_backtraceSettings.limit, limit_buf);
|
_swift_formatUnsigned(_swift_backtraceSettings.limit, limit_buf);
|
||||||
|
|
||||||
format_unsigned(_swift_backtraceSettings.top, top_buf);
|
_swift_formatUnsigned(_swift_backtraceSettings.top, top_buf);
|
||||||
format_address(&crashInfo, addr_buf);
|
_swift_formatAddress(&crashInfo, addr_buf);
|
||||||
|
|
||||||
// Actually execute it
|
// Actually execute it
|
||||||
return _swift_spawnBacktracer(backtracer_argv, memserver_fd);
|
return _swift_spawnBacktracer(backtracer_argv, memserver_fd);
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "BacktracePrivate.h"
|
||||||
|
|
||||||
#ifndef lengthof
|
#ifndef lengthof
|
||||||
#define lengthof(x) (sizeof(x) / sizeof(x[0]))
|
#define lengthof(x) (sizeof(x) / sizeof(x[0]))
|
||||||
#endif
|
#endif
|
||||||
@@ -225,9 +227,33 @@ handle_fatal_signal(int signum,
|
|||||||
crashInfo.fault_address = (uint64_t)pinfo->si_addr;
|
crashInfo.fault_address = (uint64_t)pinfo->si_addr;
|
||||||
crashInfo.mctx = (uint64_t)(((ucontext_t *)uctx)->uc_mcontext);
|
crashInfo.mctx = (uint64_t)(((ucontext_t *)uctx)->uc_mcontext);
|
||||||
|
|
||||||
|
// Display a progress message
|
||||||
|
void *pc = 0;
|
||||||
|
ucontext_t *ctx = (ucontext_t *)uctx;
|
||||||
|
|
||||||
|
#ifdef __DARWIN_UNIX03
|
||||||
|
#define CTX_MEMBER(x) __##x
|
||||||
|
#else
|
||||||
|
#define CTX_MEMBER(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
pc = (void *)(ctx->uc_mcontext->CTX_MEMBER(ss).CTX_MEMBER(rip));
|
||||||
|
#elif defined(__arm64__)
|
||||||
|
pc = (void *)(ctx->uc_mcontext->CTX_MEMBER(ss).CTX_MEMBER(pc));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_swift_displayCrashMessage(signum, pc);
|
||||||
|
|
||||||
/* Start the backtracer; this will suspend the process, so there's no need
|
/* Start the backtracer; this will suspend the process, so there's no need
|
||||||
to try to suspend other threads from here. */
|
to try to suspend other threads from here. */
|
||||||
run_backtracer();
|
if (!run_backtracer()) {
|
||||||
|
const char *message = "\n\nBacktracing failed\n";
|
||||||
|
if (_swift_backtraceSettings.outputTo == OutputTo::Stderr)
|
||||||
|
write(STDERR_FILENO, message, strlen(message));
|
||||||
|
else
|
||||||
|
write(STDOUT_FILENO, message, strlen(message));
|
||||||
|
}
|
||||||
|
|
||||||
// Restart the other threads
|
// Restart the other threads
|
||||||
resume_other_threads();
|
resume_other_threads();
|
||||||
@@ -275,60 +301,6 @@ const char *backtracer_argv[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
// We can't call sprintf() here because we're in a signal handler,
|
|
||||||
// so we need to be async-signal-safe.
|
|
||||||
void
|
|
||||||
format_address(uintptr_t addr, char buffer[18])
|
|
||||||
{
|
|
||||||
char *ptr = buffer + 18;
|
|
||||||
*--ptr = '\0';
|
|
||||||
while (ptr > buffer) {
|
|
||||||
char digit = '0' + (addr & 0xf);
|
|
||||||
if (digit > '9')
|
|
||||||
digit += 'a' - '0' - 10;
|
|
||||||
*--ptr = digit;
|
|
||||||
addr >>= 4;
|
|
||||||
if (!addr)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left-justify in the buffer
|
|
||||||
if (ptr > buffer) {
|
|
||||||
char *pt2 = buffer;
|
|
||||||
while (*ptr)
|
|
||||||
*pt2++ = *ptr++;
|
|
||||||
*pt2++ = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void
|
|
||||||
format_address(const void *ptr, char buffer[18])
|
|
||||||
{
|
|
||||||
format_address(reinterpret_cast<uintptr_t>(ptr), buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// See above; we can't use sprintf() here.
|
|
||||||
void
|
|
||||||
format_unsigned(unsigned u, char buffer[22])
|
|
||||||
{
|
|
||||||
char *ptr = buffer + 22;
|
|
||||||
*--ptr = '\0';
|
|
||||||
while (ptr > buffer) {
|
|
||||||
char digit = '0' + (u % 10);
|
|
||||||
*--ptr = digit;
|
|
||||||
u /= 10;
|
|
||||||
if (!u)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Left-justify in the buffer
|
|
||||||
if (ptr > buffer) {
|
|
||||||
char *pt2 = buffer;
|
|
||||||
while (*ptr)
|
|
||||||
*pt2++ = *ptr++;
|
|
||||||
*pt2++ = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
trueOrFalse(bool b) {
|
trueOrFalse(bool b) {
|
||||||
return b ? "true" : "false";
|
return b ? "true" : "false";
|
||||||
@@ -436,15 +408,15 @@ run_backtracer()
|
|||||||
|
|
||||||
backtracer_argv[28] = trueOrFalse(_swift_backtraceSettings.cache);
|
backtracer_argv[28] = trueOrFalse(_swift_backtraceSettings.cache);
|
||||||
|
|
||||||
format_unsigned(_swift_backtraceSettings.timeout, timeout_buf);
|
_swift_formatUnsigned(_swift_backtraceSettings.timeout, timeout_buf);
|
||||||
|
|
||||||
if (_swift_backtraceSettings.limit < 0)
|
if (_swift_backtraceSettings.limit < 0)
|
||||||
std::strcpy(limit_buf, "none");
|
std::strcpy(limit_buf, "none");
|
||||||
else
|
else
|
||||||
format_unsigned(_swift_backtraceSettings.limit, limit_buf);
|
_swift_formatUnsigned(_swift_backtraceSettings.limit, limit_buf);
|
||||||
|
|
||||||
format_unsigned(_swift_backtraceSettings.top, top_buf);
|
_swift_formatUnsigned(_swift_backtraceSettings.top, top_buf);
|
||||||
format_address(&crashInfo, addr_buf);
|
_swift_formatAddress(&crashInfo, addr_buf);
|
||||||
|
|
||||||
// Actually execute it
|
// Actually execute it
|
||||||
return _swift_spawnBacktracer(backtracer_argv);
|
return _swift_spawnBacktracer(backtracer_argv);
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
|
|
||||||
#include "ImageInspection.h"
|
#include "ImageInspection.h"
|
||||||
#include "swift/Demangling/Demangle.h"
|
#include "swift/Demangling/Demangle.h"
|
||||||
#include "swift/Runtime/Backtrace.h"
|
|
||||||
#include "swift/Runtime/Debug.h"
|
#include "swift/Runtime/Debug.h"
|
||||||
#include "swift/Runtime/Portability.h"
|
#include "swift/Runtime/Portability.h"
|
||||||
#include "swift/Runtime/Win32.h"
|
#include "swift/Runtime/Win32.h"
|
||||||
@@ -71,6 +70,8 @@
|
|||||||
#include "swift/Runtime/Atomic.h"
|
#include "swift/Runtime/Atomic.h"
|
||||||
#endif // SWIFT_HAVE_CRASHREPORTERCLIENT
|
#endif // SWIFT_HAVE_CRASHREPORTERCLIENT
|
||||||
|
|
||||||
|
#include "BacktracePrivate.h"
|
||||||
|
|
||||||
namespace FatalErrorFlags {
|
namespace FatalErrorFlags {
|
||||||
enum: uint32_t {
|
enum: uint32_t {
|
||||||
ReportBacktrace = 1 << 0
|
ReportBacktrace = 1 << 0
|
||||||
|
|||||||
Reference in New Issue
Block a user