From 86d1678403a46cd30019487dcc21166c1d09a597 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Sun, 10 Mar 2019 19:27:59 -0700 Subject: [PATCH] Support using LLVM's libunwind as the unwinder implementation This avoids the dependency on host libraries such as libgcc_s which may be undesirable in some deployment environments where these aren't available. --- Cargo.lock | 1 + config.toml.example | 3 ++ src/bootstrap/config.rs | 3 ++ src/bootstrap/configure.py | 2 ++ src/bootstrap/lib.rs | 3 ++ src/libstd/Cargo.toml | 1 + src/libunwind/Cargo.toml | 9 +++++ src/libunwind/build.rs | 67 +++++++++++++++++++++++++++++++++++++- src/llvm-project | 2 +- 9 files changed, 89 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7007017078e6..4a71884cb086e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3849,6 +3849,7 @@ dependencies = [ name = "unwind" version = "0.0.0" dependencies = [ + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/config.toml.example b/config.toml.example index 5e0a2fbf0d373..8b2153cd2e63c 100644 --- a/config.toml.example +++ b/config.toml.example @@ -421,6 +421,9 @@ # development of NLL #test-compare-mode = false +# Use LLVM libunwind as the implementation for Rust's unwinder. +#llvm-libunwind = false + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index cb71550c12d4d..0c31c41ceda86 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -48,6 +48,7 @@ pub struct Config { pub exclude: Vec, pub rustc_error_format: Option, pub test_compare_mode: bool, + pub llvm_libunwind: bool, pub run_host_only: bool, @@ -329,6 +330,7 @@ struct Rust { remap_debuginfo: Option, jemalloc: Option, test_compare_mode: Option, + llvm_libunwind: Option, } /// TOML representation of how each build target is configured. @@ -548,6 +550,7 @@ impl Config { set(&mut config.rust_rpath, rust.rpath); set(&mut config.jemalloc, rust.jemalloc); set(&mut config.test_compare_mode, rust.test_compare_mode); + set(&mut config.llvm_libunwind, rust.llvm_libunwind); set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); set(&mut config.rust_dist_src, rust.dist_src); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index b2d8f2d8ebfcf..ade8afee7c109 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -68,6 +68,8 @@ def v(*args): o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags") o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags") +o("llvm-libunwind", "rust.llvm_libunwind", "use LLVM libunwind") + # Optimization and debugging options. These may be overridden by the release # channel, etc. o("optimize", "rust.optimize", "build optimized rust code") diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 47ac04baf6d6d..bcd28e9cf5e70 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -506,6 +506,9 @@ impl Build { fn std_features(&self) -> String { let mut features = "panic-unwind".to_string(); + if self.config.llvm_libunwind { + features.push_str(" llvm-libunwind"); + } if self.config.backtrace { features.push_str(" backtrace"); } diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 9ac03adfc2778..875483518e872 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -54,6 +54,7 @@ backtrace = ["backtrace-sys"] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] compiler_builtins_c = ["compiler_builtins/c"] +llvm-libunwind = ["unwind/llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = ["core/panic_immediate_abort"] diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml index 2378b0a315a16..4ddc878997ee5 100644 --- a/src/libunwind/Cargo.toml +++ b/src/libunwind/Cargo.toml @@ -4,6 +4,9 @@ name = "unwind" version = "0.0.0" build = "build.rs" edition = "2018" +include = [ + '/libunwind/*', +] [lib] name = "unwind" @@ -16,3 +19,9 @@ doc = false core = { path = "../libcore" } libc = { version = "0.2.43", features = ['rustc-dep-of-std'], default-features = false } compiler_builtins = "0.1.0" + +[build-dependencies] +cc = { optional = true, version = "1.0.1" } + +[features] +llvm-libunwind = ["cc"] diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index b50a11fa03ab6..f3fda9eaa75f4 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -4,7 +4,13 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); - if target.contains("linux") { + if cfg!(feature = "llvm-libunwind") && + (target.contains("linux") || + target.contains("fuchsia")) { + // Build the unwinding from libunwind C/C++ source code. + #[cfg(feature = "llvm-libunwind")] + llvm_libunwind::compile(); + } else if target.contains("linux") { if target.contains("musl") { // musl is handled in lib.rs } else if !target.contains("android") { @@ -37,3 +43,62 @@ fn main() { println!("cargo:rustc-link-lib=unwind"); } } + +#[cfg(feature = "llvm-libunwind")] +mod llvm_libunwind { + use std::env; + use std::path::Path; + + /// Compile the libunwind C/C++ source code. + pub fn compile() { + let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); + let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + let cfg = &mut cc::Build::new(); + + cfg.cpp(true); + cfg.cpp_set_stdlib(None); + cfg.warnings(false); + + if target_env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + cfg.flag("/EHsc"); + cfg.define("_CRT_SECURE_NO_WARNINGS", None); + cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); + } else { + cfg.flag("-std=c99"); + cfg.flag("-std=c++11"); + cfg.flag("-nostdinc++"); + if cfg.is_flag_supported("-funwind-tables").unwrap_or_default() && + cfg.is_flag_supported("-fno-exceptions").unwrap_or_default() { + cfg.flag("-funwind-tables"); + cfg.flag("-fno-exceptions"); + } + cfg.flag("-fno-rtti"); + cfg.flag("-fstrict-aliasing"); + } + + let mut unwind_sources = vec![ + "Unwind-EHABI.cpp", + "Unwind-seh.cpp", + "Unwind-sjlj.c", + "UnwindLevel1-gcc-ext.c", + "UnwindLevel1.c", + "UnwindRegistersRestore.S", + "UnwindRegistersSave.S", + "libunwind.cpp", + ]; + + if target_vendor == "apple" { + unwind_sources.push("Unwind_AppleExtras.cpp"); + } + + let root = Path::new("../llvm-project/libunwind"); + cfg.include(root.join("include")); + for src in unwind_sources { + cfg.file(root.join("src").join(src)); + } + + cfg.compile("unwind"); + } +} diff --git a/src/llvm-project b/src/llvm-project index 1f484cbe0e863..84abffda0e03b 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 1f484cbe0e863e9e215f1b3d7198063444d60873 +Subproject commit 84abffda0e03b03c62bdfc3cfeda1c2cf1f88c85