From 86d1678403a46cd30019487dcc21166c1d09a597 Mon Sep 17 00:00:00 2001
From: Petr Hosek <phosek@google.com>
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<PathBuf>,
     pub rustc_error_format: Option<String>,
     pub test_compare_mode: bool,
+    pub llvm_libunwind: bool,
 
     pub run_host_only: bool,
 
@@ -329,6 +330,7 @@ struct Rust {
     remap_debuginfo: Option<bool>,
     jemalloc: Option<bool>,
     test_compare_mode: Option<bool>,
+    llvm_libunwind: Option<bool>,
 }
 
 /// 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