Browse Source

Initial commit

Amanieu d'Antras 4 năm trước cách đây
commit
2b773ec94b
72 tập tin đã thay đổi với 21992 bổ sung0 xóa
  1. 74 0
      .github/workflows/ci.yml
  2. 2 0
      .gitignore
  3. 12 0
      CHANGELOG.md
  4. 20 0
      Cargo.toml
  5. 201 0
      LICENSE-APACHE
  6. 25 0
      LICENSE-MIT
  7. 183 0
      README.md
  8. 80 0
      build.rs
  9. 4 0
      eh_frame.ld
  10. 26 0
      examples/backtrace.rs
  11. 6 0
      include/assert.h
  12. 1 0
      include/inttypes.h
  13. 8 0
      include/stdio.h
  14. 9 0
      include/stdlib.h
  15. 9 0
      include/string.h
  16. 2 0
      llvm-libunwind/.clang-format
  17. 348 0
      llvm-libunwind/CMakeLists.txt
  18. 311 0
      llvm-libunwind/LICENSE.TXT
  19. 64 0
      llvm-libunwind/cmake/Modules/HandleCompilerRT.cmake
  20. 272 0
      llvm-libunwind/cmake/Modules/HandleLibunwindFlags.cmake
  21. 105 0
      llvm-libunwind/cmake/config-ix.cmake
  22. 161 0
      llvm-libunwind/docs/BuildingLibunwind.rst
  23. 7 0
      llvm-libunwind/docs/CMakeLists.txt
  24. 13 0
      llvm-libunwind/docs/README.txt
  25. 252 0
      llvm-libunwind/docs/conf.py
  26. 104 0
      llvm-libunwind/docs/index.rst
  27. 176 0
      llvm-libunwind/include/__libunwind_config.h
  28. 1103 0
      llvm-libunwind/include/libunwind.h
  29. 477 0
      llvm-libunwind/include/mach-o/compact_unwind_encoding.h
  30. 395 0
      llvm-libunwind/include/unwind.h
  31. 630 0
      llvm-libunwind/src/AddressSpace.hpp
  32. 202 0
      llvm-libunwind/src/CMakeLists.txt
  33. 697 0
      llvm-libunwind/src/CompactUnwinder.hpp
  34. 829 0
      llvm-libunwind/src/DwarfInstructions.hpp
  35. 813 0
      llvm-libunwind/src/DwarfParser.hpp
  36. 169 0
      llvm-libunwind/src/EHHeaderParser.hpp
  37. 149 0
      llvm-libunwind/src/FrameHeaderCache.hpp
  38. 114 0
      llvm-libunwind/src/RWMutex.hpp
  39. 4491 0
      llvm-libunwind/src/Registers.hpp
  40. 1003 0
      llvm-libunwind/src/Unwind-EHABI.cpp
  41. 50 0
      llvm-libunwind/src/Unwind-EHABI.h
  42. 489 0
      llvm-libunwind/src/Unwind-seh.cpp
  43. 528 0
      llvm-libunwind/src/Unwind-sjlj.c
  44. 2128 0
      llvm-libunwind/src/UnwindCursor.hpp
  45. 326 0
      llvm-libunwind/src/UnwindLevel1-gcc-ext.c
  46. 513 0
      llvm-libunwind/src/UnwindLevel1.c
  47. 1161 0
      llvm-libunwind/src/UnwindRegistersRestore.S
  48. 1114 0
      llvm-libunwind/src/UnwindRegistersSave.S
  49. 113 0
      llvm-libunwind/src/Unwind_AppleExtras.cpp
  50. 223 0
      llvm-libunwind/src/assembly.h
  51. 241 0
      llvm-libunwind/src/config.h
  52. 239 0
      llvm-libunwind/src/dwarf2.h
  53. 328 0
      llvm-libunwind/src/libunwind.cpp
  54. 65 0
      llvm-libunwind/src/libunwind_ext.h
  55. 35 0
      llvm-libunwind/test/CMakeLists.txt
  56. 24 0
      llvm-libunwind/test/alignment.compile.pass.cpp
  57. 72 0
      llvm-libunwind/test/frameheadercache_test.pass.cpp
  58. 0 0
      llvm-libunwind/test/libunwind/__init__.py
  59. 0 0
      llvm-libunwind/test/libunwind/test/__init__.py
  60. 69 0
      llvm-libunwind/test/libunwind/test/config.py
  61. 64 0
      llvm-libunwind/test/libunwind_01.pass.cpp
  62. 39 0
      llvm-libunwind/test/libunwind_02.pass.cpp
  63. 10 0
      llvm-libunwind/test/lit.cfg.py
  64. 58 0
      llvm-libunwind/test/lit.site.cfg.in
  65. 56 0
      llvm-libunwind/test/remember_state_leak.pass.sh.s
  66. 31 0
      llvm-libunwind/test/signal_frame.pass.cpp
  67. 46 0
      llvm-libunwind/test/signal_unwind.pass.cpp
  68. 9 0
      llvm-libunwind/test/unw_getcontext.pass.cpp
  69. 51 0
      llvm-libunwind/test/unwind_leaffunction.pass.cpp
  70. 40 0
      src/aarch64.rs
  71. 292 0
      src/lib.rs
  72. 31 0
      src/riscv.rs

+ 74 - 0
.github/workflows/ci.yml

@@ -0,0 +1,74 @@
+on: [push, pull_request]
+
+name: Continuous integration
+
+jobs:
+  build:
+    name: Check
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: nightly
+          override: true
+      - uses: actions-rs/cargo@v1
+        with:
+          command: check
+
+  test:
+    name: Test
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: nightly
+          override: true
+      - uses: actions-rs/cargo@v1
+        env:
+          RUSTFLAGS: -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld
+          RUSTDOCFLAGS: -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld
+        with:
+          command: test
+          args: --target x86_64-unknown-linux-gnu
+      - uses: actions-rs/cargo@v1
+        env:
+          RUSTFLAGS: -Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld
+        with:
+          command: run
+          args: --target x86_64-unknown-linux-gnu --example backtrace
+
+  fmt:
+    name: Rustfmt
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: stable
+          override: true
+      - run: rustup component add rustfmt
+      - uses: actions-rs/cargo@v1
+        with:
+          command: fmt
+          args: -- --check
+
+  clippy:
+    name: Clippy
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: nightly
+          override: true
+      - run: rustup component add clippy
+      - uses: actions-rs/cargo@v1
+        with:
+          command: clippy
+          args: -- -D warnings

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/target
+Cargo.lock

+ 12 - 0
CHANGELOG.md

@@ -0,0 +1,12 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## v0.1.0 - 2021-05-12
+
+- Initial release
+
+[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.1.0...HEAD

+ 20 - 0
Cargo.toml

@@ -0,0 +1,20 @@
+[package]
+name = "mini-backtrace"
+version = "0.1.0"
+edition = "2018"
+authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
+description = "Backtrace support for no_std and embedded programs"
+license = "Apache-2.0/MIT"
+repository = "https://github.com/Amanieu/mini-backtrace"
+keywords = ["backtrace", "no_std", "dwarf"]
+categories = ["development-tools", "no-std", "embedded"]
+
+[dependencies]
+cty = "0.2.1"
+arrayvec = { version = "0.7.0", default-features = false }
+cfg-if = "1.0.0"
+
+[build-dependencies]
+cc = "1.0.67"
+bindgen = "0.58.1"
+walkdir = "2.3.2"

+ 201 - 0
LICENSE-APACHE

@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+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.

+ 25 - 0
LICENSE-MIT

@@ -0,0 +1,25 @@
+Copyright (c) 2016 Amanieu d'Antras
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.

+ 183 - 0
README.md

@@ -0,0 +1,183 @@
+mini-backtrace
+=======
+
+[![Crates.io](https://img.shields.io/crates/v/mini-backtrace.svg)](https://crates.io/crates/mini-backtrace)
+[![Documentation](https://docs.rs/mini-backtrace/badge.svg)](https://docs.rs/mini-backtrace)
+
+This crate provides backtrace support for `no_std` and embedded programs.
+
+This is done through by compiling LLVM's libunwind with certain flags to remove
+all OS dependencies, including libc and any memory allocations.
+
+## Usage
+
+### Setup
+
+There are two prerequisites for using this crate:
+
+1. Unwind tables must be built into the binary, even with unwinding is set to
+   abort. This can be done with the `-C force-unwind-tables` flag.
+
+2. Several `__eh_frame_*` symbols need to be defined by the linker so that the
+   the unwinding tables can be located by libunwind. This can be done by
+   including the [`eh_frame.ld`] linker script fragment.
+
+Both of these can be done by setting `RUSTFLAGS`:
+
+```sh
+export RUSTFLAGS="-Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld"
+```
+
+Note that these flags also apply to build-dependencies and proc
+macros by default. This can be worked around by explicitly
+specifying a target when invoking cargo:
+
+```sh
+# Applies RUSTFLAGS to everything
+cargo build
+
+# Doesn't apply RUSTFLAGS to build dependencies and proc macros
+cargo build --target x86_64-unknown-linux-gnu
+```
+
+[`eh_frame.ld`]: https://github.com/Amanieu/mini-backtrace/blob/master/eh_frame.ld
+
+### Capturing backtraces
+
+Add the `mini-backtrace` crate as a dependency to your program:
+
+```toml
+[dependencies]
+mini-backtrace = "0.1"
+```
+
+You can capture a backtrace by using the `Backtrace` type which returns a list
+of frames as an `ArrayVec` of instruction pointer addresses.
+
+```rust
+use mini_backtrace::Backtrace;
+
+// Capture up to 16 frames. This is returned using an ArrayVec that doesn't
+// perform any dynamic memory allocation.
+let bt = Backtrace::<16>::capture();
+println!("Backtrace:");
+for frame in bt.frames {
+    println!("  {:#x}", frame);
+}
+if bt.frames_omitted {
+    println!(" ... <frames omitted>");
+}
+```
+
+This will output:
+
+```text
+Backtrace:
+  0x5587058c3eb1
+  0x5587058c3cdb
+  0x5587058c491e
+  0x5587058c38b1
+  0x5587058daf1a
+  0x5587058c3890
+  0x5587058c414c
+```
+
+### Position-independent code
+
+If your code is executing at a different address than the one it is linked at
+then you will need to fix up the frame pointer addresses to be relative to the
+module base address. This can be done with the following function:
+
+```rust
+fn adjust_for_pic(ip: usize) -> usize {
+    extern "C" {
+        // Symbol defined by the linker
+        static __executable_start: [u8; 0];
+    }
+    let base = unsafe { __executable_start.as_ptr() as usize };
+    ip - base
+}
+```
+
+After post-processing, the output should look like this:
+
+```text
+Backtrace:
+  0x8eb1
+  0x8cdb
+  0x999e
+  0x88b1
+  0x1ffba
+  0x8890
+  0x91cc
+```
+
+Have a look at `examples/backtrace.rs` for a complete example.
+
+Note that `adjust_for_pic` should *only* be called for position-independent
+binaries. Statically-linked binaries should emit unadjusted addresses so that
+the backtraces can be correctly resolved.
+
+### Resolving backtraces
+
+The addresses generated by `Backtrace` can be converted to human-readable
+function names, filenames and line numbers by using the `addr2line` tool from
+LLVM or binutils with [rustfilt] to demangle Rust symbol names.
+
+Simply run `addr2line -fipe /path/to/binary | rustfilt` in a terminal and then
+paste the addresses from the backtrace:
+
+```text
+$ llvm-addr2line -fipe target/x86_64-unknown-linux-gnu/debug/examples/backtrace | rustfilt
+  0x8ed1
+  0x8ea6
+  0x8e96
+  0x8cdb
+  0x99be
+  0x88b1
+  0x1ffda
+  0x8890
+  0x91ec
+backtrace::bar at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:15
+backtrace::foo at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:10
+backtrace::main at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:5
+core::ops::function::FnOnce::call_once at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
+std::sys_common::backtrace::__rust_begin_short_backtrace at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:128
+std::rt::lang_start::{{closure}} at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:49
+std::panicking::try at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/panicking.rs:344
+ (inlined by) std::panic::catch_unwind at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/panic.rs:431
+ (inlined by) std::rt::lang_start_internal at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/rt.rs:34
+std::rt::lang_start at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:48
+main at ??:0
+```
+
+[rustfilt]: https://github.com/luser/rustfilt
+
+### Backtraces from signal/interrupt handlers
+
+The libunwind unwinder used by this crate is usually unable to unwind past
+signal handler or interrupt handler frames. Instead, you can use
+`Backtrace::capture_from_context` and pass in the register state at the point
+where the exception occurred. In a signal handler this can be obtained through
+the `uc_mcontext` field of `ucontext_t`.
+
+This is currently only implemented for:
+- AArch64
+- RISC-V (RV32 & RV64)
+
+## [Change log](CHANGELOG.md)
+
+## License
+
+Licensed under either of:
+
+ * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
+additional terms or conditions.

+ 80 - 0
build.rs

@@ -0,0 +1,80 @@
+use std::env;
+use std::path::PathBuf;
+use walkdir::WalkDir;
+
+fn compile_libunwind() {
+    let mut cfg = cc::Build::new();
+    cfg.warnings(false);
+    cfg.cpp_set_stdlib(None);
+    cfg.cpp(true);
+    cfg.flag("-std=c++11");
+    cfg.flag("-fno-exceptions");
+    cfg.flag("-fno-rtti");
+    cfg.flag("-fstrict-aliasing");
+    cfg.flag("-fvisibility=hidden");
+    cfg.flag("-funwind-tables");
+    cfg.define("_LIBUNWIND_NO_HEAP", None);
+    cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
+    cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", None);
+    cfg.define("_LIBUNWIND_HAS_NO_THREADS", None);
+    cfg.define("NDEBUG", None);
+    cfg.include("llvm-libunwind/include");
+    cfg.include("include");
+
+    let libunwind_sources = [
+        "llvm-libunwind/src/UnwindRegistersRestore.S",
+        "llvm-libunwind/src/UnwindRegistersSave.S",
+        "llvm-libunwind/src/libunwind.cpp",
+        // Needed on ARM targets for EHABI unwinding
+        "llvm-libunwind/src/Unwind-EHABI.cpp",
+    ];
+    for source in &libunwind_sources {
+        cfg.file(source);
+    }
+
+    cfg.compile("llvm_libunwind");
+}
+
+fn gen_libunwind_bindings() {
+    println!("cargo:rerun-if-changed=bindgen-wrapper.h");
+
+    let args = vec![
+        "-nostdlibinc".to_string(),
+        "-ffreestanding".to_string(),
+        "-I".to_string(),
+        "llvm-libunwind/include".to_string(),
+        "-target".to_string(),
+        env::var("TARGET").unwrap(),
+        "-D_LIBUNWIND_IS_NATIVE_ONLY".to_string(),
+    ];
+
+    let bindings = bindgen::Builder::default()
+        .header("llvm-libunwind/include/libunwind.h")
+        .use_core()
+        .ctypes_prefix("::cty")
+        .prepend_enum_name(false)
+        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
+        .clang_args(&args)
+        .generate()
+        .expect("Unable to generate bindings");
+
+    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
+    bindings
+        .write_to_file(out_path.join("bindings.rs"))
+        .expect("Couldn't write bindings!");
+}
+
+fn main() {
+    compile_libunwind();
+    gen_libunwind_bindings();
+
+    for entry in WalkDir::new("llvm-libunwind")
+        .into_iter()
+        .chain(WalkDir::new("include").into_iter())
+    {
+        println!(
+            "cargo:rerun-if-changed={}",
+            entry.unwrap().path().to_str().unwrap()
+        );
+    }
+}

+ 4 - 0
eh_frame.ld

@@ -0,0 +1,4 @@
+__eh_frame_hdr_start = ADDR(.eh_frame_hdr);
+__eh_frame_hdr_end = ADDR(.eh_frame_hdr) + SIZEOF(.eh_frame_hdr);
+__eh_frame_start = ADDR(.eh_frame);
+__eh_frame_end = ADDR(.eh_frame) + SIZEOF(.eh_frame);

+ 26 - 0
examples/backtrace.rs

@@ -0,0 +1,26 @@
+use mini_backtrace::Backtrace;
+
+fn main() {
+    let bt = Backtrace::<16>::capture();
+    println!("Backtrace:");
+    for frame in bt.frames {
+        println!("  {:#x}", adjust_for_pic(frame));
+    }
+    if bt.frames_omitted {
+        println!(" ... <frames omitted>");
+    }
+}
+
+// For position-independent code, convert the addresses to be relative to the
+// executable base address.
+//
+// This should *only* be done for position-independent binaries, not statically
+// linked ones.
+fn adjust_for_pic(ip: usize) -> usize {
+    extern "C" {
+        // Symbol defined by the linker
+        static __executable_start: [u8; 0];
+    }
+    let base = unsafe { __executable_start.as_ptr() as usize };
+    ip - base
+}

+ 6 - 0
include/assert.h

@@ -0,0 +1,6 @@
+#ifndef __ASSERT_H
+#define __ASSERT_H
+
+#define assert(x) ((void)0)
+
+#endif

+ 1 - 0
include/inttypes.h

@@ -0,0 +1 @@
+

+ 8 - 0
include/stdio.h

@@ -0,0 +1,8 @@
+#ifndef __STDIO_H
+#define __STDIO_H
+
+#include <stddef.h>
+
+#define fprintf(...) ((void)0)
+
+#endif

+ 9 - 0
include/stdlib.h

@@ -0,0 +1,9 @@
+#ifndef __STDLIB_H
+#define __STDLIB_H
+
+#include <stddef.h>
+
+#define alloca __builtin_alloca
+#define abort __builtin_trap
+
+#endif

+ 9 - 0
include/string.h

@@ -0,0 +1,9 @@
+#ifndef __STRING_H
+#define __STRING_H
+
+#define memcpy __builtin_memcpy
+#define memmove __builtin_memmove
+#define memset __builtin_memset
+#define memcmp __builtin_memcmp
+
+#endif

+ 2 - 0
llvm-libunwind/.clang-format

@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+

+ 348 - 0
llvm-libunwind/CMakeLists.txt

@@ -0,0 +1,348 @@
+if (NOT IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../libcxx")
+  message(FATAL_ERROR "libunwind requires being built in a monorepo layout with libcxx available")
+endif()
+
+#===============================================================================
+# Setup Project
+#===============================================================================
+
+cmake_minimum_required(VERSION 3.13.4)
+
+# Add path for custom modules
+set(CMAKE_MODULE_PATH
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+  ${CMAKE_MODULE_PATH}
+  )
+
+set(LIBUNWIND_SOURCE_DIR  ${CMAKE_CURRENT_SOURCE_DIR})
+set(LIBUNWIND_BINARY_DIR  ${CMAKE_CURRENT_BINARY_DIR})
+set(LIBUNWIND_LIBCXX_PATH "${CMAKE_CURRENT_LIST_DIR}/../libcxx" CACHE PATH
+        "Specify path to libc++ source.")
+
+if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBUNWIND_STANDALONE_BUILD)
+  project(libunwind LANGUAGES C CXX ASM)
+
+  set(PACKAGE_NAME libunwind)
+  set(PACKAGE_VERSION 13.0.0git)
+  set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
+  set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org")
+
+  # Add the CMake module path of libcxx so we can reuse HandleOutOfTreeLLVM.cmake
+  set(LIBUNWIND_LIBCXX_CMAKE_PATH "${LIBUNWIND_LIBCXX_PATH}/cmake/Modules")
+  list(APPEND CMAKE_MODULE_PATH "${LIBUNWIND_LIBCXX_CMAKE_PATH}")
+
+  # In a standalone build, we don't have llvm to automatically generate the
+  # llvm-lit script for us.  So we need to provide an explicit directory that
+  # the configurator should write the script into.
+  set(LIBUNWIND_STANDALONE_BUILD 1)
+  set(LLVM_LIT_OUTPUT_DIR "${LIBUNWIND_BINARY_DIR}/bin")
+
+  # Find the LLVM sources and simulate LLVM CMake options.
+  include(HandleOutOfTreeLLVM)
+else()
+  set(LLVM_LIT "${CMAKE_SOURCE_DIR}/utils/lit/lit.py")
+endif()
+
+#===============================================================================
+# Setup CMake Options
+#===============================================================================
+include(CMakeDependentOption)
+include(HandleCompilerRT)
+
+# Define options.
+option(LIBUNWIND_BUILD_32_BITS "Build 32 bit libunwind" ${LLVM_BUILD_32_BITS})
+option(LIBUNWIND_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON)
+option(LIBUNWIND_ENABLE_PEDANTIC "Compile with pedantic enabled." ON)
+option(LIBUNWIND_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF)
+option(LIBUNWIND_ENABLE_SHARED "Build libunwind as a shared library." ON)
+option(LIBUNWIND_ENABLE_STATIC "Build libunwind as a static library." ON)
+option(LIBUNWIND_ENABLE_CROSS_UNWINDING "Enable cross-platform unwinding support." OFF)
+option(LIBUNWIND_ENABLE_ARM_WMMX "Enable unwinding support for ARM WMMX registers." OFF)
+option(LIBUNWIND_ENABLE_THREADS "Build libunwind with threading support." ON)
+option(LIBUNWIND_WEAK_PTHREAD_LIB "Use weak references to refer to pthread functions." OFF)
+option(LIBUNWIND_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF)
+option(LIBUNWIND_INCLUDE_DOCS "Build the libunwind documentation." ${LLVM_INCLUDE_DOCS})
+option(LIBUNWIND_INCLUDE_TESTS "Build the libunwind tests." ${LLVM_INCLUDE_TESTS})
+option(LIBUNWIND_IS_BAREMETAL "Build libunwind for baremetal targets." OFF)
+option(LIBUNWIND_USE_FRAME_HEADER_CACHE "Cache frame headers for unwinding. Requires locking dl_iterate_phdr." OFF)
+option(LIBUNWIND_REMEMBER_HEAP_ALLOC "Use heap instead of the stack for .cfi_remember_state." OFF)
+
+set(LIBUNWIND_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
+    "Define suffix of library directory name (32/64)")
+option(LIBUNWIND_INSTALL_LIBRARY "Install the libunwind library." ON)
+cmake_dependent_option(LIBUNWIND_INSTALL_STATIC_LIBRARY
+  "Install the static libunwind library." ON
+  "LIBUNWIND_ENABLE_STATIC;LIBUNWIND_INSTALL_LIBRARY" OFF)
+cmake_dependent_option(LIBUNWIND_INSTALL_SHARED_LIBRARY
+  "Install the shared libunwind library." ON
+  "LIBUNWIND_ENABLE_SHARED;LIBUNWIND_INSTALL_LIBRARY" OFF)
+set(LIBUNWIND_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.")
+set(LIBUNWIND_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.")
+set(LIBUNWIND_SYSROOT "" CACHE PATH "Sysroot for cross compiling.")
+set(LIBUNWIND_TEST_LINKER_FLAGS "" CACHE STRING
+    "Additional linker flags for test programs.")
+set(LIBUNWIND_TEST_COMPILER_FLAGS "" CACHE STRING
+    "Additional compiler flags for test programs.")
+set(LIBUNWIND_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/lit.site.cfg.in" CACHE STRING
+    "The Lit testing configuration to use when running the tests.")
+set(LIBUNWIND_TEST_PARAMS "" CACHE STRING
+    "A list of parameters to run the Lit test suite with.")
+
+if (NOT LIBUNWIND_ENABLE_SHARED AND NOT LIBUNWIND_ENABLE_STATIC)
+  message(FATAL_ERROR "libunwind must be built as either a shared or static library.")
+endif()
+
+# Check that we can build with 32 bits if requested.
+if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32)
+  if (LIBUNWIND_BUILD_32_BITS AND NOT LLVM_BUILD_32_BITS) # Don't duplicate the output from LLVM
+    message(STATUS "Building 32 bits executables and libraries.")
+  endif()
+elseif(LIBUNWIND_BUILD_32_BITS)
+  message(FATAL_ERROR "LIBUNWIND_BUILD_32_BITS=ON is not supported on this platform.")
+endif()
+
+option(LIBUNWIND_HIDE_SYMBOLS
+  "Do not export any symbols from the static library." OFF)
+
+#===============================================================================
+# Configure System
+#===============================================================================
+
+# Add path for custom modules
+set(CMAKE_MODULE_PATH
+    "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
+    ${CMAKE_MODULE_PATH})
+
+if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
+  set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE})
+  set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE})
+  if(LIBCXX_LIBDIR_SUBDIR)
+    string(APPEND LIBUNWIND_LIBRARY_DIR /${LIBUNWIND_LIBDIR_SUBDIR})
+    string(APPEND LIBUNWIND_INSTALL_LIBRARY_DIR /${LIBUNWIND_LIBDIR_SUBDIR})
+  endif()
+elseif(LLVM_LIBRARY_OUTPUT_INTDIR)
+  set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
+  set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LIBUNWIND_LIBDIR_SUFFIX})
+else()
+  set(LIBUNWIND_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBUNWIND_LIBDIR_SUFFIX})
+  set(LIBUNWIND_INSTALL_LIBRARY_DIR lib${LIBUNWIND_LIBDIR_SUFFIX})
+endif()
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
+
+set(LIBUNWIND_C_FLAGS "")
+set(LIBUNWIND_CXX_FLAGS "")
+set(LIBUNWIND_COMPILE_FLAGS "")
+set(LIBUNWIND_LINK_FLAGS "")
+
+# Include macros for adding and removing libunwind flags.
+include(HandleLibunwindFlags)
+
+#===============================================================================
+# Setup Compiler Flags
+#===============================================================================
+
+# Get required flags.
+add_target_flags_if(LIBUNWIND_BUILD_32_BITS "-m32")
+
+if(LIBUNWIND_TARGET_TRIPLE)
+  add_target_flags("--target=${LIBUNWIND_TARGET_TRIPLE}")
+elseif(CMAKE_CXX_COMPILER_TARGET)
+  set(LIBUNWIND_TARGET_TRIPLE "${CMAKE_CXX_COMPILER_TARGET}")
+endif()
+if(LIBUNWIND_GCC_TOOLCHAIN)
+  add_target_flags("--gcc-toolchain=${LIBUNWIND_GCC_TOOLCHAIN}")
+elseif(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN)
+  set(LIBUNWIND_GCC_TOOLCHAIN "${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}")
+endif()
+if(LIBUNWIND_SYSROOT)
+  add_target_flags("--sysroot=${LIBUNWIND_SYSROOT}")
+elseif(CMAKE_SYSROOT)
+  set(LIBUNWIND_SYSROOT "${CMAKE_SYSROOT}")
+endif()
+
+if (LIBUNWIND_TARGET_TRIPLE)
+  set(TARGET_TRIPLE "${LIBUNWIND_TARGET_TRIPLE}")
+endif()
+
+# Configure compiler.
+include(config-ix)
+
+if (LIBUNWIND_USE_COMPILER_RT AND NOT LIBUNWIND_HAS_NODEFAULTLIBS_FLAG)
+  list(APPEND LIBUNWIND_LINK_FLAGS "-rtlib=compiler-rt")
+endif()
+
+add_compile_flags_if_supported(-Werror=return-type)
+
+# Get warning flags
+add_compile_flags_if_supported(-W)
+add_compile_flags_if_supported(-Wall)
+add_compile_flags_if_supported(-Wchar-subscripts)
+add_compile_flags_if_supported(-Wconversion)
+add_compile_flags_if_supported(-Wmismatched-tags)
+add_compile_flags_if_supported(-Wmissing-braces)
+add_compile_flags_if_supported(-Wnewline-eof)
+add_compile_flags_if_supported(-Wno-unused-function)
+add_compile_flags_if_supported(-Wshadow)
+add_compile_flags_if_supported(-Wshorten-64-to-32)
+add_compile_flags_if_supported(-Wsign-compare)
+add_compile_flags_if_supported(-Wsign-conversion)
+add_compile_flags_if_supported(-Wstrict-aliasing=2)
+add_compile_flags_if_supported(-Wstrict-overflow=4)
+add_compile_flags_if_supported(-Wunused-parameter)
+add_compile_flags_if_supported(-Wunused-variable)
+add_compile_flags_if_supported(-Wwrite-strings)
+add_compile_flags_if_supported(-Wundef)
+
+add_compile_flags_if_supported(-Wno-suggest-override)
+
+if (WIN32)
+  # The headers lack matching dllexport attributes (_LIBUNWIND_EXPORT);
+  # silence the warning instead of cluttering the headers (which aren't
+  # necessarily the ones that the callers will use anyway) with the
+  # attributes.
+  add_compile_flags_if_supported(-Wno-dll-attribute-on-redeclaration)
+endif()
+
+if (LIBUNWIND_ENABLE_WERROR)
+  add_compile_flags_if_supported(-Werror)
+  add_compile_flags_if_supported(-WX)
+else()
+  add_compile_flags_if_supported(-Wno-error)
+  add_compile_flags_if_supported(-WX-)
+endif()
+
+if (LIBUNWIND_ENABLE_PEDANTIC)
+  add_compile_flags_if_supported(-pedantic)
+endif()
+
+# Get feature flags.
+# Exceptions
+# Catches C++ exceptions only and tells the compiler to assume that extern C
+# functions never throw a C++ exception.
+add_cxx_compile_flags_if_supported(-fstrict-aliasing)
+add_cxx_compile_flags_if_supported(-EHsc)
+
+# Don't run the linker in this CMake check.
+#
+# The reason why this was added is that when building libunwind for
+# ARM Linux, we need to pass the -funwind-tables flag in order for it to
+# work properly with ARM EHABI.
+#
+# However, when performing CMake checks, adding this flag causes the check
+# to produce a false negative, because the compiler generates calls
+# to __aeabi_unwind_cpp_pr0, which is defined in libunwind itself,
+# which isn't built yet, so the linker complains about undefined symbols.
+#
+# This leads to libunwind not being built with this flag, which makes
+# libunwind quite useless in this setup.
+set(_previous_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+add_compile_flags_if_supported(-funwind-tables)
+set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_previous_CMAKE_TRY_COMPILE_TARGET_TYPE})
+
+if (LIBUNWIND_USES_ARM_EHABI AND NOT LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG)
+  message(SEND_ERROR "The -funwind-tables flag must be supported "
+                     "because this target uses ARM Exception Handling ABI")
+endif()
+
+add_cxx_compile_flags_if_supported(-fno-exceptions)
+add_cxx_compile_flags_if_supported(-fno-rtti)
+
+# Ensure that we don't depend on C++ standard library.
+if (LIBUNWIND_HAS_NOSTDINCXX_FLAG)
+  list(APPEND LIBUNWIND_COMPILE_FLAGS -nostdinc++)
+  # Remove -stdlib flags to prevent them from causing an unused flag warning.
+  string(REPLACE "--stdlib=libc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+  string(REPLACE "--stdlib=libstdc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+  string(REPLACE "-stdlib=libc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+  string(REPLACE "-stdlib=libstdc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+endif()
+
+# Assert
+string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
+if (LIBUNWIND_ENABLE_ASSERTIONS)
+  # MSVC doesn't like _DEBUG on release builds. See PR 4379.
+  if (NOT MSVC)
+    add_compile_flags(-D_DEBUG)
+  endif()
+
+  # On Release builds cmake automatically defines NDEBUG, so we
+  # explicitly undefine it:
+  if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
+    add_compile_flags(-UNDEBUG)
+  endif()
+else()
+  if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
+    add_compile_flags(-DNDEBUG)
+  endif()
+endif()
+
+# Cross-unwinding
+if (NOT LIBUNWIND_ENABLE_CROSS_UNWINDING)
+  add_compile_flags(-D_LIBUNWIND_IS_NATIVE_ONLY)
+endif()
+
+# Threading-support
+if (NOT LIBUNWIND_ENABLE_THREADS)
+  add_compile_flags(-D_LIBUNWIND_HAS_NO_THREADS)
+endif()
+
+# ARM WMMX register support
+if (LIBUNWIND_ENABLE_ARM_WMMX)
+  # __ARM_WMMX is a compiler pre-define (as per the ACLE 2.0). Clang does not
+  # define this macro for any supported target at present. Therefore, here we
+  # provide the option to explicitly enable support for WMMX registers in the
+  # unwinder.
+  add_compile_flags(-D__ARM_WMMX)
+endif()
+
+if(LIBUNWIND_IS_BAREMETAL)
+  add_compile_definitions(_LIBUNWIND_IS_BAREMETAL)
+endif()
+
+if(LIBUNWIND_USE_FRAME_HEADER_CACHE)
+  add_compile_definitions(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
+endif()
+
+if(LIBUNWIND_REMEMBER_HEAP_ALLOC)
+  add_compile_definitions(_LIBUNWIND_REMEMBER_HEAP_ALLOC)
+endif()
+
+# This is the _ONLY_ place where add_definitions is called.
+if (MSVC)
+  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+# Disable DLL annotations on Windows for static builds.
+if (WIN32 AND LIBUNWIND_ENABLE_STATIC AND NOT LIBUNWIND_ENABLE_SHARED)
+  add_definitions(-D_LIBUNWIND_HIDE_SYMBOLS)
+endif()
+
+if (LIBUNWIND_HAS_COMMENT_LIB_PRAGMA)
+  if (LIBUNWIND_HAS_DL_LIB)
+    add_definitions(-D_LIBUNWIND_LINK_DL_LIB)
+  endif()
+  if (LIBUNWIND_HAS_PTHREAD_LIB)
+    add_definitions(-D_LIBUNWIND_LINK_PTHREAD_LIB)
+  endif()
+endif()
+
+#===============================================================================
+# Setup Source Code
+#===============================================================================
+
+include_directories(include)
+
+add_subdirectory(src)
+
+if (LIBUNWIND_INCLUDE_DOCS)
+  add_subdirectory(docs)
+endif()
+
+if (LIBUNWIND_INCLUDE_TESTS AND EXISTS ${LLVM_CMAKE_PATH})
+  add_subdirectory(test)
+endif()

+ 311 - 0
llvm-libunwind/LICENSE.TXT

@@ -0,0 +1,311 @@
+==============================================================================
+The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
+==============================================================================
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+    1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+    2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+    3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+    4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+    5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+    6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+    7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+    8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+    9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+    END OF TERMS AND CONDITIONS
+
+    APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+    Copyright [yyyy] [name of copyright owner]
+
+    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.
+
+
+---- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
+
+==============================================================================
+Software from third parties included in the LLVM Project:
+==============================================================================
+The LLVM Project contains third party software which is under different license
+terms. All such code will be identified clearly using at least one of two
+mechanisms:
+1) It will be in a separate directory tree with its own `LICENSE.txt` or
+   `LICENSE` file at the top containing the specific license and restrictions
+   which apply to that software, or
+2) It will contain specific license and restriction terms at the top of every
+   file.
+
+==============================================================================
+Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
+==============================================================================
+
+The libunwind library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license.  As a user of this code you may choose
+to use it under either license.  As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+    LLVM Team
+
+    University of Illinois at Urbana-Champaign
+
+    http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimers.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimers in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the names of the LLVM Team, University of Illinois at
+      Urbana-Champaign, nor the names of its contributors may be used to
+      endorse or promote products derived from this Software without specific
+      prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 64 - 0
llvm-libunwind/cmake/Modules/HandleCompilerRT.cmake

@@ -0,0 +1,64 @@
+function(find_compiler_rt_library name dest)
+  if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS)
+    message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function")
+  endif()
+  set(dest "" PARENT_SCOPE)
+  set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
+      "--rtlib=compiler-rt" "--print-libgcc-file-name")
+  if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET)
+    list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}")
+  endif()
+  get_property(LIBUNWIND_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
+  string(REPLACE " " ";" LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}")
+  list(APPEND CLANG_COMMAND ${LIBUNWIND_CXX_FLAGS})
+  execute_process(
+      COMMAND ${CLANG_COMMAND}
+      RESULT_VARIABLE HAD_ERROR
+      OUTPUT_VARIABLE LIBRARY_FILE
+  )
+  string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
+  file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
+  string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")
+  if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")
+    message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}")
+    set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE)
+  else()
+    message(STATUS "Failed to find compiler-rt library")
+  endif()
+endfunction()
+
+function(find_compiler_rt_dir dest)
+  if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS)
+    message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function")
+  endif()
+  set(dest "" PARENT_SCOPE)
+  if (APPLE)
+    set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
+        "-print-file-name=lib")
+    execute_process(
+        COMMAND ${CLANG_COMMAND}
+        RESULT_VARIABLE HAD_ERROR
+        OUTPUT_VARIABLE LIBRARY_DIR
+    )
+    string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR)
+    file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR)
+    set(LIBRARY_DIR "${LIBRARY_DIR}/darwin")
+  else()
+    set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
+        "--rtlib=compiler-rt" "--print-libgcc-file-name")
+    execute_process(
+        COMMAND ${CLANG_COMMAND}
+        RESULT_VARIABLE HAD_ERROR
+        OUTPUT_VARIABLE LIBRARY_FILE
+    )
+    string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
+    file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
+    get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY)
+  endif()
+  if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}")
+    message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}")
+    set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE)
+  else()
+    message(STATUS "Failed to find compiler-rt directory")
+  endif()
+endfunction()

+ 272 - 0
llvm-libunwind/cmake/Modules/HandleLibunwindFlags.cmake

@@ -0,0 +1,272 @@
+# HandleLibcxxFlags - A set of macros used to setup the flags used to compile
+# and link libc++abi. These macros add flags to the following CMake variables.
+# - LIBUNWIND_COMPILE_FLAGS: flags used to compile libunwind
+# - LIBUNWIND_LINK_FLAGS: flags used to link libunwind
+# - LIBUNWIND_LIBRARIES: libraries to link libunwind to.
+
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+
+unset(add_flag_if_supported)
+
+# Mangle the name of a compiler flag into a valid CMake identifier.
+# Ex: --std=c++11 -> STD_EQ_CXX11
+macro(mangle_name str output)
+  string(STRIP "${str}" strippedStr)
+  string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}")
+  string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}")
+  string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}")
+  string(REPLACE "-" "_" strippedStr "${strippedStr}")
+  string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}")
+  string(REPLACE "+" "X" strippedStr "${strippedStr}")
+  string(TOUPPER "${strippedStr}" ${output})
+endmacro()
+
+# Remove a list of flags from all CMake variables that affect compile flags.
+# This can be used to remove unwanted flags specified on the command line
+# or added in other parts of LLVM's cmake configuration.
+macro(remove_flags)
+  foreach(var ${ARGN})
+    string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+    string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
+    string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
+    string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
+    string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+    string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
+    string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
+    string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
+    string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}")
+    remove_definitions(${var})
+  endforeach()
+endmacro(remove_flags)
+
+macro(check_flag_supported flag)
+    mangle_name("${flag}" flagname)
+    check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
+endmacro()
+
+macro(append_flags DEST)
+  foreach(value ${ARGN})
+    list(APPEND ${DEST} ${value})
+    list(APPEND ${DEST} ${value})
+  endforeach()
+endmacro()
+
+# If the specified 'condition' is true then append the specified list of flags to DEST
+macro(append_flags_if condition DEST)
+  if (${condition})
+    list(APPEND ${DEST} ${ARGN})
+  endif()
+endmacro()
+
+# Add each flag in the list specified by DEST if that flag is supported by the current compiler.
+macro(append_flags_if_supported DEST)
+  foreach(flag ${ARGN})
+    mangle_name("${flag}" flagname)
+    check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
+    append_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${DEST} ${flag})
+  endforeach()
+endmacro()
+
+# Add a macro definition if condition is true.
+macro(define_if condition def)
+  if (${condition})
+    add_definitions(${def})
+  endif()
+endmacro()
+
+# Add a macro definition if condition is not true.
+macro(define_if_not condition def)
+  if (NOT ${condition})
+    add_definitions(${def})
+  endif()
+endmacro()
+
+# Add a macro definition to the __config_site file if the specified condition
+# is 'true'. Note that '-D${def}' is not added. Instead it is expected that
+# the build include the '__config_site' header.
+macro(config_define_if condition def)
+  if (${condition})
+    set(${def} ON)
+    set(LIBUNWIND_NEEDS_SITE_CONFIG ON)
+  endif()
+endmacro()
+
+macro(config_define_if_not condition def)
+  if (NOT ${condition})
+    set(${def} ON)
+    set(LIBUNWIND_NEEDS_SITE_CONFIG ON)
+  endif()
+endmacro()
+
+macro(config_define value def)
+  set(${def} ${value})
+  set(LIBUNWIND_NEEDS_SITE_CONFIG ON)
+endmacro()
+
+# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS',
+# 'LIBUNWIND_COMPILE_FLAGS' and 'LIBUNWIND_LINK_FLAGS'.
+macro(add_target_flags)
+  foreach(value ${ARGN})
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}")
+    list(APPEND LIBUNWIND_COMPILE_FLAGS ${value})
+    list(APPEND LIBUNWIND_LINK_FLAGS ${value})
+  endforeach()
+endmacro()
+
+# If the specified 'condition' is true then add a list of flags to
+# all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBUNWIND_COMPILE_FLAGS'
+# and 'LIBUNWIND_LINK_FLAGS'.
+macro(add_target_flags_if condition)
+  if (${condition})
+    add_target_flags(${ARGN})
+  endif()
+endmacro()
+
+# Add a specified list of flags to both 'LIBUNWIND_COMPILE_FLAGS' and
+# 'LIBUNWIND_LINK_FLAGS'.
+macro(add_flags)
+  foreach(value ${ARGN})
+    list(APPEND LIBUNWIND_COMPILE_FLAGS ${value})
+    list(APPEND LIBUNWIND_LINK_FLAGS ${value})
+  endforeach()
+endmacro()
+
+# If the specified 'condition' is true then add a list of flags to both
+# 'LIBUNWIND_COMPILE_FLAGS' and 'LIBUNWIND_LINK_FLAGS'.
+macro(add_flags_if condition)
+  if (${condition})
+    add_flags(${ARGN})
+  endif()
+endmacro()
+
+# Add each flag in the list to LIBUNWIND_COMPILE_FLAGS and LIBUNWIND_LINK_FLAGS
+# if that flag is supported by the current compiler.
+macro(add_flags_if_supported)
+  foreach(flag ${ARGN})
+      mangle_name("${flag}" flagname)
+      check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
+      add_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
+  endforeach()
+endmacro()
+
+# Add a list of flags to 'LIBUNWIND_COMPILE_FLAGS'.
+macro(add_compile_flags)
+  foreach(f ${ARGN})
+    list(APPEND LIBUNWIND_COMPILE_FLAGS ${f})
+  endforeach()
+endmacro()
+
+# If 'condition' is true then add the specified list of flags to
+# 'LIBUNWIND_COMPILE_FLAGS'
+macro(add_compile_flags_if condition)
+  if (${condition})
+    add_compile_flags(${ARGN})
+  endif()
+endmacro()
+
+# For each specified flag, add that flag to 'LIBUNWIND_COMPILE_FLAGS' if the
+# flag is supported by the C++ compiler.
+macro(add_compile_flags_if_supported)
+  foreach(flag ${ARGN})
+      mangle_name("${flag}" flagname)
+      check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
+      add_compile_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
+  endforeach()
+endmacro()
+
+# Add a list of flags to 'LIBUNWIND_C_FLAGS'.
+macro(add_c_flags)
+  foreach(f ${ARGN})
+    list(APPEND LIBUNWIND_C_FLAGS ${f})
+  endforeach()
+endmacro()
+
+# If 'condition' is true then add the specified list of flags to
+# 'LIBUNWIND_C_FLAGS'
+macro(add_c_flags_if condition)
+  if (${condition})
+    add_c_flags(${ARGN})
+  endif()
+endmacro()
+
+# For each specified flag, add that flag to 'LIBUNWIND_C_FLAGS' if the
+# flag is supported by the C compiler.
+macro(add_c_compile_flags_if_supported)
+  foreach(flag ${ARGN})
+      mangle_name("${flag}" flagname)
+      check_c_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
+      add_c_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
+  endforeach()
+endmacro()
+
+# Add a list of flags to 'LIBUNWIND_CXX_FLAGS'.
+macro(add_cxx_flags)
+  foreach(f ${ARGN})
+    list(APPEND LIBUNWIND_CXX_FLAGS ${f})
+  endforeach()
+endmacro()
+
+# If 'condition' is true then add the specified list of flags to
+# 'LIBUNWIND_CXX_FLAGS'
+macro(add_cxx_flags_if condition)
+  if (${condition})
+    add_cxx_flags(${ARGN})
+  endif()
+endmacro()
+
+# For each specified flag, add that flag to 'LIBUNWIND_CXX_FLAGS' if the
+# flag is supported by the C compiler.
+macro(add_cxx_compile_flags_if_supported)
+  foreach(flag ${ARGN})
+      mangle_name("${flag}" flagname)
+      check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
+      add_cxx_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
+  endforeach()
+endmacro()
+
+# Add a list of flags to 'LIBUNWIND_LINK_FLAGS'.
+macro(add_link_flags)
+  foreach(f ${ARGN})
+    list(APPEND LIBUNWIND_LINK_FLAGS ${f})
+  endforeach()
+endmacro()
+
+# If 'condition' is true then add the specified list of flags to
+# 'LIBUNWIND_LINK_FLAGS'
+macro(add_link_flags_if condition)
+  if (${condition})
+    add_link_flags(${ARGN})
+  endif()
+endmacro()
+
+# For each specified flag, add that flag to 'LIBUNWIND_LINK_FLAGS' if the
+# flag is supported by the C++ compiler.
+macro(add_link_flags_if_supported)
+  foreach(flag ${ARGN})
+    mangle_name("${flag}" flagname)
+    check_cxx_compiler_flag("${flag}" "LIBUNWIND_SUPPORTS_${flagname}_FLAG")
+    add_link_flags_if(LIBUNWIND_SUPPORTS_${flagname}_FLAG ${flag})
+  endforeach()
+endmacro()
+
+# Add a list of libraries or link flags to 'LIBUNWIND_LIBRARIES'.
+macro(add_library_flags)
+  foreach(lib ${ARGN})
+    list(APPEND LIBUNWIND_LIBRARIES ${lib})
+  endforeach()
+endmacro()
+
+# if 'condition' is true then add the specified list of libraries and flags
+# to 'LIBUNWIND_LIBRARIES'.
+macro(add_library_flags_if condition)
+  if(${condition})
+    add_library_flags(${ARGN})
+  endif()
+endmacro()
+
+# Turn a comma separated CMake list into a space separated string.
+macro(split_list listname)
+  string(REPLACE ";" " " ${listname} "${${listname}}")
+endmacro()

+ 105 - 0
llvm-libunwind/cmake/config-ix.cmake

@@ -0,0 +1,105 @@
+include(CMakePushCheckState)
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+include(CheckLibraryExists)
+include(CheckSymbolExists)
+include(CheckCSourceCompiles)
+
+check_library_exists(c fopen "" LIBUNWIND_HAS_C_LIB)
+
+if (NOT LIBUNWIND_USE_COMPILER_RT)
+  if (ANDROID)
+    check_library_exists(gcc __gcc_personality_v0 "" LIBUNWIND_HAS_GCC_LIB)
+  else ()
+    check_library_exists(gcc_s __gcc_personality_v0 "" LIBUNWIND_HAS_GCC_S_LIB)
+    check_library_exists(gcc __absvdi2 "" LIBUNWIND_HAS_GCC_LIB)
+  endif ()
+endif()
+
+# libunwind is using -nostdlib++ at the link step when available,
+# otherwise -nodefaultlibs is used. We want all our checks to also
+# use one of these options, otherwise we may end up with an inconsistency between
+# the flags we think we require during configuration (if the checks are
+# performed without one of those options) and the flags that are actually
+# required during compilation (which has the -nostdlib++ or -nodefaultlibs). libc is
+# required for the link to go through. We remove sanitizers from the
+# configuration checks to avoid spurious link errors.
+
+check_c_compiler_flag(-nostdlib++ LIBUNWIND_SUPPORTS_NOSTDLIBXX_FLAG)
+if (LIBUNWIND_SUPPORTS_NOSTDLIBXX_FLAG)
+  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nostdlib++")
+else()
+  check_c_compiler_flag(-nodefaultlibs LIBUNWIND_SUPPORTS_NODEFAULTLIBS_FLAG)
+  if (LIBUNWIND_SUPPORTS_NODEFAULTLIBS_FLAG)
+    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs")
+  endif()
+endif()
+
+if (LIBUNWIND_SUPPORTS_NOSTDLIBXX_FLAG OR LIBUNWIND_SUPPORTS_NODEFAULTLIBS_FLAG)
+  if (LIBUNWIND_HAS_C_LIB)
+    list(APPEND CMAKE_REQUIRED_LIBRARIES c)
+  endif ()
+  if (LIBUNWIND_USE_COMPILER_RT)
+    find_compiler_rt_library(builtins LIBUNWIND_BUILTINS_LIBRARY)
+    list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBUNWIND_BUILTINS_LIBRARY}")
+  else ()
+    if (LIBUNWIND_HAS_GCC_S_LIB)
+      list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s)
+    endif ()
+    if (LIBUNWIND_HAS_GCC_LIB)
+      list(APPEND CMAKE_REQUIRED_LIBRARIES gcc)
+    endif ()
+  endif ()
+  if (MINGW)
+    # Mingw64 requires quite a few "C" runtime libraries in order for basic
+    # programs to link successfully with -nodefaultlibs.
+    if (LIBUNWIND_USE_COMPILER_RT)
+      set(MINGW_RUNTIME ${LIBUNWIND_BUILTINS_LIBRARY})
+    else ()
+      set(MINGW_RUNTIME gcc_s gcc)
+    endif()
+    set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32
+                        shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME}
+                        moldname mingwex msvcrt)
+    list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES})
+  endif()
+  if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize)
+    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all")
+  endif ()
+  if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage)
+    set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters")
+  endif ()
+endif ()
+
+# Check compiler pragmas
+if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  cmake_push_check_state()
+  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror=unknown-pragmas")
+  check_c_source_compiles("
+#pragma comment(lib, \"c\")
+int main() { return 0; }
+" LIBUNWIND_HAS_COMMENT_LIB_PRAGMA)
+  cmake_pop_check_state()
+endif()
+
+# Check compiler flags
+check_cxx_compiler_flag(-nostdinc++ LIBUNWIND_HAS_NOSTDINCXX_FLAG)
+
+# Check symbols
+check_symbol_exists(__arm__ "" LIBUNWIND_TARGET_ARM)
+check_symbol_exists(__USING_SJLJ_EXCEPTIONS__ "" LIBUNWIND_USES_SJLJ_EXCEPTIONS)
+check_symbol_exists(__ARM_DWARF_EH__ "" LIBUNWIND_USES_DWARF_EH)
+
+if(LIBUNWIND_TARGET_ARM AND NOT LIBUNWIND_USES_SJLJ_EXCEPTIONS AND NOT LIBUNWIND_USES_DWARF_EH)
+  # This condition is copied from __libunwind_config.h
+  set(LIBUNWIND_USES_ARM_EHABI ON)
+endif()
+
+# Check libraries
+if(FUCHSIA)
+  set(LIBUNWIND_HAS_DL_LIB NO)
+  set(LIBUNWIND_HAS_PTHREAD_LIB NO)
+else()
+  check_library_exists(dl dladdr "" LIBUNWIND_HAS_DL_LIB)
+  check_library_exists(pthread pthread_once "" LIBUNWIND_HAS_PTHREAD_LIB)
+endif()

+ 161 - 0
llvm-libunwind/docs/BuildingLibunwind.rst

@@ -0,0 +1,161 @@
+.. _BuildingLibunwind:
+
+==================
+Building libunwind
+==================
+
+.. contents::
+  :local:
+
+.. _build instructions:
+
+Getting Started
+===============
+
+On Mac OS, the easiest way to get this library is to link with -lSystem.
+However if you want to build tip-of-trunk from here (getting the bleeding
+edge), read on.
+
+The basic steps needed to build libc++ are:
+
+#. Checkout LLVM, libunwind, and related projects:
+
+   * ``cd where-you-want-llvm-to-live``
+   * ``git clone https://github.com/llvm/llvm-project.git``
+
+#. Configure and build libunwind:
+
+   CMake is the only supported configuration system.
+
+   Clang is the preferred compiler when building and using libunwind.
+
+   * ``cd where you want to build llvm``
+   * ``mkdir build``
+   * ``cd build``
+   * ``cmake -G <generator> -DLLVM_ENABLE_PROJECTS=libunwind [options] <path to llvm sources>``
+
+   For more information about configuring libunwind see :ref:`CMake Options`.
+
+   * ``make unwind`` --- will build libunwind.
+   * ``make check-unwind`` --- will run the test suite.
+
+   Shared and static libraries for libunwind should now be present in llvm/build/lib.
+
+#. **Optional**: Install libunwind
+
+   If your system already provides an unwinder, it is important to be careful
+   not to replace it. Remember Use the CMake option ``CMAKE_INSTALL_PREFIX`` to
+   select a safe place to install libunwind.
+
+   * ``make install-unwind`` --- Will install the libraries and the headers
+
+
+It is sometimes beneficial to build outside of the LLVM tree. An out-of-tree
+build would look like this:
+
+.. code-block:: bash
+
+  $ cd where-you-want-libunwind-to-live
+  $ # Check out llvm, and libunwind
+  $ ``svn co https://llvm.org/svn/llvm-project/llvm/trunk llvm``
+  $ ``svn co https://llvm.org/svn/llvm-project/libunwind/trunk libunwind``
+  $ cd where-you-want-to-build
+  $ mkdir build && cd build
+  $ export CC=clang CXX=clang++
+  $ cmake -DLLVM_PATH=path/to/llvm \
+          path/to/libunwind
+  $ make
+
+
+.. _CMake Options:
+
+CMake Options
+=============
+
+Here are some of the CMake variables that are used often, along with a
+brief explanation and LLVM-specific notes. For full documentation, check the
+CMake docs or execute ``cmake --help-variable VARIABLE_NAME``.
+
+**CMAKE_BUILD_TYPE**:STRING
+  Sets the build type for ``make`` based generators. Possible values are
+  Release, Debug, RelWithDebInfo and MinSizeRel. On systems like Visual Studio
+  the user sets the build type with the IDE settings.
+
+**CMAKE_INSTALL_PREFIX**:PATH
+  Path where LLVM will be installed if "make install" is invoked or the
+  "INSTALL" target is built.
+
+**CMAKE_CXX_COMPILER**:STRING
+  The C++ compiler to use when building and testing libunwind.
+
+
+.. _libunwind-specific options:
+
+libunwind specific options
+--------------------------
+
+.. option:: LIBUNWIND_BUILD_32_BITS:BOOL
+
+  **Default**: Same as LLVM_BUILD_32_BITS
+
+  Toggle whether libunwind should be built with -m32.
+
+.. option:: LIBUNWIND_ENABLE_ASSERTIONS:BOOL
+
+  **Default**: ``ON``
+
+  Toggle assertions independent of the build mode.
+
+.. option:: LIBUNWIND_ENABLE_PEDANTIC:BOOL
+
+  **Default**: ``ON``
+
+  Compile with -Wpedantic.
+
+.. option:: LIBUNWIND_ENABLE_WERROR:BOOL
+
+  **Default**: ``ON``
+
+  Compile with -Werror
+
+.. option:: LIBUNWIND_ENABLE_SHARED:BOOL
+
+  **Default**: ``ON``
+
+  Build libunwind as a shared library.
+
+.. option:: LIBUNWIND_ENABLE_STATIC:BOOL
+
+  **Default**: ``ON``
+
+  Build libunwind as a static archive.
+
+.. option:: LIBUNWIND_ENABLE_CROSS_UNWINDING:BOOL
+
+  **Default**: ``OFF``
+
+  Enable cross-platform unwinding support.
+
+.. option:: LIBUNWIND_ENABLE_ARM_WMMX:BOOL
+
+  **Default**: ``OFF``
+
+  Enable unwinding support for ARM WMMX registers.
+
+.. option:: LIBUNWIND_ENABLE_THREADS:BOOL
+
+  **Default**: ``ON``
+
+  Build libunwind with threading support.
+
+.. option:: LIBUNWIND_TARGET_TRIPLE:STRING
+
+  Target triple for cross compiling
+
+.. option:: LIBUNWIND_GCC_TOOLCHAIN:PATH
+
+  GCC toolchain for cross compiling
+
+.. option:: LIBUNWIND_SYSROOT
+
+  Sysroot for cross compiling

+ 7 - 0
llvm-libunwind/docs/CMakeLists.txt

@@ -0,0 +1,7 @@
+include(FindSphinx)
+if (SPHINX_FOUND AND LLVM_ENABLE_SPHINX)
+  include(AddSphinxTarget)
+  if (${SPHINX_OUTPUT_HTML})
+    add_sphinx_target(html libunwind)
+  endif()
+endif()

+ 13 - 0
llvm-libunwind/docs/README.txt

@@ -0,0 +1,13 @@
+libunwind Documentation
+====================
+
+The libunwind documentation is written using the Sphinx documentation generator. It is
+currently tested with Sphinx 1.1.3.
+
+To build the documents into html configure libunwind with the following cmake options:
+
+  * -DLLVM_ENABLE_SPHINX=ON
+  * -DLIBUNWIND_INCLUDE_DOCS=ON
+
+After configuring libunwind with these options the make rule `docs-libunwind-html`
+should be available.

+ 252 - 0
llvm-libunwind/docs/conf.py

@@ -0,0 +1,252 @@
+# -*- coding: utf-8 -*-
+#
+# libunwind documentation build configuration file.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+from datetime import date
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'libunwind'
+copyright = u'2011-%d, LLVM Project' % date.today().year
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '13.0'
+# The full version, including alpha/beta/rc tags.
+release = '13.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%Y-%m-%d'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+show_authors = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'friendly'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'haiku'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'libunwinddoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('contents', 'libunwind.tex', u'libunwind Documentation',
+   u'LLVM project', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('contents', 'libunwind', u'libunwind Documentation',
+     [u'LLVM project'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('contents', 'libunwind', u'libunwind Documentation',
+   u'LLVM project', 'libunwind', 'LLVM Unwinder',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# FIXME: Define intersphinx configration.
+intersphinx_mapping = {}
+
+
+# -- Options for extensions ----------------------------------------------------
+
+# Enable this if you want TODOs to show up in the generated documentation.
+todo_include_todos = True

+ 104 - 0
llvm-libunwind/docs/index.rst

@@ -0,0 +1,104 @@
+.. _index:
+
+=======================
+libunwind LLVM Unwinder
+=======================
+
+Overview
+========
+
+libunwind is an implementation of the interface defined by the HP libunwind
+project. It was contributed by Apple as a way to enable clang++ to port to
+platforms that do not have a system unwinder. It is intended to be a small and
+fast implementation of the ABI, leaving off some features of HP's libunwind
+that never materialized (e.g. remote unwinding).
+
+The unwinder has two levels of API. The high level APIs are the `_Unwind_*`
+functions which implement functionality required by `__cxa_*` exception
+functions. The low level APIs are the `unw_*` functions which are an interface
+defined by the old HP libunwind project.
+
+Getting Started with libunwind
+------------------------------
+
+.. toctree::
+   :maxdepth: 2
+
+   BuildingLibunwind
+
+Current Status
+--------------
+
+libunwind is a production-quality unwinder, with platform support for DWARF
+unwind info, SjLj, and ARM EHABI.
+
+The low level libunwind API was designed to work either in-process (aka local)
+or to operate on another process (aka remote), but only the local path has been
+implemented. Remote unwinding remains as future work.
+
+Platform and Compiler Support
+-----------------------------
+
+libunwind is known to work on the following platforms:
+
+============ ======================== ============ ========================
+OS           Arch                     Compilers    Unwind Info
+============ ======================== ============ ========================
+Any          i386, x86_64, ARM        Clang        SjLj
+Bare Metal   ARM                      Clang, GCC   EHABI
+FreeBSD      i386, x86_64, ARM64      Clang        DWARF CFI
+iOS          ARM                      Clang        SjLj
+Linux        ARM                      Clang, GCC   EHABI
+Linux        i386, x86_64, ARM64      Clang, GCC   DWARF CFI
+macOS        i386, x86_64             Clang, GCC   DWARF CFI
+NetBSD       x86_64                   Clang, GCC   DWARF CFI
+Windows      i386, x86_64, ARM, ARM64 Clang        DWARF CFI
+============ ======================== ============ ========================
+
+The following minimum compiler versions are strongly recommended.
+
+* Clang 3.5 and above
+* GCC 4.7 and above.
+
+Anything older *may* work.
+
+Notes and Known Issues
+----------------------
+
+* TODO
+
+
+Getting Involved
+================
+
+First please review our `Developer's Policy <https://llvm.org/docs/DeveloperPolicy.html>`__
+and `Getting started with LLVM <https://llvm.org/docs/GettingStarted.html>`__.
+
+**Bug Reports**
+
+If you think you've found a bug in libunwind, please report it using
+the `LLVM Bugzilla`_. If you're not sure, you
+can post a message to the `cfe-dev mailing list`_ or on IRC.
+Please include "libunwind" in your subject.
+
+**Patches**
+
+If you want to contribute a patch to libunwind, the best place for that is
+`Phabricator <https://llvm.org/docs/Phabricator.html>`_. Please include [libunwind] in the subject and
+add `cfe-commits` as a subscriber. Also make sure you are subscribed to the
+`cfe-commits mailing list <http://lists.llvm.org/mailman/listinfo/cfe-commits>`_.
+
+**Discussion and Questions**
+
+Send discussions and questions to the
+`cfe-dev mailing list <http://lists.llvm.org/mailman/listinfo/cfe-dev>`_.
+Please include [libunwind] in the subject.
+
+
+Quick Links
+===========
+* `LLVM Homepage <https://llvm.org/>`_
+* `LLVM Bugzilla <https://bugs.llvm.org/>`_
+* `cfe-commits Mailing List`_
+* `cfe-dev Mailing List`_
+* `Browse libunwind Sources <https://github.com/llvm/llvm-project/blob/main/libunwind/>`_

+ 176 - 0
llvm-libunwind/include/__libunwind_config.h

@@ -0,0 +1,176 @@
+//===------------------------- __libunwind_config.h -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ____LIBUNWIND_CONFIG_H__
+#define ____LIBUNWIND_CONFIG_H__
+
+#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
+    !defined(__ARM_DWARF_EH__)
+#define _LIBUNWIND_ARM_EHABI
+#endif
+
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86       8
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64    32
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC       112
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64     116
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64     95
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM       287
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K      32
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS      65
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC     31
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON   34
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV     64
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE        143
+
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+# if defined(__linux__)
+#  define _LIBUNWIND_TARGET_LINUX 1
+# endif
+# if defined(__i386__)
+#  define _LIBUNWIND_TARGET_I386
+#  define _LIBUNWIND_CONTEXT_SIZE 8
+#  define _LIBUNWIND_CURSOR_SIZE 15
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86
+# elif defined(__x86_64__)
+#  define _LIBUNWIND_TARGET_X86_64 1
+#  if defined(_WIN64)
+#    define _LIBUNWIND_CONTEXT_SIZE 54
+#    ifdef __SEH__
+#      define _LIBUNWIND_CURSOR_SIZE 204
+#    else
+#      define _LIBUNWIND_CURSOR_SIZE 66
+#    endif
+#  else
+#    define _LIBUNWIND_CONTEXT_SIZE 21
+#    define _LIBUNWIND_CURSOR_SIZE 33
+#  endif
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64
+# elif defined(__powerpc64__)
+#  define _LIBUNWIND_TARGET_PPC64 1
+#  define _LIBUNWIND_CONTEXT_SIZE 167
+#  define _LIBUNWIND_CURSOR_SIZE 179
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64
+# elif defined(__ppc__)
+#  define _LIBUNWIND_TARGET_PPC 1
+#  define _LIBUNWIND_CONTEXT_SIZE 117
+#  define _LIBUNWIND_CURSOR_SIZE 124
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
+# elif defined(__aarch64__)
+#  define _LIBUNWIND_TARGET_AARCH64 1
+#  define _LIBUNWIND_CONTEXT_SIZE 66
+#  if defined(__SEH__)
+#    define _LIBUNWIND_CURSOR_SIZE 164
+#  else
+#    define _LIBUNWIND_CURSOR_SIZE 78
+#  endif
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
+# elif defined(__arm__)
+#  define _LIBUNWIND_TARGET_ARM 1
+#  if defined(__SEH__)
+#    define _LIBUNWIND_CONTEXT_SIZE 42
+#    define _LIBUNWIND_CURSOR_SIZE 80
+#  elif defined(__ARM_WMMX)
+#    define _LIBUNWIND_CONTEXT_SIZE 61
+#    define _LIBUNWIND_CURSOR_SIZE 68
+#  else
+#    define _LIBUNWIND_CONTEXT_SIZE 42
+#    define _LIBUNWIND_CURSOR_SIZE 49
+#  endif
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM
+# elif defined(__or1k__)
+#  define _LIBUNWIND_TARGET_OR1K 1
+#  define _LIBUNWIND_CONTEXT_SIZE 16
+#  define _LIBUNWIND_CURSOR_SIZE 24
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K
+# elif defined(__hexagon__)
+#  define _LIBUNWIND_TARGET_HEXAGON 1
+// Values here change when : Registers.hpp - hexagon_thread_state_t change
+#  define _LIBUNWIND_CONTEXT_SIZE 18
+#  define _LIBUNWIND_CURSOR_SIZE 24
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON
+# elif defined(__mips__)
+#  if defined(_ABIO32) && _MIPS_SIM == _ABIO32
+#    define _LIBUNWIND_TARGET_MIPS_O32 1
+#    if defined(__mips_hard_float)
+#      define _LIBUNWIND_CONTEXT_SIZE 50
+#      define _LIBUNWIND_CURSOR_SIZE 57
+#    else
+#      define _LIBUNWIND_CONTEXT_SIZE 18
+#      define _LIBUNWIND_CURSOR_SIZE 24
+#    endif
+#  elif defined(_ABIN32) && _MIPS_SIM == _ABIN32
+#    define _LIBUNWIND_TARGET_MIPS_NEWABI 1
+#    if defined(__mips_hard_float)
+#      define _LIBUNWIND_CONTEXT_SIZE 67
+#      define _LIBUNWIND_CURSOR_SIZE 74
+#    else
+#      define _LIBUNWIND_CONTEXT_SIZE 35
+#      define _LIBUNWIND_CURSOR_SIZE 42
+#    endif
+#  elif defined(_ABI64) && _MIPS_SIM == _ABI64
+#    define _LIBUNWIND_TARGET_MIPS_NEWABI 1
+#    if defined(__mips_hard_float)
+#      define _LIBUNWIND_CONTEXT_SIZE 67
+#      define _LIBUNWIND_CURSOR_SIZE 79
+#    else
+#      define _LIBUNWIND_CONTEXT_SIZE 35
+#      define _LIBUNWIND_CURSOR_SIZE 47
+#    endif
+#  else
+#    error "Unsupported MIPS ABI and/or environment"
+#  endif
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
+# elif defined(__sparc__)
+  #define _LIBUNWIND_TARGET_SPARC 1
+  #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
+  #define _LIBUNWIND_CONTEXT_SIZE 16
+  #define _LIBUNWIND_CURSOR_SIZE 23
+# elif defined(__riscv)
+#  define _LIBUNWIND_TARGET_RISCV 1
+#  if defined(__riscv_flen)
+#   define RISCV_FLEN __riscv_flen
+#  else
+#   define RISCV_FLEN 0
+#  endif
+#  define _LIBUNWIND_CONTEXT_SIZE (32 * (__riscv_xlen + RISCV_FLEN) / 64)
+#  if __riscv_xlen == 32
+#   define _LIBUNWIND_CURSOR_SIZE (_LIBUNWIND_CONTEXT_SIZE + 7)
+#  elif __riscv_xlen == 64
+#   define _LIBUNWIND_CURSOR_SIZE (_LIBUNWIND_CONTEXT_SIZE + 12)
+#  else
+#   error "Unsupported RISC-V ABI"
+#  endif
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV
+# elif defined(__ve__)
+#  define _LIBUNWIND_TARGET_VE 1
+#  define _LIBUNWIND_CONTEXT_SIZE 67
+#  define _LIBUNWIND_CURSOR_SIZE 79
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE
+# else
+#  error "Unsupported architecture."
+# endif
+#else // !_LIBUNWIND_IS_NATIVE_ONLY
+# define _LIBUNWIND_TARGET_I386
+# define _LIBUNWIND_TARGET_X86_64 1
+# define _LIBUNWIND_TARGET_PPC 1
+# define _LIBUNWIND_TARGET_PPC64 1
+# define _LIBUNWIND_TARGET_AARCH64 1
+# define _LIBUNWIND_TARGET_ARM 1
+# define _LIBUNWIND_TARGET_OR1K 1
+# define _LIBUNWIND_TARGET_MIPS_O32 1
+# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
+# define _LIBUNWIND_TARGET_SPARC 1
+# define _LIBUNWIND_TARGET_HEXAGON 1
+# define _LIBUNWIND_TARGET_RISCV 1
+# define _LIBUNWIND_TARGET_VE 1
+# define _LIBUNWIND_CONTEXT_SIZE 167
+# define _LIBUNWIND_CURSOR_SIZE 179
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
+#endif // _LIBUNWIND_IS_NATIVE_ONLY
+
+#endif // ____LIBUNWIND_CONFIG_H__

+ 1103 - 0
llvm-libunwind/include/libunwind.h

@@ -0,0 +1,1103 @@
+//===---------------------------- libunwind.h -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+// Compatible with libunwind API documented at:
+//   http://www.nongnu.org/libunwind/man/libunwind(3).html
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LIBUNWIND__
+#define __LIBUNWIND__
+
+#include <__libunwind_config.h>
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __APPLE__
+  #if __clang__
+    #if __has_include(<Availability.h>)
+      #include <Availability.h>
+    #endif
+  #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
+    #include <Availability.h>
+  #endif
+
+  #ifdef __arm__
+     #define LIBUNWIND_AVAIL __attribute__((unavailable))
+  #elif defined(__OSX_AVAILABLE_STARTING)
+    #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
+  #else
+    #include <AvailabilityMacros.h>
+    #ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+      #define LIBUNWIND_AVAIL AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+    #else
+      #define LIBUNWIND_AVAIL __attribute__((unavailable))
+    #endif
+  #endif
+#else
+  #define LIBUNWIND_AVAIL
+#endif
+
+#if defined(_WIN32) && defined(__SEH__)
+  #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16)))
+#else
+  #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR
+#endif
+
+/* error codes */
+enum {
+  UNW_ESUCCESS      = 0,     /* no error */
+  UNW_EUNSPEC       = -6540, /* unspecified (general) error */
+  UNW_ENOMEM        = -6541, /* out of memory */
+  UNW_EBADREG       = -6542, /* bad register number */
+  UNW_EREADONLYREG  = -6543, /* attempt to write read-only register */
+  UNW_ESTOPUNWIND   = -6544, /* stop unwinding */
+  UNW_EINVALIDIP    = -6545, /* invalid IP */
+  UNW_EBADFRAME     = -6546, /* bad frame */
+  UNW_EINVAL        = -6547, /* unsupported operation or bad value */
+  UNW_EBADVERSION   = -6548, /* unwind info has unsupported version */
+  UNW_ENOINFO       = -6549  /* no unwind info found */
+#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */
+#endif
+};
+
+struct unw_context_t {
+  uint64_t data[_LIBUNWIND_CONTEXT_SIZE];
+};
+typedef struct unw_context_t unw_context_t;
+
+struct unw_cursor_t {
+  uint64_t data[_LIBUNWIND_CURSOR_SIZE];
+} LIBUNWIND_CURSOR_ALIGNMENT_ATTR;
+typedef struct unw_cursor_t unw_cursor_t;
+
+typedef struct unw_addr_space *unw_addr_space_t;
+
+typedef int unw_regnum_t;
+typedef uintptr_t unw_word_t;
+#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
+typedef uint64_t unw_fpreg_t;
+#else
+typedef double unw_fpreg_t;
+#endif
+
+struct unw_proc_info_t {
+  unw_word_t  start_ip;         /* start address of function */
+  unw_word_t  end_ip;           /* address after end of function */
+  unw_word_t  lsda;             /* address of language specific data area, */
+                                /*  or zero if not used */
+  unw_word_t  handler;          /* personality routine, or zero if not used */
+  unw_word_t  gp;               /* not used */
+  unw_word_t  flags;            /* not used */
+  uint32_t    format;           /* compact unwind encoding, or zero if none */
+  uint32_t    unwind_info_size; /* size of DWARF unwind info, or zero if none */
+  unw_word_t  unwind_info;      /* address of DWARF unwind info, or zero */
+  unw_word_t  extra;            /* mach_header of mach-o image containing func */
+};
+typedef struct unw_proc_info_t unw_proc_info_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL;
+extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL;
+extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL;
+extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL;
+extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL;
+extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL;
+extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t)  LIBUNWIND_AVAIL;
+extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL;
+
+#ifdef __arm__
+/* Save VFP registers in FSTMX format (instead of FSTMD). */
+extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL;
+#endif
+
+
+extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
+extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL;
+extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
+extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL;
+extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL;
+//extern int       unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*);
+
+extern unw_addr_space_t unw_local_addr_space;
+
+#ifdef __cplusplus
+}
+#endif
+
+// architecture independent register numbers
+enum {
+  UNW_REG_IP = -1, // instruction pointer
+  UNW_REG_SP = -2, // stack pointer
+};
+
+// 32-bit x86 registers
+enum {
+  UNW_X86_EAX = 0,
+  UNW_X86_ECX = 1,
+  UNW_X86_EDX = 2,
+  UNW_X86_EBX = 3,
+  UNW_X86_EBP = 4,
+  UNW_X86_ESP = 5,
+  UNW_X86_ESI = 6,
+  UNW_X86_EDI = 7
+};
+
+// 64-bit x86_64 registers
+enum {
+  UNW_X86_64_RAX = 0,
+  UNW_X86_64_RDX = 1,
+  UNW_X86_64_RCX = 2,
+  UNW_X86_64_RBX = 3,
+  UNW_X86_64_RSI = 4,
+  UNW_X86_64_RDI = 5,
+  UNW_X86_64_RBP = 6,
+  UNW_X86_64_RSP = 7,
+  UNW_X86_64_R8  = 8,
+  UNW_X86_64_R9  = 9,
+  UNW_X86_64_R10 = 10,
+  UNW_X86_64_R11 = 11,
+  UNW_X86_64_R12 = 12,
+  UNW_X86_64_R13 = 13,
+  UNW_X86_64_R14 = 14,
+  UNW_X86_64_R15 = 15,
+  UNW_X86_64_RIP = 16,
+  UNW_X86_64_XMM0 = 17,
+  UNW_X86_64_XMM1 = 18,
+  UNW_X86_64_XMM2 = 19,
+  UNW_X86_64_XMM3 = 20,
+  UNW_X86_64_XMM4 = 21,
+  UNW_X86_64_XMM5 = 22,
+  UNW_X86_64_XMM6 = 23,
+  UNW_X86_64_XMM7 = 24,
+  UNW_X86_64_XMM8 = 25,
+  UNW_X86_64_XMM9 = 26,
+  UNW_X86_64_XMM10 = 27,
+  UNW_X86_64_XMM11 = 28,
+  UNW_X86_64_XMM12 = 29,
+  UNW_X86_64_XMM13 = 30,
+  UNW_X86_64_XMM14 = 31,
+  UNW_X86_64_XMM15 = 32,
+};
+
+
+// 32-bit ppc register numbers
+enum {
+  UNW_PPC_R0  = 0,
+  UNW_PPC_R1  = 1,
+  UNW_PPC_R2  = 2,
+  UNW_PPC_R3  = 3,
+  UNW_PPC_R4  = 4,
+  UNW_PPC_R5  = 5,
+  UNW_PPC_R6  = 6,
+  UNW_PPC_R7  = 7,
+  UNW_PPC_R8  = 8,
+  UNW_PPC_R9  = 9,
+  UNW_PPC_R10 = 10,
+  UNW_PPC_R11 = 11,
+  UNW_PPC_R12 = 12,
+  UNW_PPC_R13 = 13,
+  UNW_PPC_R14 = 14,
+  UNW_PPC_R15 = 15,
+  UNW_PPC_R16 = 16,
+  UNW_PPC_R17 = 17,
+  UNW_PPC_R18 = 18,
+  UNW_PPC_R19 = 19,
+  UNW_PPC_R20 = 20,
+  UNW_PPC_R21 = 21,
+  UNW_PPC_R22 = 22,
+  UNW_PPC_R23 = 23,
+  UNW_PPC_R24 = 24,
+  UNW_PPC_R25 = 25,
+  UNW_PPC_R26 = 26,
+  UNW_PPC_R27 = 27,
+  UNW_PPC_R28 = 28,
+  UNW_PPC_R29 = 29,
+  UNW_PPC_R30 = 30,
+  UNW_PPC_R31 = 31,
+  UNW_PPC_F0  = 32,
+  UNW_PPC_F1  = 33,
+  UNW_PPC_F2  = 34,
+  UNW_PPC_F3  = 35,
+  UNW_PPC_F4  = 36,
+  UNW_PPC_F5  = 37,
+  UNW_PPC_F6  = 38,
+  UNW_PPC_F7  = 39,
+  UNW_PPC_F8  = 40,
+  UNW_PPC_F9  = 41,
+  UNW_PPC_F10 = 42,
+  UNW_PPC_F11 = 43,
+  UNW_PPC_F12 = 44,
+  UNW_PPC_F13 = 45,
+  UNW_PPC_F14 = 46,
+  UNW_PPC_F15 = 47,
+  UNW_PPC_F16 = 48,
+  UNW_PPC_F17 = 49,
+  UNW_PPC_F18 = 50,
+  UNW_PPC_F19 = 51,
+  UNW_PPC_F20 = 52,
+  UNW_PPC_F21 = 53,
+  UNW_PPC_F22 = 54,
+  UNW_PPC_F23 = 55,
+  UNW_PPC_F24 = 56,
+  UNW_PPC_F25 = 57,
+  UNW_PPC_F26 = 58,
+  UNW_PPC_F27 = 59,
+  UNW_PPC_F28 = 60,
+  UNW_PPC_F29 = 61,
+  UNW_PPC_F30 = 62,
+  UNW_PPC_F31 = 63,
+  UNW_PPC_MQ  = 64,
+  UNW_PPC_LR  = 65,
+  UNW_PPC_CTR = 66,
+  UNW_PPC_AP  = 67,
+  UNW_PPC_CR0 = 68,
+  UNW_PPC_CR1 = 69,
+  UNW_PPC_CR2 = 70,
+  UNW_PPC_CR3 = 71,
+  UNW_PPC_CR4 = 72,
+  UNW_PPC_CR5 = 73,
+  UNW_PPC_CR6 = 74,
+  UNW_PPC_CR7 = 75,
+  UNW_PPC_XER = 76,
+  UNW_PPC_V0  = 77,
+  UNW_PPC_V1  = 78,
+  UNW_PPC_V2  = 79,
+  UNW_PPC_V3  = 80,
+  UNW_PPC_V4  = 81,
+  UNW_PPC_V5  = 82,
+  UNW_PPC_V6  = 83,
+  UNW_PPC_V7  = 84,
+  UNW_PPC_V8  = 85,
+  UNW_PPC_V9  = 86,
+  UNW_PPC_V10 = 87,
+  UNW_PPC_V11 = 88,
+  UNW_PPC_V12 = 89,
+  UNW_PPC_V13 = 90,
+  UNW_PPC_V14 = 91,
+  UNW_PPC_V15 = 92,
+  UNW_PPC_V16 = 93,
+  UNW_PPC_V17 = 94,
+  UNW_PPC_V18 = 95,
+  UNW_PPC_V19 = 96,
+  UNW_PPC_V20 = 97,
+  UNW_PPC_V21 = 98,
+  UNW_PPC_V22 = 99,
+  UNW_PPC_V23 = 100,
+  UNW_PPC_V24 = 101,
+  UNW_PPC_V25 = 102,
+  UNW_PPC_V26 = 103,
+  UNW_PPC_V27 = 104,
+  UNW_PPC_V28 = 105,
+  UNW_PPC_V29 = 106,
+  UNW_PPC_V30 = 107,
+  UNW_PPC_V31 = 108,
+  UNW_PPC_VRSAVE  = 109,
+  UNW_PPC_VSCR    = 110,
+  UNW_PPC_SPE_ACC = 111,
+  UNW_PPC_SPEFSCR = 112
+};
+
+// 64-bit ppc register numbers
+enum {
+  UNW_PPC64_R0      = 0,
+  UNW_PPC64_R1      = 1,
+  UNW_PPC64_R2      = 2,
+  UNW_PPC64_R3      = 3,
+  UNW_PPC64_R4      = 4,
+  UNW_PPC64_R5      = 5,
+  UNW_PPC64_R6      = 6,
+  UNW_PPC64_R7      = 7,
+  UNW_PPC64_R8      = 8,
+  UNW_PPC64_R9      = 9,
+  UNW_PPC64_R10     = 10,
+  UNW_PPC64_R11     = 11,
+  UNW_PPC64_R12     = 12,
+  UNW_PPC64_R13     = 13,
+  UNW_PPC64_R14     = 14,
+  UNW_PPC64_R15     = 15,
+  UNW_PPC64_R16     = 16,
+  UNW_PPC64_R17     = 17,
+  UNW_PPC64_R18     = 18,
+  UNW_PPC64_R19     = 19,
+  UNW_PPC64_R20     = 20,
+  UNW_PPC64_R21     = 21,
+  UNW_PPC64_R22     = 22,
+  UNW_PPC64_R23     = 23,
+  UNW_PPC64_R24     = 24,
+  UNW_PPC64_R25     = 25,
+  UNW_PPC64_R26     = 26,
+  UNW_PPC64_R27     = 27,
+  UNW_PPC64_R28     = 28,
+  UNW_PPC64_R29     = 29,
+  UNW_PPC64_R30     = 30,
+  UNW_PPC64_R31     = 31,
+  UNW_PPC64_F0      = 32,
+  UNW_PPC64_F1      = 33,
+  UNW_PPC64_F2      = 34,
+  UNW_PPC64_F3      = 35,
+  UNW_PPC64_F4      = 36,
+  UNW_PPC64_F5      = 37,
+  UNW_PPC64_F6      = 38,
+  UNW_PPC64_F7      = 39,
+  UNW_PPC64_F8      = 40,
+  UNW_PPC64_F9      = 41,
+  UNW_PPC64_F10     = 42,
+  UNW_PPC64_F11     = 43,
+  UNW_PPC64_F12     = 44,
+  UNW_PPC64_F13     = 45,
+  UNW_PPC64_F14     = 46,
+  UNW_PPC64_F15     = 47,
+  UNW_PPC64_F16     = 48,
+  UNW_PPC64_F17     = 49,
+  UNW_PPC64_F18     = 50,
+  UNW_PPC64_F19     = 51,
+  UNW_PPC64_F20     = 52,
+  UNW_PPC64_F21     = 53,
+  UNW_PPC64_F22     = 54,
+  UNW_PPC64_F23     = 55,
+  UNW_PPC64_F24     = 56,
+  UNW_PPC64_F25     = 57,
+  UNW_PPC64_F26     = 58,
+  UNW_PPC64_F27     = 59,
+  UNW_PPC64_F28     = 60,
+  UNW_PPC64_F29     = 61,
+  UNW_PPC64_F30     = 62,
+  UNW_PPC64_F31     = 63,
+  // 64: reserved
+  UNW_PPC64_LR      = 65,
+  UNW_PPC64_CTR     = 66,
+  // 67: reserved
+  UNW_PPC64_CR0     = 68,
+  UNW_PPC64_CR1     = 69,
+  UNW_PPC64_CR2     = 70,
+  UNW_PPC64_CR3     = 71,
+  UNW_PPC64_CR4     = 72,
+  UNW_PPC64_CR5     = 73,
+  UNW_PPC64_CR6     = 74,
+  UNW_PPC64_CR7     = 75,
+  UNW_PPC64_XER     = 76,
+  UNW_PPC64_V0      = 77,
+  UNW_PPC64_V1      = 78,
+  UNW_PPC64_V2      = 79,
+  UNW_PPC64_V3      = 80,
+  UNW_PPC64_V4      = 81,
+  UNW_PPC64_V5      = 82,
+  UNW_PPC64_V6      = 83,
+  UNW_PPC64_V7      = 84,
+  UNW_PPC64_V8      = 85,
+  UNW_PPC64_V9      = 86,
+  UNW_PPC64_V10     = 87,
+  UNW_PPC64_V11     = 88,
+  UNW_PPC64_V12     = 89,
+  UNW_PPC64_V13     = 90,
+  UNW_PPC64_V14     = 91,
+  UNW_PPC64_V15     = 92,
+  UNW_PPC64_V16     = 93,
+  UNW_PPC64_V17     = 94,
+  UNW_PPC64_V18     = 95,
+  UNW_PPC64_V19     = 96,
+  UNW_PPC64_V20     = 97,
+  UNW_PPC64_V21     = 98,
+  UNW_PPC64_V22     = 99,
+  UNW_PPC64_V23     = 100,
+  UNW_PPC64_V24     = 101,
+  UNW_PPC64_V25     = 102,
+  UNW_PPC64_V26     = 103,
+  UNW_PPC64_V27     = 104,
+  UNW_PPC64_V28     = 105,
+  UNW_PPC64_V29     = 106,
+  UNW_PPC64_V30     = 107,
+  UNW_PPC64_V31     = 108,
+  // 109, 111-113: OpenPOWER ELF V2 ABI: reserved
+  // Borrowing VRSAVE number from PPC32.
+  UNW_PPC64_VRSAVE  = 109,
+  UNW_PPC64_VSCR    = 110,
+  UNW_PPC64_TFHAR   = 114,
+  UNW_PPC64_TFIAR   = 115,
+  UNW_PPC64_TEXASR  = 116,
+  UNW_PPC64_VS0     = UNW_PPC64_F0,
+  UNW_PPC64_VS1     = UNW_PPC64_F1,
+  UNW_PPC64_VS2     = UNW_PPC64_F2,
+  UNW_PPC64_VS3     = UNW_PPC64_F3,
+  UNW_PPC64_VS4     = UNW_PPC64_F4,
+  UNW_PPC64_VS5     = UNW_PPC64_F5,
+  UNW_PPC64_VS6     = UNW_PPC64_F6,
+  UNW_PPC64_VS7     = UNW_PPC64_F7,
+  UNW_PPC64_VS8     = UNW_PPC64_F8,
+  UNW_PPC64_VS9     = UNW_PPC64_F9,
+  UNW_PPC64_VS10    = UNW_PPC64_F10,
+  UNW_PPC64_VS11    = UNW_PPC64_F11,
+  UNW_PPC64_VS12    = UNW_PPC64_F12,
+  UNW_PPC64_VS13    = UNW_PPC64_F13,
+  UNW_PPC64_VS14    = UNW_PPC64_F14,
+  UNW_PPC64_VS15    = UNW_PPC64_F15,
+  UNW_PPC64_VS16    = UNW_PPC64_F16,
+  UNW_PPC64_VS17    = UNW_PPC64_F17,
+  UNW_PPC64_VS18    = UNW_PPC64_F18,
+  UNW_PPC64_VS19    = UNW_PPC64_F19,
+  UNW_PPC64_VS20    = UNW_PPC64_F20,
+  UNW_PPC64_VS21    = UNW_PPC64_F21,
+  UNW_PPC64_VS22    = UNW_PPC64_F22,
+  UNW_PPC64_VS23    = UNW_PPC64_F23,
+  UNW_PPC64_VS24    = UNW_PPC64_F24,
+  UNW_PPC64_VS25    = UNW_PPC64_F25,
+  UNW_PPC64_VS26    = UNW_PPC64_F26,
+  UNW_PPC64_VS27    = UNW_PPC64_F27,
+  UNW_PPC64_VS28    = UNW_PPC64_F28,
+  UNW_PPC64_VS29    = UNW_PPC64_F29,
+  UNW_PPC64_VS30    = UNW_PPC64_F30,
+  UNW_PPC64_VS31    = UNW_PPC64_F31,
+  UNW_PPC64_VS32    = UNW_PPC64_V0,
+  UNW_PPC64_VS33    = UNW_PPC64_V1,
+  UNW_PPC64_VS34    = UNW_PPC64_V2,
+  UNW_PPC64_VS35    = UNW_PPC64_V3,
+  UNW_PPC64_VS36    = UNW_PPC64_V4,
+  UNW_PPC64_VS37    = UNW_PPC64_V5,
+  UNW_PPC64_VS38    = UNW_PPC64_V6,
+  UNW_PPC64_VS39    = UNW_PPC64_V7,
+  UNW_PPC64_VS40    = UNW_PPC64_V8,
+  UNW_PPC64_VS41    = UNW_PPC64_V9,
+  UNW_PPC64_VS42    = UNW_PPC64_V10,
+  UNW_PPC64_VS43    = UNW_PPC64_V11,
+  UNW_PPC64_VS44    = UNW_PPC64_V12,
+  UNW_PPC64_VS45    = UNW_PPC64_V13,
+  UNW_PPC64_VS46    = UNW_PPC64_V14,
+  UNW_PPC64_VS47    = UNW_PPC64_V15,
+  UNW_PPC64_VS48    = UNW_PPC64_V16,
+  UNW_PPC64_VS49    = UNW_PPC64_V17,
+  UNW_PPC64_VS50    = UNW_PPC64_V18,
+  UNW_PPC64_VS51    = UNW_PPC64_V19,
+  UNW_PPC64_VS52    = UNW_PPC64_V20,
+  UNW_PPC64_VS53    = UNW_PPC64_V21,
+  UNW_PPC64_VS54    = UNW_PPC64_V22,
+  UNW_PPC64_VS55    = UNW_PPC64_V23,
+  UNW_PPC64_VS56    = UNW_PPC64_V24,
+  UNW_PPC64_VS57    = UNW_PPC64_V25,
+  UNW_PPC64_VS58    = UNW_PPC64_V26,
+  UNW_PPC64_VS59    = UNW_PPC64_V27,
+  UNW_PPC64_VS60    = UNW_PPC64_V28,
+  UNW_PPC64_VS61    = UNW_PPC64_V29,
+  UNW_PPC64_VS62    = UNW_PPC64_V30,
+  UNW_PPC64_VS63    = UNW_PPC64_V31
+};
+
+// 64-bit ARM64 registers
+enum {
+  UNW_ARM64_X0 = 0,
+  UNW_ARM64_X1 = 1,
+  UNW_ARM64_X2 = 2,
+  UNW_ARM64_X3 = 3,
+  UNW_ARM64_X4 = 4,
+  UNW_ARM64_X5 = 5,
+  UNW_ARM64_X6 = 6,
+  UNW_ARM64_X7 = 7,
+  UNW_ARM64_X8 = 8,
+  UNW_ARM64_X9 = 9,
+  UNW_ARM64_X10 = 10,
+  UNW_ARM64_X11 = 11,
+  UNW_ARM64_X12 = 12,
+  UNW_ARM64_X13 = 13,
+  UNW_ARM64_X14 = 14,
+  UNW_ARM64_X15 = 15,
+  UNW_ARM64_X16 = 16,
+  UNW_ARM64_X17 = 17,
+  UNW_ARM64_X18 = 18,
+  UNW_ARM64_X19 = 19,
+  UNW_ARM64_X20 = 20,
+  UNW_ARM64_X21 = 21,
+  UNW_ARM64_X22 = 22,
+  UNW_ARM64_X23 = 23,
+  UNW_ARM64_X24 = 24,
+  UNW_ARM64_X25 = 25,
+  UNW_ARM64_X26 = 26,
+  UNW_ARM64_X27 = 27,
+  UNW_ARM64_X28 = 28,
+  UNW_ARM64_X29 = 29,
+  UNW_ARM64_FP = 29,
+  UNW_ARM64_X30 = 30,
+  UNW_ARM64_LR = 30,
+  UNW_ARM64_X31 = 31,
+  UNW_ARM64_SP = 31,
+  UNW_ARM64_PC = 32,
+  // reserved block
+  UNW_ARM64_RA_SIGN_STATE = 34,
+  // reserved block
+  UNW_ARM64_D0 = 64,
+  UNW_ARM64_D1 = 65,
+  UNW_ARM64_D2 = 66,
+  UNW_ARM64_D3 = 67,
+  UNW_ARM64_D4 = 68,
+  UNW_ARM64_D5 = 69,
+  UNW_ARM64_D6 = 70,
+  UNW_ARM64_D7 = 71,
+  UNW_ARM64_D8 = 72,
+  UNW_ARM64_D9 = 73,
+  UNW_ARM64_D10 = 74,
+  UNW_ARM64_D11 = 75,
+  UNW_ARM64_D12 = 76,
+  UNW_ARM64_D13 = 77,
+  UNW_ARM64_D14 = 78,
+  UNW_ARM64_D15 = 79,
+  UNW_ARM64_D16 = 80,
+  UNW_ARM64_D17 = 81,
+  UNW_ARM64_D18 = 82,
+  UNW_ARM64_D19 = 83,
+  UNW_ARM64_D20 = 84,
+  UNW_ARM64_D21 = 85,
+  UNW_ARM64_D22 = 86,
+  UNW_ARM64_D23 = 87,
+  UNW_ARM64_D24 = 88,
+  UNW_ARM64_D25 = 89,
+  UNW_ARM64_D26 = 90,
+  UNW_ARM64_D27 = 91,
+  UNW_ARM64_D28 = 92,
+  UNW_ARM64_D29 = 93,
+  UNW_ARM64_D30 = 94,
+  UNW_ARM64_D31 = 95,
+};
+
+// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1.
+// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3.
+// In this scheme, even though the 64-bit floating point registers D0-D31
+// overlap physically with the 32-bit floating pointer registers S0-S31,
+// they are given a non-overlapping range of register numbers.
+//
+// Commented out ranges are not preserved during unwinding.
+enum {
+  UNW_ARM_R0  = 0,
+  UNW_ARM_R1  = 1,
+  UNW_ARM_R2  = 2,
+  UNW_ARM_R3  = 3,
+  UNW_ARM_R4  = 4,
+  UNW_ARM_R5  = 5,
+  UNW_ARM_R6  = 6,
+  UNW_ARM_R7  = 7,
+  UNW_ARM_R8  = 8,
+  UNW_ARM_R9  = 9,
+  UNW_ARM_R10 = 10,
+  UNW_ARM_R11 = 11,
+  UNW_ARM_R12 = 12,
+  UNW_ARM_SP  = 13,  // Logical alias for UNW_REG_SP
+  UNW_ARM_R13 = 13,
+  UNW_ARM_LR  = 14,
+  UNW_ARM_R14 = 14,
+  UNW_ARM_IP  = 15,  // Logical alias for UNW_REG_IP
+  UNW_ARM_R15 = 15,
+  // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31.
+  UNW_ARM_S0  = 64,
+  UNW_ARM_S1  = 65,
+  UNW_ARM_S2  = 66,
+  UNW_ARM_S3  = 67,
+  UNW_ARM_S4  = 68,
+  UNW_ARM_S5  = 69,
+  UNW_ARM_S6  = 70,
+  UNW_ARM_S7  = 71,
+  UNW_ARM_S8  = 72,
+  UNW_ARM_S9  = 73,
+  UNW_ARM_S10 = 74,
+  UNW_ARM_S11 = 75,
+  UNW_ARM_S12 = 76,
+  UNW_ARM_S13 = 77,
+  UNW_ARM_S14 = 78,
+  UNW_ARM_S15 = 79,
+  UNW_ARM_S16 = 80,
+  UNW_ARM_S17 = 81,
+  UNW_ARM_S18 = 82,
+  UNW_ARM_S19 = 83,
+  UNW_ARM_S20 = 84,
+  UNW_ARM_S21 = 85,
+  UNW_ARM_S22 = 86,
+  UNW_ARM_S23 = 87,
+  UNW_ARM_S24 = 88,
+  UNW_ARM_S25 = 89,
+  UNW_ARM_S26 = 90,
+  UNW_ARM_S27 = 91,
+  UNW_ARM_S28 = 92,
+  UNW_ARM_S29 = 93,
+  UNW_ARM_S30 = 94,
+  UNW_ARM_S31 = 95,
+  //  96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP.
+  // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX)
+  UNW_ARM_WR0 = 112,
+  UNW_ARM_WR1 = 113,
+  UNW_ARM_WR2 = 114,
+  UNW_ARM_WR3 = 115,
+  UNW_ARM_WR4 = 116,
+  UNW_ARM_WR5 = 117,
+  UNW_ARM_WR6 = 118,
+  UNW_ARM_WR7 = 119,
+  UNW_ARM_WR8 = 120,
+  UNW_ARM_WR9 = 121,
+  UNW_ARM_WR10 = 122,
+  UNW_ARM_WR11 = 123,
+  UNW_ARM_WR12 = 124,
+  UNW_ARM_WR13 = 125,
+  UNW_ARM_WR14 = 126,
+  UNW_ARM_WR15 = 127,
+  // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC}
+  // 134-143 -- Reserved
+  // 144-150 -- R8_USR-R14_USR
+  // 151-157 -- R8_FIQ-R14_FIQ
+  // 158-159 -- R13_IRQ-R14_IRQ
+  // 160-161 -- R13_ABT-R14_ABT
+  // 162-163 -- R13_UND-R14_UND
+  // 164-165 -- R13_SVC-R14_SVC
+  // 166-191 -- Reserved
+  UNW_ARM_WC0 = 192,
+  UNW_ARM_WC1 = 193,
+  UNW_ARM_WC2 = 194,
+  UNW_ARM_WC3 = 195,
+  // 196-199 -- wC4-wC7 (Intel wireless MMX control)
+  // 200-255 -- Reserved
+  UNW_ARM_D0  = 256,
+  UNW_ARM_D1  = 257,
+  UNW_ARM_D2  = 258,
+  UNW_ARM_D3  = 259,
+  UNW_ARM_D4  = 260,
+  UNW_ARM_D5  = 261,
+  UNW_ARM_D6  = 262,
+  UNW_ARM_D7  = 263,
+  UNW_ARM_D8  = 264,
+  UNW_ARM_D9  = 265,
+  UNW_ARM_D10 = 266,
+  UNW_ARM_D11 = 267,
+  UNW_ARM_D12 = 268,
+  UNW_ARM_D13 = 269,
+  UNW_ARM_D14 = 270,
+  UNW_ARM_D15 = 271,
+  UNW_ARM_D16 = 272,
+  UNW_ARM_D17 = 273,
+  UNW_ARM_D18 = 274,
+  UNW_ARM_D19 = 275,
+  UNW_ARM_D20 = 276,
+  UNW_ARM_D21 = 277,
+  UNW_ARM_D22 = 278,
+  UNW_ARM_D23 = 279,
+  UNW_ARM_D24 = 280,
+  UNW_ARM_D25 = 281,
+  UNW_ARM_D26 = 282,
+  UNW_ARM_D27 = 283,
+  UNW_ARM_D28 = 284,
+  UNW_ARM_D29 = 285,
+  UNW_ARM_D30 = 286,
+  UNW_ARM_D31 = 287,
+  // 288-319 -- Reserved for VFP/Neon
+  // 320-8191 -- Reserved
+  // 8192-16383 -- Unspecified vendor co-processor register.
+};
+
+// OpenRISC1000 register numbers
+enum {
+  UNW_OR1K_R0  = 0,
+  UNW_OR1K_R1  = 1,
+  UNW_OR1K_R2  = 2,
+  UNW_OR1K_R3  = 3,
+  UNW_OR1K_R4  = 4,
+  UNW_OR1K_R5  = 5,
+  UNW_OR1K_R6  = 6,
+  UNW_OR1K_R7  = 7,
+  UNW_OR1K_R8  = 8,
+  UNW_OR1K_R9  = 9,
+  UNW_OR1K_R10 = 10,
+  UNW_OR1K_R11 = 11,
+  UNW_OR1K_R12 = 12,
+  UNW_OR1K_R13 = 13,
+  UNW_OR1K_R14 = 14,
+  UNW_OR1K_R15 = 15,
+  UNW_OR1K_R16 = 16,
+  UNW_OR1K_R17 = 17,
+  UNW_OR1K_R18 = 18,
+  UNW_OR1K_R19 = 19,
+  UNW_OR1K_R20 = 20,
+  UNW_OR1K_R21 = 21,
+  UNW_OR1K_R22 = 22,
+  UNW_OR1K_R23 = 23,
+  UNW_OR1K_R24 = 24,
+  UNW_OR1K_R25 = 25,
+  UNW_OR1K_R26 = 26,
+  UNW_OR1K_R27 = 27,
+  UNW_OR1K_R28 = 28,
+  UNW_OR1K_R29 = 29,
+  UNW_OR1K_R30 = 30,
+  UNW_OR1K_R31 = 31,
+  UNW_OR1K_EPCR = 32,
+};
+
+// MIPS registers
+enum {
+  UNW_MIPS_R0  = 0,
+  UNW_MIPS_R1  = 1,
+  UNW_MIPS_R2  = 2,
+  UNW_MIPS_R3  = 3,
+  UNW_MIPS_R4  = 4,
+  UNW_MIPS_R5  = 5,
+  UNW_MIPS_R6  = 6,
+  UNW_MIPS_R7  = 7,
+  UNW_MIPS_R8  = 8,
+  UNW_MIPS_R9  = 9,
+  UNW_MIPS_R10 = 10,
+  UNW_MIPS_R11 = 11,
+  UNW_MIPS_R12 = 12,
+  UNW_MIPS_R13 = 13,
+  UNW_MIPS_R14 = 14,
+  UNW_MIPS_R15 = 15,
+  UNW_MIPS_R16 = 16,
+  UNW_MIPS_R17 = 17,
+  UNW_MIPS_R18 = 18,
+  UNW_MIPS_R19 = 19,
+  UNW_MIPS_R20 = 20,
+  UNW_MIPS_R21 = 21,
+  UNW_MIPS_R22 = 22,
+  UNW_MIPS_R23 = 23,
+  UNW_MIPS_R24 = 24,
+  UNW_MIPS_R25 = 25,
+  UNW_MIPS_R26 = 26,
+  UNW_MIPS_R27 = 27,
+  UNW_MIPS_R28 = 28,
+  UNW_MIPS_R29 = 29,
+  UNW_MIPS_R30 = 30,
+  UNW_MIPS_R31 = 31,
+  UNW_MIPS_F0  = 32,
+  UNW_MIPS_F1  = 33,
+  UNW_MIPS_F2  = 34,
+  UNW_MIPS_F3  = 35,
+  UNW_MIPS_F4  = 36,
+  UNW_MIPS_F5  = 37,
+  UNW_MIPS_F6  = 38,
+  UNW_MIPS_F7  = 39,
+  UNW_MIPS_F8  = 40,
+  UNW_MIPS_F9  = 41,
+  UNW_MIPS_F10 = 42,
+  UNW_MIPS_F11 = 43,
+  UNW_MIPS_F12 = 44,
+  UNW_MIPS_F13 = 45,
+  UNW_MIPS_F14 = 46,
+  UNW_MIPS_F15 = 47,
+  UNW_MIPS_F16 = 48,
+  UNW_MIPS_F17 = 49,
+  UNW_MIPS_F18 = 50,
+  UNW_MIPS_F19 = 51,
+  UNW_MIPS_F20 = 52,
+  UNW_MIPS_F21 = 53,
+  UNW_MIPS_F22 = 54,
+  UNW_MIPS_F23 = 55,
+  UNW_MIPS_F24 = 56,
+  UNW_MIPS_F25 = 57,
+  UNW_MIPS_F26 = 58,
+  UNW_MIPS_F27 = 59,
+  UNW_MIPS_F28 = 60,
+  UNW_MIPS_F29 = 61,
+  UNW_MIPS_F30 = 62,
+  UNW_MIPS_F31 = 63,
+  UNW_MIPS_HI = 64,
+  UNW_MIPS_LO = 65,
+};
+
+// SPARC registers
+enum {
+  UNW_SPARC_G0 = 0,
+  UNW_SPARC_G1 = 1,
+  UNW_SPARC_G2 = 2,
+  UNW_SPARC_G3 = 3,
+  UNW_SPARC_G4 = 4,
+  UNW_SPARC_G5 = 5,
+  UNW_SPARC_G6 = 6,
+  UNW_SPARC_G7 = 7,
+  UNW_SPARC_O0 = 8,
+  UNW_SPARC_O1 = 9,
+  UNW_SPARC_O2 = 10,
+  UNW_SPARC_O3 = 11,
+  UNW_SPARC_O4 = 12,
+  UNW_SPARC_O5 = 13,
+  UNW_SPARC_O6 = 14,
+  UNW_SPARC_O7 = 15,
+  UNW_SPARC_L0 = 16,
+  UNW_SPARC_L1 = 17,
+  UNW_SPARC_L2 = 18,
+  UNW_SPARC_L3 = 19,
+  UNW_SPARC_L4 = 20,
+  UNW_SPARC_L5 = 21,
+  UNW_SPARC_L6 = 22,
+  UNW_SPARC_L7 = 23,
+  UNW_SPARC_I0 = 24,
+  UNW_SPARC_I1 = 25,
+  UNW_SPARC_I2 = 26,
+  UNW_SPARC_I3 = 27,
+  UNW_SPARC_I4 = 28,
+  UNW_SPARC_I5 = 29,
+  UNW_SPARC_I6 = 30,
+  UNW_SPARC_I7 = 31,
+};
+
+// Hexagon register numbers
+enum {
+  UNW_HEXAGON_R0,
+  UNW_HEXAGON_R1,
+  UNW_HEXAGON_R2,
+  UNW_HEXAGON_R3,
+  UNW_HEXAGON_R4,
+  UNW_HEXAGON_R5,
+  UNW_HEXAGON_R6,
+  UNW_HEXAGON_R7,
+  UNW_HEXAGON_R8,
+  UNW_HEXAGON_R9,
+  UNW_HEXAGON_R10,
+  UNW_HEXAGON_R11,
+  UNW_HEXAGON_R12,
+  UNW_HEXAGON_R13,
+  UNW_HEXAGON_R14,
+  UNW_HEXAGON_R15,
+  UNW_HEXAGON_R16,
+  UNW_HEXAGON_R17,
+  UNW_HEXAGON_R18,
+  UNW_HEXAGON_R19,
+  UNW_HEXAGON_R20,
+  UNW_HEXAGON_R21,
+  UNW_HEXAGON_R22,
+  UNW_HEXAGON_R23,
+  UNW_HEXAGON_R24,
+  UNW_HEXAGON_R25,
+  UNW_HEXAGON_R26,
+  UNW_HEXAGON_R27,
+  UNW_HEXAGON_R28,
+  UNW_HEXAGON_R29,
+  UNW_HEXAGON_R30,
+  UNW_HEXAGON_R31,
+  UNW_HEXAGON_P3_0,
+  UNW_HEXAGON_PC,
+};
+
+// RISC-V registers. These match the DWARF register numbers defined by section
+// 4 of the RISC-V ELF psABI specification, which can be found at:
+//
+// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md
+enum {
+  UNW_RISCV_X0  = 0,
+  UNW_RISCV_X1  = 1,
+  UNW_RISCV_X2  = 2,
+  UNW_RISCV_X3  = 3,
+  UNW_RISCV_X4  = 4,
+  UNW_RISCV_X5  = 5,
+  UNW_RISCV_X6  = 6,
+  UNW_RISCV_X7  = 7,
+  UNW_RISCV_X8  = 8,
+  UNW_RISCV_X9  = 9,
+  UNW_RISCV_X10 = 10,
+  UNW_RISCV_X11 = 11,
+  UNW_RISCV_X12 = 12,
+  UNW_RISCV_X13 = 13,
+  UNW_RISCV_X14 = 14,
+  UNW_RISCV_X15 = 15,
+  UNW_RISCV_X16 = 16,
+  UNW_RISCV_X17 = 17,
+  UNW_RISCV_X18 = 18,
+  UNW_RISCV_X19 = 19,
+  UNW_RISCV_X20 = 20,
+  UNW_RISCV_X21 = 21,
+  UNW_RISCV_X22 = 22,
+  UNW_RISCV_X23 = 23,
+  UNW_RISCV_X24 = 24,
+  UNW_RISCV_X25 = 25,
+  UNW_RISCV_X26 = 26,
+  UNW_RISCV_X27 = 27,
+  UNW_RISCV_X28 = 28,
+  UNW_RISCV_X29 = 29,
+  UNW_RISCV_X30 = 30,
+  UNW_RISCV_X31 = 31,
+  UNW_RISCV_F0  = 32,
+  UNW_RISCV_F1  = 33,
+  UNW_RISCV_F2  = 34,
+  UNW_RISCV_F3  = 35,
+  UNW_RISCV_F4  = 36,
+  UNW_RISCV_F5  = 37,
+  UNW_RISCV_F6  = 38,
+  UNW_RISCV_F7  = 39,
+  UNW_RISCV_F8  = 40,
+  UNW_RISCV_F9  = 41,
+  UNW_RISCV_F10 = 42,
+  UNW_RISCV_F11 = 43,
+  UNW_RISCV_F12 = 44,
+  UNW_RISCV_F13 = 45,
+  UNW_RISCV_F14 = 46,
+  UNW_RISCV_F15 = 47,
+  UNW_RISCV_F16 = 48,
+  UNW_RISCV_F17 = 49,
+  UNW_RISCV_F18 = 50,
+  UNW_RISCV_F19 = 51,
+  UNW_RISCV_F20 = 52,
+  UNW_RISCV_F21 = 53,
+  UNW_RISCV_F22 = 54,
+  UNW_RISCV_F23 = 55,
+  UNW_RISCV_F24 = 56,
+  UNW_RISCV_F25 = 57,
+  UNW_RISCV_F26 = 58,
+  UNW_RISCV_F27 = 59,
+  UNW_RISCV_F28 = 60,
+  UNW_RISCV_F29 = 61,
+  UNW_RISCV_F30 = 62,
+  UNW_RISCV_F31 = 63,
+};
+
+// VE register numbers
+enum {
+  UNW_VE_S0   = 0,
+  UNW_VE_S1   = 1,
+  UNW_VE_S2   = 2,
+  UNW_VE_S3   = 3,
+  UNW_VE_S4   = 4,
+  UNW_VE_S5   = 5,
+  UNW_VE_S6   = 6,
+  UNW_VE_S7   = 7,
+  UNW_VE_S8   = 8,
+  UNW_VE_S9   = 9,
+  UNW_VE_S10  = 10,
+  UNW_VE_S11  = 11,
+  UNW_VE_S12  = 12,
+  UNW_VE_S13  = 13,
+  UNW_VE_S14  = 14,
+  UNW_VE_S15  = 15,
+  UNW_VE_S16  = 16,
+  UNW_VE_S17  = 17,
+  UNW_VE_S18  = 18,
+  UNW_VE_S19  = 19,
+  UNW_VE_S20  = 20,
+  UNW_VE_S21  = 21,
+  UNW_VE_S22  = 22,
+  UNW_VE_S23  = 23,
+  UNW_VE_S24  = 24,
+  UNW_VE_S25  = 25,
+  UNW_VE_S26  = 26,
+  UNW_VE_S27  = 27,
+  UNW_VE_S28  = 28,
+  UNW_VE_S29  = 29,
+  UNW_VE_S30  = 30,
+  UNW_VE_S31  = 31,
+  UNW_VE_S32  = 32,
+  UNW_VE_S33  = 33,
+  UNW_VE_S34  = 34,
+  UNW_VE_S35  = 35,
+  UNW_VE_S36  = 36,
+  UNW_VE_S37  = 37,
+  UNW_VE_S38  = 38,
+  UNW_VE_S39  = 39,
+  UNW_VE_S40  = 40,
+  UNW_VE_S41  = 41,
+  UNW_VE_S42  = 42,
+  UNW_VE_S43  = 43,
+  UNW_VE_S44  = 44,
+  UNW_VE_S45  = 45,
+  UNW_VE_S46  = 46,
+  UNW_VE_S47  = 47,
+  UNW_VE_S48  = 48,
+  UNW_VE_S49  = 49,
+  UNW_VE_S50  = 50,
+  UNW_VE_S51  = 51,
+  UNW_VE_S52  = 52,
+  UNW_VE_S53  = 53,
+  UNW_VE_S54  = 54,
+  UNW_VE_S55  = 55,
+  UNW_VE_S56  = 56,
+  UNW_VE_S57  = 57,
+  UNW_VE_S58  = 58,
+  UNW_VE_S59  = 59,
+  UNW_VE_S60  = 60,
+  UNW_VE_S61  = 61,
+  UNW_VE_S62  = 62,
+  UNW_VE_S63  = 63,
+  UNW_VE_V0   = 64 + 0,
+  UNW_VE_V1   = 64 + 1,
+  UNW_VE_V2   = 64 + 2,
+  UNW_VE_V3   = 64 + 3,
+  UNW_VE_V4   = 64 + 4,
+  UNW_VE_V5   = 64 + 5,
+  UNW_VE_V6   = 64 + 6,
+  UNW_VE_V7   = 64 + 7,
+  UNW_VE_V8   = 64 + 8,
+  UNW_VE_V9   = 64 + 9,
+  UNW_VE_V10  = 64 + 10,
+  UNW_VE_V11  = 64 + 11,
+  UNW_VE_V12  = 64 + 12,
+  UNW_VE_V13  = 64 + 13,
+  UNW_VE_V14  = 64 + 14,
+  UNW_VE_V15  = 64 + 15,
+  UNW_VE_V16  = 64 + 16,
+  UNW_VE_V17  = 64 + 17,
+  UNW_VE_V18  = 64 + 18,
+  UNW_VE_V19  = 64 + 19,
+  UNW_VE_V20  = 64 + 20,
+  UNW_VE_V21  = 64 + 21,
+  UNW_VE_V22  = 64 + 22,
+  UNW_VE_V23  = 64 + 23,
+  UNW_VE_V24  = 64 + 24,
+  UNW_VE_V25  = 64 + 25,
+  UNW_VE_V26  = 64 + 26,
+  UNW_VE_V27  = 64 + 27,
+  UNW_VE_V28  = 64 + 28,
+  UNW_VE_V29  = 64 + 29,
+  UNW_VE_V30  = 64 + 30,
+  UNW_VE_V31  = 64 + 31,
+  UNW_VE_V32  = 64 + 32,
+  UNW_VE_V33  = 64 + 33,
+  UNW_VE_V34  = 64 + 34,
+  UNW_VE_V35  = 64 + 35,
+  UNW_VE_V36  = 64 + 36,
+  UNW_VE_V37  = 64 + 37,
+  UNW_VE_V38  = 64 + 38,
+  UNW_VE_V39  = 64 + 39,
+  UNW_VE_V40  = 64 + 40,
+  UNW_VE_V41  = 64 + 41,
+  UNW_VE_V42  = 64 + 42,
+  UNW_VE_V43  = 64 + 43,
+  UNW_VE_V44  = 64 + 44,
+  UNW_VE_V45  = 64 + 45,
+  UNW_VE_V46  = 64 + 46,
+  UNW_VE_V47  = 64 + 47,
+  UNW_VE_V48  = 64 + 48,
+  UNW_VE_V49  = 64 + 49,
+  UNW_VE_V50  = 64 + 50,
+  UNW_VE_V51  = 64 + 51,
+  UNW_VE_V52  = 64 + 52,
+  UNW_VE_V53  = 64 + 53,
+  UNW_VE_V54  = 64 + 54,
+  UNW_VE_V55  = 64 + 55,
+  UNW_VE_V56  = 64 + 56,
+  UNW_VE_V57  = 64 + 57,
+  UNW_VE_V58  = 64 + 58,
+  UNW_VE_V59  = 64 + 59,
+  UNW_VE_V60  = 64 + 60,
+  UNW_VE_V61  = 64 + 61,
+  UNW_VE_V62  = 64 + 62,
+  UNW_VE_V63  = 64 + 63,
+  UNW_VE_VM0  = 128 + 0,
+  UNW_VE_VM1  = 128 + 1,
+  UNW_VE_VM2  = 128 + 2,
+  UNW_VE_VM3  = 128 + 3,
+  UNW_VE_VM4  = 128 + 4,
+  UNW_VE_VM5  = 128 + 5,
+  UNW_VE_VM6  = 128 + 6,
+  UNW_VE_VM7  = 128 + 7,
+  UNW_VE_VM8  = 128 + 8,
+  UNW_VE_VM9  = 128 + 9,
+  UNW_VE_VM10 = 128 + 10,
+  UNW_VE_VM11 = 128 + 11,
+  UNW_VE_VM12 = 128 + 12,
+  UNW_VE_VM13 = 128 + 13,
+  UNW_VE_VM14 = 128 + 14,
+  UNW_VE_VM15 = 128 + 15, // = 143
+
+  // Following registers don't have DWARF register numbers.
+  UNW_VE_VIXR = 144,
+  UNW_VE_VL   = 145,
+};
+
+#endif

+ 477 - 0
llvm-libunwind/include/mach-o/compact_unwind_encoding.h

@@ -0,0 +1,477 @@
+//===------------------ mach-o/compact_unwind_encoding.h ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+// Darwin's alternative to DWARF based unwind encodings.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __COMPACT_UNWIND_ENCODING__
+#define __COMPACT_UNWIND_ENCODING__
+
+#include <stdint.h>
+
+//
+// Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section
+// of object files. Or compilers can emit compact unwind information in
+// the __LD,__compact_unwind section.
+//
+// When the linker creates a final linked image, it will create a
+// __TEXT,__unwind_info section.  This section is a small and fast way for the
+// runtime to access unwind info for any given function.  If the compiler
+// emitted compact unwind info for the function, that compact unwind info will
+// be encoded in the __TEXT,__unwind_info section. If the compiler emitted
+// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset
+// of the FDE in the __TEXT,__eh_frame section in the final linked image.
+//
+// Note: Previously, the linker would transform some DWARF unwind infos into
+//       compact unwind info.  But that is fragile and no longer done.
+
+
+//
+// The compact unwind endoding is a 32-bit value which encoded in an
+// architecture specific way, which registers to restore from where, and how
+// to unwind out of the function.
+//
+typedef uint32_t compact_unwind_encoding_t;
+
+
+// architecture independent bits
+enum {
+    UNWIND_IS_NOT_FUNCTION_START           = 0x80000000,
+    UNWIND_HAS_LSDA                        = 0x40000000,
+    UNWIND_PERSONALITY_MASK                = 0x30000000,
+};
+
+
+
+
+//
+// x86
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF
+//  ebp based:
+//        15-bits (5*3-bits per reg) register permutation
+//        8-bits for stack offset
+//  frameless:
+//        8-bits stack size
+//        3-bits stack adjust
+//        3-bits register count
+//        10-bits register permutation
+//
+enum {
+    UNWIND_X86_MODE_MASK                         = 0x0F000000,
+    UNWIND_X86_MODE_EBP_FRAME                    = 0x01000000,
+    UNWIND_X86_MODE_STACK_IMMD                   = 0x02000000,
+    UNWIND_X86_MODE_STACK_IND                    = 0x03000000,
+    UNWIND_X86_MODE_DWARF                        = 0x04000000,
+
+    UNWIND_X86_EBP_FRAME_REGISTERS               = 0x00007FFF,
+    UNWIND_X86_EBP_FRAME_OFFSET                  = 0x00FF0000,
+
+    UNWIND_X86_FRAMELESS_STACK_SIZE              = 0x00FF0000,
+    UNWIND_X86_FRAMELESS_STACK_ADJUST            = 0x0000E000,
+    UNWIND_X86_FRAMELESS_STACK_REG_COUNT         = 0x00001C00,
+    UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION   = 0x000003FF,
+
+    UNWIND_X86_DWARF_SECTION_OFFSET              = 0x00FFFFFF,
+};
+
+enum {
+    UNWIND_X86_REG_NONE     = 0,
+    UNWIND_X86_REG_EBX      = 1,
+    UNWIND_X86_REG_ECX      = 2,
+    UNWIND_X86_REG_EDX      = 3,
+    UNWIND_X86_REG_EDI      = 4,
+    UNWIND_X86_REG_ESI      = 5,
+    UNWIND_X86_REG_EBP      = 6,
+};
+
+//
+// For x86 there are four modes for the compact unwind encoding:
+// UNWIND_X86_MODE_EBP_FRAME:
+//    EBP based frame where EBP is push on stack immediately after return address,
+//    then ESP is moved to EBP. Thus, to unwind ESP is restored with the current
+//    EPB value, then EBP is restored by popping off the stack, and the return
+//    is done by popping the stack once more into the pc.
+//    All non-volatile registers that need to be restored must have been saved
+//    in a small range in the stack that starts EBP-4 to EBP-1020.  The offset/4
+//    is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits.  The registers saved
+//    are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries.
+//    Each entry contains which register to restore.
+// UNWIND_X86_MODE_STACK_IMMD:
+//    A "frameless" (EBP not used as frame pointer) function with a small 
+//    constant stack size.  To return, a constant (encoded in the compact
+//    unwind encoding) is added to the ESP. Then the return is done by
+//    popping the stack into the pc.
+//    All non-volatile registers that need to be restored must have been saved
+//    on the stack immediately after the return address.  The stack_size/4 is
+//    encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024).
+//    The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT.
+//    UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
+//    saved and their order.
+// UNWIND_X86_MODE_STACK_IND:
+//    A "frameless" (EBP not used as frame pointer) function large constant 
+//    stack size.  This case is like the previous, except the stack size is too
+//    large to encode in the compact unwind encoding.  Instead it requires that 
+//    the function contains "subl $nnnnnnnn,ESP" in its prolog.  The compact 
+//    encoding contains the offset to the nnnnnnnn value in the function in
+//    UNWIND_X86_FRAMELESS_STACK_SIZE.  
+// UNWIND_X86_MODE_DWARF:
+//    No compact unwind encoding is available.  Instead the low 24-bits of the
+//    compact encoding is the offset of the DWARF FDE in the __eh_frame section.
+//    This mode is never used in object files.  It is only generated by the 
+//    linker in final linked images which have only DWARF unwind info for a
+//    function.
+//
+// The permutation encoding is a Lehmer code sequence encoded into a
+// single variable-base number so we can encode the ordering of up to
+// six registers in a 10-bit space.
+//
+// The following is the algorithm used to create the permutation encoding used
+// with frameless stacks.  It is passed the number of registers to be saved and
+// an array of the register numbers saved.
+//
+//uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6])
+//{
+//    uint32_t renumregs[6];
+//    for (int i=6-registerCount; i < 6; ++i) {
+//        int countless = 0;
+//        for (int j=6-registerCount; j < i; ++j) {
+//            if ( registers[j] < registers[i] )
+//                ++countless;
+//        }
+//        renumregs[i] = registers[i] - countless -1;
+//    }
+//    uint32_t permutationEncoding = 0;
+//    switch ( registerCount ) {
+//        case 6:
+//            permutationEncoding |= (120*renumregs[0] + 24*renumregs[1]
+//                                    + 6*renumregs[2] + 2*renumregs[3]
+//                                      + renumregs[4]);
+//            break;
+//        case 5:
+//            permutationEncoding |= (120*renumregs[1] + 24*renumregs[2]
+//                                    + 6*renumregs[3] + 2*renumregs[4]
+//                                      + renumregs[5]);
+//            break;
+//        case 4:
+//            permutationEncoding |= (60*renumregs[2] + 12*renumregs[3]
+//                                   + 3*renumregs[4] + renumregs[5]);
+//            break;
+//        case 3:
+//            permutationEncoding |= (20*renumregs[3] + 4*renumregs[4]
+//                                     + renumregs[5]);
+//            break;
+//        case 2:
+//            permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+//            break;
+//        case 1:
+//            permutationEncoding |= (renumregs[5]);
+//            break;
+//    }
+//    return permutationEncoding;
+//}
+//
+
+
+
+
+//
+// x86_64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF
+//  rbp based:
+//        15-bits (5*3-bits per reg) register permutation
+//        8-bits for stack offset
+//  frameless:
+//        8-bits stack size
+//        3-bits stack adjust
+//        3-bits register count
+//        10-bits register permutation
+//
+enum {
+    UNWIND_X86_64_MODE_MASK                         = 0x0F000000,
+    UNWIND_X86_64_MODE_RBP_FRAME                    = 0x01000000,
+    UNWIND_X86_64_MODE_STACK_IMMD                   = 0x02000000,
+    UNWIND_X86_64_MODE_STACK_IND                    = 0x03000000,
+    UNWIND_X86_64_MODE_DWARF                        = 0x04000000,
+
+    UNWIND_X86_64_RBP_FRAME_REGISTERS               = 0x00007FFF,
+    UNWIND_X86_64_RBP_FRAME_OFFSET                  = 0x00FF0000,
+
+    UNWIND_X86_64_FRAMELESS_STACK_SIZE              = 0x00FF0000,
+    UNWIND_X86_64_FRAMELESS_STACK_ADJUST            = 0x0000E000,
+    UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT         = 0x00001C00,
+    UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION   = 0x000003FF,
+
+    UNWIND_X86_64_DWARF_SECTION_OFFSET              = 0x00FFFFFF,
+};
+
+enum {
+    UNWIND_X86_64_REG_NONE       = 0,
+    UNWIND_X86_64_REG_RBX        = 1,
+    UNWIND_X86_64_REG_R12        = 2,
+    UNWIND_X86_64_REG_R13        = 3,
+    UNWIND_X86_64_REG_R14        = 4,
+    UNWIND_X86_64_REG_R15        = 5,
+    UNWIND_X86_64_REG_RBP        = 6,
+};
+//
+// For x86_64 there are four modes for the compact unwind encoding:
+// UNWIND_X86_64_MODE_RBP_FRAME:
+//    RBP based frame where RBP is push on stack immediately after return address,
+//    then RSP is moved to RBP. Thus, to unwind RSP is restored with the current 
+//    EPB value, then RBP is restored by popping off the stack, and the return 
+//    is done by popping the stack once more into the pc.
+//    All non-volatile registers that need to be restored must have been saved
+//    in a small range in the stack that starts RBP-8 to RBP-2040.  The offset/8 
+//    is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits.  The registers saved
+//    are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries.
+//    Each entry contains which register to restore.  
+// UNWIND_X86_64_MODE_STACK_IMMD:
+//    A "frameless" (RBP not used as frame pointer) function with a small 
+//    constant stack size.  To return, a constant (encoded in the compact 
+//    unwind encoding) is added to the RSP. Then the return is done by 
+//    popping the stack into the pc.
+//    All non-volatile registers that need to be restored must have been saved
+//    on the stack immediately after the return address.  The stack_size/8 is
+//    encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048).
+//    The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
+//    UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
+//    saved and their order.  
+// UNWIND_X86_64_MODE_STACK_IND:
+//    A "frameless" (RBP not used as frame pointer) function large constant 
+//    stack size.  This case is like the previous, except the stack size is too
+//    large to encode in the compact unwind encoding.  Instead it requires that 
+//    the function contains "subq $nnnnnnnn,RSP" in its prolog.  The compact 
+//    encoding contains the offset to the nnnnnnnn value in the function in
+//    UNWIND_X86_64_FRAMELESS_STACK_SIZE.  
+// UNWIND_X86_64_MODE_DWARF:
+//    No compact unwind encoding is available.  Instead the low 24-bits of the
+//    compact encoding is the offset of the DWARF FDE in the __eh_frame section.
+//    This mode is never used in object files.  It is only generated by the 
+//    linker in final linked images which have only DWARF unwind info for a
+//    function.
+//
+
+
+// ARM64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 4=frame-based, 3=DWARF, 2=frameless
+//  frameless:
+//        12-bits of stack size
+//  frame-based:
+//        4-bits D reg pairs saved
+//        5-bits X reg pairs saved
+//  DWARF:
+//        24-bits offset of DWARF FDE in __eh_frame section
+//
+enum {
+    UNWIND_ARM64_MODE_MASK                     = 0x0F000000,
+    UNWIND_ARM64_MODE_FRAMELESS                = 0x02000000,
+    UNWIND_ARM64_MODE_DWARF                    = 0x03000000,
+    UNWIND_ARM64_MODE_FRAME                    = 0x04000000,
+
+    UNWIND_ARM64_FRAME_X19_X20_PAIR            = 0x00000001,
+    UNWIND_ARM64_FRAME_X21_X22_PAIR            = 0x00000002,
+    UNWIND_ARM64_FRAME_X23_X24_PAIR            = 0x00000004,
+    UNWIND_ARM64_FRAME_X25_X26_PAIR            = 0x00000008,
+    UNWIND_ARM64_FRAME_X27_X28_PAIR            = 0x00000010,
+    UNWIND_ARM64_FRAME_D8_D9_PAIR              = 0x00000100,
+    UNWIND_ARM64_FRAME_D10_D11_PAIR            = 0x00000200,
+    UNWIND_ARM64_FRAME_D12_D13_PAIR            = 0x00000400,
+    UNWIND_ARM64_FRAME_D14_D15_PAIR            = 0x00000800,
+
+    UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK     = 0x00FFF000,
+    UNWIND_ARM64_DWARF_SECTION_OFFSET          = 0x00FFFFFF,
+};
+// For arm64 there are three modes for the compact unwind encoding:
+// UNWIND_ARM64_MODE_FRAME:
+//    This is a standard arm64 prolog where FP/LR are immediately pushed on the
+//    stack, then SP is copied to FP. If there are any non-volatile registers
+//    saved, then are copied into the stack frame in pairs in a contiguous
+//    range right below the saved FP/LR pair.  Any subset of the five X pairs 
+//    and four D pairs can be saved, but the memory layout must be in register
+//    number order.  
+// UNWIND_ARM64_MODE_FRAMELESS:
+//    A "frameless" leaf function, where FP/LR are not saved. The return address 
+//    remains in LR throughout the function. If any non-volatile registers
+//    are saved, they must be pushed onto the stack before any stack space is
+//    allocated for local variables.  The stack sized (including any saved
+//    non-volatile registers) divided by 16 is encoded in the bits 
+//    UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
+// UNWIND_ARM64_MODE_DWARF:
+//    No compact unwind encoding is available.  Instead the low 24-bits of the
+//    compact encoding is the offset of the DWARF FDE in the __eh_frame section.
+//    This mode is never used in object files.  It is only generated by the 
+//    linker in final linked images which have only DWARF unwind info for a
+//    function.
+//
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Relocatable Object Files: __LD,__compact_unwind
+//
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// A compiler can generated compact unwind information for a function by adding
+// a "row" to the __LD,__compact_unwind section.  This section has the 
+// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers. 
+// It is removed by the new linker, so never ends up in final executables. 
+// This section is a table, initially with one row per function (that needs 
+// unwind info).  The table columns and some conceptual entries are:
+//
+//     range-start               pointer to start of function/range
+//     range-length              
+//     compact-unwind-encoding   32-bit encoding  
+//     personality-function      or zero if no personality function
+//     lsda                      or zero if no LSDA data
+//
+// The length and encoding fields are 32-bits.  The other are all pointer sized. 
+//
+// In x86_64 assembly, these entry would look like:
+//
+//     .section __LD,__compact_unwind,regular,debug
+//
+//     #compact unwind for _foo
+//     .quad    _foo
+//     .set     L1,LfooEnd-_foo
+//     .long    L1
+//     .long    0x01010001
+//     .quad    0
+//     .quad    0
+//
+//     #compact unwind for _bar
+//     .quad    _bar
+//     .set     L2,LbarEnd-_bar
+//     .long    L2
+//     .long    0x01020011
+//     .quad    __gxx_personality
+//     .quad    except_tab1
+//
+//
+// Notes: There is no need for any labels in the the __compact_unwind section.  
+//        The use of the .set directive is to force the evaluation of the 
+//        range-length at assembly time, instead of generating relocations.
+//
+// To support future compiler optimizations where which non-volatile registers 
+// are saved changes within a function (e.g. delay saving non-volatiles until
+// necessary), there can by multiple lines in the __compact_unwind table for one
+// function, each with a different (non-overlapping) range and each with 
+// different compact unwind encodings that correspond to the non-volatiles 
+// saved at that range of the function.
+//
+// If a particular function is so wacky that there is no compact unwind way
+// to encode it, then the compiler can emit traditional DWARF unwind info.  
+// The runtime will use which ever is available.
+//
+// Runtime support for compact unwind encodings are only available on 10.6 
+// and later.  So, the compiler should not generate it when targeting pre-10.6. 
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Final Linked Images: __TEXT,__unwind_info
+//
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// The __TEXT,__unwind_info section is laid out for an efficient two level lookup.
+// The header of the section contains a coarse index that maps function address
+// to the page (4096 byte block) containing the unwind info for that function.  
+//
+
+#define UNWIND_SECTION_VERSION 1
+struct unwind_info_section_header
+{
+    uint32_t    version;            // UNWIND_SECTION_VERSION
+    uint32_t    commonEncodingsArraySectionOffset;
+    uint32_t    commonEncodingsArrayCount;
+    uint32_t    personalityArraySectionOffset;
+    uint32_t    personalityArrayCount;
+    uint32_t    indexSectionOffset;
+    uint32_t    indexCount;
+    // compact_unwind_encoding_t[]
+    // uint32_t personalities[]
+    // unwind_info_section_header_index_entry[]
+    // unwind_info_section_header_lsda_index_entry[]
+};
+
+struct unwind_info_section_header_index_entry
+{
+    uint32_t        functionOffset;
+    uint32_t        secondLevelPagesSectionOffset;  // section offset to start of regular or compress page
+    uint32_t        lsdaIndexArraySectionOffset;    // section offset to start of lsda_index array for this range
+};
+
+struct unwind_info_section_header_lsda_index_entry
+{
+    uint32_t        functionOffset;
+    uint32_t        lsdaOffset;
+};
+
+//
+// There are two kinds of second level index pages: regular and compressed.
+// A compressed page can hold up to 1021 entries, but it cannot be used
+// if too many different encoding types are used.  The regular page holds
+// 511 entries.
+//
+
+struct unwind_info_regular_second_level_entry
+{
+    uint32_t                    functionOffset;
+    compact_unwind_encoding_t    encoding;
+};
+
+#define UNWIND_SECOND_LEVEL_REGULAR 2
+struct unwind_info_regular_second_level_page_header
+{
+    uint32_t    kind;    // UNWIND_SECOND_LEVEL_REGULAR
+    uint16_t    entryPageOffset;
+    uint16_t    entryCount;
+    // entry array
+};
+
+#define UNWIND_SECOND_LEVEL_COMPRESSED 3
+struct unwind_info_compressed_second_level_page_header
+{
+    uint32_t    kind;    // UNWIND_SECOND_LEVEL_COMPRESSED
+    uint16_t    entryPageOffset;
+    uint16_t    entryCount;
+    uint16_t    encodingsPageOffset;
+    uint16_t    encodingsCount;
+    // 32-bit entry array
+    // encodings array
+};
+
+#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry)            (entry & 0x00FFFFFF)
+#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry)        ((entry >> 24) & 0xFF)
+
+
+
+#endif
+

+ 395 - 0
llvm-libunwind/include/unwind.h

@@ -0,0 +1,395 @@
+//===------------------------------- unwind.h -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+// C++ ABI Level 1 ABI documented at:
+//   https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_H__
+#define __UNWIND_H__
+
+#include <__libunwind_config.h>
+
+#include <stdint.h>
+#include <stddef.h>
+
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32)
+#include <windows.h>
+#include <ntverp.h>
+#endif
+
+#if defined(__APPLE__)
+#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable ))
+#else
+#define LIBUNWIND_UNAVAIL
+#endif
+
+typedef enum {
+  _URC_NO_REASON = 0,
+  _URC_OK = 0,
+  _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+  _URC_FATAL_PHASE2_ERROR = 2,
+  _URC_FATAL_PHASE1_ERROR = 3,
+  _URC_NORMAL_STOP = 4,
+  _URC_END_OF_STACK = 5,
+  _URC_HANDLER_FOUND = 6,
+  _URC_INSTALL_CONTEXT = 7,
+  _URC_CONTINUE_UNWIND = 8,
+#if defined(_LIBUNWIND_ARM_EHABI)
+  _URC_FAILURE = 9
+#endif
+} _Unwind_Reason_Code;
+
+typedef enum {
+  _UA_SEARCH_PHASE = 1,
+  _UA_CLEANUP_PHASE = 2,
+  _UA_HANDLER_FRAME = 4,
+  _UA_FORCE_UNWIND = 8,
+  _UA_END_OF_STACK = 16 // gcc extension to C++ ABI
+} _Unwind_Action;
+
+typedef struct _Unwind_Context _Unwind_Context;   // opaque
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+typedef uint32_t _Unwind_State;
+
+static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME   = 0;
+static const _Unwind_State _US_UNWIND_FRAME_STARTING  = 1;
+static const _Unwind_State _US_UNWIND_FRAME_RESUME    = 2;
+static const _Unwind_State _US_ACTION_MASK            = 3;
+/* Undocumented flag for force unwinding. */
+static const _Unwind_State _US_FORCE_UNWIND           = 8;
+
+typedef uint32_t _Unwind_EHT_Header;
+
+struct _Unwind_Control_Block;
+typedef struct _Unwind_Control_Block _Unwind_Control_Block;
+typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */
+
+struct _Unwind_Control_Block {
+  uint64_t exception_class;
+  void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*);
+
+  /* Unwinder cache, private fields for the unwinder's use */
+  struct {
+    uint32_t reserved1; /* init reserved1 to 0, then don't touch */
+    uint32_t reserved2;
+    uint32_t reserved3;
+    uint32_t reserved4;
+    uint32_t reserved5;
+  } unwinder_cache;
+
+  /* Propagation barrier cache (valid after phase 1): */
+  struct {
+    uint32_t sp;
+    uint32_t bitpattern[5];
+  } barrier_cache;
+
+  /* Cleanup cache (preserved over cleanup): */
+  struct {
+    uint32_t bitpattern[4];
+  } cleanup_cache;
+
+  /* Pr cache (for pr's benefit): */
+  struct {
+    uint32_t fnstart; /* function start address */
+    _Unwind_EHT_Header* ehtp; /* pointer to EHT entry header word */
+    uint32_t additional;
+    uint32_t reserved1;
+  } pr_cache;
+
+  long long int :0; /* Enforce the 8-byte alignment */
+} __attribute__((__aligned__(8)));
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+      (_Unwind_State state,
+       _Unwind_Exception* exceptionObject,
+       struct _Unwind_Context* context);
+
+typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(
+    _Unwind_State state, _Unwind_Exception *exceptionObject,
+    struct _Unwind_Context *context);
+#else
+struct _Unwind_Context;   // opaque
+struct _Unwind_Exception; // forward declaration
+typedef struct _Unwind_Exception _Unwind_Exception;
+
+struct _Unwind_Exception {
+  uint64_t exception_class;
+  void (*exception_cleanup)(_Unwind_Reason_Code reason,
+                            _Unwind_Exception *exc);
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+  uintptr_t private_[6];
+#else
+  uintptr_t private_1; // non-zero means forced unwind
+  uintptr_t private_2; // holds sp that phase1 found for phase2 to use
+#endif
+#if __SIZEOF_POINTER__ == 4
+  // The implementation of _Unwind_Exception uses an attribute mode on the
+  // above fields which has the side effect of causing this whole struct to
+  // round up to 32 bytes in size (48 with SEH). To be more explicit, we add
+  // pad fields added for binary compatibility.
+  uint32_t reserved[3];
+#endif
+  // The Itanium ABI requires that _Unwind_Exception objects are "double-word
+  // aligned".  GCC has interpreted this to mean "use the maximum useful
+  // alignment for the target"; so do we.
+} __attribute__((__aligned__));
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+    (int version,
+     _Unwind_Action actions,
+     uint64_t exceptionClass,
+     _Unwind_Exception* exceptionObject,
+     struct _Unwind_Context* context,
+     void* stop_parameter );
+
+typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(
+    int version, _Unwind_Action actions, uint64_t exceptionClass,
+    _Unwind_Exception *exceptionObject, struct _Unwind_Context *context);
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// The following are the base functions documented by the C++ ABI
+//
+#ifdef __USING_SJLJ_EXCEPTIONS__
+extern _Unwind_Reason_Code
+    _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object);
+extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object);
+#else
+extern _Unwind_Reason_Code
+    _Unwind_RaiseException(_Unwind_Exception *exception_object);
+extern void _Unwind_Resume(_Unwind_Exception *exception_object);
+#endif
+extern void _Unwind_DeleteException(_Unwind_Exception *exception_object);
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+typedef enum {
+  _UVRSC_CORE = 0, /* integer register */
+  _UVRSC_VFP = 1, /* vfp */
+  _UVRSC_WMMXD = 3, /* Intel WMMX data register */
+  _UVRSC_WMMXC = 4 /* Intel WMMX control register */
+} _Unwind_VRS_RegClass;
+
+typedef enum {
+  _UVRSD_UINT32 = 0,
+  _UVRSD_VFPX = 1,
+  _UVRSD_UINT64 = 3,
+  _UVRSD_FLOAT = 4,
+  _UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+typedef enum {
+  _UVRSR_OK = 0,
+  _UVRSR_NOT_IMPLEMENTED = 1,
+  _UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+
+extern void _Unwind_Complete(_Unwind_Exception* exception_object);
+
+extern _Unwind_VRS_Result
+_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+                uint32_t regno, _Unwind_VRS_DataRepresentation representation,
+                void *valuep);
+
+extern _Unwind_VRS_Result
+_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+                uint32_t regno, _Unwind_VRS_DataRepresentation representation,
+                void *valuep);
+
+extern _Unwind_VRS_Result
+_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+                uint32_t discriminator,
+                _Unwind_VRS_DataRepresentation representation);
+#endif
+
+#if !defined(_LIBUNWIND_ARM_EHABI)
+
+extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
+extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
+                          uintptr_t new_value);
+extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
+extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
+
+#else  // defined(_LIBUNWIND_ARM_EHABI)
+
+#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
+#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern
+#else
+#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 static __inline__
+#endif
+
+// These are de facto helper functions for ARM, which delegate the function
+// calls to _Unwind_VRS_Get/Set().  These are not a part of ARM EHABI
+// specification, thus these function MUST be inlined.  Please don't replace
+// these with the "extern" function declaration; otherwise, the program
+// including this <unwind.h> header won't be ABI compatible and will result in
+// link error when we are linking the program with libgcc.
+
+_LIBUNWIND_EXPORT_UNWIND_LEVEL1
+uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index) {
+  uintptr_t value = 0;
+  _Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
+  return value;
+}
+
+_LIBUNWIND_EXPORT_UNWIND_LEVEL1
+void _Unwind_SetGR(struct _Unwind_Context *context, int index,
+                   uintptr_t value) {
+  _Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
+}
+
+_LIBUNWIND_EXPORT_UNWIND_LEVEL1
+uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
+  // remove the thumb-bit before returning
+  return _Unwind_GetGR(context, 15) & (~(uintptr_t)0x1);
+}
+
+_LIBUNWIND_EXPORT_UNWIND_LEVEL1
+void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) {
+  uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
+  _Unwind_SetGR(context, 15, value | thumb_bit);
+}
+#endif  // defined(_LIBUNWIND_ARM_EHABI)
+
+extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context);
+extern uintptr_t
+    _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context);
+#ifdef __USING_SJLJ_EXCEPTIONS__
+extern _Unwind_Reason_Code
+    _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object,
+                              _Unwind_Stop_Fn stop, void *stop_parameter);
+#else
+extern _Unwind_Reason_Code
+    _Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
+                         _Unwind_Stop_Fn stop, void *stop_parameter);
+#endif
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t;
+extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
+extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
+#endif
+
+//
+// The following are semi-suppoted extensions to the C++ ABI
+//
+
+//
+//  called by __cxa_rethrow().
+//
+#ifdef __USING_SJLJ_EXCEPTIONS__
+extern _Unwind_Reason_Code
+    _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object);
+#else
+extern _Unwind_Reason_Code
+    _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object);
+#endif
+
+// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
+// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack
+// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON.
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
+                                                void *);
+extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
+
+// _Unwind_GetCFA is a gcc extension that can be called from within a
+// personality handler to get the CFA (stack pointer before call) of
+// current frame.
+extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *);
+
+
+// _Unwind_GetIPInfo is a gcc extension that can be called from within a
+// personality handler.  Similar to _Unwind_GetIP() but also returns in
+// *ipBefore a non-zero value if the instruction pointer is at or before the
+// instruction causing the unwind. Normally, in a function call, the IP returned
+// is the return address which is after the call instruction and may be past the
+// end of the function containing the call instruction.
+extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
+                                   int *ipBefore);
+
+
+// __register_frame() is used with dynamically generated code to register the
+// FDE for a generated (JIT) code.  The FDE must use pc-rel addressing to point
+// to its function and optional LSDA.
+// __register_frame() has existed in all versions of Mac OS X, but in 10.4 and
+// 10.5 it was buggy and did not actually register the FDE with the unwinder.
+// In 10.6 and later it does register properly.
+extern void __register_frame(const void *fde);
+extern void __deregister_frame(const void *fde);
+
+// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
+// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind
+// info" which the runtime uses in preference to DWARF unwind info.  This
+// function will only work if the target function has an FDE but no compact
+// unwind info.
+struct dwarf_eh_bases {
+  uintptr_t tbase;
+  uintptr_t dbase;
+  uintptr_t func;
+};
+extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *);
+
+
+// This function attempts to find the start (address of first instruction) of
+// a function given an address inside the function.  It only works if the
+// function has an FDE (DWARF unwind info).
+// This function is unimplemented on Mac OS X 10.6 and later.  Instead, use
+// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
+extern void *_Unwind_FindEnclosingFunction(void *pc);
+
+// Mac OS X does not support text-rel and data-rel addressing so these functions
+// are unimplemented
+extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context)
+    LIBUNWIND_UNAVAIL;
+extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context)
+    LIBUNWIND_UNAVAIL;
+
+// Mac OS X 10.4 and 10.5 had implementations of these functions in
+// libgcc_s.dylib, but they never worked.
+/// These functions are no longer available on Mac OS X.
+extern void __register_frame_info_bases(const void *fde, void *ob, void *tb,
+                                        void *db) LIBUNWIND_UNAVAIL;
+extern void __register_frame_info(const void *fde, void *ob)
+    LIBUNWIND_UNAVAIL;
+extern void __register_frame_info_table_bases(const void *fde, void *ob,
+                                              void *tb, void *db)
+    LIBUNWIND_UNAVAIL;
+extern void __register_frame_info_table(const void *fde, void *ob)
+    LIBUNWIND_UNAVAIL;
+extern void __register_frame_table(const void *fde)
+    LIBUNWIND_UNAVAIL;
+extern void *__deregister_frame_info(const void *fde)
+    LIBUNWIND_UNAVAIL;
+extern void *__deregister_frame_info_bases(const void *fde)
+    LIBUNWIND_UNAVAIL;
+
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+#ifndef _WIN32
+typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
+typedef struct _CONTEXT CONTEXT;
+typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
+#elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000
+typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
+#endif
+// This is the common wrapper for GCC-style personality functions with SEH.
+extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc,
+                                                   void *frame, CONTEXT *ctx,
+                                                   DISPATCHER_CONTEXT *disp,
+                                                   _Unwind_Personality_Fn pers);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UNWIND_H__

+ 630 - 0
llvm-libunwind/src/AddressSpace.hpp

@@ -0,0 +1,630 @@
+//===------------------------- AddressSpace.hpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+// Abstracts accessing local vs remote address spaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ADDRESSSPACE_HPP__
+#define __ADDRESSSPACE_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "config.h"
+#include "dwarf2.h"
+#include "EHHeaderParser.hpp"
+#include "Registers.hpp"
+
+#ifndef _LIBUNWIND_USE_DLADDR
+  #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
+    #define _LIBUNWIND_USE_DLADDR 1
+  #else
+    #define _LIBUNWIND_USE_DLADDR 0
+  #endif
+#endif
+
+#if _LIBUNWIND_USE_DLADDR
+#include <dlfcn.h>
+#if defined(__ELF__) && defined(_LIBUNWIND_LINK_DL_LIB)
+#pragma comment(lib, "dl")
+#endif
+#endif
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+struct EHABIIndexEntry {
+  uint32_t functionOffset;
+  uint32_t data;
+};
+#endif
+
+#ifdef __APPLE__
+
+  struct dyld_unwind_sections
+  {
+    const struct mach_header*   mh;
+    const void*                 dwarf_section;
+    uintptr_t                   dwarf_section_length;
+    const void*                 compact_unwind_section;
+    uintptr_t                   compact_unwind_section_length;
+  };
+
+  // In 10.7.0 or later, libSystem.dylib implements this function.
+  extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
+
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
+
+// When statically linked on bare-metal, the symbols for the EH table are looked
+// up without going through the dynamic loader.
+
+// The following linker script may be used to produce the necessary sections and symbols.
+// Unless the --eh-frame-hdr linker option is provided, the section is not generated
+// and does not take space in the output file.
+//
+//   .eh_frame :
+//   {
+//       __eh_frame_start = .;
+//       KEEP(*(.eh_frame))
+//       __eh_frame_end = .;
+//   }
+//
+//   .eh_frame_hdr :
+//   {
+//       KEEP(*(.eh_frame_hdr))
+//   }
+//
+//   __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
+//   __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
+
+extern char __eh_frame_start;
+extern char __eh_frame_end;
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+extern char __eh_frame_hdr_start;
+extern char __eh_frame_hdr_end;
+#endif
+
+#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
+
+// When statically linked on bare-metal, the symbols for the EH table are looked
+// up without going through the dynamic loader.
+extern char __exidx_start;
+extern char __exidx_end;
+
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
+
+#include <windows.h>
+#include <psapi.h>
+
+#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) ||                               \
+      defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
+
+#include <link.h>
+
+#endif
+
+namespace libunwind {
+
+/// Used by findUnwindSections() to return info about needed sections.
+struct UnwindInfoSections {
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) ||                                \
+    defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) ||                              \
+    defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+  // No dso_base for SEH.
+  uintptr_t       dso_base;
+#endif
+#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+  uintptr_t       text_segment_length;
+#endif
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+  uintptr_t       dwarf_section;
+  uintptr_t       dwarf_section_length;
+#endif
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+  uintptr_t       dwarf_index_section;
+  uintptr_t       dwarf_index_section_length;
+#endif
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+  uintptr_t       compact_unwind_section;
+  uintptr_t       compact_unwind_section_length;
+#endif
+#if defined(_LIBUNWIND_ARM_EHABI)
+  uintptr_t       arm_section;
+  uintptr_t       arm_section_length;
+#endif
+};
+
+
+/// LocalAddressSpace is used as a template parameter to UnwindCursor when
+/// unwinding a thread in the same process.  The wrappers compile away,
+/// making local unwinds fast.
+class _LIBUNWIND_HIDDEN LocalAddressSpace {
+public:
+  typedef uintptr_t pint_t;
+  typedef intptr_t  sint_t;
+  uint8_t         get8(pint_t addr) {
+    uint8_t val;
+    memcpy(&val, (void *)addr, sizeof(val));
+    return val;
+  }
+  uint16_t         get16(pint_t addr) {
+    uint16_t val;
+    memcpy(&val, (void *)addr, sizeof(val));
+    return val;
+  }
+  uint32_t         get32(pint_t addr) {
+    uint32_t val;
+    memcpy(&val, (void *)addr, sizeof(val));
+    return val;
+  }
+  uint64_t         get64(pint_t addr) {
+    uint64_t val;
+    memcpy(&val, (void *)addr, sizeof(val));
+    return val;
+  }
+  double           getDouble(pint_t addr) {
+    double val;
+    memcpy(&val, (void *)addr, sizeof(val));
+    return val;
+  }
+  v128             getVector(pint_t addr) {
+    v128 val;
+    memcpy(&val, (void *)addr, sizeof(val));
+    return val;
+  }
+  uintptr_t       getP(pint_t addr);
+  uint64_t        getRegister(pint_t addr);
+  static uint64_t getULEB128(pint_t &addr, pint_t end);
+  static int64_t  getSLEB128(pint_t &addr, pint_t end);
+
+  pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
+                     pint_t datarelBase = 0);
+  bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
+                        unw_word_t *offset);
+  bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
+  bool findOtherFDE(pint_t targetAddr, pint_t &fde);
+
+  static LocalAddressSpace sThisAddressSpace;
+};
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
+#if __SIZEOF_POINTER__ == 8
+  return get64(addr);
+#else
+  return get32(addr);
+#endif
+}
+
+inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
+#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
+  return get64(addr);
+#else
+  return get32(addr);
+#endif
+}
+
+/// Read a ULEB128 into a 64-bit word.
+inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
+  const uint8_t *p = (uint8_t *)addr;
+  const uint8_t *pend = (uint8_t *)end;
+  uint64_t result = 0;
+  int bit = 0;
+  do {
+    uint64_t b;
+
+    if (p == pend)
+      _LIBUNWIND_ABORT("truncated uleb128 expression");
+
+    b = *p & 0x7f;
+
+    if (bit >= 64 || b << bit >> bit != b) {
+      _LIBUNWIND_ABORT("malformed uleb128 expression");
+    } else {
+      result |= b << bit;
+      bit += 7;
+    }
+  } while (*p++ >= 0x80);
+  addr = (pint_t) p;
+  return result;
+}
+
+/// Read a SLEB128 into a 64-bit word.
+inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
+  const uint8_t *p = (uint8_t *)addr;
+  const uint8_t *pend = (uint8_t *)end;
+  int64_t result = 0;
+  int bit = 0;
+  uint8_t byte;
+  do {
+    if (p == pend)
+      _LIBUNWIND_ABORT("truncated sleb128 expression");
+    byte = *p++;
+    result |= (uint64_t)(byte & 0x7f) << bit;
+    bit += 7;
+  } while (byte & 0x80);
+  // sign extend negative numbers
+  if ((byte & 0x40) != 0 && bit < 64)
+    result |= (-1ULL) << bit;
+  addr = (pint_t) p;
+  return result;
+}
+
+inline LocalAddressSpace::pint_t
+LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
+                               pint_t datarelBase) {
+  pint_t startAddr = addr;
+  const uint8_t *p = (uint8_t *)addr;
+  pint_t result;
+
+  // first get value
+  switch (encoding & 0x0F) {
+  case DW_EH_PE_ptr:
+    result = getP(addr);
+    p += sizeof(pint_t);
+    addr = (pint_t) p;
+    break;
+  case DW_EH_PE_uleb128:
+    result = (pint_t)getULEB128(addr, end);
+    break;
+  case DW_EH_PE_udata2:
+    result = get16(addr);
+    p += 2;
+    addr = (pint_t) p;
+    break;
+  case DW_EH_PE_udata4:
+    result = get32(addr);
+    p += 4;
+    addr = (pint_t) p;
+    break;
+  case DW_EH_PE_udata8:
+    result = (pint_t)get64(addr);
+    p += 8;
+    addr = (pint_t) p;
+    break;
+  case DW_EH_PE_sleb128:
+    result = (pint_t)getSLEB128(addr, end);
+    break;
+  case DW_EH_PE_sdata2:
+    // Sign extend from signed 16-bit value.
+    result = (pint_t)(int16_t)get16(addr);
+    p += 2;
+    addr = (pint_t) p;
+    break;
+  case DW_EH_PE_sdata4:
+    // Sign extend from signed 32-bit value.
+    result = (pint_t)(int32_t)get32(addr);
+    p += 4;
+    addr = (pint_t) p;
+    break;
+  case DW_EH_PE_sdata8:
+    result = (pint_t)get64(addr);
+    p += 8;
+    addr = (pint_t) p;
+    break;
+  default:
+    _LIBUNWIND_ABORT("unknown pointer encoding");
+  }
+
+  // then add relative offset
+  switch (encoding & 0x70) {
+  case DW_EH_PE_absptr:
+    // do nothing
+    break;
+  case DW_EH_PE_pcrel:
+    result += startAddr;
+    break;
+  case DW_EH_PE_textrel:
+    _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
+    break;
+  case DW_EH_PE_datarel:
+    // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
+    // default value of 0, and we abort in the event that someone calls this
+    // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
+    if (datarelBase == 0)
+      _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
+    result += datarelBase;
+    break;
+  case DW_EH_PE_funcrel:
+    _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+    break;
+  case DW_EH_PE_aligned:
+    _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
+    break;
+  default:
+    _LIBUNWIND_ABORT("unknown pointer encoding");
+    break;
+  }
+
+  if (encoding & DW_EH_PE_indirect)
+    result = getP(result);
+
+  return result;
+}
+
+#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+
+// The ElfW() macro for pointer-size independent ELF header traversal is not
+// provided by <link.h> on some systems (e.g., FreeBSD). On these systems the
+// data structures are just called Elf_XXX. Define ElfW() locally.
+#if !defined(ElfW)
+  #define ElfW(type) Elf_##type
+#endif
+#if !defined(Elf_Half)
+  typedef ElfW(Half) Elf_Half;
+#endif
+#if !defined(Elf_Phdr)
+  typedef ElfW(Phdr) Elf_Phdr;
+#endif
+#if !defined(Elf_Addr)
+  typedef ElfW(Addr) Elf_Addr;
+#endif
+
+static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
+  Elf_Addr image_base = pinfo->dlpi_addr;
+#if defined(__ANDROID__) && __ANDROID_API__ < 18
+  if (image_base == 0) {
+    // Normally, an image base of 0 indicates a non-PIE executable. On
+    // versions of Android prior to API 18, the dynamic linker reported a
+    // dlpi_addr of 0 for PIE executables. Compute the true image base
+    // using the PT_PHDR segment.
+    // See https://github.com/android/ndk/issues/505.
+    for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
+      const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
+      if (phdr->p_type == PT_PHDR) {
+        image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
+          phdr->p_vaddr;
+        break;
+      }
+    }
+  }
+#endif
+  return image_base;
+}
+
+struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
+  LocalAddressSpace *addressSpace;
+  UnwindInfoSections *sects;
+  uintptr_t targetAddr;
+};
+
+#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
+#include "FrameHeaderCache.hpp"
+
+// Typically there is one cache per process, but when libunwind is built as a
+// hermetic static library, then each shared object may have its own cache.
+static FrameHeaderCache TheFrameHeaderCache;
+#endif
+
+static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
+                               dl_iterate_cb_data *cbdata) {
+  if (phdr->p_type == PT_LOAD) {
+    uintptr_t begin = image_base + phdr->p_vaddr;
+    uintptr_t end = begin + phdr->p_memsz;
+    if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
+      cbdata->sects->dso_base = begin;
+      cbdata->sects->text_segment_length = phdr->p_memsz;
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
+                                      dl_iterate_cb_data *cbdata) {
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+  if (phdr->p_type == PT_GNU_EH_FRAME) {
+    EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
+    uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
+    cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
+    cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
+    if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
+            *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
+            hdrInfo)) {
+      // .eh_frame_hdr records the start of .eh_frame, but not its size.
+      // Rely on a zero terminator to find the end of the section.
+      cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
+      cbdata->sects->dwarf_section_length = UINTPTR_MAX;
+      return true;
+    }
+  }
+  return false;
+#elif defined(_LIBUNWIND_ARM_EHABI)
+  if (phdr->p_type == PT_ARM_EXIDX) {
+    uintptr_t exidx_start = image_base + phdr->p_vaddr;
+    cbdata->sects->arm_section = exidx_start;
+    cbdata->sects->arm_section_length = phdr->p_memsz;
+    return true;
+  }
+  return false;
+#else
+#error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
+#endif
+}
+
+static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
+                                    size_t pinfo_size, void *data) {
+  auto cbdata = static_cast<dl_iterate_cb_data *>(data);
+  if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
+    return 0;
+#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
+  if (TheFrameHeaderCache.find(pinfo, pinfo_size, data))
+    return 1;
+#else
+  // Avoid warning about unused variable.
+  (void)pinfo_size;
+#endif
+
+  Elf_Addr image_base = calculateImageBase(pinfo);
+
+  // Most shared objects seen in this callback function likely don't contain the
+  // target address, so optimize for that. Scan for a matching PT_LOAD segment
+  // first and bail when it isn't found.
+  bool found_text = false;
+  for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) {
+    if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) {
+      found_text = true;
+      break;
+    }
+  }
+  if (!found_text)
+    return 0;
+
+  // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
+  // backward.
+  bool found_unwind = false;
+  for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
+    const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
+    if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
+      found_unwind = true;
+      break;
+    }
+  }
+  if (!found_unwind)
+    return 0;
+
+#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
+  TheFrameHeaderCache.add(cbdata->sects);
+#endif
+  return 1;
+}
+
+#endif  // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+
+
+inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
+                                                  UnwindInfoSections &info) {
+#ifdef __APPLE__
+  dyld_unwind_sections dyldInfo;
+  if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
+    info.dso_base                      = (uintptr_t)dyldInfo.mh;
+ #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+    info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
+    info.dwarf_section_length          = dyldInfo.dwarf_section_length;
+ #endif
+    info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
+    info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
+    return true;
+  }
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
+  info.dso_base = 0;
+  // Bare metal is statically linked, so no need to ask the dynamic loader
+  info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
+  info.dwarf_section =        (uintptr_t)(&__eh_frame_start);
+  _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
+                             (void *)info.dwarf_section, (void *)info.dwarf_section_length);
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+  info.dwarf_index_section =        (uintptr_t)(&__eh_frame_hdr_start);
+  info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
+  _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
+                             (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
+#endif
+  if (info.dwarf_section_length)
+    return true;
+#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
+  // Bare metal is statically linked, so no need to ask the dynamic loader
+  info.arm_section =        (uintptr_t)(&__exidx_start);
+  info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
+  _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
+                             (void *)info.arm_section, (void *)info.arm_section_length);
+  if (info.arm_section && info.arm_section_length)
+    return true;
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
+  HMODULE mods[1024];
+  HANDLE process = GetCurrentProcess();
+  DWORD needed;
+
+  if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
+    DWORD err = GetLastError();
+    _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
+                               "returned error %d", (int)err);
+    return false;
+  }
+
+  for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
+    PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
+    PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
+    PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
+    PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
+    bool found_obj = false;
+    bool found_hdr = false;
+
+    info.dso_base = (uintptr_t)mods[i];
+    for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
+      uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
+      uintptr_t end = begin + pish->Misc.VirtualSize;
+      if (!strncmp((const char *)pish->Name, ".text",
+                   IMAGE_SIZEOF_SHORT_NAME)) {
+        if (targetAddr >= begin && targetAddr < end)
+          found_obj = true;
+      } else if (!strncmp((const char *)pish->Name, ".eh_frame",
+                          IMAGE_SIZEOF_SHORT_NAME)) {
+        info.dwarf_section = begin;
+        info.dwarf_section_length = pish->Misc.VirtualSize;
+        found_hdr = true;
+      }
+      if (found_obj && found_hdr)
+        return true;
+    }
+  }
+  return false;
+#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
+  // Don't even bother, since Windows has functions that do all this stuff
+  // for us.
+  (void)targetAddr;
+  (void)info;
+  return true;
+#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
+  int length = 0;
+  info.arm_section =
+      (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
+  info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
+  if (info.arm_section && info.arm_section_length)
+    return true;
+#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+  dl_iterate_cb_data cb_data = {this, &info, targetAddr};
+  int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
+  return static_cast<bool>(found);
+#endif
+
+  return false;
+}
+
+
+inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
+  // TO DO: if OS has way to dynamically register FDEs, check that.
+  (void)targetAddr;
+  (void)fde;
+  return false;
+}
+
+inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
+                                                size_t bufLen,
+                                                unw_word_t *offset) {
+#if _LIBUNWIND_USE_DLADDR
+  Dl_info dyldInfo;
+  if (dladdr((void *)addr, &dyldInfo)) {
+    if (dyldInfo.dli_sname != NULL) {
+      snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
+      *offset = (addr - (pint_t) dyldInfo.dli_saddr);
+      return true;
+    }
+  }
+#else
+  (void)addr;
+  (void)buf;
+  (void)bufLen;
+  (void)offset;
+#endif
+  return false;
+}
+
+} // namespace libunwind
+
+#endif // __ADDRESSSPACE_HPP__

+ 202 - 0
llvm-libunwind/src/CMakeLists.txt

@@ -0,0 +1,202 @@
+# Get sources
+
+set(LIBUNWIND_CXX_SOURCES
+    libunwind.cpp
+    Unwind-EHABI.cpp
+    Unwind-seh.cpp
+    )
+if(APPLE)
+  list(APPEND LIBUNWIND_CXX_SOURCES
+    Unwind_AppleExtras.cpp
+    )
+endif()
+
+set(LIBUNWIND_C_SOURCES
+    UnwindLevel1.c
+    UnwindLevel1-gcc-ext.c
+    Unwind-sjlj.c
+    )
+set_source_files_properties(${LIBUNWIND_C_SOURCES}
+                            PROPERTIES
+                              COMPILE_FLAGS "-std=c99")
+
+set(LIBUNWIND_ASM_SOURCES
+    UnwindRegistersRestore.S
+    UnwindRegistersSave.S
+    )
+
+# See add_asm_sources() in compiler-rt for explanation of this workaround.
+if((APPLE AND CMAKE_VERSION VERSION_LESS 3.19) OR (MINGW AND CMAKE_VERSION VERSION_LESS 3.17))
+  set_source_files_properties(${LIBUNWIND_ASM_SOURCES} PROPERTIES LANGUAGE C)
+endif()
+
+set(LIBUNWIND_HEADERS
+    AddressSpace.hpp
+    assembly.h
+    CompactUnwinder.hpp
+    config.h
+    dwarf2.h
+    DwarfInstructions.hpp
+    DwarfParser.hpp
+    EHHeaderParser.hpp
+    FrameHeaderCache.hpp
+    libunwind_ext.h
+    Registers.hpp
+    RWMutex.hpp
+    Unwind-EHABI.h
+    UnwindCursor.hpp
+    ../include/libunwind.h
+    ../include/unwind.h
+    )
+if(APPLE)
+  list(APPEND LIBUNWIND_HEADERS
+    ../include/mach-o/compact_unwind_encoding.h
+    )
+endif()
+
+if (MSVC_IDE)
+  # Force them all into the headers dir on MSVC, otherwise they end up at
+  # project scope because they don't have extensions.
+  source_group("Header Files" FILES ${LIBUNWIND_HEADERS})
+endif()
+
+set(LIBUNWIND_SOURCES
+    ${LIBUNWIND_CXX_SOURCES}
+    ${LIBUNWIND_C_SOURCES}
+    ${LIBUNWIND_ASM_SOURCES})
+
+# Generate library list.
+add_library_flags_if(LIBUNWIND_HAS_C_LIB c)
+if (LIBUNWIND_USE_COMPILER_RT)
+  add_library_flags("${LIBUNWIND_BUILTINS_LIBRARY}")
+else()
+  add_library_flags_if(LIBUNWIND_HAS_GCC_S_LIB gcc_s)
+  add_library_flags_if(LIBUNWIND_HAS_GCC_LIB gcc)
+endif()
+add_library_flags_if(LIBUNWIND_HAS_DL_LIB dl)
+if (LIBUNWIND_ENABLE_THREADS)
+  add_library_flags_if(LIBUNWIND_HAS_PTHREAD_LIB pthread)
+  add_compile_flags_if(LIBUNWIND_WEAK_PTHREAD_LIB -DLIBUNWIND_USE_WEAK_PTHREAD=1)
+endif()
+
+# Setup flags.
+if (LIBUNWIND_SUPPORTS_NOSTDLIBXX_FLAG)
+  add_link_flags_if_supported(-nostdlib++)
+else()
+  add_link_flags_if_supported(-nodefaultlibs)
+endif()
+
+# MINGW_LIBRARIES is defined in config-ix.cmake
+add_library_flags_if(MINGW "${MINGW_LIBRARIES}")
+
+if (LIBUNWIND_ENABLE_SHARED AND
+    NOT (LIBUNWIND_SUPPORTS_FNO_EXCEPTIONS_FLAG AND
+         LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG))
+  message(FATAL_ERROR
+          "Compiler doesn't support generation of unwind tables if exception "
+          "support is disabled.  Building libunwind DSO with runtime dependency "
+          "on C++ ABI library is not supported.")
+endif()
+
+if (APPLE)
+  add_compile_flags("-U__STRICT_ANSI__")
+  add_link_flags("-compatibility_version 1" "-install_name /usr/lib/libunwind.1.dylib")
+
+  if (CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6")
+    add_link_flags("-current_version ${LIBUNWIND_VERSION}" "/usr/lib/libSystem.B.dylib")
+  endif ()
+endif ()
+
+string(REPLACE ";" " " LIBUNWIND_COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}")
+string(REPLACE ";" " " LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}")
+string(REPLACE ";" " " LIBUNWIND_C_FLAGS "${LIBUNWIND_C_FLAGS}")
+string(REPLACE ";" " " LIBUNWIND_LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}")
+
+set_property(SOURCE ${LIBUNWIND_CXX_SOURCES}
+             APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBUNWIND_CXX_FLAGS}")
+set_property(SOURCE ${LIBUNWIND_C_SOURCES}
+             APPEND_STRING PROPERTY COMPILE_FLAGS " ${LIBUNWIND_C_FLAGS}")
+
+# NOTE: avoid implicit dependencies on C++ runtimes.  libunwind uses C++ for
+# ease, but does not rely on C++ at runtime.
+set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
+
+# Build the shared library.
+if (LIBUNWIND_ENABLE_SHARED)
+  add_library(unwind_shared SHARED ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS})
+  if(CMAKE_C_COMPILER_ID STREQUAL MSVC)
+    target_compile_options(unwind_shared PRIVATE /GR-)
+  else()
+    target_compile_options(unwind_shared PRIVATE -fno-rtti)
+  endif()
+  target_link_libraries(unwind_shared PRIVATE ${LIBUNWIND_LIBRARIES})
+  set_target_properties(unwind_shared PROPERTIES
+    CXX_EXTENSIONS OFF
+    CXX_STANDARD 11
+    CXX_STANDARD_REQUIRED ON
+    COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}"
+    LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}"
+    LINKER_LANGUAGE C
+    OUTPUT_NAME "unwind"
+    VERSION "1.0"
+    SOVERSION "1")
+  list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_shared")
+  if (LIBUNWIND_INSTALL_SHARED_LIBRARY)
+    list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_shared")
+  endif()
+endif()
+
+# Build the static library.
+if (LIBUNWIND_ENABLE_STATIC)
+  add_library(unwind_static STATIC ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS})
+  if(CMAKE_C_COMPILER_ID STREQUAL MSVC)
+    target_compile_options(unwind_static PRIVATE /GR-)
+  else()
+    target_compile_options(unwind_static PRIVATE -fno-rtti)
+  endif()
+  target_link_libraries(unwind_static PRIVATE ${LIBUNWIND_LIBRARIES})
+  set_target_properties(unwind_static PROPERTIES
+    CXX_EXTENSIONS OFF
+    CXX_STANDARD 11
+    CXX_STANDARD_REQUIRED ON
+    COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}"
+    LINK_FLAGS "${LIBUNWIND_LINK_FLAGS}"
+    LINKER_LANGUAGE C
+    OUTPUT_NAME "unwind")
+
+  if(LIBUNWIND_HIDE_SYMBOLS)
+    append_flags_if_supported(UNWIND_STATIC_LIBRARY_FLAGS -fvisibility=hidden)
+    append_flags_if_supported(UNWIND_STATIC_LIBRARY_FLAGS -fvisibility-global-new-delete-hidden)
+    target_compile_options(unwind_static PRIVATE ${UNWIND_STATIC_LIBRARY_FLAGS})
+    target_compile_definitions(unwind_static PRIVATE _LIBUNWIND_HIDE_SYMBOLS)
+  endif()
+
+  list(APPEND LIBUNWIND_BUILD_TARGETS "unwind_static")
+  if (LIBUNWIND_INSTALL_STATIC_LIBRARY)
+    list(APPEND LIBUNWIND_INSTALL_TARGETS "unwind_static")
+  endif()
+endif()
+
+# Add a meta-target for both libraries.
+add_custom_target(unwind DEPENDS ${LIBUNWIND_BUILD_TARGETS})
+
+if (LIBUNWIND_INSTALL_LIBRARY)
+  install(TARGETS ${LIBUNWIND_INSTALL_TARGETS}
+    LIBRARY DESTINATION ${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind
+    ARCHIVE DESTINATION ${LIBUNWIND_INSTALL_LIBRARY_DIR} COMPONENT unwind
+    RUNTIME DESTINATION bin COMPONENT unwind)
+endif()
+
+if (NOT CMAKE_CONFIGURATION_TYPES AND LIBUNWIND_INSTALL_LIBRARY)
+  add_custom_target(install-unwind
+    DEPENDS unwind
+    COMMAND "${CMAKE_COMMAND}"
+            -DCMAKE_INSTALL_COMPONENT=unwind
+            -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake")
+  add_custom_target(install-unwind-stripped
+    DEPENDS unwind
+    COMMAND "${CMAKE_COMMAND}"
+            -DCMAKE_INSTALL_COMPONENT=unwind
+            -DCMAKE_INSTALL_DO_STRIP=1
+            -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake")
+endif()

+ 697 - 0
llvm-libunwind/src/CompactUnwinder.hpp

@@ -0,0 +1,697 @@
+//===-------------------------- CompactUnwinder.hpp -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Does runtime stack unwinding using compact unwind encodings.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __COMPACT_UNWINDER_HPP__
+#define __COMPACT_UNWINDER_HPP__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "Registers.hpp"
+
+#define EXTRACT_BITS(value, mask)                                              \
+  ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
+
+namespace libunwind {
+
+#if defined(_LIBUNWIND_TARGET_I386)
+/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_x86 register set
+template <typename A>
+class CompactUnwinder_x86 {
+public:
+
+  static int stepWithCompactEncoding(compact_unwind_encoding_t info,
+                                     uint32_t functionStart, A &addressSpace,
+                                     Registers_x86 &registers);
+
+private:
+  typename A::pint_t pint_t;
+
+  static void frameUnwind(A &addressSpace, Registers_x86 &registers);
+  static void framelessUnwind(A &addressSpace,
+                              typename A::pint_t returnAddressLocation,
+                              Registers_x86 &registers);
+  static int
+      stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
+                                      uint32_t functionStart, A &addressSpace,
+                                      Registers_x86 &registers);
+  static int stepWithCompactEncodingFrameless(
+      compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+      A &addressSpace, Registers_x86 &registers, bool indirectStackSize);
+};
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncoding(
+    compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+    A &addressSpace, Registers_x86 &registers) {
+  switch (compactEncoding & UNWIND_X86_MODE_MASK) {
+  case UNWIND_X86_MODE_EBP_FRAME:
+    return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
+                                           addressSpace, registers);
+  case UNWIND_X86_MODE_STACK_IMMD:
+    return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+                                            addressSpace, registers, false);
+  case UNWIND_X86_MODE_STACK_IND:
+    return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+                                            addressSpace, registers, true);
+  }
+  _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
+    compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+    A &addressSpace, Registers_x86 &registers) {
+  uint32_t savedRegistersOffset =
+      EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
+  uint32_t savedRegistersLocations =
+      EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+
+  uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
+  for (int i = 0; i < 5; ++i) {
+    switch (savedRegistersLocations & 0x7) {
+    case UNWIND_X86_REG_NONE:
+      // no register saved in this slot
+      break;
+    case UNWIND_X86_REG_EBX:
+      registers.setEBX(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_ECX:
+      registers.setECX(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_EDX:
+      registers.setEDX(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_EDI:
+      registers.setEDI(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_ESI:
+      registers.setESI(addressSpace.get32(savedRegisters));
+      break;
+    default:
+      (void)functionStart;
+      _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for  "
+                           "function starting at 0x%X",
+                            compactEncoding, functionStart);
+      _LIBUNWIND_ABORT("invalid compact unwind encoding");
+    }
+    savedRegisters += 4;
+    savedRegistersLocations = (savedRegistersLocations >> 3);
+  }
+  frameUnwind(addressSpace, registers);
+  return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
+    compact_unwind_encoding_t encoding, uint32_t functionStart,
+    A &addressSpace, Registers_x86 &registers, bool indirectStackSize) {
+  uint32_t stackSizeEncoded =
+      EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+  uint32_t stackAdjust =
+      EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+  uint32_t regCount =
+      EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+  uint32_t permutation =
+      EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+  uint32_t stackSize = stackSizeEncoded * 4;
+  if (indirectStackSize) {
+    // stack size is encoded in subl $xxx,%esp instruction
+    uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
+    stackSize = subl + 4 * stackAdjust;
+  }
+  // decompress permutation
+  uint32_t permunreg[6];
+  switch (regCount) {
+  case 6:
+    permunreg[0] = permutation / 120;
+    permutation -= (permunreg[0] * 120);
+    permunreg[1] = permutation / 24;
+    permutation -= (permunreg[1] * 24);
+    permunreg[2] = permutation / 6;
+    permutation -= (permunreg[2] * 6);
+    permunreg[3] = permutation / 2;
+    permutation -= (permunreg[3] * 2);
+    permunreg[4] = permutation;
+    permunreg[5] = 0;
+    break;
+  case 5:
+    permunreg[0] = permutation / 120;
+    permutation -= (permunreg[0] * 120);
+    permunreg[1] = permutation / 24;
+    permutation -= (permunreg[1] * 24);
+    permunreg[2] = permutation / 6;
+    permutation -= (permunreg[2] * 6);
+    permunreg[3] = permutation / 2;
+    permutation -= (permunreg[3] * 2);
+    permunreg[4] = permutation;
+    break;
+  case 4:
+    permunreg[0] = permutation / 60;
+    permutation -= (permunreg[0] * 60);
+    permunreg[1] = permutation / 12;
+    permutation -= (permunreg[1] * 12);
+    permunreg[2] = permutation / 3;
+    permutation -= (permunreg[2] * 3);
+    permunreg[3] = permutation;
+    break;
+  case 3:
+    permunreg[0] = permutation / 20;
+    permutation -= (permunreg[0] * 20);
+    permunreg[1] = permutation / 4;
+    permutation -= (permunreg[1] * 4);
+    permunreg[2] = permutation;
+    break;
+  case 2:
+    permunreg[0] = permutation / 5;
+    permutation -= (permunreg[0] * 5);
+    permunreg[1] = permutation;
+    break;
+  case 1:
+    permunreg[0] = permutation;
+    break;
+  }
+  // re-number registers back to standard numbers
+  int registersSaved[6];
+  bool used[7] = { false, false, false, false, false, false, false };
+  for (uint32_t i = 0; i < regCount; ++i) {
+    uint32_t renum = 0;
+    for (int u = 1; u < 7; ++u) {
+      if (!used[u]) {
+        if (renum == permunreg[i]) {
+          registersSaved[i] = u;
+          used[u] = true;
+          break;
+        }
+        ++renum;
+      }
+    }
+  }
+  uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
+  for (uint32_t i = 0; i < regCount; ++i) {
+    switch (registersSaved[i]) {
+    case UNWIND_X86_REG_EBX:
+      registers.setEBX(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_ECX:
+      registers.setECX(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_EDX:
+      registers.setEDX(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_EDI:
+      registers.setEDI(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_ESI:
+      registers.setESI(addressSpace.get32(savedRegisters));
+      break;
+    case UNWIND_X86_REG_EBP:
+      registers.setEBP(addressSpace.get32(savedRegisters));
+      break;
+    default:
+      _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
+                           "function starting at 0x%X",
+                           encoding, functionStart);
+      _LIBUNWIND_ABORT("invalid compact unwind encoding");
+    }
+    savedRegisters += 4;
+  }
+  framelessUnwind(addressSpace, savedRegisters, registers);
+  return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
+                                         Registers_x86 &registers) {
+  typename A::pint_t bp = registers.getEBP();
+  // ebp points to old ebp
+  registers.setEBP(addressSpace.get32(bp));
+  // old esp is ebp less saved ebp and return address
+  registers.setSP((uint32_t)bp + 8);
+  // pop return address into eip
+  registers.setIP(addressSpace.get32(bp + 4));
+}
+
+template <typename A>
+void CompactUnwinder_x86<A>::framelessUnwind(
+    A &addressSpace, typename A::pint_t returnAddressLocation,
+    Registers_x86 &registers) {
+  // return address is on stack after last saved register
+  registers.setIP(addressSpace.get32(returnAddressLocation));
+  // old esp is before return address
+  registers.setSP((uint32_t)returnAddressLocation + 4);
+}
+#endif // _LIBUNWIND_TARGET_I386
+
+
+#if defined(_LIBUNWIND_TARGET_X86_64)
+/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_x86_64 register set
+template <typename A>
+class CompactUnwinder_x86_64 {
+public:
+
+  static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
+                                     uint64_t functionStart, A &addressSpace,
+                                     Registers_x86_64 &registers);
+
+private:
+  typename A::pint_t pint_t;
+
+  static void frameUnwind(A &addressSpace, Registers_x86_64 &registers);
+  static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
+                              Registers_x86_64 &registers);
+  static int
+      stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
+                                      uint64_t functionStart, A &addressSpace,
+                                      Registers_x86_64 &registers);
+  static int stepWithCompactEncodingFrameless(
+      compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+      A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize);
+};
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
+    compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+    A &addressSpace, Registers_x86_64 &registers) {
+  switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
+  case UNWIND_X86_64_MODE_RBP_FRAME:
+    return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
+                                           addressSpace, registers);
+  case UNWIND_X86_64_MODE_STACK_IMMD:
+    return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+                                            addressSpace, registers, false);
+  case UNWIND_X86_64_MODE_STACK_IND:
+    return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+                                            addressSpace, registers, true);
+  }
+  _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
+    compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+    A &addressSpace, Registers_x86_64 &registers) {
+  uint32_t savedRegistersOffset =
+      EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
+  uint32_t savedRegistersLocations =
+      EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
+
+  uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
+  for (int i = 0; i < 5; ++i) {
+    switch (savedRegistersLocations & 0x7) {
+    case UNWIND_X86_64_REG_NONE:
+      // no register saved in this slot
+      break;
+    case UNWIND_X86_64_REG_RBX:
+      registers.setRBX(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_R12:
+      registers.setR12(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_R13:
+      registers.setR13(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_R14:
+      registers.setR14(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_R15:
+      registers.setR15(addressSpace.get64(savedRegisters));
+      break;
+    default:
+      (void)functionStart;
+      _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
+                           "function starting at 0x%llX",
+                            compactEncoding, functionStart);
+      _LIBUNWIND_ABORT("invalid compact unwind encoding");
+    }
+    savedRegisters += 8;
+    savedRegistersLocations = (savedRegistersLocations >> 3);
+  }
+  frameUnwind(addressSpace, registers);
+  return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
+    compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
+    Registers_x86_64 &registers, bool indirectStackSize) {
+  uint32_t stackSizeEncoded =
+      EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+  uint32_t stackAdjust =
+      EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+  uint32_t regCount =
+      EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+  uint32_t permutation =
+      EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+  uint32_t stackSize = stackSizeEncoded * 8;
+  if (indirectStackSize) {
+    // stack size is encoded in subl $xxx,%esp instruction
+    uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
+    stackSize = subl + 8 * stackAdjust;
+  }
+  // decompress permutation
+  uint32_t permunreg[6];
+  switch (regCount) {
+  case 6:
+    permunreg[0] = permutation / 120;
+    permutation -= (permunreg[0] * 120);
+    permunreg[1] = permutation / 24;
+    permutation -= (permunreg[1] * 24);
+    permunreg[2] = permutation / 6;
+    permutation -= (permunreg[2] * 6);
+    permunreg[3] = permutation / 2;
+    permutation -= (permunreg[3] * 2);
+    permunreg[4] = permutation;
+    permunreg[5] = 0;
+    break;
+  case 5:
+    permunreg[0] = permutation / 120;
+    permutation -= (permunreg[0] * 120);
+    permunreg[1] = permutation / 24;
+    permutation -= (permunreg[1] * 24);
+    permunreg[2] = permutation / 6;
+    permutation -= (permunreg[2] * 6);
+    permunreg[3] = permutation / 2;
+    permutation -= (permunreg[3] * 2);
+    permunreg[4] = permutation;
+    break;
+  case 4:
+    permunreg[0] = permutation / 60;
+    permutation -= (permunreg[0] * 60);
+    permunreg[1] = permutation / 12;
+    permutation -= (permunreg[1] * 12);
+    permunreg[2] = permutation / 3;
+    permutation -= (permunreg[2] * 3);
+    permunreg[3] = permutation;
+    break;
+  case 3:
+    permunreg[0] = permutation / 20;
+    permutation -= (permunreg[0] * 20);
+    permunreg[1] = permutation / 4;
+    permutation -= (permunreg[1] * 4);
+    permunreg[2] = permutation;
+    break;
+  case 2:
+    permunreg[0] = permutation / 5;
+    permutation -= (permunreg[0] * 5);
+    permunreg[1] = permutation;
+    break;
+  case 1:
+    permunreg[0] = permutation;
+    break;
+  }
+  // re-number registers back to standard numbers
+  int registersSaved[6];
+  bool used[7] = { false, false, false, false, false, false, false };
+  for (uint32_t i = 0; i < regCount; ++i) {
+    uint32_t renum = 0;
+    for (int u = 1; u < 7; ++u) {
+      if (!used[u]) {
+        if (renum == permunreg[i]) {
+          registersSaved[i] = u;
+          used[u] = true;
+          break;
+        }
+        ++renum;
+      }
+    }
+  }
+  uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
+  for (uint32_t i = 0; i < regCount; ++i) {
+    switch (registersSaved[i]) {
+    case UNWIND_X86_64_REG_RBX:
+      registers.setRBX(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_R12:
+      registers.setR12(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_R13:
+      registers.setR13(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_R14:
+      registers.setR14(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_R15:
+      registers.setR15(addressSpace.get64(savedRegisters));
+      break;
+    case UNWIND_X86_64_REG_RBP:
+      registers.setRBP(addressSpace.get64(savedRegisters));
+      break;
+    default:
+      _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
+                           "function starting at 0x%llX",
+                            encoding, functionStart);
+      _LIBUNWIND_ABORT("invalid compact unwind encoding");
+    }
+    savedRegisters += 8;
+  }
+  framelessUnwind(addressSpace, savedRegisters, registers);
+  return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
+                                            Registers_x86_64 &registers) {
+  uint64_t rbp = registers.getRBP();
+  // ebp points to old ebp
+  registers.setRBP(addressSpace.get64(rbp));
+  // old esp is ebp less saved ebp and return address
+  registers.setSP(rbp + 16);
+  // pop return address into eip
+  registers.setIP(addressSpace.get64(rbp + 8));
+}
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
+                                                uint64_t returnAddressLocation,
+                                                Registers_x86_64 &registers) {
+  // return address is on stack after last saved register
+  registers.setIP(addressSpace.get64(returnAddressLocation));
+  // old esp is before return address
+  registers.setSP(returnAddressLocation + 8);
+}
+#endif // _LIBUNWIND_TARGET_X86_64
+
+
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_arm64 register set
+template <typename A>
+class CompactUnwinder_arm64 {
+public:
+
+  static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
+                                     uint64_t functionStart, A &addressSpace,
+                                     Registers_arm64 &registers);
+
+private:
+  typename A::pint_t pint_t;
+
+  static int
+      stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
+                                   uint64_t functionStart, A &addressSpace,
+                                   Registers_arm64 &registers);
+  static int stepWithCompactEncodingFrameless(
+      compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+      A &addressSpace, Registers_arm64 &registers);
+};
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
+    compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+    A &addressSpace, Registers_arm64 &registers) {
+  switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
+  case UNWIND_ARM64_MODE_FRAME:
+    return stepWithCompactEncodingFrame(compactEncoding, functionStart,
+                                        addressSpace, registers);
+  case UNWIND_ARM64_MODE_FRAMELESS:
+    return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+                                            addressSpace, registers);
+  }
+  _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
+    compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
+    Registers_arm64 &registers) {
+  uint32_t stackSize =
+      16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
+
+  uint64_t savedRegisterLoc = registers.getSP() + stackSize;
+
+  if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
+    registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
+    registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
+    registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
+    registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
+    registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+
+  if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
+    registers.setFloatRegister(UNW_ARM64_D8,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setFloatRegister(UNW_ARM64_D9,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
+    registers.setFloatRegister(UNW_ARM64_D10,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setFloatRegister(UNW_ARM64_D11,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
+    registers.setFloatRegister(UNW_ARM64_D12,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setFloatRegister(UNW_ARM64_D13,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
+    registers.setFloatRegister(UNW_ARM64_D14,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setFloatRegister(UNW_ARM64_D15,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+
+  // subtract stack size off of sp
+  registers.setSP(savedRegisterLoc);
+
+  // set pc to be value in lr
+  registers.setIP(registers.getRegister(UNW_ARM64_LR));
+
+  return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
+    compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
+    Registers_arm64 &registers) {
+  uint64_t savedRegisterLoc = registers.getFP() - 8;
+
+  if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
+    registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
+    registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
+    registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
+    registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
+    registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+
+  if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
+    registers.setFloatRegister(UNW_ARM64_D8,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setFloatRegister(UNW_ARM64_D9,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
+    registers.setFloatRegister(UNW_ARM64_D10,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setFloatRegister(UNW_ARM64_D11,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
+    registers.setFloatRegister(UNW_ARM64_D12,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setFloatRegister(UNW_ARM64_D13,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+  if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
+    registers.setFloatRegister(UNW_ARM64_D14,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+    registers.setFloatRegister(UNW_ARM64_D15,
+                               addressSpace.getDouble(savedRegisterLoc));
+    savedRegisterLoc -= 8;
+  }
+
+  uint64_t fp = registers.getFP();
+  // fp points to old fp
+  registers.setFP(addressSpace.get64(fp));
+  // old sp is fp less saved fp and lr
+  registers.setSP(fp + 16);
+  // pop return address into pc
+  registers.setIP(addressSpace.get64(fp + 8));
+
+  return UNW_STEP_SUCCESS;
+}
+#endif // _LIBUNWIND_TARGET_AARCH64
+
+
+} // namespace libunwind
+
+#endif // __COMPACT_UNWINDER_HPP__

+ 829 - 0
llvm-libunwind/src/DwarfInstructions.hpp

@@ -0,0 +1,829 @@
+//===-------------------------- DwarfInstructions.hpp ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Processor specific interpretation of DWARF unwind info.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DWARF_INSTRUCTIONS_HPP__
+#define __DWARF_INSTRUCTIONS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dwarf2.h"
+#include "Registers.hpp"
+#include "DwarfParser.hpp"
+#include "config.h"
+
+
+namespace libunwind {
+
+
+/// DwarfInstructions maps abtract DWARF unwind instructions to a particular
+/// architecture
+template <typename A, typename R>
+class DwarfInstructions {
+public:
+  typedef typename A::pint_t pint_t;
+  typedef typename A::sint_t sint_t;
+
+  static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
+                           R &registers, bool &isSignalFrame);
+
+private:
+
+  enum {
+    DW_X86_64_RET_ADDR = 16
+  };
+
+  enum {
+    DW_X86_RET_ADDR = 8
+  };
+
+  typedef typename CFI_Parser<A>::RegisterLocation  RegisterLocation;
+  typedef typename CFI_Parser<A>::PrologInfo        PrologInfo;
+  typedef typename CFI_Parser<A>::FDE_Info          FDE_Info;
+  typedef typename CFI_Parser<A>::CIE_Info          CIE_Info;
+
+  static pint_t evaluateExpression(pint_t expression, A &addressSpace,
+                                   const R &registers,
+                                   pint_t initialStackValue);
+  static pint_t getSavedRegister(A &addressSpace, const R &registers,
+                                 pint_t cfa, const RegisterLocation &savedReg);
+  static double getSavedFloatRegister(A &addressSpace, const R &registers,
+                                  pint_t cfa, const RegisterLocation &savedReg);
+  static v128 getSavedVectorRegister(A &addressSpace, const R &registers,
+                                  pint_t cfa, const RegisterLocation &savedReg);
+
+  static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
+                       const R &registers) {
+    if (prolog.cfaRegister != 0)
+      return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
+             prolog.cfaRegisterOffset);
+    if (prolog.cfaExpression != 0)
+      return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, 
+                                registers, 0);
+    assert(0 && "getCFA(): unknown location");
+    __builtin_unreachable();
+  }
+};
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
+    A &addressSpace, const R &registers, pint_t cfa,
+    const RegisterLocation &savedReg) {
+  switch (savedReg.location) {
+  case CFI_Parser<A>::kRegisterInCFA:
+    return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value);
+
+  case CFI_Parser<A>::kRegisterAtExpression:
+    return (pint_t)addressSpace.getRegister(evaluateExpression(
+        (pint_t)savedReg.value, addressSpace, registers, cfa));
+
+  case CFI_Parser<A>::kRegisterIsExpression:
+    return evaluateExpression((pint_t)savedReg.value, addressSpace,
+                              registers, cfa);
+
+  case CFI_Parser<A>::kRegisterInRegister:
+    return registers.getRegister((int)savedReg.value);
+  case CFI_Parser<A>::kRegisterUndefined:
+    return 0;
+  case CFI_Parser<A>::kRegisterUnused:
+  case CFI_Parser<A>::kRegisterOffsetFromCFA:
+    // FIX ME
+    break;
+  }
+  _LIBUNWIND_ABORT("unsupported restore location for register");
+}
+
+template <typename A, typename R>
+double DwarfInstructions<A, R>::getSavedFloatRegister(
+    A &addressSpace, const R &registers, pint_t cfa,
+    const RegisterLocation &savedReg) {
+  switch (savedReg.location) {
+  case CFI_Parser<A>::kRegisterInCFA:
+    return addressSpace.getDouble(cfa + (pint_t)savedReg.value);
+
+  case CFI_Parser<A>::kRegisterAtExpression:
+    return addressSpace.getDouble(
+        evaluateExpression((pint_t)savedReg.value, addressSpace,
+                            registers, cfa));
+
+  case CFI_Parser<A>::kRegisterIsExpression:
+  case CFI_Parser<A>::kRegisterUnused:
+  case CFI_Parser<A>::kRegisterUndefined:
+  case CFI_Parser<A>::kRegisterOffsetFromCFA:
+  case CFI_Parser<A>::kRegisterInRegister:
+    // FIX ME
+    break;
+  }
+  _LIBUNWIND_ABORT("unsupported restore location for float register");
+}
+
+template <typename A, typename R>
+v128 DwarfInstructions<A, R>::getSavedVectorRegister(
+    A &addressSpace, const R &registers, pint_t cfa,
+    const RegisterLocation &savedReg) {
+  switch (savedReg.location) {
+  case CFI_Parser<A>::kRegisterInCFA:
+    return addressSpace.getVector(cfa + (pint_t)savedReg.value);
+
+  case CFI_Parser<A>::kRegisterAtExpression:
+    return addressSpace.getVector(
+        evaluateExpression((pint_t)savedReg.value, addressSpace,
+                            registers, cfa));
+
+  case CFI_Parser<A>::kRegisterIsExpression:
+  case CFI_Parser<A>::kRegisterUnused:
+  case CFI_Parser<A>::kRegisterUndefined:
+  case CFI_Parser<A>::kRegisterOffsetFromCFA:
+  case CFI_Parser<A>::kRegisterInRegister:
+    // FIX ME
+    break;
+  }
+  _LIBUNWIND_ABORT("unsupported restore location for vector register");
+}
+
+template <typename A, typename R>
+int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
+                                           pint_t fdeStart, R &registers,
+                                           bool &isSignalFrame) {
+  FDE_Info fdeInfo;
+  CIE_Info cieInfo;
+  if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
+                               &cieInfo) == NULL) {
+    PrologInfo prolog;
+    if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
+                                            R::getArch(), &prolog)) {
+      // get pointer to cfa (architecture specific)
+      pint_t cfa = getCFA(addressSpace, prolog, registers);
+
+       // restore registers that DWARF says were saved
+      R newRegisters = registers;
+      pint_t returnAddress = 0;
+      const int lastReg = R::lastDwarfRegNum();
+      assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
+             "register range too large");
+      assert(lastReg >= (int)cieInfo.returnAddressRegister &&
+             "register range does not contain return address register");
+      for (int i = 0; i <= lastReg; ++i) {
+        if (prolog.savedRegisters[i].location !=
+            CFI_Parser<A>::kRegisterUnused) {
+          if (registers.validFloatRegister(i))
+            newRegisters.setFloatRegister(
+                i, getSavedFloatRegister(addressSpace, registers, cfa,
+                                         prolog.savedRegisters[i]));
+          else if (registers.validVectorRegister(i))
+            newRegisters.setVectorRegister(
+                i, getSavedVectorRegister(addressSpace, registers, cfa,
+                                          prolog.savedRegisters[i]));
+          else if (i == (int)cieInfo.returnAddressRegister)
+            returnAddress = getSavedRegister(addressSpace, registers, cfa,
+                                             prolog.savedRegisters[i]);
+          else if (registers.validRegister(i))
+            newRegisters.setRegister(
+                i, getSavedRegister(addressSpace, registers, cfa,
+                                    prolog.savedRegisters[i]));
+          else
+            return UNW_EBADREG;
+        } else if (i == (int)cieInfo.returnAddressRegister) {
+            // Leaf function keeps the return address in register and there is no
+            // explicit intructions how to restore it.
+            returnAddress = registers.getRegister(cieInfo.returnAddressRegister);
+        }
+      }
+
+      // By definition, the CFA is the stack pointer at the call site, so
+      // restoring SP means setting it to CFA.
+      newRegisters.setSP(cfa);
+
+      isSignalFrame = cieInfo.isSignalFrame;
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+      // If the target is aarch64 then the return address may have been signed
+      // using the v8.3 pointer authentication extensions. The original
+      // return address needs to be authenticated before the return address is
+      // restored. autia1716 is used instead of autia as autia1716 assembles
+      // to a NOP on pre-v8.3a architectures.
+      if ((R::getArch() == REGISTERS_ARM64) &&
+          prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value &&
+          returnAddress != 0) {
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+        return UNW_ECROSSRASIGNING;
+#else
+        register unsigned long long x17 __asm("x17") = returnAddress;
+        register unsigned long long x16 __asm("x16") = cfa;
+
+        // These are the autia1716/autib1716 instructions. The hint instructions
+        // are used here as gcc does not assemble autia1716/autib1716 for pre
+        // armv8.3a targets.
+        if (cieInfo.addressesSignedWithBKey)
+          asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
+        else
+          asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+        returnAddress = x17;
+#endif
+      }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+      if (R::getArch() == REGISTERS_SPARC) {
+        // Skip call site instruction and delay slot
+        returnAddress += 8;
+        // Skip unimp instruction if function returns a struct
+        if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
+          returnAddress += 4;
+      }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_PPC64)
+#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
+#define PPC64_ELFV1_R2_OFFSET 40
+#define PPC64_ELFV2_R2_LOAD_INST_ENCODING 0xe8410018u // ld r2,24(r1)
+#define PPC64_ELFV2_R2_OFFSET 24
+      // If the instruction at return address is a TOC (r2) restore,
+      // then r2 was saved and needs to be restored.
+      // ELFv2 ABI specifies that the TOC Pointer must be saved at SP + 24,
+      // while in ELFv1 ABI it is saved at SP + 40.
+      if (R::getArch() == REGISTERS_PPC64 && returnAddress != 0) {
+        pint_t sp = newRegisters.getRegister(UNW_REG_SP);
+        pint_t r2 = 0;
+        switch (addressSpace.get32(returnAddress)) {
+        case PPC64_ELFV1_R2_LOAD_INST_ENCODING:
+          r2 = addressSpace.get64(sp + PPC64_ELFV1_R2_OFFSET);
+          break;
+        case PPC64_ELFV2_R2_LOAD_INST_ENCODING:
+          r2 = addressSpace.get64(sp + PPC64_ELFV2_R2_OFFSET);
+          break;
+        }
+        if (r2)
+          newRegisters.setRegister(UNW_PPC64_R2, r2);
+      }
+#endif
+
+      // Return address is address after call site instruction, so setting IP to
+      // that does simualates a return.
+      newRegisters.setIP(returnAddress);
+
+      // Simulate the step by replacing the register set with the new ones.
+      registers = newRegisters;
+
+      return UNW_STEP_SUCCESS;
+    }
+  }
+  return UNW_EBADFRAME;
+}
+
+template <typename A, typename R>
+typename A::pint_t
+DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
+                                            const R &registers,
+                                            pint_t initialStackValue) {
+  const bool log = false;
+  pint_t p = expression;
+  pint_t expressionEnd = expression + 20; // temp, until len read
+  pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd);
+  expressionEnd = p + length;
+  if (log)
+    fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n",
+            (uint64_t)length);
+  pint_t stack[100];
+  pint_t *sp = stack;
+  *(++sp) = initialStackValue;
+
+  while (p < expressionEnd) {
+    if (log) {
+      for (pint_t *t = sp; t > stack; --t) {
+        fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t));
+      }
+    }
+    uint8_t opcode = addressSpace.get8(p++);
+    sint_t svalue, svalue2;
+    pint_t value;
+    uint32_t reg;
+    switch (opcode) {
+    case DW_OP_addr:
+      // push immediate address sized value
+      value = addressSpace.getP(p);
+      p += sizeof(pint_t);
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_deref:
+      // pop stack, dereference, push result
+      value = *sp--;
+      *(++sp) = addressSpace.getP(value);
+      if (log)
+        fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_const1u:
+      // push immediate 1 byte value
+      value = addressSpace.get8(p);
+      p += 1;
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_const1s:
+      // push immediate 1 byte signed value
+      svalue = (int8_t) addressSpace.get8(p);
+      p += 1;
+      *(++sp) = (pint_t)svalue;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
+      break;
+
+    case DW_OP_const2u:
+      // push immediate 2 byte value
+      value = addressSpace.get16(p);
+      p += 2;
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_const2s:
+      // push immediate 2 byte signed value
+      svalue = (int16_t) addressSpace.get16(p);
+      p += 2;
+      *(++sp) = (pint_t)svalue;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
+      break;
+
+    case DW_OP_const4u:
+      // push immediate 4 byte value
+      value = addressSpace.get32(p);
+      p += 4;
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_const4s:
+      // push immediate 4 byte signed value
+      svalue = (int32_t)addressSpace.get32(p);
+      p += 4;
+      *(++sp) = (pint_t)svalue;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
+      break;
+
+    case DW_OP_const8u:
+      // push immediate 8 byte value
+      value = (pint_t)addressSpace.get64(p);
+      p += 8;
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_const8s:
+      // push immediate 8 byte signed value
+      value = (pint_t)addressSpace.get64(p);
+      p += 8;
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_constu:
+      // push immediate ULEB128 value
+      value = (pint_t)addressSpace.getULEB128(p, expressionEnd);
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_consts:
+      // push immediate SLEB128 value
+      svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+      *(++sp) = (pint_t)svalue;
+      if (log)
+        fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
+      break;
+
+    case DW_OP_dup:
+      // push top of stack
+      value = *sp;
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "duplicate top of stack\n");
+      break;
+
+    case DW_OP_drop:
+      // pop
+      --sp;
+      if (log)
+        fprintf(stderr, "pop top of stack\n");
+      break;
+
+    case DW_OP_over:
+      // dup second
+      value = sp[-1];
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "duplicate second in stack\n");
+      break;
+
+    case DW_OP_pick:
+      // pick from
+      reg = addressSpace.get8(p);
+      p += 1;
+      value = sp[-(int)reg];
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "duplicate %d in stack\n", reg);
+      break;
+
+    case DW_OP_swap:
+      // swap top two
+      value = sp[0];
+      sp[0] = sp[-1];
+      sp[-1] = value;
+      if (log)
+        fprintf(stderr, "swap top of stack\n");
+      break;
+
+    case DW_OP_rot:
+      // rotate top three
+      value = sp[0];
+      sp[0] = sp[-1];
+      sp[-1] = sp[-2];
+      sp[-2] = value;
+      if (log)
+        fprintf(stderr, "rotate top three of stack\n");
+      break;
+
+    case DW_OP_xderef:
+      // pop stack, dereference, push result
+      value = *sp--;
+      *sp = *((pint_t*)value);
+      if (log)
+        fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_abs:
+      svalue = (sint_t)*sp;
+      if (svalue < 0)
+        *sp = (pint_t)(-svalue);
+      if (log)
+        fprintf(stderr, "abs\n");
+      break;
+
+    case DW_OP_and:
+      value = *sp--;
+      *sp &= value;
+      if (log)
+        fprintf(stderr, "and\n");
+      break;
+
+    case DW_OP_div:
+      svalue = (sint_t)(*sp--);
+      svalue2 = (sint_t)*sp;
+      *sp = (pint_t)(svalue2 / svalue);
+      if (log)
+        fprintf(stderr, "div\n");
+      break;
+
+    case DW_OP_minus:
+      value = *sp--;
+      *sp = *sp - value;
+      if (log)
+        fprintf(stderr, "minus\n");
+      break;
+
+    case DW_OP_mod:
+      svalue = (sint_t)(*sp--);
+      svalue2 = (sint_t)*sp;
+      *sp = (pint_t)(svalue2 % svalue);
+      if (log)
+        fprintf(stderr, "module\n");
+      break;
+
+    case DW_OP_mul:
+      svalue = (sint_t)(*sp--);
+      svalue2 = (sint_t)*sp;
+      *sp = (pint_t)(svalue2 * svalue);
+      if (log)
+        fprintf(stderr, "mul\n");
+      break;
+
+    case DW_OP_neg:
+      *sp = 0 - *sp;
+      if (log)
+        fprintf(stderr, "neg\n");
+      break;
+
+    case DW_OP_not:
+      svalue = (sint_t)(*sp);
+      *sp = (pint_t)(~svalue);
+      if (log)
+        fprintf(stderr, "not\n");
+      break;
+
+    case DW_OP_or:
+      value = *sp--;
+      *sp |= value;
+      if (log)
+        fprintf(stderr, "or\n");
+      break;
+
+    case DW_OP_plus:
+      value = *sp--;
+      *sp += value;
+      if (log)
+        fprintf(stderr, "plus\n");
+      break;
+
+    case DW_OP_plus_uconst:
+      // pop stack, add uelb128 constant, push result
+      *sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd));
+      if (log)
+        fprintf(stderr, "add constant\n");
+      break;
+
+    case DW_OP_shl:
+      value = *sp--;
+      *sp = *sp << value;
+      if (log)
+        fprintf(stderr, "shift left\n");
+      break;
+
+    case DW_OP_shr:
+      value = *sp--;
+      *sp = *sp >> value;
+      if (log)
+        fprintf(stderr, "shift left\n");
+      break;
+
+    case DW_OP_shra:
+      value = *sp--;
+      svalue = (sint_t)*sp;
+      *sp = (pint_t)(svalue >> value);
+      if (log)
+        fprintf(stderr, "shift left arithmetric\n");
+      break;
+
+    case DW_OP_xor:
+      value = *sp--;
+      *sp ^= value;
+      if (log)
+        fprintf(stderr, "xor\n");
+      break;
+
+    case DW_OP_skip:
+      svalue = (int16_t) addressSpace.get16(p);
+      p += 2;
+      p = (pint_t)((sint_t)p + svalue);
+      if (log)
+        fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue);
+      break;
+
+    case DW_OP_bra:
+      svalue = (int16_t) addressSpace.get16(p);
+      p += 2;
+      if (*sp--)
+        p = (pint_t)((sint_t)p + svalue);
+      if (log)
+        fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue);
+      break;
+
+    case DW_OP_eq:
+      value = *sp--;
+      *sp = (*sp == value);
+      if (log)
+        fprintf(stderr, "eq\n");
+      break;
+
+    case DW_OP_ge:
+      value = *sp--;
+      *sp = (*sp >= value);
+      if (log)
+        fprintf(stderr, "ge\n");
+      break;
+
+    case DW_OP_gt:
+      value = *sp--;
+      *sp = (*sp > value);
+      if (log)
+        fprintf(stderr, "gt\n");
+      break;
+
+    case DW_OP_le:
+      value = *sp--;
+      *sp = (*sp <= value);
+      if (log)
+        fprintf(stderr, "le\n");
+      break;
+
+    case DW_OP_lt:
+      value = *sp--;
+      *sp = (*sp < value);
+      if (log)
+        fprintf(stderr, "lt\n");
+      break;
+
+    case DW_OP_ne:
+      value = *sp--;
+      *sp = (*sp != value);
+      if (log)
+        fprintf(stderr, "ne\n");
+      break;
+
+    case DW_OP_lit0:
+    case DW_OP_lit1:
+    case DW_OP_lit2:
+    case DW_OP_lit3:
+    case DW_OP_lit4:
+    case DW_OP_lit5:
+    case DW_OP_lit6:
+    case DW_OP_lit7:
+    case DW_OP_lit8:
+    case DW_OP_lit9:
+    case DW_OP_lit10:
+    case DW_OP_lit11:
+    case DW_OP_lit12:
+    case DW_OP_lit13:
+    case DW_OP_lit14:
+    case DW_OP_lit15:
+    case DW_OP_lit16:
+    case DW_OP_lit17:
+    case DW_OP_lit18:
+    case DW_OP_lit19:
+    case DW_OP_lit20:
+    case DW_OP_lit21:
+    case DW_OP_lit22:
+    case DW_OP_lit23:
+    case DW_OP_lit24:
+    case DW_OP_lit25:
+    case DW_OP_lit26:
+    case DW_OP_lit27:
+    case DW_OP_lit28:
+    case DW_OP_lit29:
+    case DW_OP_lit30:
+    case DW_OP_lit31:
+      value = static_cast<pint_t>(opcode - DW_OP_lit0);
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_reg0:
+    case DW_OP_reg1:
+    case DW_OP_reg2:
+    case DW_OP_reg3:
+    case DW_OP_reg4:
+    case DW_OP_reg5:
+    case DW_OP_reg6:
+    case DW_OP_reg7:
+    case DW_OP_reg8:
+    case DW_OP_reg9:
+    case DW_OP_reg10:
+    case DW_OP_reg11:
+    case DW_OP_reg12:
+    case DW_OP_reg13:
+    case DW_OP_reg14:
+    case DW_OP_reg15:
+    case DW_OP_reg16:
+    case DW_OP_reg17:
+    case DW_OP_reg18:
+    case DW_OP_reg19:
+    case DW_OP_reg20:
+    case DW_OP_reg21:
+    case DW_OP_reg22:
+    case DW_OP_reg23:
+    case DW_OP_reg24:
+    case DW_OP_reg25:
+    case DW_OP_reg26:
+    case DW_OP_reg27:
+    case DW_OP_reg28:
+    case DW_OP_reg29:
+    case DW_OP_reg30:
+    case DW_OP_reg31:
+      reg = static_cast<uint32_t>(opcode - DW_OP_reg0);
+      *(++sp) = registers.getRegister((int)reg);
+      if (log)
+        fprintf(stderr, "push reg %d\n", reg);
+      break;
+
+    case DW_OP_regx:
+      reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
+      *(++sp) = registers.getRegister((int)reg);
+      if (log)
+        fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
+      break;
+
+    case DW_OP_breg0:
+    case DW_OP_breg1:
+    case DW_OP_breg2:
+    case DW_OP_breg3:
+    case DW_OP_breg4:
+    case DW_OP_breg5:
+    case DW_OP_breg6:
+    case DW_OP_breg7:
+    case DW_OP_breg8:
+    case DW_OP_breg9:
+    case DW_OP_breg10:
+    case DW_OP_breg11:
+    case DW_OP_breg12:
+    case DW_OP_breg13:
+    case DW_OP_breg14:
+    case DW_OP_breg15:
+    case DW_OP_breg16:
+    case DW_OP_breg17:
+    case DW_OP_breg18:
+    case DW_OP_breg19:
+    case DW_OP_breg20:
+    case DW_OP_breg21:
+    case DW_OP_breg22:
+    case DW_OP_breg23:
+    case DW_OP_breg24:
+    case DW_OP_breg25:
+    case DW_OP_breg26:
+    case DW_OP_breg27:
+    case DW_OP_breg28:
+    case DW_OP_breg29:
+    case DW_OP_breg30:
+    case DW_OP_breg31:
+      reg = static_cast<uint32_t>(opcode - DW_OP_breg0);
+      svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+      svalue += static_cast<sint_t>(registers.getRegister((int)reg));
+      *(++sp) = (pint_t)(svalue);
+      if (log)
+        fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
+      break;
+
+    case DW_OP_bregx:
+      reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
+      svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+      svalue += static_cast<sint_t>(registers.getRegister((int)reg));
+      *(++sp) = (pint_t)(svalue);
+      if (log)
+        fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
+      break;
+
+    case DW_OP_fbreg:
+      _LIBUNWIND_ABORT("DW_OP_fbreg not implemented");
+      break;
+
+    case DW_OP_piece:
+      _LIBUNWIND_ABORT("DW_OP_piece not implemented");
+      break;
+
+    case DW_OP_deref_size:
+      // pop stack, dereference, push result
+      value = *sp--;
+      switch (addressSpace.get8(p++)) {
+      case 1:
+        value = addressSpace.get8(value);
+        break;
+      case 2:
+        value = addressSpace.get16(value);
+        break;
+      case 4:
+        value = addressSpace.get32(value);
+        break;
+      case 8:
+        value = (pint_t)addressSpace.get64(value);
+        break;
+      default:
+        _LIBUNWIND_ABORT("DW_OP_deref_size with bad size");
+      }
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value);
+      break;
+
+    case DW_OP_xderef_size:
+    case DW_OP_nop:
+    case DW_OP_push_object_addres:
+    case DW_OP_call2:
+    case DW_OP_call4:
+    case DW_OP_call_ref:
+    default:
+      _LIBUNWIND_ABORT("DWARF opcode not implemented");
+    }
+
+  }
+  if (log)
+    fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp);
+  return *sp;
+}
+
+
+
+} // namespace libunwind
+
+#endif // __DWARF_INSTRUCTIONS_HPP__

+ 813 - 0
llvm-libunwind/src/DwarfParser.hpp

@@ -0,0 +1,813 @@
+//===--------------------------- DwarfParser.hpp --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Parses DWARF CFIs (FDEs and CIEs).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DWARF_PARSER_HPP__
+#define __DWARF_PARSER_HPP__
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libunwind.h"
+#include "dwarf2.h"
+#include "Registers.hpp"
+
+#include "config.h"
+
+namespace libunwind {
+
+/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
+/// See DWARF Spec for details:
+///    http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A>
+class CFI_Parser {
+public:
+  typedef typename A::pint_t pint_t;
+
+  /// Information encoded in a CIE (Common Information Entry)
+  struct CIE_Info {
+    pint_t    cieStart;
+    pint_t    cieLength;
+    pint_t    cieInstructions;
+    uint8_t   pointerEncoding;
+    uint8_t   lsdaEncoding;
+    uint8_t   personalityEncoding;
+    uint8_t   personalityOffsetInCIE;
+    pint_t    personality;
+    uint32_t  codeAlignFactor;
+    int       dataAlignFactor;
+    bool      isSignalFrame;
+    bool      fdesHaveAugmentationData;
+    uint8_t   returnAddressRegister;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+    bool      addressesSignedWithBKey;
+#endif
+  };
+
+  /// Information about an FDE (Frame Description Entry)
+  struct FDE_Info {
+    pint_t  fdeStart;
+    pint_t  fdeLength;
+    pint_t  fdeInstructions;
+    pint_t  pcStart;
+    pint_t  pcEnd;
+    pint_t  lsda;
+  };
+
+  enum {
+    kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
+  };
+  enum RegisterSavedWhere {
+    kRegisterUnused,
+    kRegisterUndefined,
+    kRegisterInCFA,
+    kRegisterOffsetFromCFA,
+    kRegisterInRegister,
+    kRegisterAtExpression,
+    kRegisterIsExpression
+  };
+  struct RegisterLocation {
+    RegisterSavedWhere location;
+    bool initialStateSaved;
+    int64_t value;
+  };
+  /// Information about a frame layout and registers saved determined
+  /// by "running" the DWARF FDE "instructions"
+  struct PrologInfo {
+    uint32_t          cfaRegister;
+    int32_t           cfaRegisterOffset;  // CFA = (cfaRegister)+cfaRegisterOffset
+    int64_t           cfaExpression;      // CFA = expression
+    uint32_t          spExtraArgSize;
+    RegisterLocation  savedRegisters[kMaxRegisterNumber + 1];
+    enum class InitializeTime { kLazy, kNormal };
+
+    // When saving registers, this data structure is lazily initialized.
+    PrologInfo(InitializeTime IT = InitializeTime::kNormal) {
+      if (IT == InitializeTime::kNormal)
+        memset(this, 0, sizeof(*this));
+    }
+    void checkSaveRegister(uint64_t reg, PrologInfo &initialState) {
+      if (!savedRegisters[reg].initialStateSaved) {
+        initialState.savedRegisters[reg] = savedRegisters[reg];
+        savedRegisters[reg].initialStateSaved = true;
+      }
+    }
+    void setRegister(uint64_t reg, RegisterSavedWhere newLocation,
+                     int64_t newValue, PrologInfo &initialState) {
+      checkSaveRegister(reg, initialState);
+      savedRegisters[reg].location = newLocation;
+      savedRegisters[reg].value = newValue;
+    }
+    void setRegisterLocation(uint64_t reg, RegisterSavedWhere newLocation,
+                             PrologInfo &initialState) {
+      checkSaveRegister(reg, initialState);
+      savedRegisters[reg].location = newLocation;
+    }
+    void setRegisterValue(uint64_t reg, int64_t newValue,
+                          PrologInfo &initialState) {
+      checkSaveRegister(reg, initialState);
+      savedRegisters[reg].value = newValue;
+    }
+    void restoreRegisterToInitialState(uint64_t reg, PrologInfo &initialState) {
+      if (savedRegisters[reg].initialStateSaved)
+        savedRegisters[reg] = initialState.savedRegisters[reg];
+      // else the register still holds its initial state
+    }
+  };
+
+  struct PrologInfoStackEntry {
+    PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
+        : next(n), info(i) {}
+    PrologInfoStackEntry *next;
+    PrologInfo info;
+  };
+
+  struct RememberStack {
+    PrologInfoStackEntry *entry;
+    RememberStack() : entry(nullptr) {}
+    ~RememberStack() {
+#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)
+      // Clean up rememberStack. Even in the case where every
+      // DW_CFA_remember_state is paired with a DW_CFA_restore_state,
+      // parseInstructions can skip restore opcodes if it reaches the target PC
+      // and stops interpreting, so we have to make sure we don't leak memory.
+      while (entry) {
+        PrologInfoStackEntry *next = entry->next;
+        _LIBUNWIND_REMEMBER_FREE(entry);
+        entry = next;
+      }
+#endif
+    }
+  };
+
+  static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
+                      uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
+                      CIE_Info *cieInfo);
+  static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
+                               FDE_Info *fdeInfo, CIE_Info *cieInfo);
+  static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
+                                   const CIE_Info &cieInfo, pint_t upToPC,
+                                   int arch, PrologInfo *results);
+
+  static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
+};
+
+/// Parse a FDE into a CIE_Info and an FDE_Info
+template <typename A>
+const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
+                                     FDE_Info *fdeInfo, CIE_Info *cieInfo) {
+  pint_t p = fdeStart;
+  pint_t cfiLength = (pint_t)addressSpace.get32(p);
+  p += 4;
+  if (cfiLength == 0xffffffff) {
+    // 0xffffffff means length is really next 8 bytes
+    cfiLength = (pint_t)addressSpace.get64(p);
+    p += 8;
+  }
+  if (cfiLength == 0)
+    return "FDE has zero length"; // zero terminator
+  uint32_t ciePointer = addressSpace.get32(p);
+  if (ciePointer == 0)
+    return "FDE is really a CIE"; // this is a CIE not an FDE
+  pint_t nextCFI = p + cfiLength;
+  pint_t cieStart = p - ciePointer;
+  const char *err = parseCIE(addressSpace, cieStart, cieInfo);
+  if (err != NULL)
+    return err;
+  p += 4;
+  // Parse pc begin and range.
+  pint_t pcStart =
+      addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+  pint_t pcRange =
+      addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+  // Parse rest of info.
+  fdeInfo->lsda = 0;
+  // Check for augmentation length.
+  if (cieInfo->fdesHaveAugmentationData) {
+    pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
+    pint_t endOfAug = p + augLen;
+    if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
+      // Peek at value (without indirection).  Zero means no LSDA.
+      pint_t lsdaStart = p;
+      if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
+          0) {
+        // Reset pointer and re-parse LSDA address.
+        p = lsdaStart;
+        fdeInfo->lsda =
+            addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+      }
+    }
+    p = endOfAug;
+  }
+  fdeInfo->fdeStart = fdeStart;
+  fdeInfo->fdeLength = nextCFI - fdeStart;
+  fdeInfo->fdeInstructions = p;
+  fdeInfo->pcStart = pcStart;
+  fdeInfo->pcEnd = pcStart + pcRange;
+  return NULL; // success
+}
+
+/// Scan an eh_frame section to find an FDE for a pc
+template <typename A>
+bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
+                            uintptr_t sectionLength, pint_t fdeHint,
+                            FDE_Info *fdeInfo, CIE_Info *cieInfo) {
+  //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
+  pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
+  const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX)
+                                  ? static_cast<pint_t>(-1)
+                                  : (ehSectionStart + sectionLength);
+  while (p < ehSectionEnd) {
+    pint_t currentCFI = p;
+    //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
+    pint_t cfiLength = addressSpace.get32(p);
+    p += 4;
+    if (cfiLength == 0xffffffff) {
+      // 0xffffffff means length is really next 8 bytes
+      cfiLength = (pint_t)addressSpace.get64(p);
+      p += 8;
+    }
+    if (cfiLength == 0)
+      return false; // zero terminator
+    uint32_t id = addressSpace.get32(p);
+    if (id == 0) {
+      // Skip over CIEs.
+      p += cfiLength;
+    } else {
+      // Process FDE to see if it covers pc.
+      pint_t nextCFI = p + cfiLength;
+      uint32_t ciePointer = addressSpace.get32(p);
+      pint_t cieStart = p - ciePointer;
+      // Validate pointer to CIE is within section.
+      if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
+        if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
+          p += 4;
+          // Parse pc begin and range.
+          pint_t pcStart =
+              addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+          pint_t pcRange = addressSpace.getEncodedP(
+              p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+          // Test if pc is within the function this FDE covers.
+          if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
+            // parse rest of info
+            fdeInfo->lsda = 0;
+            // check for augmentation length
+            if (cieInfo->fdesHaveAugmentationData) {
+              pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
+              pint_t endOfAug = p + augLen;
+              if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
+                // Peek at value (without indirection).  Zero means no LSDA.
+                pint_t lsdaStart = p;
+                if (addressSpace.getEncodedP(
+                        p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
+                  // Reset pointer and re-parse LSDA address.
+                  p = lsdaStart;
+                  fdeInfo->lsda = addressSpace
+                      .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+                }
+              }
+              p = endOfAug;
+            }
+            fdeInfo->fdeStart = currentCFI;
+            fdeInfo->fdeLength = nextCFI - currentCFI;
+            fdeInfo->fdeInstructions = p;
+            fdeInfo->pcStart = pcStart;
+            fdeInfo->pcEnd = pcStart + pcRange;
+            return true;
+          } else {
+            // pc is not in begin/range, skip this FDE
+          }
+        } else {
+          // Malformed CIE, now augmentation describing pc range encoding.
+        }
+      } else {
+        // malformed FDE.  CIE is bad
+      }
+      p = nextCFI;
+    }
+  }
+  return false;
+}
+
+/// Extract info from a CIE
+template <typename A>
+const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
+                                    CIE_Info *cieInfo) {
+  cieInfo->pointerEncoding = 0;
+  cieInfo->lsdaEncoding = DW_EH_PE_omit;
+  cieInfo->personalityEncoding = 0;
+  cieInfo->personalityOffsetInCIE = 0;
+  cieInfo->personality = 0;
+  cieInfo->codeAlignFactor = 0;
+  cieInfo->dataAlignFactor = 0;
+  cieInfo->isSignalFrame = false;
+  cieInfo->fdesHaveAugmentationData = false;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+  cieInfo->addressesSignedWithBKey = false;
+#endif
+  cieInfo->cieStart = cie;
+  pint_t p = cie;
+  pint_t cieLength = (pint_t)addressSpace.get32(p);
+  p += 4;
+  pint_t cieContentEnd = p + cieLength;
+  if (cieLength == 0xffffffff) {
+    // 0xffffffff means length is really next 8 bytes
+    cieLength = (pint_t)addressSpace.get64(p);
+    p += 8;
+    cieContentEnd = p + cieLength;
+  }
+  if (cieLength == 0)
+    return NULL;
+  // CIE ID is always 0
+  if (addressSpace.get32(p) != 0)
+    return "CIE ID is not zero";
+  p += 4;
+  // Version is always 1 or 3
+  uint8_t version = addressSpace.get8(p);
+  if ((version != 1) && (version != 3))
+    return "CIE version is not 1 or 3";
+  ++p;
+  // save start of augmentation string and find end
+  pint_t strStart = p;
+  while (addressSpace.get8(p) != 0)
+    ++p;
+  ++p;
+  // parse code aligment factor
+  cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
+  // parse data alignment factor
+  cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
+  // parse return address register
+  uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
+                                  : addressSpace.getULEB128(p, cieContentEnd);
+  assert(raReg < 255 && "return address register too large");
+  cieInfo->returnAddressRegister = (uint8_t)raReg;
+  // parse augmentation data based on augmentation string
+  const char *result = NULL;
+  if (addressSpace.get8(strStart) == 'z') {
+    // parse augmentation data length
+    addressSpace.getULEB128(p, cieContentEnd);
+    for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
+      switch (addressSpace.get8(s)) {
+      case 'z':
+        cieInfo->fdesHaveAugmentationData = true;
+        break;
+      case 'P':
+        cieInfo->personalityEncoding = addressSpace.get8(p);
+        ++p;
+        cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
+        cieInfo->personality = addressSpace
+            .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+        break;
+      case 'L':
+        cieInfo->lsdaEncoding = addressSpace.get8(p);
+        ++p;
+        break;
+      case 'R':
+        cieInfo->pointerEncoding = addressSpace.get8(p);
+        ++p;
+        break;
+      case 'S':
+        cieInfo->isSignalFrame = true;
+        break;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+      case 'B':
+        cieInfo->addressesSignedWithBKey = true;
+        break;
+#endif
+      default:
+        // ignore unknown letters
+        break;
+      }
+    }
+  }
+  cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
+  cieInfo->cieInstructions = p;
+  return result;
+}
+
+
+/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
+template <typename A>
+bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
+                                         const FDE_Info &fdeInfo,
+                                         const CIE_Info &cieInfo, pint_t upToPC,
+                                         int arch, PrologInfo *results) {
+  // Alloca is used for the allocation of the rememberStack entries. It removes
+  // the dependency on new/malloc but the below for loop can not be refactored
+  // into functions. Entry could be saved during the processing of a CIE and
+  // restored by an FDE.
+  RememberStack rememberStack;
+
+  struct ParseInfo {
+    pint_t instructions;
+    pint_t instructionsEnd;
+    pint_t pcoffset;
+  };
+
+  ParseInfo parseInfoArray[] = {
+      {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,
+       (pint_t)(-1)},
+      {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,
+       upToPC - fdeInfo.pcStart}};
+
+  for (const auto &info : parseInfoArray) {
+    pint_t p = info.instructions;
+    pint_t instructionsEnd = info.instructionsEnd;
+    pint_t pcoffset = info.pcoffset;
+    pint_t codeOffset = 0;
+
+    // initialState initialized as registers in results are modified. Use
+    // PrologInfo accessor functions to avoid reading uninitialized data.
+    PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
+
+    _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64
+                           ")\n",
+                           static_cast<uint64_t>(instructionsEnd));
+
+    // see DWARF Spec, section 6.4.2 for details on unwind opcodes
+    while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
+      uint64_t reg;
+      uint64_t reg2;
+      int64_t offset;
+      uint64_t length;
+      uint8_t opcode = addressSpace.get8(p);
+      uint8_t operand;
+
+      ++p;
+      switch (opcode) {
+      case DW_CFA_nop:
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
+        break;
+      case DW_CFA_set_loc:
+        codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
+                                              cieInfo.pointerEncoding);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
+        break;
+      case DW_CFA_advance_loc1:
+        codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
+        p += 1;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
+                               static_cast<uint64_t>(codeOffset));
+        break;
+      case DW_CFA_advance_loc2:
+        codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
+        p += 2;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
+                               static_cast<uint64_t>(codeOffset));
+        break;
+      case DW_CFA_advance_loc4:
+        codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
+        p += 4;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
+                               static_cast<uint64_t>(codeOffset));
+        break;
+      case DW_CFA_offset_extended:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
+          return false;
+        }
+        results->setRegister(reg, kRegisterInCFA, offset, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 ")\n",
+                               reg, offset);
+        break;
+      case DW_CFA_restore_extended:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
+          return false;
+        }
+        results->restoreRegisterToInitialState(reg, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",
+                               reg);
+        break;
+      case DW_CFA_undefined:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_undefined DWARF unwind, reg too big");
+          return false;
+        }
+        results->setRegisterLocation(reg, kRegisterUndefined, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
+        break;
+      case DW_CFA_same_value:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_same_value DWARF unwind, reg too big");
+          return false;
+        }
+        // <rdar://problem/8456377> DW_CFA_same_value unsupported
+        // "same value" means register was stored in frame, but its current
+        // value has not changed, so no need to restore from frame.
+        // We model this as if the register was never saved.
+        results->setRegisterLocation(reg, kRegisterUnused, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
+        break;
+      case DW_CFA_register:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        reg2 = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_register DWARF unwind, reg too big");
+          return false;
+        }
+        if (reg2 > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_register DWARF unwind, reg2 too big");
+          return false;
+        }
+        results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
+                             initialState);
+        _LIBUNWIND_TRACE_DWARF(
+            "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
+        break;
+      case DW_CFA_remember_state: {
+        // Avoid operator new because that would be an upward dependency.
+        // Avoid malloc because it needs heap allocation.
+        PrologInfoStackEntry *entry =
+            (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(
+                sizeof(PrologInfoStackEntry));
+        if (entry != NULL) {
+          entry->next = rememberStack.entry;
+          entry->info = *results;
+          rememberStack.entry = entry;
+        } else {
+          return false;
+        }
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
+        break;
+      }
+      case DW_CFA_restore_state:
+        if (rememberStack.entry != NULL) {
+          PrologInfoStackEntry *top = rememberStack.entry;
+          *results = top->info;
+          rememberStack.entry = top->next;
+          _LIBUNWIND_REMEMBER_FREE(top);
+        } else {
+          return false;
+        }
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
+        break;
+      case DW_CFA_def_cfa:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
+          return false;
+        }
+        results->cfaRegister = (uint32_t)reg;
+        results->cfaRegisterOffset = (int32_t)offset;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64
+                               ")\n",
+                               reg, offset);
+        break;
+      case DW_CFA_def_cfa_register:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
+          return false;
+        }
+        results->cfaRegister = (uint32_t)reg;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
+        break;
+      case DW_CFA_def_cfa_offset:
+        results->cfaRegisterOffset =
+            (int32_t)addressSpace.getULEB128(p, instructionsEnd);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
+                               results->cfaRegisterOffset);
+        break;
+      case DW_CFA_def_cfa_expression:
+        results->cfaRegister = 0;
+        results->cfaExpression = (int64_t)p;
+        length = addressSpace.getULEB128(p, instructionsEnd);
+        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+        p += static_cast<pint_t>(length);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
+                               ", length=%" PRIu64 ")\n",
+                               results->cfaExpression, length);
+        break;
+      case DW_CFA_expression:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_expression DWARF unwind, reg too big");
+          return false;
+        }
+        results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
+                             initialState);
+        length = addressSpace.getULEB128(p, instructionsEnd);
+        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+        p += static_cast<pint_t>(length);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
+                               "expression=0x%" PRIx64 ", "
+                               "length=%" PRIu64 ")\n",
+                               reg, results->savedRegisters[reg].value, length);
+        break;
+      case DW_CFA_offset_extended_sf:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
+          return false;
+        }
+        offset = addressSpace.getSLEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        results->setRegister(reg, kRegisterInCFA, offset, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 ")\n",
+                               reg, offset);
+        break;
+      case DW_CFA_def_cfa_sf:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        offset = addressSpace.getSLEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
+          return false;
+        }
+        results->cfaRegister = (uint32_t)reg;
+        results->cfaRegisterOffset = (int32_t)offset;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 ")\n",
+                               reg, offset);
+        break;
+      case DW_CFA_def_cfa_offset_sf:
+        results->cfaRegisterOffset =
+            (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *
+                      cieInfo.dataAlignFactor);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
+                               results->cfaRegisterOffset);
+        break;
+      case DW_CFA_val_offset:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG(
+              "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
+              ") out of range\n",
+              reg);
+          return false;
+        }
+        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 "\n",
+                               reg, offset);
+        break;
+      case DW_CFA_val_offset_sf:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
+          return false;
+        }
+        offset = addressSpace.getSLEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
+                               "offset=%" PRId64 "\n",
+                               reg, offset);
+        break;
+      case DW_CFA_val_expression:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0(
+              "malformed DW_CFA_val_expression DWARF unwind, reg too big");
+          return false;
+        }
+        results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
+                             initialState);
+        length = addressSpace.getULEB128(p, instructionsEnd);
+        assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+        p += static_cast<pint_t>(length);
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
+                               "expression=0x%" PRIx64 ", length=%" PRIu64
+                               ")\n",
+                               reg, results->savedRegisters[reg].value, length);
+        break;
+      case DW_CFA_GNU_args_size:
+        length = addressSpace.getULEB128(p, instructionsEnd);
+        results->spExtraArgSize = (uint32_t)length;
+        _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
+        break;
+      case DW_CFA_GNU_negative_offset_extended:
+        reg = addressSpace.getULEB128(p, instructionsEnd);
+        if (reg > kMaxRegisterNumber) {
+          _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
+                          "unwind, reg too big");
+          return false;
+        }
+        offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+                 cieInfo.dataAlignFactor;
+        results->setRegister(reg, kRegisterInCFA, -offset, initialState);
+        _LIBUNWIND_TRACE_DWARF(
+            "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
+        break;
+
+#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
+        // The same constant is used to represent different instructions on
+        // AArch64 (negate_ra_state) and SPARC (window_save).
+        static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
+                      "uses the same constant");
+      case DW_CFA_AARCH64_negate_ra_state:
+        switch (arch) {
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+        case REGISTERS_ARM64: {
+          int64_t value =
+              results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1;
+          results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value,
+                                    initialState);
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
+        } break;
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+        // case DW_CFA_GNU_window_save:
+        case REGISTERS_SPARC:
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
+          for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
+            results->setRegister(reg, kRegisterInRegister,
+                                 ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
+                                 initialState);
+          }
+
+          for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
+            results->setRegister(reg, kRegisterInCFA,
+                                 ((int64_t)reg - UNW_SPARC_L0) * 4,
+                                 initialState);
+          }
+          break;
+#endif
+        }
+        break;
+#else
+        (void)arch;
+#endif
+
+      default:
+        operand = opcode & 0x3F;
+        switch (opcode & 0xC0) {
+        case DW_CFA_offset:
+          reg = operand;
+          if (reg > kMaxRegisterNumber) {
+            _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
+                           ") out of range",
+                           reg);
+            return false;
+          }
+          offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+                   cieInfo.dataAlignFactor;
+          results->setRegister(reg, kRegisterInCFA, offset, initialState);
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
+                                 operand, offset);
+          break;
+        case DW_CFA_advance_loc:
+          codeOffset += operand * cieInfo.codeAlignFactor;
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
+                                 static_cast<uint64_t>(codeOffset));
+          break;
+        case DW_CFA_restore:
+          reg = operand;
+          if (reg > kMaxRegisterNumber) {
+            _LIBUNWIND_LOG(
+                "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
+                ") out of range",
+                reg);
+            return false;
+          }
+          results->restoreRegisterToInitialState(reg, initialState);
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
+                                 static_cast<uint64_t>(operand));
+          break;
+        default:
+          _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+} // namespace libunwind
+
+#endif // __DWARF_PARSER_HPP__

+ 169 - 0
llvm-libunwind/src/EHHeaderParser.hpp

@@ -0,0 +1,169 @@
+//===------------------------- EHHeaderParser.hpp -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Parses ELF .eh_frame_hdr sections.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __EHHEADERPARSER_HPP__
+#define __EHHEADERPARSER_HPP__
+
+#include "libunwind.h"
+
+#include "DwarfParser.hpp"
+
+namespace libunwind {
+
+/// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section.
+///
+/// See DWARF spec for details:
+///    http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A> class EHHeaderParser {
+public:
+  typedef typename A::pint_t pint_t;
+
+  /// Information encoded in the EH frame header.
+  struct EHHeaderInfo {
+    pint_t eh_frame_ptr;
+    size_t fde_count;
+    pint_t table;
+    uint8_t table_enc;
+  };
+
+  static bool decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
+                          EHHeaderInfo &ehHdrInfo);
+  static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
+                      uint32_t sectionLength,
+                      typename CFI_Parser<A>::FDE_Info *fdeInfo,
+                      typename CFI_Parser<A>::CIE_Info *cieInfo);
+
+private:
+  static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry,
+                               pint_t ehHdrStart, pint_t ehHdrEnd,
+                               uint8_t tableEnc,
+                               typename CFI_Parser<A>::FDE_Info *fdeInfo,
+                               typename CFI_Parser<A>::CIE_Info *cieInfo);
+  static size_t getTableEntrySize(uint8_t tableEnc);
+};
+
+template <typename A>
+bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
+                                    pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
+  pint_t p = ehHdrStart;
+  uint8_t version = addressSpace.get8(p++);
+  if (version != 1) {
+    _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version");
+    return false;
+  }
+
+  uint8_t eh_frame_ptr_enc = addressSpace.get8(p++);
+  uint8_t fde_count_enc = addressSpace.get8(p++);
+  ehHdrInfo.table_enc = addressSpace.get8(p++);
+
+  ehHdrInfo.eh_frame_ptr =
+      addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
+  ehHdrInfo.fde_count =
+      fde_count_enc == DW_EH_PE_omit
+          ? 0
+          : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
+  ehHdrInfo.table = p;
+
+  return true;
+}
+
+template <typename A>
+bool EHHeaderParser<A>::decodeTableEntry(
+    A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd,
+    uint8_t tableEnc, typename CFI_Parser<A>::FDE_Info *fdeInfo,
+    typename CFI_Parser<A>::CIE_Info *cieInfo) {
+  // Have to decode the whole FDE for the PC range anyway, so just throw away
+  // the PC start.
+  addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
+  pint_t fde =
+      addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
+  const char *message =
+      CFI_Parser<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo);
+  if (message != NULL) {
+    _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s",
+                         message);
+    return false;
+  }
+
+  return true;
+}
+
+template <typename A>
+bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
+                                uint32_t sectionLength,
+                                typename CFI_Parser<A>::FDE_Info *fdeInfo,
+                                typename CFI_Parser<A>::CIE_Info *cieInfo) {
+  pint_t ehHdrEnd = ehHdrStart + sectionLength;
+
+  EHHeaderParser<A>::EHHeaderInfo hdrInfo;
+  if (!EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd,
+                                      hdrInfo))
+    return false;
+
+  if (hdrInfo.fde_count == 0) return false;
+
+  size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc);
+  pint_t tableEntry;
+
+  size_t low = 0;
+  for (size_t len = hdrInfo.fde_count; len > 1;) {
+    size_t mid = low + (len / 2);
+    tableEntry = hdrInfo.table + mid * tableEntrySize;
+    pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd,
+                                            hdrInfo.table_enc, ehHdrStart);
+
+    if (start == pc) {
+      low = mid;
+      break;
+    } else if (start < pc) {
+      low = mid;
+      len -= (len / 2);
+    } else {
+      len /= 2;
+    }
+  }
+
+  tableEntry = hdrInfo.table + low * tableEntrySize;
+  if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd,
+                       hdrInfo.table_enc, fdeInfo, cieInfo)) {
+    if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd)
+      return true;
+  }
+
+  return false;
+}
+
+template <typename A>
+size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) {
+  switch (tableEnc & 0x0f) {
+  case DW_EH_PE_sdata2:
+  case DW_EH_PE_udata2:
+    return 4;
+  case DW_EH_PE_sdata4:
+  case DW_EH_PE_udata4:
+    return 8;
+  case DW_EH_PE_sdata8:
+  case DW_EH_PE_udata8:
+    return 16;
+  case DW_EH_PE_sleb128:
+  case DW_EH_PE_uleb128:
+    _LIBUNWIND_ABORT("Can't binary search on variable length encoded data.");
+  case DW_EH_PE_omit:
+    return 0;
+  default:
+    _LIBUNWIND_ABORT("Unknown DWARF encoding for search table.");
+  }
+}
+
+}
+
+#endif

+ 149 - 0
llvm-libunwind/src/FrameHeaderCache.hpp

@@ -0,0 +1,149 @@
+//===-FrameHeaderCache.hpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// Cache the elf program headers necessary to unwind the stack more efficiently
+// in the presence of many dsos.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __FRAMEHEADER_CACHE_HPP__
+#define __FRAMEHEADER_CACHE_HPP__
+
+#include "config.h"
+#include <limits.h>
+
+#ifdef _LIBUNWIND_DEBUG_FRAMEHEADER_CACHE
+#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) _LIBUNWIND_LOG0(x)
+#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...)                            \
+  _LIBUNWIND_LOG(msg, __VA_ARGS__)
+#else
+#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x)
+#define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...)
+#endif
+
+// This cache should only be be used from within a dl_iterate_phdr callback.
+// dl_iterate_phdr does the necessary synchronization to prevent problems
+// with concurrent access via the libc load lock. Adding synchronization
+// for other uses is possible, but not currently done.
+
+class _LIBUNWIND_HIDDEN FrameHeaderCache {
+  struct CacheEntry {
+    uintptr_t LowPC() { return Info.dso_base; };
+    uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; };
+    UnwindInfoSections Info;
+    CacheEntry *Next;
+  };
+
+  static const size_t kCacheEntryCount = 8;
+
+  // Can't depend on the C++ standard library in libunwind, so use an array to
+  // allocate the entries, and two linked lists for ordering unused and recently
+  // used entries.  FIXME: Would the the extra memory for a doubly-linked list
+  // be better than the runtime cost of traversing a very short singly-linked
+  // list on a cache miss? The entries themselves are all small and consecutive,
+  // so unlikely to cause page faults when following the pointers. The memory
+  // spent on additional pointers could also be spent on more entries.
+
+  CacheEntry Entries[kCacheEntryCount];
+  CacheEntry *MostRecentlyUsed;
+  CacheEntry *Unused;
+
+  void resetCache() {
+    _LIBUNWIND_FRAMEHEADERCACHE_TRACE0("FrameHeaderCache reset");
+    MostRecentlyUsed = nullptr;
+    Unused = &Entries[0];
+    for (size_t i = 0; i < kCacheEntryCount - 1; i++) {
+      Entries[i].Next = &Entries[i + 1];
+    }
+    Entries[kCacheEntryCount - 1].Next = nullptr;
+  }
+
+  bool cacheNeedsReset(dl_phdr_info *PInfo) {
+    // C libraries increment dl_phdr_info.adds and dl_phdr_info.subs when
+    // loading and unloading shared libraries. If these values change between
+    // iterations of dl_iterate_phdr, then invalidate the cache.
+
+    // These are static to avoid needing an initializer, and unsigned long long
+    // because that is their type within the extended dl_phdr_info.  Initialize
+    // these to something extremely unlikely to be found upon the first call to
+    // dl_iterate_phdr.
+    static unsigned long long LastAdds = ULLONG_MAX;
+    static unsigned long long LastSubs = ULLONG_MAX;
+    if (PInfo->dlpi_adds != LastAdds || PInfo->dlpi_subs != LastSubs) {
+      // Resetting the entire cache is a big hammer, but this path is rare--
+      // usually just on the very first call, when the cache is empty anyway--so
+      // added complexity doesn't buy much.
+      LastAdds = PInfo->dlpi_adds;
+      LastSubs = PInfo->dlpi_subs;
+      resetCache();
+      return true;
+    }
+    return false;
+  }
+
+public:
+  bool find(dl_phdr_info *PInfo, size_t, void *data) {
+    if (cacheNeedsReset(PInfo) || MostRecentlyUsed == nullptr)
+      return false;
+
+    auto *CBData = static_cast<dl_iterate_cb_data *>(data);
+    CacheEntry *Current = MostRecentlyUsed;
+    CacheEntry *Previous = nullptr;
+    while (Current != nullptr) {
+      _LIBUNWIND_FRAMEHEADERCACHE_TRACE(
+          "FrameHeaderCache check %lx in [%lx - %lx)", CBData->targetAddr,
+          Current->LowPC(), Current->HighPC());
+      if (Current->LowPC() <= CBData->targetAddr &&
+          CBData->targetAddr < Current->HighPC()) {
+        _LIBUNWIND_FRAMEHEADERCACHE_TRACE(
+            "FrameHeaderCache hit %lx in [%lx - %lx)", CBData->targetAddr,
+            Current->LowPC(), Current->HighPC());
+        if (Previous) {
+          // If there is no Previous, then Current is already the
+          // MostRecentlyUsed, and no need to move it up.
+          Previous->Next = Current->Next;
+          Current->Next = MostRecentlyUsed;
+          MostRecentlyUsed = Current;
+        }
+        *CBData->sects = Current->Info;
+        return true;
+      }
+      Previous = Current;
+      Current = Current->Next;
+    }
+    _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache miss for address %lx",
+                                      CBData->targetAddr);
+    return false;
+  }
+
+  void add(const UnwindInfoSections *UIS) {
+    CacheEntry *Current = nullptr;
+
+    if (Unused != nullptr) {
+      Current = Unused;
+      Unused = Unused->Next;
+    } else {
+      Current = MostRecentlyUsed;
+      CacheEntry *Previous = nullptr;
+      while (Current->Next != nullptr) {
+        Previous = Current;
+        Current = Current->Next;
+      }
+      Previous->Next = nullptr;
+      _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache evict [%lx - %lx)",
+                                        Current->LowPC(), Current->HighPC());
+    }
+
+    Current->Info = *UIS;
+    Current->Next = MostRecentlyUsed;
+    MostRecentlyUsed = Current;
+    _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache add [%lx - %lx)",
+                                      MostRecentlyUsed->LowPC(),
+                                      MostRecentlyUsed->HighPC());
+  }
+};
+
+#endif // __FRAMEHEADER_CACHE_HPP__

+ 114 - 0
llvm-libunwind/src/RWMutex.hpp

@@ -0,0 +1,114 @@
+//===----------------------------- Registers.hpp --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+// Abstract interface to shared reader/writer log, hiding platform and
+// configuration differences.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __RWMUTEX_HPP__
+#define __RWMUTEX_HPP__
+
+#if defined(_WIN32)
+#include <windows.h>
+#elif !defined(_LIBUNWIND_HAS_NO_THREADS)
+#include <pthread.h>
+#if defined(__ELF__) && defined(_LIBUNWIND_LINK_PTHREAD_LIB)
+#pragma comment(lib, "pthread")
+#endif
+#endif
+
+namespace libunwind {
+
+#if defined(_LIBUNWIND_HAS_NO_THREADS)
+
+class _LIBUNWIND_HIDDEN RWMutex {
+public:
+  bool lock_shared() { return true; }
+  bool unlock_shared() { return true; }
+  bool lock() { return true; }
+  bool unlock() { return true; }
+};
+
+#elif defined(_WIN32)
+
+class _LIBUNWIND_HIDDEN RWMutex {
+public:
+  bool lock_shared() {
+    AcquireSRWLockShared(&_lock);
+    return true;
+  }
+  bool unlock_shared() {
+    ReleaseSRWLockShared(&_lock);
+    return true;
+  }
+  bool lock() {
+    AcquireSRWLockExclusive(&_lock);
+    return true;
+  }
+  bool unlock() {
+    ReleaseSRWLockExclusive(&_lock);
+    return true;
+  }
+
+private:
+  SRWLOCK _lock = SRWLOCK_INIT;
+};
+
+#elif !defined(LIBUNWIND_USE_WEAK_PTHREAD)
+
+class _LIBUNWIND_HIDDEN RWMutex {
+public:
+  bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0;  }
+  bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; }
+  bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; }
+  bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; }
+
+private:
+  pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER;
+};
+
+#else
+
+extern "C" int __attribute__((weak))
+pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+               void *(*start_routine)(void *), void *arg);
+extern "C" int __attribute__((weak))
+pthread_rwlock_rdlock(pthread_rwlock_t *lock);
+extern "C" int __attribute__((weak))
+pthread_rwlock_wrlock(pthread_rwlock_t *lock);
+extern "C" int __attribute__((weak))
+pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
+// Calls to the locking functions are gated on pthread_create, and not the
+// functions themselves, because the data structure should only be locked if
+// another thread has been created. This is what similar libraries do.
+
+class _LIBUNWIND_HIDDEN RWMutex {
+public:
+  bool lock_shared() {
+    return !pthread_create || (pthread_rwlock_rdlock(&_lock) == 0);
+  }
+  bool unlock_shared() {
+    return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0);
+  }
+  bool lock() {
+    return !pthread_create || (pthread_rwlock_wrlock(&_lock) == 0);
+  }
+  bool unlock() {
+    return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0);
+  }
+
+private:
+  pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER;
+};
+
+#endif
+
+} // namespace libunwind
+
+#endif // __RWMUTEX_HPP__

+ 4491 - 0
llvm-libunwind/src/Registers.hpp

@@ -0,0 +1,4491 @@
+//===----------------------------- Registers.hpp --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Models register sets for supported processors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __REGISTERS_HPP__
+#define __REGISTERS_HPP__
+
+#include <stdint.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "config.h"
+
+namespace libunwind {
+
+// For emulating 128-bit registers
+struct v128 { uint32_t vec[4]; };
+
+enum {
+  REGISTERS_X86,
+  REGISTERS_X86_64,
+  REGISTERS_PPC,
+  REGISTERS_PPC64,
+  REGISTERS_ARM64,
+  REGISTERS_ARM,
+  REGISTERS_OR1K,
+  REGISTERS_MIPS_O32,
+  REGISTERS_MIPS_NEWABI,
+  REGISTERS_SPARC,
+  REGISTERS_HEXAGON,
+  REGISTERS_RISCV,
+  REGISTERS_VE,
+};
+
+#if defined(_LIBUNWIND_TARGET_I386)
+class _LIBUNWIND_HIDDEN Registers_x86;
+extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
+/// Registers_x86 holds the register state of a thread in a 32-bit intel
+/// process.
+class _LIBUNWIND_HIDDEN Registers_x86 {
+public:
+  Registers_x86();
+  Registers_x86(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int) const { return false; }
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int) const { return false; }
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto() { __libunwind_Registers_x86_jumpto(this); }
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; }
+  static int  getArch() { return REGISTERS_X86; }
+
+  uint32_t  getSP() const          { return _registers.__esp; }
+  void      setSP(uint32_t value)  { _registers.__esp = value; }
+  uint32_t  getIP() const          { return _registers.__eip; }
+  void      setIP(uint32_t value)  { _registers.__eip = value; }
+  uint32_t  getEBP() const         { return _registers.__ebp; }
+  void      setEBP(uint32_t value) { _registers.__ebp = value; }
+  uint32_t  getEBX() const         { return _registers.__ebx; }
+  void      setEBX(uint32_t value) { _registers.__ebx = value; }
+  uint32_t  getECX() const         { return _registers.__ecx; }
+  void      setECX(uint32_t value) { _registers.__ecx = value; }
+  uint32_t  getEDX() const         { return _registers.__edx; }
+  void      setEDX(uint32_t value) { _registers.__edx = value; }
+  uint32_t  getESI() const         { return _registers.__esi; }
+  void      setESI(uint32_t value) { _registers.__esi = value; }
+  uint32_t  getEDI() const         { return _registers.__edi; }
+  void      setEDI(uint32_t value) { _registers.__edi = value; }
+
+private:
+  struct GPRs {
+    unsigned int __eax;
+    unsigned int __ebx;
+    unsigned int __ecx;
+    unsigned int __edx;
+    unsigned int __edi;
+    unsigned int __esi;
+    unsigned int __ebp;
+    unsigned int __esp;
+    unsigned int __ss;
+    unsigned int __eflags;
+    unsigned int __eip;
+    unsigned int __cs;
+    unsigned int __ds;
+    unsigned int __es;
+    unsigned int __fs;
+    unsigned int __gs;
+  };
+
+  GPRs _registers;
+};
+
+inline Registers_x86::Registers_x86(const void *registers) {
+  static_assert((check_fit<Registers_x86, unw_context_t>::does_fit),
+                "x86 registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_x86::Registers_x86() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_x86::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum > 7)
+    return false;
+  return true;
+}
+
+inline uint32_t Registers_x86::getRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__eip;
+  case UNW_REG_SP:
+    return _registers.__esp;
+  case UNW_X86_EAX:
+    return _registers.__eax;
+  case UNW_X86_ECX:
+    return _registers.__ecx;
+  case UNW_X86_EDX:
+    return _registers.__edx;
+  case UNW_X86_EBX:
+    return _registers.__ebx;
+#if !defined(__APPLE__)
+  case UNW_X86_ESP:
+#else
+  case UNW_X86_EBP:
+#endif
+    return _registers.__ebp;
+#if !defined(__APPLE__)
+  case UNW_X86_EBP:
+#else
+  case UNW_X86_ESP:
+#endif
+    return _registers.__esp;
+  case UNW_X86_ESI:
+    return _registers.__esi;
+  case UNW_X86_EDI:
+    return _registers.__edi;
+  }
+  _LIBUNWIND_ABORT("unsupported x86 register");
+}
+
+inline void Registers_x86::setRegister(int regNum, uint32_t value) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__eip = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__esp = value;
+    return;
+  case UNW_X86_EAX:
+    _registers.__eax = value;
+    return;
+  case UNW_X86_ECX:
+    _registers.__ecx = value;
+    return;
+  case UNW_X86_EDX:
+    _registers.__edx = value;
+    return;
+  case UNW_X86_EBX:
+    _registers.__ebx = value;
+    return;
+#if !defined(__APPLE__)
+  case UNW_X86_ESP:
+#else
+  case UNW_X86_EBP:
+#endif
+    _registers.__ebp = value;
+    return;
+#if !defined(__APPLE__)
+  case UNW_X86_EBP:
+#else
+  case UNW_X86_ESP:
+#endif
+    _registers.__esp = value;
+    return;
+  case UNW_X86_ESI:
+    _registers.__esi = value;
+    return;
+  case UNW_X86_EDI:
+    _registers.__edi = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported x86 register");
+}
+
+inline const char *Registers_x86::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "ip";
+  case UNW_REG_SP:
+    return "esp";
+  case UNW_X86_EAX:
+    return "eax";
+  case UNW_X86_ECX:
+    return "ecx";
+  case UNW_X86_EDX:
+    return "edx";
+  case UNW_X86_EBX:
+    return "ebx";
+  case UNW_X86_EBP:
+    return "ebp";
+  case UNW_X86_ESP:
+    return "esp";
+  case UNW_X86_ESI:
+    return "esi";
+  case UNW_X86_EDI:
+    return "edi";
+  default:
+    return "unknown register";
+  }
+}
+
+inline double Registers_x86::getFloatRegister(int) const {
+  _LIBUNWIND_ABORT("no x86 float registers");
+}
+
+inline void Registers_x86::setFloatRegister(int, double) {
+  _LIBUNWIND_ABORT("no x86 float registers");
+}
+
+inline v128 Registers_x86::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("no x86 vector registers");
+}
+
+inline void Registers_x86::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("no x86 vector registers");
+}
+#endif // _LIBUNWIND_TARGET_I386
+
+
+#if defined(_LIBUNWIND_TARGET_X86_64)
+/// Registers_x86_64  holds the register state of a thread in a 64-bit intel
+/// process.
+class _LIBUNWIND_HIDDEN Registers_x86_64;
+extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);
+class _LIBUNWIND_HIDDEN Registers_x86_64 {
+public:
+  Registers_x86_64();
+  Registers_x86_64(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint64_t    getRegister(int num) const;
+  void        setRegister(int num, uint64_t value);
+  bool        validFloatRegister(int) const { return false; }
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto() { __libunwind_Registers_x86_64_jumpto(this); }
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; }
+  static int  getArch() { return REGISTERS_X86_64; }
+
+  uint64_t  getSP() const          { return _registers.__rsp; }
+  void      setSP(uint64_t value)  { _registers.__rsp = value; }
+  uint64_t  getIP() const          { return _registers.__rip; }
+  void      setIP(uint64_t value)  { _registers.__rip = value; }
+  uint64_t  getRBP() const         { return _registers.__rbp; }
+  void      setRBP(uint64_t value) { _registers.__rbp = value; }
+  uint64_t  getRBX() const         { return _registers.__rbx; }
+  void      setRBX(uint64_t value) { _registers.__rbx = value; }
+  uint64_t  getR12() const         { return _registers.__r12; }
+  void      setR12(uint64_t value) { _registers.__r12 = value; }
+  uint64_t  getR13() const         { return _registers.__r13; }
+  void      setR13(uint64_t value) { _registers.__r13 = value; }
+  uint64_t  getR14() const         { return _registers.__r14; }
+  void      setR14(uint64_t value) { _registers.__r14 = value; }
+  uint64_t  getR15() const         { return _registers.__r15; }
+  void      setR15(uint64_t value) { _registers.__r15 = value; }
+
+private:
+  struct GPRs {
+    uint64_t __rax;
+    uint64_t __rbx;
+    uint64_t __rcx;
+    uint64_t __rdx;
+    uint64_t __rdi;
+    uint64_t __rsi;
+    uint64_t __rbp;
+    uint64_t __rsp;
+    uint64_t __r8;
+    uint64_t __r9;
+    uint64_t __r10;
+    uint64_t __r11;
+    uint64_t __r12;
+    uint64_t __r13;
+    uint64_t __r14;
+    uint64_t __r15;
+    uint64_t __rip;
+    uint64_t __rflags;
+    uint64_t __cs;
+    uint64_t __fs;
+    uint64_t __gs;
+#if defined(_WIN64)
+    uint64_t __padding; // 16-byte align
+#endif
+  };
+  GPRs _registers;
+#if defined(_WIN64)
+  v128 _xmm[16];
+#endif
+};
+
+inline Registers_x86_64::Registers_x86_64(const void *registers) {
+  static_assert((check_fit<Registers_x86_64, unw_context_t>::does_fit),
+                "x86_64 registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_x86_64::Registers_x86_64() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_x86_64::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum > 15)
+    return false;
+  return true;
+}
+
+inline uint64_t Registers_x86_64::getRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__rip;
+  case UNW_REG_SP:
+    return _registers.__rsp;
+  case UNW_X86_64_RAX:
+    return _registers.__rax;
+  case UNW_X86_64_RDX:
+    return _registers.__rdx;
+  case UNW_X86_64_RCX:
+    return _registers.__rcx;
+  case UNW_X86_64_RBX:
+    return _registers.__rbx;
+  case UNW_X86_64_RSI:
+    return _registers.__rsi;
+  case UNW_X86_64_RDI:
+    return _registers.__rdi;
+  case UNW_X86_64_RBP:
+    return _registers.__rbp;
+  case UNW_X86_64_RSP:
+    return _registers.__rsp;
+  case UNW_X86_64_R8:
+    return _registers.__r8;
+  case UNW_X86_64_R9:
+    return _registers.__r9;
+  case UNW_X86_64_R10:
+    return _registers.__r10;
+  case UNW_X86_64_R11:
+    return _registers.__r11;
+  case UNW_X86_64_R12:
+    return _registers.__r12;
+  case UNW_X86_64_R13:
+    return _registers.__r13;
+  case UNW_X86_64_R14:
+    return _registers.__r14;
+  case UNW_X86_64_R15:
+    return _registers.__r15;
+  }
+  _LIBUNWIND_ABORT("unsupported x86_64 register");
+}
+
+inline void Registers_x86_64::setRegister(int regNum, uint64_t value) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__rip = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__rsp = value;
+    return;
+  case UNW_X86_64_RAX:
+    _registers.__rax = value;
+    return;
+  case UNW_X86_64_RDX:
+    _registers.__rdx = value;
+    return;
+  case UNW_X86_64_RCX:
+    _registers.__rcx = value;
+    return;
+  case UNW_X86_64_RBX:
+    _registers.__rbx = value;
+    return;
+  case UNW_X86_64_RSI:
+    _registers.__rsi = value;
+    return;
+  case UNW_X86_64_RDI:
+    _registers.__rdi = value;
+    return;
+  case UNW_X86_64_RBP:
+    _registers.__rbp = value;
+    return;
+  case UNW_X86_64_RSP:
+    _registers.__rsp = value;
+    return;
+  case UNW_X86_64_R8:
+    _registers.__r8 = value;
+    return;
+  case UNW_X86_64_R9:
+    _registers.__r9 = value;
+    return;
+  case UNW_X86_64_R10:
+    _registers.__r10 = value;
+    return;
+  case UNW_X86_64_R11:
+    _registers.__r11 = value;
+    return;
+  case UNW_X86_64_R12:
+    _registers.__r12 = value;
+    return;
+  case UNW_X86_64_R13:
+    _registers.__r13 = value;
+    return;
+  case UNW_X86_64_R14:
+    _registers.__r14 = value;
+    return;
+  case UNW_X86_64_R15:
+    _registers.__r15 = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported x86_64 register");
+}
+
+inline const char *Registers_x86_64::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "rip";
+  case UNW_REG_SP:
+    return "rsp";
+  case UNW_X86_64_RAX:
+    return "rax";
+  case UNW_X86_64_RDX:
+    return "rdx";
+  case UNW_X86_64_RCX:
+    return "rcx";
+  case UNW_X86_64_RBX:
+    return "rbx";
+  case UNW_X86_64_RSI:
+    return "rsi";
+  case UNW_X86_64_RDI:
+    return "rdi";
+  case UNW_X86_64_RBP:
+    return "rbp";
+  case UNW_X86_64_RSP:
+    return "rsp";
+  case UNW_X86_64_R8:
+    return "r8";
+  case UNW_X86_64_R9:
+    return "r9";
+  case UNW_X86_64_R10:
+    return "r10";
+  case UNW_X86_64_R11:
+    return "r11";
+  case UNW_X86_64_R12:
+    return "r12";
+  case UNW_X86_64_R13:
+    return "r13";
+  case UNW_X86_64_R14:
+    return "r14";
+  case UNW_X86_64_R15:
+    return "r15";
+  case UNW_X86_64_XMM0:
+    return "xmm0";
+  case UNW_X86_64_XMM1:
+    return "xmm1";
+  case UNW_X86_64_XMM2:
+    return "xmm2";
+  case UNW_X86_64_XMM3:
+    return "xmm3";
+  case UNW_X86_64_XMM4:
+    return "xmm4";
+  case UNW_X86_64_XMM5:
+    return "xmm5";
+  case UNW_X86_64_XMM6:
+    return "xmm6";
+  case UNW_X86_64_XMM7:
+    return "xmm7";
+  case UNW_X86_64_XMM8:
+    return "xmm8";
+  case UNW_X86_64_XMM9:
+    return "xmm9";
+  case UNW_X86_64_XMM10:
+    return "xmm10";
+  case UNW_X86_64_XMM11:
+    return "xmm11";
+  case UNW_X86_64_XMM12:
+    return "xmm12";
+  case UNW_X86_64_XMM13:
+    return "xmm13";
+  case UNW_X86_64_XMM14:
+    return "xmm14";
+  case UNW_X86_64_XMM15:
+    return "xmm15";
+  default:
+    return "unknown register";
+  }
+}
+
+inline double Registers_x86_64::getFloatRegister(int) const {
+  _LIBUNWIND_ABORT("no x86_64 float registers");
+}
+
+inline void Registers_x86_64::setFloatRegister(int, double) {
+  _LIBUNWIND_ABORT("no x86_64 float registers");
+}
+
+inline bool Registers_x86_64::validVectorRegister(int regNum) const {
+#if defined(_WIN64)
+  if (regNum < UNW_X86_64_XMM0)
+    return false;
+  if (regNum > UNW_X86_64_XMM15)
+    return false;
+  return true;
+#else
+  (void)regNum; // suppress unused parameter warning
+  return false;
+#endif
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int regNum) const {
+#if defined(_WIN64)
+  assert(validVectorRegister(regNum));
+  return _xmm[regNum - UNW_X86_64_XMM0];
+#else
+  (void)regNum; // suppress unused parameter warning
+  _LIBUNWIND_ABORT("no x86_64 vector registers");
+#endif
+}
+
+inline void Registers_x86_64::setVectorRegister(int regNum, v128 value) {
+#if defined(_WIN64)
+  assert(validVectorRegister(regNum));
+  _xmm[regNum - UNW_X86_64_XMM0] = value;
+#else
+  (void)regNum; (void)value; // suppress unused parameter warnings
+  _LIBUNWIND_ABORT("no x86_64 vector registers");
+#endif
+}
+#endif // _LIBUNWIND_TARGET_X86_64
+
+
+#if defined(_LIBUNWIND_TARGET_PPC)
+/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC
+/// process.
+class _LIBUNWIND_HIDDEN Registers_ppc {
+public:
+  Registers_ppc();
+  Registers_ppc(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; }
+  static int  getArch() { return REGISTERS_PPC; }
+
+  uint64_t  getSP() const         { return _registers.__r1; }
+  void      setSP(uint32_t value) { _registers.__r1 = value; }
+  uint64_t  getIP() const         { return _registers.__srr0; }
+  void      setIP(uint32_t value) { _registers.__srr0 = value; }
+
+private:
+  struct ppc_thread_state_t {
+    unsigned int __srr0; /* Instruction address register (PC) */
+    unsigned int __srr1; /* Machine state register (supervisor) */
+    unsigned int __r0;
+    unsigned int __r1;
+    unsigned int __r2;
+    unsigned int __r3;
+    unsigned int __r4;
+    unsigned int __r5;
+    unsigned int __r6;
+    unsigned int __r7;
+    unsigned int __r8;
+    unsigned int __r9;
+    unsigned int __r10;
+    unsigned int __r11;
+    unsigned int __r12;
+    unsigned int __r13;
+    unsigned int __r14;
+    unsigned int __r15;
+    unsigned int __r16;
+    unsigned int __r17;
+    unsigned int __r18;
+    unsigned int __r19;
+    unsigned int __r20;
+    unsigned int __r21;
+    unsigned int __r22;
+    unsigned int __r23;
+    unsigned int __r24;
+    unsigned int __r25;
+    unsigned int __r26;
+    unsigned int __r27;
+    unsigned int __r28;
+    unsigned int __r29;
+    unsigned int __r30;
+    unsigned int __r31;
+    unsigned int __cr;     /* Condition register */
+    unsigned int __xer;    /* User's integer exception register */
+    unsigned int __lr;     /* Link register */
+    unsigned int __ctr;    /* Count register */
+    unsigned int __mq;     /* MQ register (601 only) */
+    unsigned int __vrsave; /* Vector Save Register */
+  };
+
+  struct ppc_float_state_t {
+    double __fpregs[32];
+
+    unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */
+    unsigned int __fpscr;     /* floating point status register */
+  };
+
+  ppc_thread_state_t _registers;
+  ppc_float_state_t  _floatRegisters;
+  v128               _vectorRegisters[32]; // offset 424
+};
+
+inline Registers_ppc::Registers_ppc(const void *registers) {
+  static_assert((check_fit<Registers_ppc, unw_context_t>::does_fit),
+                "ppc registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+  static_assert(sizeof(ppc_thread_state_t) == 160,
+                "expected float register offset to be 160");
+  memcpy(&_floatRegisters,
+         static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t),
+         sizeof(_floatRegisters));
+  static_assert(sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t) == 424,
+                "expected vector register offset to be 424 bytes");
+  memcpy(_vectorRegisters,
+         static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t) +
+             sizeof(ppc_float_state_t),
+         sizeof(_vectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc() {
+  memset(&_registers, 0, sizeof(_registers));
+  memset(&_floatRegisters, 0, sizeof(_floatRegisters));
+  memset(&_vectorRegisters, 0, sizeof(_vectorRegisters));
+}
+
+inline bool Registers_ppc::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum == UNW_PPC_VRSAVE)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum <= UNW_PPC_R31)
+    return true;
+  if (regNum == UNW_PPC_MQ)
+    return true;
+  if (regNum == UNW_PPC_LR)
+    return true;
+  if (regNum == UNW_PPC_CTR)
+    return true;
+  if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7))
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_ppc::getRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__srr0;
+  case UNW_REG_SP:
+    return _registers.__r1;
+  case UNW_PPC_R0:
+    return _registers.__r0;
+  case UNW_PPC_R1:
+    return _registers.__r1;
+  case UNW_PPC_R2:
+    return _registers.__r2;
+  case UNW_PPC_R3:
+    return _registers.__r3;
+  case UNW_PPC_R4:
+    return _registers.__r4;
+  case UNW_PPC_R5:
+    return _registers.__r5;
+  case UNW_PPC_R6:
+    return _registers.__r6;
+  case UNW_PPC_R7:
+    return _registers.__r7;
+  case UNW_PPC_R8:
+    return _registers.__r8;
+  case UNW_PPC_R9:
+    return _registers.__r9;
+  case UNW_PPC_R10:
+    return _registers.__r10;
+  case UNW_PPC_R11:
+    return _registers.__r11;
+  case UNW_PPC_R12:
+    return _registers.__r12;
+  case UNW_PPC_R13:
+    return _registers.__r13;
+  case UNW_PPC_R14:
+    return _registers.__r14;
+  case UNW_PPC_R15:
+    return _registers.__r15;
+  case UNW_PPC_R16:
+    return _registers.__r16;
+  case UNW_PPC_R17:
+    return _registers.__r17;
+  case UNW_PPC_R18:
+    return _registers.__r18;
+  case UNW_PPC_R19:
+    return _registers.__r19;
+  case UNW_PPC_R20:
+    return _registers.__r20;
+  case UNW_PPC_R21:
+    return _registers.__r21;
+  case UNW_PPC_R22:
+    return _registers.__r22;
+  case UNW_PPC_R23:
+    return _registers.__r23;
+  case UNW_PPC_R24:
+    return _registers.__r24;
+  case UNW_PPC_R25:
+    return _registers.__r25;
+  case UNW_PPC_R26:
+    return _registers.__r26;
+  case UNW_PPC_R27:
+    return _registers.__r27;
+  case UNW_PPC_R28:
+    return _registers.__r28;
+  case UNW_PPC_R29:
+    return _registers.__r29;
+  case UNW_PPC_R30:
+    return _registers.__r30;
+  case UNW_PPC_R31:
+    return _registers.__r31;
+  case UNW_PPC_LR:
+    return _registers.__lr;
+  case UNW_PPC_CR0:
+    return (_registers.__cr & 0xF0000000);
+  case UNW_PPC_CR1:
+    return (_registers.__cr & 0x0F000000);
+  case UNW_PPC_CR2:
+    return (_registers.__cr & 0x00F00000);
+  case UNW_PPC_CR3:
+    return (_registers.__cr & 0x000F0000);
+  case UNW_PPC_CR4:
+    return (_registers.__cr & 0x0000F000);
+  case UNW_PPC_CR5:
+    return (_registers.__cr & 0x00000F00);
+  case UNW_PPC_CR6:
+    return (_registers.__cr & 0x000000F0);
+  case UNW_PPC_CR7:
+    return (_registers.__cr & 0x0000000F);
+  case UNW_PPC_VRSAVE:
+    return _registers.__vrsave;
+  }
+  _LIBUNWIND_ABORT("unsupported ppc register");
+}
+
+inline void Registers_ppc::setRegister(int regNum, uint32_t value) {
+  //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__srr0 = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__r1 = value;
+    return;
+  case UNW_PPC_R0:
+    _registers.__r0 = value;
+    return;
+  case UNW_PPC_R1:
+    _registers.__r1 = value;
+    return;
+  case UNW_PPC_R2:
+    _registers.__r2 = value;
+    return;
+  case UNW_PPC_R3:
+    _registers.__r3 = value;
+    return;
+  case UNW_PPC_R4:
+    _registers.__r4 = value;
+    return;
+  case UNW_PPC_R5:
+    _registers.__r5 = value;
+    return;
+  case UNW_PPC_R6:
+    _registers.__r6 = value;
+    return;
+  case UNW_PPC_R7:
+    _registers.__r7 = value;
+    return;
+  case UNW_PPC_R8:
+    _registers.__r8 = value;
+    return;
+  case UNW_PPC_R9:
+    _registers.__r9 = value;
+    return;
+  case UNW_PPC_R10:
+    _registers.__r10 = value;
+    return;
+  case UNW_PPC_R11:
+    _registers.__r11 = value;
+    return;
+  case UNW_PPC_R12:
+    _registers.__r12 = value;
+    return;
+  case UNW_PPC_R13:
+    _registers.__r13 = value;
+    return;
+  case UNW_PPC_R14:
+    _registers.__r14 = value;
+    return;
+  case UNW_PPC_R15:
+    _registers.__r15 = value;
+    return;
+  case UNW_PPC_R16:
+    _registers.__r16 = value;
+    return;
+  case UNW_PPC_R17:
+    _registers.__r17 = value;
+    return;
+  case UNW_PPC_R18:
+    _registers.__r18 = value;
+    return;
+  case UNW_PPC_R19:
+    _registers.__r19 = value;
+    return;
+  case UNW_PPC_R20:
+    _registers.__r20 = value;
+    return;
+  case UNW_PPC_R21:
+    _registers.__r21 = value;
+    return;
+  case UNW_PPC_R22:
+    _registers.__r22 = value;
+    return;
+  case UNW_PPC_R23:
+    _registers.__r23 = value;
+    return;
+  case UNW_PPC_R24:
+    _registers.__r24 = value;
+    return;
+  case UNW_PPC_R25:
+    _registers.__r25 = value;
+    return;
+  case UNW_PPC_R26:
+    _registers.__r26 = value;
+    return;
+  case UNW_PPC_R27:
+    _registers.__r27 = value;
+    return;
+  case UNW_PPC_R28:
+    _registers.__r28 = value;
+    return;
+  case UNW_PPC_R29:
+    _registers.__r29 = value;
+    return;
+  case UNW_PPC_R30:
+    _registers.__r30 = value;
+    return;
+  case UNW_PPC_R31:
+    _registers.__r31 = value;
+    return;
+  case UNW_PPC_MQ:
+    _registers.__mq = value;
+    return;
+  case UNW_PPC_LR:
+    _registers.__lr = value;
+    return;
+  case UNW_PPC_CTR:
+    _registers.__ctr = value;
+    return;
+  case UNW_PPC_CR0:
+    _registers.__cr &= 0x0FFFFFFF;
+    _registers.__cr |= (value & 0xF0000000);
+    return;
+  case UNW_PPC_CR1:
+    _registers.__cr &= 0xF0FFFFFF;
+    _registers.__cr |= (value & 0x0F000000);
+    return;
+  case UNW_PPC_CR2:
+    _registers.__cr &= 0xFF0FFFFF;
+    _registers.__cr |= (value & 0x00F00000);
+    return;
+  case UNW_PPC_CR3:
+    _registers.__cr &= 0xFFF0FFFF;
+    _registers.__cr |= (value & 0x000F0000);
+    return;
+  case UNW_PPC_CR4:
+    _registers.__cr &= 0xFFFF0FFF;
+    _registers.__cr |= (value & 0x0000F000);
+    return;
+  case UNW_PPC_CR5:
+    _registers.__cr &= 0xFFFFF0FF;
+    _registers.__cr |= (value & 0x00000F00);
+    return;
+  case UNW_PPC_CR6:
+    _registers.__cr &= 0xFFFFFF0F;
+    _registers.__cr |= (value & 0x000000F0);
+    return;
+  case UNW_PPC_CR7:
+    _registers.__cr &= 0xFFFFFFF0;
+    _registers.__cr |= (value & 0x0000000F);
+    return;
+  case UNW_PPC_VRSAVE:
+    _registers.__vrsave = value;
+    return;
+    // not saved
+    return;
+  case UNW_PPC_XER:
+    _registers.__xer = value;
+    return;
+  case UNW_PPC_AP:
+  case UNW_PPC_VSCR:
+  case UNW_PPC_SPEFSCR:
+    // not saved
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported ppc register");
+}
+
+inline bool Registers_ppc::validFloatRegister(int regNum) const {
+  if (regNum < UNW_PPC_F0)
+    return false;
+  if (regNum > UNW_PPC_F31)
+    return false;
+  return true;
+}
+
+inline double Registers_ppc::getFloatRegister(int regNum) const {
+  assert(validFloatRegister(regNum));
+  return _floatRegisters.__fpregs[regNum - UNW_PPC_F0];
+}
+
+inline void Registers_ppc::setFloatRegister(int regNum, double value) {
+  assert(validFloatRegister(regNum));
+  _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value;
+}
+
+inline bool Registers_ppc::validVectorRegister(int regNum) const {
+  if (regNum < UNW_PPC_V0)
+    return false;
+  if (regNum > UNW_PPC_V31)
+    return false;
+  return true;
+}
+
+inline v128 Registers_ppc::getVectorRegister(int regNum) const {
+  assert(validVectorRegister(regNum));
+  v128 result = _vectorRegisters[regNum - UNW_PPC_V0];
+  return result;
+}
+
+inline void Registers_ppc::setVectorRegister(int regNum, v128 value) {
+  assert(validVectorRegister(regNum));
+  _vectorRegisters[regNum - UNW_PPC_V0] = value;
+}
+
+inline const char *Registers_ppc::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "ip";
+  case UNW_REG_SP:
+    return "sp";
+  case UNW_PPC_R0:
+    return "r0";
+  case UNW_PPC_R1:
+    return "r1";
+  case UNW_PPC_R2:
+    return "r2";
+  case UNW_PPC_R3:
+    return "r3";
+  case UNW_PPC_R4:
+    return "r4";
+  case UNW_PPC_R5:
+    return "r5";
+  case UNW_PPC_R6:
+    return "r6";
+  case UNW_PPC_R7:
+    return "r7";
+  case UNW_PPC_R8:
+    return "r8";
+  case UNW_PPC_R9:
+    return "r9";
+  case UNW_PPC_R10:
+    return "r10";
+  case UNW_PPC_R11:
+    return "r11";
+  case UNW_PPC_R12:
+    return "r12";
+  case UNW_PPC_R13:
+    return "r13";
+  case UNW_PPC_R14:
+    return "r14";
+  case UNW_PPC_R15:
+    return "r15";
+  case UNW_PPC_R16:
+    return "r16";
+  case UNW_PPC_R17:
+    return "r17";
+  case UNW_PPC_R18:
+    return "r18";
+  case UNW_PPC_R19:
+    return "r19";
+  case UNW_PPC_R20:
+    return "r20";
+  case UNW_PPC_R21:
+    return "r21";
+  case UNW_PPC_R22:
+    return "r22";
+  case UNW_PPC_R23:
+    return "r23";
+  case UNW_PPC_R24:
+    return "r24";
+  case UNW_PPC_R25:
+    return "r25";
+  case UNW_PPC_R26:
+    return "r26";
+  case UNW_PPC_R27:
+    return "r27";
+  case UNW_PPC_R28:
+    return "r28";
+  case UNW_PPC_R29:
+    return "r29";
+  case UNW_PPC_R30:
+    return "r30";
+  case UNW_PPC_R31:
+    return "r31";
+  case UNW_PPC_F0:
+    return "fp0";
+  case UNW_PPC_F1:
+    return "fp1";
+  case UNW_PPC_F2:
+    return "fp2";
+  case UNW_PPC_F3:
+    return "fp3";
+  case UNW_PPC_F4:
+    return "fp4";
+  case UNW_PPC_F5:
+    return "fp5";
+  case UNW_PPC_F6:
+    return "fp6";
+  case UNW_PPC_F7:
+    return "fp7";
+  case UNW_PPC_F8:
+    return "fp8";
+  case UNW_PPC_F9:
+    return "fp9";
+  case UNW_PPC_F10:
+    return "fp10";
+  case UNW_PPC_F11:
+    return "fp11";
+  case UNW_PPC_F12:
+    return "fp12";
+  case UNW_PPC_F13:
+    return "fp13";
+  case UNW_PPC_F14:
+    return "fp14";
+  case UNW_PPC_F15:
+    return "fp15";
+  case UNW_PPC_F16:
+    return "fp16";
+  case UNW_PPC_F17:
+    return "fp17";
+  case UNW_PPC_F18:
+    return "fp18";
+  case UNW_PPC_F19:
+    return "fp19";
+  case UNW_PPC_F20:
+    return "fp20";
+  case UNW_PPC_F21:
+    return "fp21";
+  case UNW_PPC_F22:
+    return "fp22";
+  case UNW_PPC_F23:
+    return "fp23";
+  case UNW_PPC_F24:
+    return "fp24";
+  case UNW_PPC_F25:
+    return "fp25";
+  case UNW_PPC_F26:
+    return "fp26";
+  case UNW_PPC_F27:
+    return "fp27";
+  case UNW_PPC_F28:
+    return "fp28";
+  case UNW_PPC_F29:
+    return "fp29";
+  case UNW_PPC_F30:
+    return "fp30";
+  case UNW_PPC_F31:
+    return "fp31";
+  case UNW_PPC_LR:
+    return "lr";
+  default:
+    return "unknown register";
+  }
+
+}
+#endif // _LIBUNWIND_TARGET_PPC
+
+#if defined(_LIBUNWIND_TARGET_PPC64)
+/// Registers_ppc64 holds the register state of a thread in a 64-bit PowerPC
+/// process.
+class _LIBUNWIND_HIDDEN Registers_ppc64 {
+public:
+  Registers_ppc64();
+  Registers_ppc64(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint64_t    getRegister(int num) const;
+  void        setRegister(int num, uint64_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; }
+  static int  getArch() { return REGISTERS_PPC64; }
+
+  uint64_t  getSP() const         { return _registers.__r1; }
+  void      setSP(uint64_t value) { _registers.__r1 = value; }
+  uint64_t  getIP() const         { return _registers.__srr0; }
+  void      setIP(uint64_t value) { _registers.__srr0 = value; }
+
+private:
+  struct ppc64_thread_state_t {
+    uint64_t __srr0;    // Instruction address register (PC)
+    uint64_t __srr1;    // Machine state register (supervisor)
+    uint64_t __r0;
+    uint64_t __r1;
+    uint64_t __r2;
+    uint64_t __r3;
+    uint64_t __r4;
+    uint64_t __r5;
+    uint64_t __r6;
+    uint64_t __r7;
+    uint64_t __r8;
+    uint64_t __r9;
+    uint64_t __r10;
+    uint64_t __r11;
+    uint64_t __r12;
+    uint64_t __r13;
+    uint64_t __r14;
+    uint64_t __r15;
+    uint64_t __r16;
+    uint64_t __r17;
+    uint64_t __r18;
+    uint64_t __r19;
+    uint64_t __r20;
+    uint64_t __r21;
+    uint64_t __r22;
+    uint64_t __r23;
+    uint64_t __r24;
+    uint64_t __r25;
+    uint64_t __r26;
+    uint64_t __r27;
+    uint64_t __r28;
+    uint64_t __r29;
+    uint64_t __r30;
+    uint64_t __r31;
+    uint64_t __cr;      // Condition register
+    uint64_t __xer;     // User's integer exception register
+    uint64_t __lr;      // Link register
+    uint64_t __ctr;     // Count register
+    uint64_t __vrsave;  // Vector Save Register
+  };
+
+  union ppc64_vsr_t {
+    struct asfloat_s {
+      double f;
+      uint64_t v2;
+    } asfloat;
+    v128 v;
+  };
+
+  ppc64_thread_state_t _registers;
+  ppc64_vsr_t          _vectorScalarRegisters[64];
+
+  static int getVectorRegNum(int num);
+};
+
+inline Registers_ppc64::Registers_ppc64(const void *registers) {
+  static_assert((check_fit<Registers_ppc64, unw_context_t>::does_fit),
+                "ppc64 registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+  static_assert(sizeof(_registers) == 312,
+                "expected vector scalar register offset to be 312");
+  memcpy(&_vectorScalarRegisters,
+         static_cast<const uint8_t *>(registers) + sizeof(_registers),
+         sizeof(_vectorScalarRegisters));
+  static_assert(sizeof(_registers) +
+                sizeof(_vectorScalarRegisters) == 1336,
+                "expected vector register offset to be 1336 bytes");
+}
+
+inline Registers_ppc64::Registers_ppc64() {
+  memset(&_registers, 0, sizeof(_registers));
+  memset(&_vectorScalarRegisters, 0, sizeof(_vectorScalarRegisters));
+}
+
+inline bool Registers_ppc64::validRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_REG_IP:
+  case UNW_REG_SP:
+  case UNW_PPC64_XER:
+  case UNW_PPC64_LR:
+  case UNW_PPC64_CTR:
+  case UNW_PPC64_VRSAVE:
+      return true;
+  }
+
+  if (regNum >= UNW_PPC64_R0 && regNum <= UNW_PPC64_R31)
+    return true;
+  if (regNum >= UNW_PPC64_CR0 && regNum <= UNW_PPC64_CR7)
+    return true;
+
+  return false;
+}
+
+inline uint64_t Registers_ppc64::getRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__srr0;
+  case UNW_PPC64_R0:
+    return _registers.__r0;
+  case UNW_PPC64_R1:
+  case UNW_REG_SP:
+    return _registers.__r1;
+  case UNW_PPC64_R2:
+    return _registers.__r2;
+  case UNW_PPC64_R3:
+    return _registers.__r3;
+  case UNW_PPC64_R4:
+    return _registers.__r4;
+  case UNW_PPC64_R5:
+    return _registers.__r5;
+  case UNW_PPC64_R6:
+    return _registers.__r6;
+  case UNW_PPC64_R7:
+    return _registers.__r7;
+  case UNW_PPC64_R8:
+    return _registers.__r8;
+  case UNW_PPC64_R9:
+    return _registers.__r9;
+  case UNW_PPC64_R10:
+    return _registers.__r10;
+  case UNW_PPC64_R11:
+    return _registers.__r11;
+  case UNW_PPC64_R12:
+    return _registers.__r12;
+  case UNW_PPC64_R13:
+    return _registers.__r13;
+  case UNW_PPC64_R14:
+    return _registers.__r14;
+  case UNW_PPC64_R15:
+    return _registers.__r15;
+  case UNW_PPC64_R16:
+    return _registers.__r16;
+  case UNW_PPC64_R17:
+    return _registers.__r17;
+  case UNW_PPC64_R18:
+    return _registers.__r18;
+  case UNW_PPC64_R19:
+    return _registers.__r19;
+  case UNW_PPC64_R20:
+    return _registers.__r20;
+  case UNW_PPC64_R21:
+    return _registers.__r21;
+  case UNW_PPC64_R22:
+    return _registers.__r22;
+  case UNW_PPC64_R23:
+    return _registers.__r23;
+  case UNW_PPC64_R24:
+    return _registers.__r24;
+  case UNW_PPC64_R25:
+    return _registers.__r25;
+  case UNW_PPC64_R26:
+    return _registers.__r26;
+  case UNW_PPC64_R27:
+    return _registers.__r27;
+  case UNW_PPC64_R28:
+    return _registers.__r28;
+  case UNW_PPC64_R29:
+    return _registers.__r29;
+  case UNW_PPC64_R30:
+    return _registers.__r30;
+  case UNW_PPC64_R31:
+    return _registers.__r31;
+  case UNW_PPC64_CR0:
+    return (_registers.__cr & 0xF0000000);
+  case UNW_PPC64_CR1:
+    return (_registers.__cr & 0x0F000000);
+  case UNW_PPC64_CR2:
+    return (_registers.__cr & 0x00F00000);
+  case UNW_PPC64_CR3:
+    return (_registers.__cr & 0x000F0000);
+  case UNW_PPC64_CR4:
+    return (_registers.__cr & 0x0000F000);
+  case UNW_PPC64_CR5:
+    return (_registers.__cr & 0x00000F00);
+  case UNW_PPC64_CR6:
+    return (_registers.__cr & 0x000000F0);
+  case UNW_PPC64_CR7:
+    return (_registers.__cr & 0x0000000F);
+  case UNW_PPC64_XER:
+    return _registers.__xer;
+  case UNW_PPC64_LR:
+    return _registers.__lr;
+  case UNW_PPC64_CTR:
+    return _registers.__ctr;
+  case UNW_PPC64_VRSAVE:
+    return _registers.__vrsave;
+  }
+  _LIBUNWIND_ABORT("unsupported ppc64 register");
+}
+
+inline void Registers_ppc64::setRegister(int regNum, uint64_t value) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__srr0 = value;
+    return;
+  case UNW_PPC64_R0:
+    _registers.__r0 = value;
+    return;
+  case UNW_PPC64_R1:
+  case UNW_REG_SP:
+    _registers.__r1 = value;
+    return;
+  case UNW_PPC64_R2:
+    _registers.__r2 = value;
+    return;
+  case UNW_PPC64_R3:
+    _registers.__r3 = value;
+    return;
+  case UNW_PPC64_R4:
+    _registers.__r4 = value;
+    return;
+  case UNW_PPC64_R5:
+    _registers.__r5 = value;
+    return;
+  case UNW_PPC64_R6:
+    _registers.__r6 = value;
+    return;
+  case UNW_PPC64_R7:
+    _registers.__r7 = value;
+    return;
+  case UNW_PPC64_R8:
+    _registers.__r8 = value;
+    return;
+  case UNW_PPC64_R9:
+    _registers.__r9 = value;
+    return;
+  case UNW_PPC64_R10:
+    _registers.__r10 = value;
+    return;
+  case UNW_PPC64_R11:
+    _registers.__r11 = value;
+    return;
+  case UNW_PPC64_R12:
+    _registers.__r12 = value;
+    return;
+  case UNW_PPC64_R13:
+    _registers.__r13 = value;
+    return;
+  case UNW_PPC64_R14:
+    _registers.__r14 = value;
+    return;
+  case UNW_PPC64_R15:
+    _registers.__r15 = value;
+    return;
+  case UNW_PPC64_R16:
+    _registers.__r16 = value;
+    return;
+  case UNW_PPC64_R17:
+    _registers.__r17 = value;
+    return;
+  case UNW_PPC64_R18:
+    _registers.__r18 = value;
+    return;
+  case UNW_PPC64_R19:
+    _registers.__r19 = value;
+    return;
+  case UNW_PPC64_R20:
+    _registers.__r20 = value;
+    return;
+  case UNW_PPC64_R21:
+    _registers.__r21 = value;
+    return;
+  case UNW_PPC64_R22:
+    _registers.__r22 = value;
+    return;
+  case UNW_PPC64_R23:
+    _registers.__r23 = value;
+    return;
+  case UNW_PPC64_R24:
+    _registers.__r24 = value;
+    return;
+  case UNW_PPC64_R25:
+    _registers.__r25 = value;
+    return;
+  case UNW_PPC64_R26:
+    _registers.__r26 = value;
+    return;
+  case UNW_PPC64_R27:
+    _registers.__r27 = value;
+    return;
+  case UNW_PPC64_R28:
+    _registers.__r28 = value;
+    return;
+  case UNW_PPC64_R29:
+    _registers.__r29 = value;
+    return;
+  case UNW_PPC64_R30:
+    _registers.__r30 = value;
+    return;
+  case UNW_PPC64_R31:
+    _registers.__r31 = value;
+    return;
+  case UNW_PPC64_CR0:
+    _registers.__cr &= 0x0FFFFFFF;
+    _registers.__cr |= (value & 0xF0000000);
+    return;
+  case UNW_PPC64_CR1:
+    _registers.__cr &= 0xF0FFFFFF;
+    _registers.__cr |= (value & 0x0F000000);
+    return;
+  case UNW_PPC64_CR2:
+    _registers.__cr &= 0xFF0FFFFF;
+    _registers.__cr |= (value & 0x00F00000);
+    return;
+  case UNW_PPC64_CR3:
+    _registers.__cr &= 0xFFF0FFFF;
+    _registers.__cr |= (value & 0x000F0000);
+    return;
+  case UNW_PPC64_CR4:
+    _registers.__cr &= 0xFFFF0FFF;
+    _registers.__cr |= (value & 0x0000F000);
+    return;
+  case UNW_PPC64_CR5:
+    _registers.__cr &= 0xFFFFF0FF;
+    _registers.__cr |= (value & 0x00000F00);
+    return;
+  case UNW_PPC64_CR6:
+    _registers.__cr &= 0xFFFFFF0F;
+    _registers.__cr |= (value & 0x000000F0);
+    return;
+  case UNW_PPC64_CR7:
+    _registers.__cr &= 0xFFFFFFF0;
+    _registers.__cr |= (value & 0x0000000F);
+    return;
+  case UNW_PPC64_XER:
+    _registers.__xer = value;
+    return;
+  case UNW_PPC64_LR:
+    _registers.__lr = value;
+    return;
+  case UNW_PPC64_CTR:
+    _registers.__ctr = value;
+    return;
+  case UNW_PPC64_VRSAVE:
+    _registers.__vrsave = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported ppc64 register");
+}
+
+inline bool Registers_ppc64::validFloatRegister(int regNum) const {
+  return regNum >= UNW_PPC64_F0 && regNum <= UNW_PPC64_F31;
+}
+
+inline double Registers_ppc64::getFloatRegister(int regNum) const {
+  assert(validFloatRegister(regNum));
+  return _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f;
+}
+
+inline void Registers_ppc64::setFloatRegister(int regNum, double value) {
+  assert(validFloatRegister(regNum));
+  _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f = value;
+}
+
+inline bool Registers_ppc64::validVectorRegister(int regNum) const {
+#if defined(__VSX__)
+  if (regNum >= UNW_PPC64_VS0 && regNum <= UNW_PPC64_VS31)
+    return true;
+  if (regNum >= UNW_PPC64_VS32 && regNum <= UNW_PPC64_VS63)
+    return true;
+#elif defined(__ALTIVEC__)
+  if (regNum >= UNW_PPC64_V0 && regNum <= UNW_PPC64_V31)
+    return true;
+#endif
+  return false;
+}
+
+inline int Registers_ppc64::getVectorRegNum(int num)
+{
+  if (num >= UNW_PPC64_VS0 && num <= UNW_PPC64_VS31)
+    return num - UNW_PPC64_VS0;
+  else
+    return num - UNW_PPC64_VS32 + 32;
+}
+
+inline v128 Registers_ppc64::getVectorRegister(int regNum) const {
+  assert(validVectorRegister(regNum));
+  return _vectorScalarRegisters[getVectorRegNum(regNum)].v;
+}
+
+inline void Registers_ppc64::setVectorRegister(int regNum, v128 value) {
+  assert(validVectorRegister(regNum));
+  _vectorScalarRegisters[getVectorRegNum(regNum)].v = value;
+}
+
+inline const char *Registers_ppc64::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "ip";
+  case UNW_REG_SP:
+    return "sp";
+  case UNW_PPC64_R0:
+    return "r0";
+  case UNW_PPC64_R1:
+    return "r1";
+  case UNW_PPC64_R2:
+    return "r2";
+  case UNW_PPC64_R3:
+    return "r3";
+  case UNW_PPC64_R4:
+    return "r4";
+  case UNW_PPC64_R5:
+    return "r5";
+  case UNW_PPC64_R6:
+    return "r6";
+  case UNW_PPC64_R7:
+    return "r7";
+  case UNW_PPC64_R8:
+    return "r8";
+  case UNW_PPC64_R9:
+    return "r9";
+  case UNW_PPC64_R10:
+    return "r10";
+  case UNW_PPC64_R11:
+    return "r11";
+  case UNW_PPC64_R12:
+    return "r12";
+  case UNW_PPC64_R13:
+    return "r13";
+  case UNW_PPC64_R14:
+    return "r14";
+  case UNW_PPC64_R15:
+    return "r15";
+  case UNW_PPC64_R16:
+    return "r16";
+  case UNW_PPC64_R17:
+    return "r17";
+  case UNW_PPC64_R18:
+    return "r18";
+  case UNW_PPC64_R19:
+    return "r19";
+  case UNW_PPC64_R20:
+    return "r20";
+  case UNW_PPC64_R21:
+    return "r21";
+  case UNW_PPC64_R22:
+    return "r22";
+  case UNW_PPC64_R23:
+    return "r23";
+  case UNW_PPC64_R24:
+    return "r24";
+  case UNW_PPC64_R25:
+    return "r25";
+  case UNW_PPC64_R26:
+    return "r26";
+  case UNW_PPC64_R27:
+    return "r27";
+  case UNW_PPC64_R28:
+    return "r28";
+  case UNW_PPC64_R29:
+    return "r29";
+  case UNW_PPC64_R30:
+    return "r30";
+  case UNW_PPC64_R31:
+    return "r31";
+  case UNW_PPC64_CR0:
+    return "cr0";
+  case UNW_PPC64_CR1:
+    return "cr1";
+  case UNW_PPC64_CR2:
+    return "cr2";
+  case UNW_PPC64_CR3:
+    return "cr3";
+  case UNW_PPC64_CR4:
+    return "cr4";
+  case UNW_PPC64_CR5:
+    return "cr5";
+  case UNW_PPC64_CR6:
+    return "cr6";
+  case UNW_PPC64_CR7:
+    return "cr7";
+  case UNW_PPC64_XER:
+    return "xer";
+  case UNW_PPC64_LR:
+    return "lr";
+  case UNW_PPC64_CTR:
+    return "ctr";
+  case UNW_PPC64_VRSAVE:
+    return "vrsave";
+  case UNW_PPC64_F0:
+    return "fp0";
+  case UNW_PPC64_F1:
+    return "fp1";
+  case UNW_PPC64_F2:
+    return "fp2";
+  case UNW_PPC64_F3:
+    return "fp3";
+  case UNW_PPC64_F4:
+    return "fp4";
+  case UNW_PPC64_F5:
+    return "fp5";
+  case UNW_PPC64_F6:
+    return "fp6";
+  case UNW_PPC64_F7:
+    return "fp7";
+  case UNW_PPC64_F8:
+    return "fp8";
+  case UNW_PPC64_F9:
+    return "fp9";
+  case UNW_PPC64_F10:
+    return "fp10";
+  case UNW_PPC64_F11:
+    return "fp11";
+  case UNW_PPC64_F12:
+    return "fp12";
+  case UNW_PPC64_F13:
+    return "fp13";
+  case UNW_PPC64_F14:
+    return "fp14";
+  case UNW_PPC64_F15:
+    return "fp15";
+  case UNW_PPC64_F16:
+    return "fp16";
+  case UNW_PPC64_F17:
+    return "fp17";
+  case UNW_PPC64_F18:
+    return "fp18";
+  case UNW_PPC64_F19:
+    return "fp19";
+  case UNW_PPC64_F20:
+    return "fp20";
+  case UNW_PPC64_F21:
+    return "fp21";
+  case UNW_PPC64_F22:
+    return "fp22";
+  case UNW_PPC64_F23:
+    return "fp23";
+  case UNW_PPC64_F24:
+    return "fp24";
+  case UNW_PPC64_F25:
+    return "fp25";
+  case UNW_PPC64_F26:
+    return "fp26";
+  case UNW_PPC64_F27:
+    return "fp27";
+  case UNW_PPC64_F28:
+    return "fp28";
+  case UNW_PPC64_F29:
+    return "fp29";
+  case UNW_PPC64_F30:
+    return "fp30";
+  case UNW_PPC64_F31:
+    return "fp31";
+  case UNW_PPC64_V0:
+    return "v0";
+  case UNW_PPC64_V1:
+    return "v1";
+  case UNW_PPC64_V2:
+    return "v2";
+  case UNW_PPC64_V3:
+    return "v3";
+  case UNW_PPC64_V4:
+    return "v4";
+  case UNW_PPC64_V5:
+    return "v5";
+  case UNW_PPC64_V6:
+    return "v6";
+  case UNW_PPC64_V7:
+    return "v7";
+  case UNW_PPC64_V8:
+    return "v8";
+  case UNW_PPC64_V9:
+    return "v9";
+  case UNW_PPC64_V10:
+    return "v10";
+  case UNW_PPC64_V11:
+    return "v11";
+  case UNW_PPC64_V12:
+    return "v12";
+  case UNW_PPC64_V13:
+    return "v13";
+  case UNW_PPC64_V14:
+    return "v14";
+  case UNW_PPC64_V15:
+    return "v15";
+  case UNW_PPC64_V16:
+    return "v16";
+  case UNW_PPC64_V17:
+    return "v17";
+  case UNW_PPC64_V18:
+    return "v18";
+  case UNW_PPC64_V19:
+    return "v19";
+  case UNW_PPC64_V20:
+    return "v20";
+  case UNW_PPC64_V21:
+    return "v21";
+  case UNW_PPC64_V22:
+    return "v22";
+  case UNW_PPC64_V23:
+    return "v23";
+  case UNW_PPC64_V24:
+    return "v24";
+  case UNW_PPC64_V25:
+    return "v25";
+  case UNW_PPC64_V26:
+    return "v26";
+  case UNW_PPC64_V27:
+    return "v27";
+  case UNW_PPC64_V28:
+    return "v28";
+  case UNW_PPC64_V29:
+    return "v29";
+  case UNW_PPC64_V30:
+    return "v30";
+  case UNW_PPC64_V31:
+    return "v31";
+  }
+  return "unknown register";
+}
+#endif // _LIBUNWIND_TARGET_PPC64
+
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+/// Registers_arm64  holds the register state of a thread in a 64-bit arm
+/// process.
+class _LIBUNWIND_HIDDEN Registers_arm64;
+extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
+class _LIBUNWIND_HIDDEN Registers_arm64 {
+public:
+  Registers_arm64();
+  Registers_arm64(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint64_t    getRegister(int num) const;
+  void        setRegister(int num, uint64_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto() { __libunwind_Registers_arm64_jumpto(this); }
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; }
+  static int  getArch() { return REGISTERS_ARM64; }
+
+  uint64_t  getSP() const         { return _registers.__sp; }
+  void      setSP(uint64_t value) { _registers.__sp = value; }
+  uint64_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint64_t value) { _registers.__pc = value; }
+  uint64_t  getFP() const         { return _registers.__fp; }
+  void      setFP(uint64_t value) { _registers.__fp = value; }
+
+private:
+  struct GPRs {
+    uint64_t __x[29]; // x0-x28
+    uint64_t __fp;    // Frame pointer x29
+    uint64_t __lr;    // Link register x30
+    uint64_t __sp;    // Stack pointer x31
+    uint64_t __pc;    // Program counter
+    uint64_t __ra_sign_state; // RA sign state register
+  };
+
+  GPRs    _registers;
+  double  _vectorHalfRegisters[32];
+  // Currently only the lower double in 128-bit vectore registers
+  // is perserved during unwinding.  We could define new register
+  // numbers (> 96) which mean whole vector registers, then this
+  // struct would need to change to contain whole vector registers.
+};
+
+inline Registers_arm64::Registers_arm64(const void *registers) {
+  static_assert((check_fit<Registers_arm64, unw_context_t>::does_fit),
+                "arm64 registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+  static_assert(sizeof(GPRs) == 0x110,
+                "expected VFP registers to be at offset 272");
+  memcpy(_vectorHalfRegisters,
+         static_cast<const uint8_t *>(registers) + sizeof(GPRs),
+         sizeof(_vectorHalfRegisters));
+}
+
+inline Registers_arm64::Registers_arm64() {
+  memset(&_registers, 0, sizeof(_registers));
+  memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters));
+}
+
+inline bool Registers_arm64::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum > 95)
+    return false;
+  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+    return true;
+  if ((regNum > 32) && (regNum < 64))
+    return false;
+  return true;
+}
+
+inline uint64_t Registers_arm64::getRegister(int regNum) const {
+  if (regNum == UNW_REG_IP || regNum == UNW_ARM64_PC)
+    return _registers.__pc;
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM64_SP)
+    return _registers.__sp;
+  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+    return _registers.__ra_sign_state;
+  if (regNum == UNW_ARM64_FP)
+    return _registers.__fp;
+  if (regNum == UNW_ARM64_LR)
+    return _registers.__lr;
+  if ((regNum >= 0) && (regNum < 29))
+    return _registers.__x[regNum];
+  _LIBUNWIND_ABORT("unsupported arm64 register");
+}
+
+inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
+  if (regNum == UNW_REG_IP || regNum == UNW_ARM64_PC)
+    _registers.__pc = value;
+  else if (regNum == UNW_REG_SP || regNum == UNW_ARM64_SP)
+    _registers.__sp = value;
+  else if (regNum == UNW_ARM64_RA_SIGN_STATE)
+    _registers.__ra_sign_state = value;
+  else if (regNum == UNW_ARM64_FP)
+    _registers.__fp = value;
+  else if (regNum == UNW_ARM64_LR)
+    _registers.__lr = value;
+  else if ((regNum >= 0) && (regNum < 29))
+    _registers.__x[regNum] = value;
+  else
+    _LIBUNWIND_ABORT("unsupported arm64 register");
+}
+
+inline const char *Registers_arm64::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "pc";
+  case UNW_REG_SP:
+    return "sp";
+  case UNW_ARM64_X0:
+    return "x0";
+  case UNW_ARM64_X1:
+    return "x1";
+  case UNW_ARM64_X2:
+    return "x2";
+  case UNW_ARM64_X3:
+    return "x3";
+  case UNW_ARM64_X4:
+    return "x4";
+  case UNW_ARM64_X5:
+    return "x5";
+  case UNW_ARM64_X6:
+    return "x6";
+  case UNW_ARM64_X7:
+    return "x7";
+  case UNW_ARM64_X8:
+    return "x8";
+  case UNW_ARM64_X9:
+    return "x9";
+  case UNW_ARM64_X10:
+    return "x10";
+  case UNW_ARM64_X11:
+    return "x11";
+  case UNW_ARM64_X12:
+    return "x12";
+  case UNW_ARM64_X13:
+    return "x13";
+  case UNW_ARM64_X14:
+    return "x14";
+  case UNW_ARM64_X15:
+    return "x15";
+  case UNW_ARM64_X16:
+    return "x16";
+  case UNW_ARM64_X17:
+    return "x17";
+  case UNW_ARM64_X18:
+    return "x18";
+  case UNW_ARM64_X19:
+    return "x19";
+  case UNW_ARM64_X20:
+    return "x20";
+  case UNW_ARM64_X21:
+    return "x21";
+  case UNW_ARM64_X22:
+    return "x22";
+  case UNW_ARM64_X23:
+    return "x23";
+  case UNW_ARM64_X24:
+    return "x24";
+  case UNW_ARM64_X25:
+    return "x25";
+  case UNW_ARM64_X26:
+    return "x26";
+  case UNW_ARM64_X27:
+    return "x27";
+  case UNW_ARM64_X28:
+    return "x28";
+  case UNW_ARM64_FP:
+    return "fp";
+  case UNW_ARM64_LR:
+    return "lr";
+  case UNW_ARM64_SP:
+    return "sp";
+  case UNW_ARM64_PC:
+    return "pc";
+  case UNW_ARM64_D0:
+    return "d0";
+  case UNW_ARM64_D1:
+    return "d1";
+  case UNW_ARM64_D2:
+    return "d2";
+  case UNW_ARM64_D3:
+    return "d3";
+  case UNW_ARM64_D4:
+    return "d4";
+  case UNW_ARM64_D5:
+    return "d5";
+  case UNW_ARM64_D6:
+    return "d6";
+  case UNW_ARM64_D7:
+    return "d7";
+  case UNW_ARM64_D8:
+    return "d8";
+  case UNW_ARM64_D9:
+    return "d9";
+  case UNW_ARM64_D10:
+    return "d10";
+  case UNW_ARM64_D11:
+    return "d11";
+  case UNW_ARM64_D12:
+    return "d12";
+  case UNW_ARM64_D13:
+    return "d13";
+  case UNW_ARM64_D14:
+    return "d14";
+  case UNW_ARM64_D15:
+    return "d15";
+  case UNW_ARM64_D16:
+    return "d16";
+  case UNW_ARM64_D17:
+    return "d17";
+  case UNW_ARM64_D18:
+    return "d18";
+  case UNW_ARM64_D19:
+    return "d19";
+  case UNW_ARM64_D20:
+    return "d20";
+  case UNW_ARM64_D21:
+    return "d21";
+  case UNW_ARM64_D22:
+    return "d22";
+  case UNW_ARM64_D23:
+    return "d23";
+  case UNW_ARM64_D24:
+    return "d24";
+  case UNW_ARM64_D25:
+    return "d25";
+  case UNW_ARM64_D26:
+    return "d26";
+  case UNW_ARM64_D27:
+    return "d27";
+  case UNW_ARM64_D28:
+    return "d28";
+  case UNW_ARM64_D29:
+    return "d29";
+  case UNW_ARM64_D30:
+    return "d30";
+  case UNW_ARM64_D31:
+    return "d31";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_arm64::validFloatRegister(int regNum) const {
+  if (regNum < UNW_ARM64_D0)
+    return false;
+  if (regNum > UNW_ARM64_D31)
+    return false;
+  return true;
+}
+
+inline double Registers_arm64::getFloatRegister(int regNum) const {
+  assert(validFloatRegister(regNum));
+  return _vectorHalfRegisters[regNum - UNW_ARM64_D0];
+}
+
+inline void Registers_arm64::setFloatRegister(int regNum, double value) {
+  assert(validFloatRegister(regNum));
+  _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value;
+}
+
+inline bool Registers_arm64::validVectorRegister(int) const {
+  return false;
+}
+
+inline v128 Registers_arm64::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("no arm64 vector register support yet");
+}
+
+inline void Registers_arm64::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("no arm64 vector register support yet");
+}
+#endif // _LIBUNWIND_TARGET_AARCH64
+
+#if defined(_LIBUNWIND_TARGET_ARM)
+/// Registers_arm holds the register state of a thread in a 32-bit arm
+/// process.
+///
+/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit,
+/// this uses more memory than required.
+class _LIBUNWIND_HIDDEN Registers_arm {
+public:
+  Registers_arm();
+  Registers_arm(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int num) const;
+  unw_fpreg_t getFloatRegister(int num);
+  void        setFloatRegister(int num, unw_fpreg_t value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto() {
+    restoreSavedFloatRegisters();
+    restoreCoreAndJumpTo();
+  }
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; }
+  static int  getArch() { return REGISTERS_ARM; }
+
+  uint32_t  getSP() const         { return _registers.__sp; }
+  void      setSP(uint32_t value) { _registers.__sp = value; }
+  uint32_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint32_t value) { _registers.__pc = value; }
+
+  void saveVFPAsX() {
+    assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
+    _use_X_for_vfp_save = true;
+  }
+
+  void restoreSavedFloatRegisters() {
+    if (_saved_vfp_d0_d15) {
+      if (_use_X_for_vfp_save)
+        restoreVFPWithFLDMX(_vfp_d0_d15_pad);
+      else
+        restoreVFPWithFLDMD(_vfp_d0_d15_pad);
+    }
+    if (_saved_vfp_d16_d31)
+      restoreVFPv3(_vfp_d16_d31);
+#if defined(__ARM_WMMX)
+    if (_saved_iwmmx)
+      restoreiWMMX(_iwmmx);
+    if (_saved_iwmmx_control)
+      restoreiWMMXControl(_iwmmx_control);
+#endif
+  }
+
+private:
+  struct GPRs {
+    uint32_t __r[13]; // r0-r12
+    uint32_t __sp;    // Stack pointer r13
+    uint32_t __lr;    // Link register r14
+    uint32_t __pc;    // Program counter r15
+  };
+
+  static void saveVFPWithFSTMD(void*);
+  static void saveVFPWithFSTMX(void*);
+  static void saveVFPv3(void*);
+  static void restoreVFPWithFLDMD(void*);
+  static void restoreVFPWithFLDMX(void*);
+  static void restoreVFPv3(void*);
+#if defined(__ARM_WMMX)
+  static void saveiWMMX(void*);
+  static void saveiWMMXControl(uint32_t*);
+  static void restoreiWMMX(void*);
+  static void restoreiWMMXControl(uint32_t*);
+#endif
+  void restoreCoreAndJumpTo();
+
+  // ARM registers
+  GPRs _registers;
+
+  // We save floating point registers lazily because we can't know ahead of
+  // time which ones are used. See EHABI #4.7.
+
+  // Whether D0-D15 are saved in the FTSMX instead of FSTMD format.
+  //
+  // See EHABI #7.5 that explains how matching instruction sequences for load
+  // and store need to be used to correctly restore the exact register bits.
+  bool _use_X_for_vfp_save;
+  // Whether VFP D0-D15 are saved.
+  bool _saved_vfp_d0_d15;
+  // Whether VFPv3 D16-D31 are saved.
+  bool _saved_vfp_d16_d31;
+  // VFP registers D0-D15, + padding if saved using FSTMX
+  unw_fpreg_t _vfp_d0_d15_pad[17];
+  // VFPv3 registers D16-D31, always saved using FSTMD
+  unw_fpreg_t _vfp_d16_d31[16];
+#if defined(__ARM_WMMX)
+  // Whether iWMMX data registers are saved.
+  bool _saved_iwmmx;
+  // Whether iWMMX control registers are saved.
+  mutable bool _saved_iwmmx_control;
+  // iWMMX registers
+  unw_fpreg_t _iwmmx[16];
+  // iWMMX control registers
+  mutable uint32_t _iwmmx_control[4];
+#endif
+};
+
+inline Registers_arm::Registers_arm(const void *registers)
+  : _use_X_for_vfp_save(false),
+    _saved_vfp_d0_d15(false),
+    _saved_vfp_d16_d31(false) {
+  static_assert((check_fit<Registers_arm, unw_context_t>::does_fit),
+                "arm registers do not fit into unw_context_t");
+  // See __unw_getcontext() note about data.
+  memcpy(&_registers, registers, sizeof(_registers));
+  memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
+  memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
+#if defined(__ARM_WMMX)
+  _saved_iwmmx = false;
+  _saved_iwmmx_control = false;
+  memset(&_iwmmx, 0, sizeof(_iwmmx));
+  memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+#endif
+}
+
+inline Registers_arm::Registers_arm()
+  : _use_X_for_vfp_save(false),
+    _saved_vfp_d0_d15(false),
+    _saved_vfp_d16_d31(false) {
+  memset(&_registers, 0, sizeof(_registers));
+  memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
+  memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
+#if defined(__ARM_WMMX)
+  _saved_iwmmx = false;
+  _saved_iwmmx_control = false;
+  memset(&_iwmmx, 0, sizeof(_iwmmx));
+  memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+#endif
+}
+
+inline bool Registers_arm::validRegister(int regNum) const {
+  // Returns true for all non-VFP registers supported by the EHABI
+  // virtual register set (VRS).
+  if (regNum == UNW_REG_IP)
+    return true;
+
+  if (regNum == UNW_REG_SP)
+    return true;
+
+  if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15)
+    return true;
+
+#if defined(__ARM_WMMX)
+  if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3)
+    return true;
+#endif
+
+  return false;
+}
+
+inline uint32_t Registers_arm::getRegister(int regNum) const {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+    return _registers.__sp;
+
+  if (regNum == UNW_ARM_LR)
+    return _registers.__lr;
+
+  if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+    return _registers.__pc;
+
+  if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12)
+    return _registers.__r[regNum];
+
+#if defined(__ARM_WMMX)
+  if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
+    if (!_saved_iwmmx_control) {
+      _saved_iwmmx_control = true;
+      saveiWMMXControl(_iwmmx_control);
+    }
+    return _iwmmx_control[regNum - UNW_ARM_WC0];
+  }
+#endif
+
+  _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline void Registers_arm::setRegister(int regNum, uint32_t value) {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) {
+    _registers.__sp = value;
+    return;
+  }
+
+  if (regNum == UNW_ARM_LR) {
+    _registers.__lr = value;
+    return;
+  }
+
+  if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) {
+    _registers.__pc = value;
+    return;
+  }
+
+  if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) {
+    _registers.__r[regNum] = value;
+    return;
+  }
+
+#if defined(__ARM_WMMX)
+  if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
+    if (!_saved_iwmmx_control) {
+      _saved_iwmmx_control = true;
+      saveiWMMXControl(_iwmmx_control);
+    }
+    _iwmmx_control[regNum - UNW_ARM_WC0] = value;
+    return;
+  }
+#endif
+
+  _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline const char *Registers_arm::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+  case UNW_ARM_IP: // UNW_ARM_R15 is alias
+    return "pc";
+  case UNW_ARM_LR: // UNW_ARM_R14 is alias
+    return "lr";
+  case UNW_REG_SP:
+  case UNW_ARM_SP: // UNW_ARM_R13 is alias
+    return "sp";
+  case UNW_ARM_R0:
+    return "r0";
+  case UNW_ARM_R1:
+    return "r1";
+  case UNW_ARM_R2:
+    return "r2";
+  case UNW_ARM_R3:
+    return "r3";
+  case UNW_ARM_R4:
+    return "r4";
+  case UNW_ARM_R5:
+    return "r5";
+  case UNW_ARM_R6:
+    return "r6";
+  case UNW_ARM_R7:
+    return "r7";
+  case UNW_ARM_R8:
+    return "r8";
+  case UNW_ARM_R9:
+    return "r9";
+  case UNW_ARM_R10:
+    return "r10";
+  case UNW_ARM_R11:
+    return "r11";
+  case UNW_ARM_R12:
+    return "r12";
+  case UNW_ARM_S0:
+    return "s0";
+  case UNW_ARM_S1:
+    return "s1";
+  case UNW_ARM_S2:
+    return "s2";
+  case UNW_ARM_S3:
+    return "s3";
+  case UNW_ARM_S4:
+    return "s4";
+  case UNW_ARM_S5:
+    return "s5";
+  case UNW_ARM_S6:
+    return "s6";
+  case UNW_ARM_S7:
+    return "s7";
+  case UNW_ARM_S8:
+    return "s8";
+  case UNW_ARM_S9:
+    return "s9";
+  case UNW_ARM_S10:
+    return "s10";
+  case UNW_ARM_S11:
+    return "s11";
+  case UNW_ARM_S12:
+    return "s12";
+  case UNW_ARM_S13:
+    return "s13";
+  case UNW_ARM_S14:
+    return "s14";
+  case UNW_ARM_S15:
+    return "s15";
+  case UNW_ARM_S16:
+    return "s16";
+  case UNW_ARM_S17:
+    return "s17";
+  case UNW_ARM_S18:
+    return "s18";
+  case UNW_ARM_S19:
+    return "s19";
+  case UNW_ARM_S20:
+    return "s20";
+  case UNW_ARM_S21:
+    return "s21";
+  case UNW_ARM_S22:
+    return "s22";
+  case UNW_ARM_S23:
+    return "s23";
+  case UNW_ARM_S24:
+    return "s24";
+  case UNW_ARM_S25:
+    return "s25";
+  case UNW_ARM_S26:
+    return "s26";
+  case UNW_ARM_S27:
+    return "s27";
+  case UNW_ARM_S28:
+    return "s28";
+  case UNW_ARM_S29:
+    return "s29";
+  case UNW_ARM_S30:
+    return "s30";
+  case UNW_ARM_S31:
+    return "s31";
+  case UNW_ARM_D0:
+    return "d0";
+  case UNW_ARM_D1:
+    return "d1";
+  case UNW_ARM_D2:
+    return "d2";
+  case UNW_ARM_D3:
+    return "d3";
+  case UNW_ARM_D4:
+    return "d4";
+  case UNW_ARM_D5:
+    return "d5";
+  case UNW_ARM_D6:
+    return "d6";
+  case UNW_ARM_D7:
+    return "d7";
+  case UNW_ARM_D8:
+    return "d8";
+  case UNW_ARM_D9:
+    return "d9";
+  case UNW_ARM_D10:
+    return "d10";
+  case UNW_ARM_D11:
+    return "d11";
+  case UNW_ARM_D12:
+    return "d12";
+  case UNW_ARM_D13:
+    return "d13";
+  case UNW_ARM_D14:
+    return "d14";
+  case UNW_ARM_D15:
+    return "d15";
+  case UNW_ARM_D16:
+    return "d16";
+  case UNW_ARM_D17:
+    return "d17";
+  case UNW_ARM_D18:
+    return "d18";
+  case UNW_ARM_D19:
+    return "d19";
+  case UNW_ARM_D20:
+    return "d20";
+  case UNW_ARM_D21:
+    return "d21";
+  case UNW_ARM_D22:
+    return "d22";
+  case UNW_ARM_D23:
+    return "d23";
+  case UNW_ARM_D24:
+    return "d24";
+  case UNW_ARM_D25:
+    return "d25";
+  case UNW_ARM_D26:
+    return "d26";
+  case UNW_ARM_D27:
+    return "d27";
+  case UNW_ARM_D28:
+    return "d28";
+  case UNW_ARM_D29:
+    return "d29";
+  case UNW_ARM_D30:
+    return "d30";
+  case UNW_ARM_D31:
+    return "d31";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_arm::validFloatRegister(int regNum) const {
+  // NOTE: Consider the intel MMX registers floating points so the
+  // __unw_get_fpreg can be used to transmit the 64-bit data back.
+  return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31))
+#if defined(__ARM_WMMX)
+      || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15))
+#endif
+      ;
+}
+
+inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) {
+  if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) {
+    if (!_saved_vfp_d0_d15) {
+      _saved_vfp_d0_d15 = true;
+      if (_use_X_for_vfp_save)
+        saveVFPWithFSTMX(_vfp_d0_d15_pad);
+      else
+        saveVFPWithFSTMD(_vfp_d0_d15_pad);
+    }
+    return _vfp_d0_d15_pad[regNum - UNW_ARM_D0];
+  }
+
+  if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) {
+    if (!_saved_vfp_d16_d31) {
+      _saved_vfp_d16_d31 = true;
+      saveVFPv3(_vfp_d16_d31);
+    }
+    return _vfp_d16_d31[regNum - UNW_ARM_D16];
+  }
+
+#if defined(__ARM_WMMX)
+  if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+    if (!_saved_iwmmx) {
+      _saved_iwmmx = true;
+      saveiWMMX(_iwmmx);
+    }
+    return _iwmmx[regNum - UNW_ARM_WR0];
+  }
+#endif
+
+  _LIBUNWIND_ABORT("Unknown ARM float register");
+}
+
+inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) {
+  if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) {
+    if (!_saved_vfp_d0_d15) {
+      _saved_vfp_d0_d15 = true;
+      if (_use_X_for_vfp_save)
+        saveVFPWithFSTMX(_vfp_d0_d15_pad);
+      else
+        saveVFPWithFSTMD(_vfp_d0_d15_pad);
+    }
+    _vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value;
+    return;
+  }
+
+  if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) {
+    if (!_saved_vfp_d16_d31) {
+      _saved_vfp_d16_d31 = true;
+      saveVFPv3(_vfp_d16_d31);
+    }
+    _vfp_d16_d31[regNum - UNW_ARM_D16] = value;
+    return;
+  }
+
+#if defined(__ARM_WMMX)
+  if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+    if (!_saved_iwmmx) {
+      _saved_iwmmx = true;
+      saveiWMMX(_iwmmx);
+    }
+    _iwmmx[regNum - UNW_ARM_WR0] = value;
+    return;
+  }
+#endif
+
+  _LIBUNWIND_ABORT("Unknown ARM float register");
+}
+
+inline bool Registers_arm::validVectorRegister(int) const {
+  return false;
+}
+
+inline v128 Registers_arm::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
+inline void Registers_arm::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+#endif // _LIBUNWIND_TARGET_ARM
+
+
+#if defined(_LIBUNWIND_TARGET_OR1K)
+/// Registers_or1k holds the register state of a thread in an OpenRISC1000
+/// process.
+class _LIBUNWIND_HIDDEN Registers_or1k {
+public:
+  Registers_or1k();
+  Registers_or1k(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; }
+  static int  getArch() { return REGISTERS_OR1K; }
+
+  uint64_t  getSP() const         { return _registers.__r[1]; }
+  void      setSP(uint32_t value) { _registers.__r[1] = value; }
+  uint64_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint32_t value) { _registers.__pc = value; }
+
+private:
+  struct or1k_thread_state_t {
+    unsigned int __r[32]; // r0-r31
+    unsigned int __pc;    // Program counter
+    unsigned int __epcr;  // Program counter at exception
+  };
+
+  or1k_thread_state_t _registers;
+};
+
+inline Registers_or1k::Registers_or1k(const void *registers) {
+  static_assert((check_fit<Registers_or1k, unw_context_t>::does_fit),
+                "or1k registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+}
+
+inline Registers_or1k::Registers_or1k() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_or1k::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum <= UNW_OR1K_R31)
+    return true;
+  if (regNum == UNW_OR1K_EPCR)
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_or1k::getRegister(int regNum) const {
+  if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31)
+    return _registers.__r[regNum - UNW_OR1K_R0];
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__pc;
+  case UNW_REG_SP:
+    return _registers.__r[1];
+  case UNW_OR1K_EPCR:
+    return _registers.__epcr;
+  }
+  _LIBUNWIND_ABORT("unsupported or1k register");
+}
+
+inline void Registers_or1k::setRegister(int regNum, uint32_t value) {
+  if (regNum >= UNW_OR1K_R0 && regNum <= UNW_OR1K_R31) {
+    _registers.__r[regNum - UNW_OR1K_R0] = value;
+    return;
+  }
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__pc = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__r[1] = value;
+    return;
+  case UNW_OR1K_EPCR:
+    _registers.__epcr = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported or1k register");
+}
+
+inline bool Registers_or1k::validFloatRegister(int /* regNum */) const {
+  return false;
+}
+
+inline double Registers_or1k::getFloatRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("or1k float support not implemented");
+}
+
+inline void Registers_or1k::setFloatRegister(int /* regNum */,
+                                             double /* value */) {
+  _LIBUNWIND_ABORT("or1k float support not implemented");
+}
+
+inline bool Registers_or1k::validVectorRegister(int /* regNum */) const {
+  return false;
+}
+
+inline v128 Registers_or1k::getVectorRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("or1k vector support not implemented");
+}
+
+inline void Registers_or1k::setVectorRegister(int /* regNum */, v128 /* value */) {
+  _LIBUNWIND_ABORT("or1k vector support not implemented");
+}
+
+inline const char *Registers_or1k::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_OR1K_R0:
+    return "r0";
+  case UNW_OR1K_R1:
+    return "r1";
+  case UNW_OR1K_R2:
+    return "r2";
+  case UNW_OR1K_R3:
+    return "r3";
+  case UNW_OR1K_R4:
+    return "r4";
+  case UNW_OR1K_R5:
+    return "r5";
+  case UNW_OR1K_R6:
+    return "r6";
+  case UNW_OR1K_R7:
+    return "r7";
+  case UNW_OR1K_R8:
+    return "r8";
+  case UNW_OR1K_R9:
+    return "r9";
+  case UNW_OR1K_R10:
+    return "r10";
+  case UNW_OR1K_R11:
+    return "r11";
+  case UNW_OR1K_R12:
+    return "r12";
+  case UNW_OR1K_R13:
+    return "r13";
+  case UNW_OR1K_R14:
+    return "r14";
+  case UNW_OR1K_R15:
+    return "r15";
+  case UNW_OR1K_R16:
+    return "r16";
+  case UNW_OR1K_R17:
+    return "r17";
+  case UNW_OR1K_R18:
+    return "r18";
+  case UNW_OR1K_R19:
+    return "r19";
+  case UNW_OR1K_R20:
+    return "r20";
+  case UNW_OR1K_R21:
+    return "r21";
+  case UNW_OR1K_R22:
+    return "r22";
+  case UNW_OR1K_R23:
+    return "r23";
+  case UNW_OR1K_R24:
+    return "r24";
+  case UNW_OR1K_R25:
+    return "r25";
+  case UNW_OR1K_R26:
+    return "r26";
+  case UNW_OR1K_R27:
+    return "r27";
+  case UNW_OR1K_R28:
+    return "r28";
+  case UNW_OR1K_R29:
+    return "r29";
+  case UNW_OR1K_R30:
+    return "r30";
+  case UNW_OR1K_R31:
+    return "r31";
+  case UNW_OR1K_EPCR:
+    return "EPCR";
+  default:
+    return "unknown register";
+  }
+
+}
+#endif // _LIBUNWIND_TARGET_OR1K
+
+#if defined(_LIBUNWIND_TARGET_MIPS_O32)
+/// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS
+/// process.
+class _LIBUNWIND_HIDDEN Registers_mips_o32 {
+public:
+  Registers_mips_o32();
+  Registers_mips_o32(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+  static int  getArch() { return REGISTERS_MIPS_O32; }
+
+  uint32_t  getSP() const         { return _registers.__r[29]; }
+  void      setSP(uint32_t value) { _registers.__r[29] = value; }
+  uint32_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint32_t value) { _registers.__pc = value; }
+
+private:
+  struct mips_o32_thread_state_t {
+    uint32_t __r[32];
+    uint32_t __pc;
+    uint32_t __hi;
+    uint32_t __lo;
+  };
+
+  mips_o32_thread_state_t _registers;
+#ifdef __mips_hard_float
+  /// O32 with 32-bit floating point registers only uses half of this
+  /// space.  However, using the same layout for 32-bit vs 64-bit
+  /// floating point registers results in a single context size for
+  /// O32 with hard float.
+  uint32_t _padding;
+  double _floats[32];
+#endif
+};
+
+inline Registers_mips_o32::Registers_mips_o32(const void *registers) {
+  static_assert((check_fit<Registers_mips_o32, unw_context_t>::does_fit),
+                "mips_o32 registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+}
+
+inline Registers_mips_o32::Registers_mips_o32() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_mips_o32::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum <= UNW_MIPS_R31)
+    return true;
+#if __mips_isa_rev != 6
+  if (regNum == UNW_MIPS_HI)
+    return true;
+  if (regNum == UNW_MIPS_LO)
+    return true;
+#endif
+#if defined(__mips_hard_float) && __mips_fpr == 32
+  if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31)
+    return true;
+#endif
+  // FIXME: DSP accumulator registers, MSA registers
+  return false;
+}
+
+inline uint32_t Registers_mips_o32::getRegister(int regNum) const {
+  if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31)
+    return _registers.__r[regNum - UNW_MIPS_R0];
+#if defined(__mips_hard_float) && __mips_fpr == 32
+  if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) {
+    uint32_t *p;
+
+    if (regNum % 2 == 0)
+      p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0];
+    else
+      p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1;
+    return *p;
+  }
+#endif
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__pc;
+  case UNW_REG_SP:
+    return _registers.__r[29];
+  case UNW_MIPS_HI:
+    return _registers.__hi;
+  case UNW_MIPS_LO:
+    return _registers.__lo;
+  }
+  _LIBUNWIND_ABORT("unsupported mips_o32 register");
+}
+
+inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) {
+  if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) {
+    _registers.__r[regNum - UNW_MIPS_R0] = value;
+    return;
+  }
+#if defined(__mips_hard_float) && __mips_fpr == 32
+  if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) {
+    uint32_t *p;
+
+    if (regNum % 2 == 0)
+      p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0];
+    else
+      p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1;
+    *p = value;
+    return;
+  }
+#endif
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__pc = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__r[29] = value;
+    return;
+  case UNW_MIPS_HI:
+    _registers.__hi = value;
+    return;
+  case UNW_MIPS_LO:
+    _registers.__lo = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported mips_o32 register");
+}
+
+inline bool Registers_mips_o32::validFloatRegister(int regNum) const {
+#if defined(__mips_hard_float) && __mips_fpr == 64
+  if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31)
+    return true;
+#else
+  (void)regNum;
+#endif
+  return false;
+}
+
+inline double Registers_mips_o32::getFloatRegister(int regNum) const {
+#if defined(__mips_hard_float) && __mips_fpr == 64
+  assert(validFloatRegister(regNum));
+  return _floats[regNum - UNW_MIPS_F0];
+#else
+  (void)regNum;
+  _LIBUNWIND_ABORT("mips_o32 float support not implemented");
+#endif
+}
+
+inline void Registers_mips_o32::setFloatRegister(int regNum,
+                                                 double value) {
+#if defined(__mips_hard_float) && __mips_fpr == 64
+  assert(validFloatRegister(regNum));
+  _floats[regNum - UNW_MIPS_F0] = value;
+#else
+  (void)regNum;
+  (void)value;
+  _LIBUNWIND_ABORT("mips_o32 float support not implemented");
+#endif
+}
+
+inline bool Registers_mips_o32::validVectorRegister(int /* regNum */) const {
+  return false;
+}
+
+inline v128 Registers_mips_o32::getVectorRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("mips_o32 vector support not implemented");
+}
+
+inline void Registers_mips_o32::setVectorRegister(int /* regNum */, v128 /* value */) {
+  _LIBUNWIND_ABORT("mips_o32 vector support not implemented");
+}
+
+inline const char *Registers_mips_o32::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_MIPS_R0:
+    return "$0";
+  case UNW_MIPS_R1:
+    return "$1";
+  case UNW_MIPS_R2:
+    return "$2";
+  case UNW_MIPS_R3:
+    return "$3";
+  case UNW_MIPS_R4:
+    return "$4";
+  case UNW_MIPS_R5:
+    return "$5";
+  case UNW_MIPS_R6:
+    return "$6";
+  case UNW_MIPS_R7:
+    return "$7";
+  case UNW_MIPS_R8:
+    return "$8";
+  case UNW_MIPS_R9:
+    return "$9";
+  case UNW_MIPS_R10:
+    return "$10";
+  case UNW_MIPS_R11:
+    return "$11";
+  case UNW_MIPS_R12:
+    return "$12";
+  case UNW_MIPS_R13:
+    return "$13";
+  case UNW_MIPS_R14:
+    return "$14";
+  case UNW_MIPS_R15:
+    return "$15";
+  case UNW_MIPS_R16:
+    return "$16";
+  case UNW_MIPS_R17:
+    return "$17";
+  case UNW_MIPS_R18:
+    return "$18";
+  case UNW_MIPS_R19:
+    return "$19";
+  case UNW_MIPS_R20:
+    return "$20";
+  case UNW_MIPS_R21:
+    return "$21";
+  case UNW_MIPS_R22:
+    return "$22";
+  case UNW_MIPS_R23:
+    return "$23";
+  case UNW_MIPS_R24:
+    return "$24";
+  case UNW_MIPS_R25:
+    return "$25";
+  case UNW_MIPS_R26:
+    return "$26";
+  case UNW_MIPS_R27:
+    return "$27";
+  case UNW_MIPS_R28:
+    return "$28";
+  case UNW_MIPS_R29:
+    return "$29";
+  case UNW_MIPS_R30:
+    return "$30";
+  case UNW_MIPS_R31:
+    return "$31";
+  case UNW_MIPS_F0:
+    return "$f0";
+  case UNW_MIPS_F1:
+    return "$f1";
+  case UNW_MIPS_F2:
+    return "$f2";
+  case UNW_MIPS_F3:
+    return "$f3";
+  case UNW_MIPS_F4:
+    return "$f4";
+  case UNW_MIPS_F5:
+    return "$f5";
+  case UNW_MIPS_F6:
+    return "$f6";
+  case UNW_MIPS_F7:
+    return "$f7";
+  case UNW_MIPS_F8:
+    return "$f8";
+  case UNW_MIPS_F9:
+    return "$f9";
+  case UNW_MIPS_F10:
+    return "$f10";
+  case UNW_MIPS_F11:
+    return "$f11";
+  case UNW_MIPS_F12:
+    return "$f12";
+  case UNW_MIPS_F13:
+    return "$f13";
+  case UNW_MIPS_F14:
+    return "$f14";
+  case UNW_MIPS_F15:
+    return "$f15";
+  case UNW_MIPS_F16:
+    return "$f16";
+  case UNW_MIPS_F17:
+    return "$f17";
+  case UNW_MIPS_F18:
+    return "$f18";
+  case UNW_MIPS_F19:
+    return "$f19";
+  case UNW_MIPS_F20:
+    return "$f20";
+  case UNW_MIPS_F21:
+    return "$f21";
+  case UNW_MIPS_F22:
+    return "$f22";
+  case UNW_MIPS_F23:
+    return "$f23";
+  case UNW_MIPS_F24:
+    return "$f24";
+  case UNW_MIPS_F25:
+    return "$f25";
+  case UNW_MIPS_F26:
+    return "$f26";
+  case UNW_MIPS_F27:
+    return "$f27";
+  case UNW_MIPS_F28:
+    return "$f28";
+  case UNW_MIPS_F29:
+    return "$f29";
+  case UNW_MIPS_F30:
+    return "$f30";
+  case UNW_MIPS_F31:
+    return "$f31";
+  case UNW_MIPS_HI:
+    return "$hi";
+  case UNW_MIPS_LO:
+    return "$lo";
+  default:
+    return "unknown register";
+  }
+}
+#endif // _LIBUNWIND_TARGET_MIPS_O32
+
+#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI)
+/// Registers_mips_newabi holds the register state of a thread in a
+/// MIPS process using NEWABI (the N32 or N64 ABIs).
+class _LIBUNWIND_HIDDEN Registers_mips_newabi {
+public:
+  Registers_mips_newabi();
+  Registers_mips_newabi(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint64_t    getRegister(int num) const;
+  void        setRegister(int num, uint64_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+  static int  getArch() { return REGISTERS_MIPS_NEWABI; }
+
+  uint64_t  getSP() const         { return _registers.__r[29]; }
+  void      setSP(uint64_t value) { _registers.__r[29] = value; }
+  uint64_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint64_t value) { _registers.__pc = value; }
+
+private:
+  struct mips_newabi_thread_state_t {
+    uint64_t __r[32];
+    uint64_t __pc;
+    uint64_t __hi;
+    uint64_t __lo;
+  };
+
+  mips_newabi_thread_state_t _registers;
+#ifdef __mips_hard_float
+  double _floats[32];
+#endif
+};
+
+inline Registers_mips_newabi::Registers_mips_newabi(const void *registers) {
+  static_assert((check_fit<Registers_mips_newabi, unw_context_t>::does_fit),
+                "mips_newabi registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+}
+
+inline Registers_mips_newabi::Registers_mips_newabi() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_mips_newabi::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum <= UNW_MIPS_R31)
+    return true;
+#if __mips_isa_rev != 6
+  if (regNum == UNW_MIPS_HI)
+    return true;
+  if (regNum == UNW_MIPS_LO)
+    return true;
+#endif
+  // FIXME: Hard float, DSP accumulator registers, MSA registers
+  return false;
+}
+
+inline uint64_t Registers_mips_newabi::getRegister(int regNum) const {
+  if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31)
+    return _registers.__r[regNum - UNW_MIPS_R0];
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__pc;
+  case UNW_REG_SP:
+    return _registers.__r[29];
+  case UNW_MIPS_HI:
+    return _registers.__hi;
+  case UNW_MIPS_LO:
+    return _registers.__lo;
+  }
+  _LIBUNWIND_ABORT("unsupported mips_newabi register");
+}
+
+inline void Registers_mips_newabi::setRegister(int regNum, uint64_t value) {
+  if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) {
+    _registers.__r[regNum - UNW_MIPS_R0] = value;
+    return;
+  }
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__pc = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__r[29] = value;
+    return;
+  case UNW_MIPS_HI:
+    _registers.__hi = value;
+    return;
+  case UNW_MIPS_LO:
+    _registers.__lo = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported mips_newabi register");
+}
+
+inline bool Registers_mips_newabi::validFloatRegister(int regNum) const {
+#ifdef __mips_hard_float
+  if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31)
+    return true;
+#else
+  (void)regNum;
+#endif
+  return false;
+}
+
+inline double Registers_mips_newabi::getFloatRegister(int regNum) const {
+#ifdef __mips_hard_float
+  assert(validFloatRegister(regNum));
+  return _floats[regNum - UNW_MIPS_F0];
+#else
+  (void)regNum;
+  _LIBUNWIND_ABORT("mips_newabi float support not implemented");
+#endif
+}
+
+inline void Registers_mips_newabi::setFloatRegister(int regNum,
+                                                    double value) {
+#ifdef __mips_hard_float
+  assert(validFloatRegister(regNum));
+  _floats[regNum - UNW_MIPS_F0] = value;
+#else
+  (void)regNum;
+  (void)value;
+  _LIBUNWIND_ABORT("mips_newabi float support not implemented");
+#endif
+}
+
+inline bool Registers_mips_newabi::validVectorRegister(int /* regNum */) const {
+  return false;
+}
+
+inline v128 Registers_mips_newabi::getVectorRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("mips_newabi vector support not implemented");
+}
+
+inline void Registers_mips_newabi::setVectorRegister(int /* regNum */, v128 /* value */) {
+  _LIBUNWIND_ABORT("mips_newabi vector support not implemented");
+}
+
+inline const char *Registers_mips_newabi::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_MIPS_R0:
+    return "$0";
+  case UNW_MIPS_R1:
+    return "$1";
+  case UNW_MIPS_R2:
+    return "$2";
+  case UNW_MIPS_R3:
+    return "$3";
+  case UNW_MIPS_R4:
+    return "$4";
+  case UNW_MIPS_R5:
+    return "$5";
+  case UNW_MIPS_R6:
+    return "$6";
+  case UNW_MIPS_R7:
+    return "$7";
+  case UNW_MIPS_R8:
+    return "$8";
+  case UNW_MIPS_R9:
+    return "$9";
+  case UNW_MIPS_R10:
+    return "$10";
+  case UNW_MIPS_R11:
+    return "$11";
+  case UNW_MIPS_R12:
+    return "$12";
+  case UNW_MIPS_R13:
+    return "$13";
+  case UNW_MIPS_R14:
+    return "$14";
+  case UNW_MIPS_R15:
+    return "$15";
+  case UNW_MIPS_R16:
+    return "$16";
+  case UNW_MIPS_R17:
+    return "$17";
+  case UNW_MIPS_R18:
+    return "$18";
+  case UNW_MIPS_R19:
+    return "$19";
+  case UNW_MIPS_R20:
+    return "$20";
+  case UNW_MIPS_R21:
+    return "$21";
+  case UNW_MIPS_R22:
+    return "$22";
+  case UNW_MIPS_R23:
+    return "$23";
+  case UNW_MIPS_R24:
+    return "$24";
+  case UNW_MIPS_R25:
+    return "$25";
+  case UNW_MIPS_R26:
+    return "$26";
+  case UNW_MIPS_R27:
+    return "$27";
+  case UNW_MIPS_R28:
+    return "$28";
+  case UNW_MIPS_R29:
+    return "$29";
+  case UNW_MIPS_R30:
+    return "$30";
+  case UNW_MIPS_R31:
+    return "$31";
+  case UNW_MIPS_F0:
+    return "$f0";
+  case UNW_MIPS_F1:
+    return "$f1";
+  case UNW_MIPS_F2:
+    return "$f2";
+  case UNW_MIPS_F3:
+    return "$f3";
+  case UNW_MIPS_F4:
+    return "$f4";
+  case UNW_MIPS_F5:
+    return "$f5";
+  case UNW_MIPS_F6:
+    return "$f6";
+  case UNW_MIPS_F7:
+    return "$f7";
+  case UNW_MIPS_F8:
+    return "$f8";
+  case UNW_MIPS_F9:
+    return "$f9";
+  case UNW_MIPS_F10:
+    return "$f10";
+  case UNW_MIPS_F11:
+    return "$f11";
+  case UNW_MIPS_F12:
+    return "$f12";
+  case UNW_MIPS_F13:
+    return "$f13";
+  case UNW_MIPS_F14:
+    return "$f14";
+  case UNW_MIPS_F15:
+    return "$f15";
+  case UNW_MIPS_F16:
+    return "$f16";
+  case UNW_MIPS_F17:
+    return "$f17";
+  case UNW_MIPS_F18:
+    return "$f18";
+  case UNW_MIPS_F19:
+    return "$f19";
+  case UNW_MIPS_F20:
+    return "$f20";
+  case UNW_MIPS_F21:
+    return "$f21";
+  case UNW_MIPS_F22:
+    return "$f22";
+  case UNW_MIPS_F23:
+    return "$f23";
+  case UNW_MIPS_F24:
+    return "$f24";
+  case UNW_MIPS_F25:
+    return "$f25";
+  case UNW_MIPS_F26:
+    return "$f26";
+  case UNW_MIPS_F27:
+    return "$f27";
+  case UNW_MIPS_F28:
+    return "$f28";
+  case UNW_MIPS_F29:
+    return "$f29";
+  case UNW_MIPS_F30:
+    return "$f30";
+  case UNW_MIPS_F31:
+    return "$f31";
+  case UNW_MIPS_HI:
+    return "$hi";
+  case UNW_MIPS_LO:
+    return "$lo";
+  default:
+    return "unknown register";
+  }
+}
+#endif // _LIBUNWIND_TARGET_MIPS_NEWABI
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+/// Registers_sparc holds the register state of a thread in a 32-bit Sparc
+/// process.
+class _LIBUNWIND_HIDDEN Registers_sparc {
+public:
+  Registers_sparc();
+  Registers_sparc(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; }
+  static int  getArch() { return REGISTERS_SPARC; }
+
+  uint64_t  getSP() const         { return _registers.__regs[UNW_SPARC_O6]; }
+  void      setSP(uint32_t value) { _registers.__regs[UNW_SPARC_O6] = value; }
+  uint64_t  getIP() const         { return _registers.__regs[UNW_SPARC_O7]; }
+  void      setIP(uint32_t value) { _registers.__regs[UNW_SPARC_O7] = value; }
+
+private:
+  struct sparc_thread_state_t {
+    unsigned int __regs[32];
+  };
+
+  sparc_thread_state_t _registers;
+};
+
+inline Registers_sparc::Registers_sparc(const void *registers) {
+  static_assert((check_fit<Registers_sparc, unw_context_t>::does_fit),
+                "sparc registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+}
+
+inline Registers_sparc::Registers_sparc() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_sparc::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum <= UNW_SPARC_I7)
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_sparc::getRegister(int regNum) const {
+  if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) {
+    return _registers.__regs[regNum];
+  }
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__regs[UNW_SPARC_O7];
+  case UNW_REG_SP:
+    return _registers.__regs[UNW_SPARC_O6];
+  }
+  _LIBUNWIND_ABORT("unsupported sparc register");
+}
+
+inline void Registers_sparc::setRegister(int regNum, uint32_t value) {
+  if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) {
+    _registers.__regs[regNum] = value;
+    return;
+  }
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__regs[UNW_SPARC_O7] = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__regs[UNW_SPARC_O6] = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported sparc register");
+}
+
+inline bool Registers_sparc::validFloatRegister(int) const { return false; }
+
+inline double Registers_sparc::getFloatRegister(int) const {
+  _LIBUNWIND_ABORT("no Sparc float registers");
+}
+
+inline void Registers_sparc::setFloatRegister(int, double) {
+  _LIBUNWIND_ABORT("no Sparc float registers");
+}
+
+inline bool Registers_sparc::validVectorRegister(int) const { return false; }
+
+inline v128 Registers_sparc::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("no Sparc vector registers");
+}
+
+inline void Registers_sparc::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("no Sparc vector registers");
+}
+
+inline const char *Registers_sparc::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "pc";
+  case UNW_SPARC_G0:
+    return "g0";
+  case UNW_SPARC_G1:
+    return "g1";
+  case UNW_SPARC_G2:
+    return "g2";
+  case UNW_SPARC_G3:
+    return "g3";
+  case UNW_SPARC_G4:
+    return "g4";
+  case UNW_SPARC_G5:
+    return "g5";
+  case UNW_SPARC_G6:
+    return "g6";
+  case UNW_SPARC_G7:
+    return "g7";
+  case UNW_SPARC_O0:
+    return "o0";
+  case UNW_SPARC_O1:
+    return "o1";
+  case UNW_SPARC_O2:
+    return "o2";
+  case UNW_SPARC_O3:
+    return "o3";
+  case UNW_SPARC_O4:
+    return "o4";
+  case UNW_SPARC_O5:
+    return "o5";
+  case UNW_REG_SP:
+  case UNW_SPARC_O6:
+    return "sp";
+  case UNW_SPARC_O7:
+    return "o7";
+  case UNW_SPARC_L0:
+    return "l0";
+  case UNW_SPARC_L1:
+    return "l1";
+  case UNW_SPARC_L2:
+    return "l2";
+  case UNW_SPARC_L3:
+    return "l3";
+  case UNW_SPARC_L4:
+    return "l4";
+  case UNW_SPARC_L5:
+    return "l5";
+  case UNW_SPARC_L6:
+    return "l6";
+  case UNW_SPARC_L7:
+    return "l7";
+  case UNW_SPARC_I0:
+    return "i0";
+  case UNW_SPARC_I1:
+    return "i1";
+  case UNW_SPARC_I2:
+    return "i2";
+  case UNW_SPARC_I3:
+    return "i3";
+  case UNW_SPARC_I4:
+    return "i4";
+  case UNW_SPARC_I5:
+    return "i5";
+  case UNW_SPARC_I6:
+    return "fp";
+  case UNW_SPARC_I7:
+    return "i7";
+  default:
+    return "unknown register";
+  }
+}
+#endif // _LIBUNWIND_TARGET_SPARC
+
+#if defined(_LIBUNWIND_TARGET_HEXAGON)
+/// Registers_hexagon holds the register state of a thread in a Hexagon QDSP6
+/// process.
+class _LIBUNWIND_HIDDEN Registers_hexagon {
+public:
+  Registers_hexagon();
+  Registers_hexagon(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON; }
+  static int  getArch() { return REGISTERS_HEXAGON; }
+
+  uint32_t  getSP() const         { return _registers.__r[UNW_HEXAGON_R29]; }
+  void      setSP(uint32_t value) { _registers.__r[UNW_HEXAGON_R29] = value; }
+  uint32_t  getIP() const         { return _registers.__r[UNW_HEXAGON_PC]; }
+  void      setIP(uint32_t value) { _registers.__r[UNW_HEXAGON_PC] = value; }
+
+private:
+  struct hexagon_thread_state_t {
+    unsigned int __r[35];
+  };
+
+  hexagon_thread_state_t _registers;
+};
+
+inline Registers_hexagon::Registers_hexagon(const void *registers) {
+  static_assert((check_fit<Registers_hexagon, unw_context_t>::does_fit),
+                "hexagon registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+}
+
+inline Registers_hexagon::Registers_hexagon() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_hexagon::validRegister(int regNum) const {
+  if (regNum <= UNW_HEXAGON_R31)
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_hexagon::getRegister(int regNum) const {
+  if (regNum >= UNW_HEXAGON_R0 && regNum <= UNW_HEXAGON_R31)
+    return _registers.__r[regNum - UNW_HEXAGON_R0];
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__r[UNW_HEXAGON_PC];
+  case UNW_REG_SP:
+    return _registers.__r[UNW_HEXAGON_R29];
+  }
+  _LIBUNWIND_ABORT("unsupported hexagon register");
+}
+
+inline void Registers_hexagon::setRegister(int regNum, uint32_t value) {
+  if (regNum >= UNW_HEXAGON_R0 && regNum <= UNW_HEXAGON_R31) {
+    _registers.__r[regNum - UNW_HEXAGON_R0] = value;
+    return;
+  }
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__r[UNW_HEXAGON_PC] = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__r[UNW_HEXAGON_R29] = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported hexagon register");
+}
+
+inline bool Registers_hexagon::validFloatRegister(int /* regNum */) const {
+  return false;
+}
+
+inline double Registers_hexagon::getFloatRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("hexagon float support not implemented");
+}
+
+inline void Registers_hexagon::setFloatRegister(int /* regNum */,
+                                             double /* value */) {
+  _LIBUNWIND_ABORT("hexagon float support not implemented");
+}
+
+inline bool Registers_hexagon::validVectorRegister(int /* regNum */) const {
+  return false;
+}
+
+inline v128 Registers_hexagon::getVectorRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("hexagon vector support not implemented");
+}
+
+inline void Registers_hexagon::setVectorRegister(int /* regNum */, v128 /* value */) {
+  _LIBUNWIND_ABORT("hexagon vector support not implemented");
+}
+
+inline const char *Registers_hexagon::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_HEXAGON_R0:
+    return "r0";
+  case UNW_HEXAGON_R1:
+    return "r1";
+  case UNW_HEXAGON_R2:
+    return "r2";
+  case UNW_HEXAGON_R3:
+    return "r3";
+  case UNW_HEXAGON_R4:
+    return "r4";
+  case UNW_HEXAGON_R5:
+    return "r5";
+  case UNW_HEXAGON_R6:
+    return "r6";
+  case UNW_HEXAGON_R7:
+    return "r7";
+  case UNW_HEXAGON_R8:
+    return "r8";
+  case UNW_HEXAGON_R9:
+    return "r9";
+  case UNW_HEXAGON_R10:
+    return "r10";
+  case UNW_HEXAGON_R11:
+    return "r11";
+  case UNW_HEXAGON_R12:
+    return "r12";
+  case UNW_HEXAGON_R13:
+    return "r13";
+  case UNW_HEXAGON_R14:
+    return "r14";
+  case UNW_HEXAGON_R15:
+    return "r15";
+  case UNW_HEXAGON_R16:
+    return "r16";
+  case UNW_HEXAGON_R17:
+    return "r17";
+  case UNW_HEXAGON_R18:
+    return "r18";
+  case UNW_HEXAGON_R19:
+    return "r19";
+  case UNW_HEXAGON_R20:
+    return "r20";
+  case UNW_HEXAGON_R21:
+    return "r21";
+  case UNW_HEXAGON_R22:
+    return "r22";
+  case UNW_HEXAGON_R23:
+    return "r23";
+  case UNW_HEXAGON_R24:
+    return "r24";
+  case UNW_HEXAGON_R25:
+    return "r25";
+  case UNW_HEXAGON_R26:
+    return "r26";
+  case UNW_HEXAGON_R27:
+    return "r27";
+  case UNW_HEXAGON_R28:
+    return "r28";
+  case UNW_HEXAGON_R29:
+    return "r29";
+  case UNW_HEXAGON_R30:
+    return "r30";
+  case UNW_HEXAGON_R31:
+    return "r31";
+  default:
+    return "unknown register";
+  }
+
+}
+#endif // _LIBUNWIND_TARGET_HEXAGON
+
+
+#if defined(_LIBUNWIND_TARGET_RISCV)
+/// Registers_riscv holds the register state of a thread in a RISC-V
+/// process.
+
+// This check makes it safe when LIBUNWIND_ENABLE_CROSS_UNWINDING enabled.
+# ifdef __riscv
+#  if __riscv_xlen == 32
+typedef uint32_t reg_t;
+#  elif __riscv_xlen == 64
+typedef uint64_t reg_t;
+#  else
+#   error "Unsupported __riscv_xlen"
+#  endif
+
+#  if defined(__riscv_flen)
+#   if __riscv_flen == 64
+typedef double fp_t;
+#   elif __riscv_flen == 32
+typedef float fp_t;
+#   else
+#    error "Unsupported __riscv_flen"
+#   endif
+#  else
+// This is just for supressing undeclared error of fp_t.
+typedef double fp_t;
+#  endif
+# else
+// Use Max possible width when cross unwinding
+typedef uint64_t reg_t;
+typedef double fp_t;
+# define __riscv_xlen 64
+# define __riscv_flen 64
+#endif
+
+/// Registers_riscv holds the register state of a thread.
+class _LIBUNWIND_HIDDEN Registers_riscv {
+public:
+  Registers_riscv();
+  Registers_riscv(const void *registers);
+
+  bool        validRegister(int num) const;
+  reg_t       getRegister(int num) const;
+  void        setRegister(int num, reg_t value);
+  bool        validFloatRegister(int num) const;
+  fp_t        getFloatRegister(int num) const;
+  void        setFloatRegister(int num, fp_t value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV; }
+  static int  getArch() { return REGISTERS_RISCV; }
+
+  reg_t       getSP() const { return _registers[2]; }
+  void        setSP(reg_t value) { _registers[2] = value; }
+  reg_t       getIP() const { return _registers[0]; }
+  void        setIP(reg_t value) { _registers[0] = value; }
+
+private:
+  // _registers[0] holds the pc
+  reg_t _registers[32];
+# if defined(__riscv_flen)
+  fp_t _floats[32];
+# endif
+};
+
+inline Registers_riscv::Registers_riscv(const void *registers) {
+  static_assert((check_fit<Registers_riscv, unw_context_t>::does_fit),
+                "riscv registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+# if __riscv_xlen == 32
+  static_assert(sizeof(_registers) == 0x80,
+                "expected float registers to be at offset 128");
+# elif __riscv_xlen == 64
+  static_assert(sizeof(_registers) == 0x100,
+                "expected float registers to be at offset 256");
+# else
+# error "Unexpected float registers."
+# endif
+
+# if defined(__riscv_flen)
+  memcpy(_floats,
+         static_cast<const uint8_t *>(registers) + sizeof(_registers),
+         sizeof(_floats));
+# endif
+}
+
+inline Registers_riscv::Registers_riscv() {
+  memset(&_registers, 0, sizeof(_registers));
+# if defined(__riscv_flen)
+  memset(&_floats, 0, sizeof(_floats));
+# endif
+}
+
+inline bool Registers_riscv::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum > UNW_RISCV_F31)
+    return false;
+  return true;
+}
+
+inline reg_t Registers_riscv::getRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return _registers[0];
+  if (regNum == UNW_REG_SP)
+    return _registers[2];
+  if (regNum == UNW_RISCV_X0)
+    return 0;
+  if ((regNum > 0) && (regNum < 32))
+    return _registers[regNum];
+  _LIBUNWIND_ABORT("unsupported riscv register");
+}
+
+inline void Registers_riscv::setRegister(int regNum, reg_t value) {
+  if (regNum == UNW_REG_IP)
+    _registers[0] = value;
+  else if (regNum == UNW_REG_SP)
+    _registers[2] = value;
+  else if (regNum == UNW_RISCV_X0)
+    /* x0 is hardwired to zero */
+    return;
+  else if ((regNum > 0) && (regNum < 32))
+    _registers[regNum] = value;
+  else
+    _LIBUNWIND_ABORT("unsupported riscv register");
+}
+
+inline const char *Registers_riscv::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "pc";
+  case UNW_REG_SP:
+    return "sp";
+  case UNW_RISCV_X0:
+    return "zero";
+  case UNW_RISCV_X1:
+    return "ra";
+  case UNW_RISCV_X2:
+    return "sp";
+  case UNW_RISCV_X3:
+    return "gp";
+  case UNW_RISCV_X4:
+    return "tp";
+  case UNW_RISCV_X5:
+    return "t0";
+  case UNW_RISCV_X6:
+    return "t1";
+  case UNW_RISCV_X7:
+    return "t2";
+  case UNW_RISCV_X8:
+    return "s0";
+  case UNW_RISCV_X9:
+    return "s1";
+  case UNW_RISCV_X10:
+    return "a0";
+  case UNW_RISCV_X11:
+    return "a1";
+  case UNW_RISCV_X12:
+    return "a2";
+  case UNW_RISCV_X13:
+    return "a3";
+  case UNW_RISCV_X14:
+    return "a4";
+  case UNW_RISCV_X15:
+    return "a5";
+  case UNW_RISCV_X16:
+    return "a6";
+  case UNW_RISCV_X17:
+    return "a7";
+  case UNW_RISCV_X18:
+    return "s2";
+  case UNW_RISCV_X19:
+    return "s3";
+  case UNW_RISCV_X20:
+    return "s4";
+  case UNW_RISCV_X21:
+    return "s5";
+  case UNW_RISCV_X22:
+    return "s6";
+  case UNW_RISCV_X23:
+    return "s7";
+  case UNW_RISCV_X24:
+    return "s8";
+  case UNW_RISCV_X25:
+    return "s9";
+  case UNW_RISCV_X26:
+    return "s10";
+  case UNW_RISCV_X27:
+    return "s11";
+  case UNW_RISCV_X28:
+    return "t3";
+  case UNW_RISCV_X29:
+    return "t4";
+  case UNW_RISCV_X30:
+    return "t5";
+  case UNW_RISCV_X31:
+    return "t6";
+  case UNW_RISCV_F0:
+    return "ft0";
+  case UNW_RISCV_F1:
+    return "ft1";
+  case UNW_RISCV_F2:
+    return "ft2";
+  case UNW_RISCV_F3:
+    return "ft3";
+  case UNW_RISCV_F4:
+    return "ft4";
+  case UNW_RISCV_F5:
+    return "ft5";
+  case UNW_RISCV_F6:
+    return "ft6";
+  case UNW_RISCV_F7:
+    return "ft7";
+  case UNW_RISCV_F8:
+    return "fs0";
+  case UNW_RISCV_F9:
+    return "fs1";
+  case UNW_RISCV_F10:
+    return "fa0";
+  case UNW_RISCV_F11:
+    return "fa1";
+  case UNW_RISCV_F12:
+    return "fa2";
+  case UNW_RISCV_F13:
+    return "fa3";
+  case UNW_RISCV_F14:
+    return "fa4";
+  case UNW_RISCV_F15:
+    return "fa5";
+  case UNW_RISCV_F16:
+    return "fa6";
+  case UNW_RISCV_F17:
+    return "fa7";
+  case UNW_RISCV_F18:
+    return "fs2";
+  case UNW_RISCV_F19:
+    return "fs3";
+  case UNW_RISCV_F20:
+    return "fs4";
+  case UNW_RISCV_F21:
+    return "fs5";
+  case UNW_RISCV_F22:
+    return "fs6";
+  case UNW_RISCV_F23:
+    return "fs7";
+  case UNW_RISCV_F24:
+    return "fs8";
+  case UNW_RISCV_F25:
+    return "fs9";
+  case UNW_RISCV_F26:
+    return "fs10";
+  case UNW_RISCV_F27:
+    return "fs11";
+  case UNW_RISCV_F28:
+    return "ft8";
+  case UNW_RISCV_F29:
+    return "ft9";
+  case UNW_RISCV_F30:
+    return "ft10";
+  case UNW_RISCV_F31:
+    return "ft11";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_riscv::validFloatRegister(int regNum) const {
+# if defined(__riscv_flen)
+  if (regNum < UNW_RISCV_F0)
+    return false;
+  if (regNum > UNW_RISCV_F31)
+    return false;
+  return true;
+# else
+  (void)regNum;
+  return false;
+# endif
+}
+
+inline fp_t Registers_riscv::getFloatRegister(int regNum) const {
+# if defined(__riscv_flen)
+  assert(validFloatRegister(regNum));
+  return _floats[regNum - UNW_RISCV_F0];
+# else
+  (void)regNum;
+  _LIBUNWIND_ABORT("libunwind not built with float support");
+# endif
+}
+
+inline void Registers_riscv::setFloatRegister(int regNum, fp_t value) {
+# if defined(__riscv_flen)
+  assert(validFloatRegister(regNum));
+  _floats[regNum - UNW_RISCV_F0] = value;
+# else
+  (void)regNum;
+  (void)value;
+  _LIBUNWIND_ABORT("libunwind not built with float support");
+# endif
+}
+
+inline bool Registers_riscv::validVectorRegister(int) const {
+  return false;
+}
+
+inline v128 Registers_riscv::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("no riscv vector register support yet");
+}
+
+inline void Registers_riscv::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("no riscv vector register support yet");
+}
+#endif // _LIBUNWIND_TARGET_RISCV
+
+#if defined(_LIBUNWIND_TARGET_VE)
+/// Registers_ve holds the register state of a thread in a VE process.
+class _LIBUNWIND_HIDDEN Registers_ve {
+public:
+  Registers_ve();
+  Registers_ve(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint64_t    getRegister(int num) const;
+  void        setRegister(int num, uint64_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE; }
+  static int  getArch() { return REGISTERS_VE; }
+
+  uint64_t  getSP() const         { return _registers.__s[11]; }
+  void      setSP(uint64_t value) { _registers.__s[11] = value; }
+  uint64_t  getIP() const         { return _registers.__ic; }
+  void      setIP(uint64_t value) { _registers.__ic = value; }
+
+private:
+  // FIXME: Need to store not only scalar registers but also vector and vector
+  // mask registers.  VEOS uses mcontext_t defined in ucontext.h.  It takes
+  // 524288 bytes (65536*8 bytes), though.  Currently, we use libunwind for
+  // SjLj exception support only, so Registers_ve is not implemented completely.
+  struct ve_thread_state_t {
+    uint64_t __s[64]; // s0-s64
+    uint64_t __ic;    // Instruction counter (IC)
+    uint64_t __vixr;  // Vector Index Register
+    uint64_t __vl;    // Vector Length Register
+  };
+
+  ve_thread_state_t _registers; // total 67 registers
+
+  // Currently no vector register is preserved.
+};
+
+inline Registers_ve::Registers_ve(const void *registers) {
+  static_assert((check_fit<Registers_ve, unw_context_t>::does_fit),
+                "ve registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+  static_assert(sizeof(_registers) == 536,
+                "expected vector register offset to be 536");
+}
+
+inline Registers_ve::Registers_ve() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_ve::validRegister(int regNum) const {
+  if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63)
+    return true;
+
+  switch (regNum) {
+  case UNW_REG_IP:
+  case UNW_REG_SP:
+  case UNW_VE_VIXR:
+  case UNW_VE_VL:
+    return true;
+  default:
+    return false;
+  }
+}
+
+inline uint64_t Registers_ve::getRegister(int regNum) const {
+  if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63)
+    return _registers.__s[regNum - UNW_VE_S0];
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__ic;
+  case UNW_REG_SP:
+    return _registers.__s[11];
+  case UNW_VE_VIXR:
+    return _registers.__vixr;
+  case UNW_VE_VL:
+    return _registers.__vl;
+  }
+  _LIBUNWIND_ABORT("unsupported ve register");
+}
+
+inline void Registers_ve::setRegister(int regNum, uint64_t value) {
+  if (regNum >= UNW_VE_S0 && regNum <= UNW_VE_S63) {
+    _registers.__s[regNum - UNW_VE_S0] = value;
+    return;
+  }
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__ic = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__s[11] = value;
+    return;
+  case UNW_VE_VIXR:
+    _registers.__vixr = value;
+    return;
+  case UNW_VE_VL:
+    _registers.__vl = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported ve register");
+}
+
+inline bool Registers_ve::validFloatRegister(int /* regNum */) const {
+  return false;
+}
+
+inline double Registers_ve::getFloatRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("VE doesn't have float registers");
+}
+
+inline void Registers_ve::setFloatRegister(int /* regNum */,
+                                           double /* value */) {
+  _LIBUNWIND_ABORT("VE doesn't have float registers");
+}
+
+inline bool Registers_ve::validVectorRegister(int /* regNum */) const {
+  return false;
+}
+
+inline v128 Registers_ve::getVectorRegister(int /* regNum */) const {
+  _LIBUNWIND_ABORT("VE vector support not implemented");
+}
+
+inline void Registers_ve::setVectorRegister(int /* regNum */,
+                                            v128 /* value */) {
+  _LIBUNWIND_ABORT("VE vector support not implemented");
+}
+
+inline const char *Registers_ve::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "ip";
+  case UNW_REG_SP:
+    return "sp";
+  case UNW_VE_VIXR:
+    return "vixr";
+  case UNW_VE_VL:
+    return "vl";
+  case UNW_VE_S0:
+    return "s0";
+  case UNW_VE_S1:
+    return "s1";
+  case UNW_VE_S2:
+    return "s2";
+  case UNW_VE_S3:
+    return "s3";
+  case UNW_VE_S4:
+    return "s4";
+  case UNW_VE_S5:
+    return "s5";
+  case UNW_VE_S6:
+    return "s6";
+  case UNW_VE_S7:
+    return "s7";
+  case UNW_VE_S8:
+    return "s8";
+  case UNW_VE_S9:
+    return "s9";
+  case UNW_VE_S10:
+    return "s10";
+  case UNW_VE_S11:
+    return "s11";
+  case UNW_VE_S12:
+    return "s12";
+  case UNW_VE_S13:
+    return "s13";
+  case UNW_VE_S14:
+    return "s14";
+  case UNW_VE_S15:
+    return "s15";
+  case UNW_VE_S16:
+    return "s16";
+  case UNW_VE_S17:
+    return "s17";
+  case UNW_VE_S18:
+    return "s18";
+  case UNW_VE_S19:
+    return "s19";
+  case UNW_VE_S20:
+    return "s20";
+  case UNW_VE_S21:
+    return "s21";
+  case UNW_VE_S22:
+    return "s22";
+  case UNW_VE_S23:
+    return "s23";
+  case UNW_VE_S24:
+    return "s24";
+  case UNW_VE_S25:
+    return "s25";
+  case UNW_VE_S26:
+    return "s26";
+  case UNW_VE_S27:
+    return "s27";
+  case UNW_VE_S28:
+    return "s28";
+  case UNW_VE_S29:
+    return "s29";
+  case UNW_VE_S30:
+    return "s30";
+  case UNW_VE_S31:
+    return "s31";
+  case UNW_VE_S32:
+    return "s32";
+  case UNW_VE_S33:
+    return "s33";
+  case UNW_VE_S34:
+    return "s34";
+  case UNW_VE_S35:
+    return "s35";
+  case UNW_VE_S36:
+    return "s36";
+  case UNW_VE_S37:
+    return "s37";
+  case UNW_VE_S38:
+    return "s38";
+  case UNW_VE_S39:
+    return "s39";
+  case UNW_VE_S40:
+    return "s40";
+  case UNW_VE_S41:
+    return "s41";
+  case UNW_VE_S42:
+    return "s42";
+  case UNW_VE_S43:
+    return "s43";
+  case UNW_VE_S44:
+    return "s44";
+  case UNW_VE_S45:
+    return "s45";
+  case UNW_VE_S46:
+    return "s46";
+  case UNW_VE_S47:
+    return "s47";
+  case UNW_VE_S48:
+    return "s48";
+  case UNW_VE_S49:
+    return "s49";
+  case UNW_VE_S50:
+    return "s50";
+  case UNW_VE_S51:
+    return "s51";
+  case UNW_VE_S52:
+    return "s52";
+  case UNW_VE_S53:
+    return "s53";
+  case UNW_VE_S54:
+    return "s54";
+  case UNW_VE_S55:
+    return "s55";
+  case UNW_VE_S56:
+    return "s56";
+  case UNW_VE_S57:
+    return "s57";
+  case UNW_VE_S58:
+    return "s58";
+  case UNW_VE_S59:
+    return "s59";
+  case UNW_VE_S60:
+    return "s60";
+  case UNW_VE_S61:
+    return "s61";
+  case UNW_VE_S62:
+    return "s62";
+  case UNW_VE_S63:
+    return "s63";
+  case UNW_VE_V0:
+    return "v0";
+  case UNW_VE_V1:
+    return "v1";
+  case UNW_VE_V2:
+    return "v2";
+  case UNW_VE_V3:
+    return "v3";
+  case UNW_VE_V4:
+    return "v4";
+  case UNW_VE_V5:
+    return "v5";
+  case UNW_VE_V6:
+    return "v6";
+  case UNW_VE_V7:
+    return "v7";
+  case UNW_VE_V8:
+    return "v8";
+  case UNW_VE_V9:
+    return "v9";
+  case UNW_VE_V10:
+    return "v10";
+  case UNW_VE_V11:
+    return "v11";
+  case UNW_VE_V12:
+    return "v12";
+  case UNW_VE_V13:
+    return "v13";
+  case UNW_VE_V14:
+    return "v14";
+  case UNW_VE_V15:
+    return "v15";
+  case UNW_VE_V16:
+    return "v16";
+  case UNW_VE_V17:
+    return "v17";
+  case UNW_VE_V18:
+    return "v18";
+  case UNW_VE_V19:
+    return "v19";
+  case UNW_VE_V20:
+    return "v20";
+  case UNW_VE_V21:
+    return "v21";
+  case UNW_VE_V22:
+    return "v22";
+  case UNW_VE_V23:
+    return "v23";
+  case UNW_VE_V24:
+    return "v24";
+  case UNW_VE_V25:
+    return "v25";
+  case UNW_VE_V26:
+    return "v26";
+  case UNW_VE_V27:
+    return "v27";
+  case UNW_VE_V28:
+    return "v28";
+  case UNW_VE_V29:
+    return "v29";
+  case UNW_VE_V30:
+    return "v30";
+  case UNW_VE_V31:
+    return "v31";
+  case UNW_VE_V32:
+    return "v32";
+  case UNW_VE_V33:
+    return "v33";
+  case UNW_VE_V34:
+    return "v34";
+  case UNW_VE_V35:
+    return "v35";
+  case UNW_VE_V36:
+    return "v36";
+  case UNW_VE_V37:
+    return "v37";
+  case UNW_VE_V38:
+    return "v38";
+  case UNW_VE_V39:
+    return "v39";
+  case UNW_VE_V40:
+    return "v40";
+  case UNW_VE_V41:
+    return "v41";
+  case UNW_VE_V42:
+    return "v42";
+  case UNW_VE_V43:
+    return "v43";
+  case UNW_VE_V44:
+    return "v44";
+  case UNW_VE_V45:
+    return "v45";
+  case UNW_VE_V46:
+    return "v46";
+  case UNW_VE_V47:
+    return "v47";
+  case UNW_VE_V48:
+    return "v48";
+  case UNW_VE_V49:
+    return "v49";
+  case UNW_VE_V50:
+    return "v50";
+  case UNW_VE_V51:
+    return "v51";
+  case UNW_VE_V52:
+    return "v52";
+  case UNW_VE_V53:
+    return "v53";
+  case UNW_VE_V54:
+    return "v54";
+  case UNW_VE_V55:
+    return "v55";
+  case UNW_VE_V56:
+    return "v56";
+  case UNW_VE_V57:
+    return "v57";
+  case UNW_VE_V58:
+    return "v58";
+  case UNW_VE_V59:
+    return "v59";
+  case UNW_VE_V60:
+    return "v60";
+  case UNW_VE_V61:
+    return "v61";
+  case UNW_VE_V62:
+    return "v62";
+  case UNW_VE_V63:
+    return "v63";
+  case UNW_VE_VM0:
+    return "vm0";
+  case UNW_VE_VM1:
+    return "vm1";
+  case UNW_VE_VM2:
+    return "vm2";
+  case UNW_VE_VM3:
+    return "vm3";
+  case UNW_VE_VM4:
+    return "vm4";
+  case UNW_VE_VM5:
+    return "vm5";
+  case UNW_VE_VM6:
+    return "vm6";
+  case UNW_VE_VM7:
+    return "vm7";
+  case UNW_VE_VM8:
+    return "vm8";
+  case UNW_VE_VM9:
+    return "vm9";
+  case UNW_VE_VM10:
+    return "vm10";
+  case UNW_VE_VM11:
+    return "vm11";
+  case UNW_VE_VM12:
+    return "vm12";
+  case UNW_VE_VM13:
+    return "vm13";
+  case UNW_VE_VM14:
+    return "vm14";
+  case UNW_VE_VM15:
+    return "vm15";
+  }
+  return "unknown register";
+}
+#endif // _LIBUNWIND_TARGET_VE
+
+} // namespace libunwind
+
+#endif // __REGISTERS_HPP__

+ 1003 - 0
llvm-libunwind/src/Unwind-EHABI.cpp

@@ -0,0 +1,1003 @@
+//===--------------------------- Unwind-EHABI.cpp -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Implements ARM zero-cost C++ exceptions
+//
+//===----------------------------------------------------------------------===//
+
+#include "Unwind-EHABI.h"
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "libunwind.h"
+#include "libunwind_ext.h"
+#include "unwind.h"
+
+namespace {
+
+// Strange order: take words in order, but inside word, take from most to least
+// signinficant byte.
+uint8_t getByte(const uint32_t* data, size_t offset) {
+  const uint8_t* byteData = reinterpret_cast<const uint8_t*>(data);
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+  return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))];
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+  return byteData[offset];
+#else
+#error "Unable to determine endianess"
+#endif
+}
+
+const char* getNextWord(const char* data, uint32_t* out) {
+  *out = *reinterpret_cast<const uint32_t*>(data);
+  return data + 4;
+}
+
+const char* getNextNibble(const char* data, uint32_t* out) {
+  *out = *reinterpret_cast<const uint16_t*>(data);
+  return data + 2;
+}
+
+struct Descriptor {
+  // See # 9.2
+  typedef enum {
+    SU16 = 0, // Short descriptor, 16-bit entries
+    LU16 = 1, // Long descriptor,  16-bit entries
+    LU32 = 3, // Long descriptor,  32-bit entries
+    RESERVED0 =  4, RESERVED1 =  5, RESERVED2  = 6,  RESERVED3  =  7,
+    RESERVED4 =  8, RESERVED5 =  9, RESERVED6  = 10, RESERVED7  = 11,
+    RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15
+  } Format;
+
+  // See # 9.2
+  typedef enum {
+    CLEANUP = 0x0,
+    FUNC    = 0x1,
+    CATCH   = 0x2,
+    INVALID = 0x4
+  } Kind;
+};
+
+_Unwind_Reason_Code ProcessDescriptors(
+    _Unwind_State state,
+    _Unwind_Control_Block* ucbp,
+    struct _Unwind_Context* context,
+    Descriptor::Format format,
+    const char* descriptorStart,
+    uint32_t flags) {
+
+  // EHT is inlined in the index using compact form. No descriptors. #5
+  if (flags & 0x1)
+    return _URC_CONTINUE_UNWIND;
+
+  // TODO: We should check the state here, and determine whether we need to
+  // perform phase1 or phase2 unwinding.
+  (void)state;
+
+  const char* descriptor = descriptorStart;
+  uint32_t descriptorWord;
+  getNextWord(descriptor, &descriptorWord);
+  while (descriptorWord) {
+    // Read descriptor based on # 9.2.
+    uint32_t length;
+    uint32_t offset;
+    switch (format) {
+      case Descriptor::LU32:
+        descriptor = getNextWord(descriptor, &length);
+        descriptor = getNextWord(descriptor, &offset);
+      case Descriptor::LU16:
+        descriptor = getNextNibble(descriptor, &length);
+        descriptor = getNextNibble(descriptor, &offset);
+      default:
+        assert(false);
+        return _URC_FAILURE;
+    }
+
+    // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value.
+    Descriptor::Kind kind =
+        static_cast<Descriptor::Kind>((length & 0x1) | ((offset & 0x1) << 1));
+
+    // Clear off flag from last bit.
+    length &= ~1u;
+    offset &= ~1u;
+    uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset;
+    uintptr_t scopeEnd = scopeStart + length;
+    uintptr_t pc = _Unwind_GetIP(context);
+    bool isInScope = (scopeStart <= pc) && (pc < scopeEnd);
+
+    switch (kind) {
+      case Descriptor::CLEANUP: {
+        // TODO(ajwong): Handle cleanup descriptors.
+        break;
+      }
+      case Descriptor::FUNC: {
+        // TODO(ajwong): Handle function descriptors.
+        break;
+      }
+      case Descriptor::CATCH: {
+        // Catch descriptors require gobbling one more word.
+        uint32_t landing_pad;
+        descriptor = getNextWord(descriptor, &landing_pad);
+
+        if (isInScope) {
+          // TODO(ajwong): This is only phase1 compatible logic. Implement
+          // phase2.
+          landing_pad = signExtendPrel31(landing_pad & ~0x80000000);
+          if (landing_pad == 0xffffffff) {
+            return _URC_HANDLER_FOUND;
+          } else if (landing_pad == 0xfffffffe) {
+            return _URC_FAILURE;
+          } else {
+            /*
+            bool is_reference_type = landing_pad & 0x80000000;
+            void* matched_object;
+            if (__cxxabiv1::__cxa_type_match(
+                    ucbp, reinterpret_cast<const std::type_info *>(landing_pad),
+                    is_reference_type,
+                    &matched_object) != __cxxabiv1::ctm_failed)
+                return _URC_HANDLER_FOUND;
+                */
+            _LIBUNWIND_ABORT("Type matching not implemented");
+          }
+        }
+        break;
+      }
+      default:
+        _LIBUNWIND_ABORT("Invalid descriptor kind found.");
+    }
+
+    getNextWord(descriptor, &descriptorWord);
+  }
+
+  return _URC_CONTINUE_UNWIND;
+}
+
+static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state,
+                                          _Unwind_Control_Block* ucbp,
+                                          struct _Unwind_Context* context) {
+  // Read the compact model EHT entry's header # 6.3
+  const uint32_t* unwindingData = ucbp->pr_cache.ehtp;
+  assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry");
+  Descriptor::Format format =
+      static_cast<Descriptor::Format>((*unwindingData & 0x0f000000) >> 24);
+
+  const char *lsda =
+      reinterpret_cast<const char *>(_Unwind_GetLanguageSpecificData(context));
+
+  // Handle descriptors before unwinding so they are processed in the context
+  // of the correct stack frame.
+  _Unwind_Reason_Code result =
+      ProcessDescriptors(state, ucbp, context, format, lsda,
+                         ucbp->pr_cache.additional);
+
+  if (result != _URC_CONTINUE_UNWIND)
+    return result;
+
+  if (__unw_step(reinterpret_cast<unw_cursor_t *>(context)) != UNW_STEP_SUCCESS)
+    return _URC_FAILURE;
+  return _URC_CONTINUE_UNWIND;
+}
+
+// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE /
+// _UVRSD_UINT32.
+uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) {
+  return ((1U << (count_minus_one + 1)) - 1) << start;
+}
+
+// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP /
+// _UVRSD_DOUBLE.
+uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) {
+  return ((uint32_t)start << 16) | ((uint32_t)count_minus_one + 1);
+}
+
+} // end anonymous namespace
+
+/**
+ * Decodes an EHT entry.
+ *
+ * @param data Pointer to EHT.
+ * @param[out] off Offset from return value (in bytes) to begin interpretation.
+ * @param[out] len Number of bytes in unwind code.
+ * @return Pointer to beginning of unwind code.
+ */
+extern "C" const uint32_t*
+decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {
+  if ((*data & 0x80000000) == 0) {
+    // 6.2: Generic Model
+    //
+    // EHT entry is a prel31 pointing to the PR, followed by data understood
+    // only by the personality routine. Fortunately, all existing assembler
+    // implementations, including GNU assembler, LLVM integrated assembler,
+    // and ARM assembler, assume that the unwind opcodes come after the
+    // personality rountine address.
+    *off = 1; // First byte is size data.
+    *len = (((data[1] >> 24) & 0xff) + 1) * 4;
+    data++; // Skip the first word, which is the prel31 offset.
+  } else {
+    // 6.3: ARM Compact Model
+    //
+    // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded
+    // by format:
+    Descriptor::Format format =
+        static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24);
+    switch (format) {
+      case Descriptor::SU16:
+        *len = 4;
+        *off = 1;
+        break;
+      case Descriptor::LU16:
+      case Descriptor::LU32:
+        *len = 4 + 4 * ((*data & 0x00ff0000) >> 16);
+        *off = 2;
+        break;
+      default:
+        return nullptr;
+    }
+  }
+  return data;
+}
+
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
+                      size_t offset, size_t len) {
+  bool wrotePC = false;
+  bool finish = false;
+  while (offset < len && !finish) {
+    uint8_t byte = getByte(data, offset++);
+    if ((byte & 0x80) == 0) {
+      uint32_t sp;
+      _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
+      if (byte & 0x40)
+        sp -= (((uint32_t)byte & 0x3f) << 2) + 4;
+      else
+        sp += ((uint32_t)byte << 2) + 4;
+      _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
+    } else {
+      switch (byte & 0xf0) {
+        case 0x80: {
+          if (offset >= len)
+            return _URC_FAILURE;
+          uint32_t registers =
+              (((uint32_t)byte & 0x0f) << 12) |
+              (((uint32_t)getByte(data, offset++)) << 4);
+          if (!registers)
+            return _URC_FAILURE;
+          if (registers & (1 << 15))
+            wrotePC = true;
+          _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);
+          break;
+        }
+        case 0x90: {
+          uint8_t reg = byte & 0x0f;
+          if (reg == 13 || reg == 15)
+            return _URC_FAILURE;
+          uint32_t sp;
+          _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg,
+                          _UVRSD_UINT32, &sp);
+          _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
+                          &sp);
+          break;
+        }
+        case 0xa0: {
+          uint32_t registers = RegisterMask(4, byte & 0x07);
+          if (byte & 0x08)
+            registers |= 1 << 14;
+          _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);
+          break;
+        }
+        case 0xb0: {
+          switch (byte) {
+            case 0xb0:
+              finish = true;
+              break;
+            case 0xb1: {
+              if (offset >= len)
+                return _URC_FAILURE;
+              uint8_t registers = getByte(data, offset++);
+              if (registers & 0xf0 || !registers)
+                return _URC_FAILURE;
+              _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);
+              break;
+            }
+            case 0xb2: {
+              uint32_t addend = 0;
+              uint32_t shift = 0;
+              // This decodes a uleb128 value.
+              while (true) {
+                if (offset >= len)
+                  return _URC_FAILURE;
+                uint32_t v = getByte(data, offset++);
+                addend |= (v & 0x7f) << shift;
+                if ((v & 0x80) == 0)
+                  break;
+                shift += 7;
+              }
+              uint32_t sp;
+              _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
+                              &sp);
+              sp += 0x204 + (addend << 2);
+              _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
+                              &sp);
+              break;
+            }
+            case 0xb3: {
+              uint8_t v = getByte(data, offset++);
+              _Unwind_VRS_Pop(context, _UVRSC_VFP,
+                              RegisterRange(static_cast<uint8_t>(v >> 4),
+                                            v & 0x0f), _UVRSD_VFPX);
+              break;
+            }
+            case 0xb4:
+            case 0xb5:
+            case 0xb6:
+            case 0xb7:
+              return _URC_FAILURE;
+            default:
+              _Unwind_VRS_Pop(context, _UVRSC_VFP,
+                              RegisterRange(8, byte & 0x07), _UVRSD_VFPX);
+              break;
+          }
+          break;
+        }
+        case 0xc0: {
+          switch (byte) {
+#if defined(__ARM_WMMX)
+            case 0xc0:
+            case 0xc1:
+            case 0xc2:
+            case 0xc3:
+            case 0xc4:
+            case 0xc5:
+              _Unwind_VRS_Pop(context, _UVRSC_WMMXD,
+                              RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE);
+              break;
+            case 0xc6: {
+              uint8_t v = getByte(data, offset++);
+              uint8_t start = static_cast<uint8_t>(v >> 4);
+              uint8_t count_minus_one = v & 0xf;
+              if (start + count_minus_one >= 16)
+                return _URC_FAILURE;
+              _Unwind_VRS_Pop(context, _UVRSC_WMMXD,
+                              RegisterRange(start, count_minus_one),
+                              _UVRSD_DOUBLE);
+              break;
+            }
+            case 0xc7: {
+              uint8_t v = getByte(data, offset++);
+              if (!v || v & 0xf0)
+                return _URC_FAILURE;
+              _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE);
+              break;
+            }
+#endif
+            case 0xc8:
+            case 0xc9: {
+              uint8_t v = getByte(data, offset++);
+              uint8_t start =
+                  static_cast<uint8_t>(((byte == 0xc8) ? 16 : 0) + (v >> 4));
+              uint8_t count_minus_one = v & 0xf;
+              if (start + count_minus_one >= 32)
+                return _URC_FAILURE;
+              _Unwind_VRS_Pop(context, _UVRSC_VFP,
+                              RegisterRange(start, count_minus_one),
+                              _UVRSD_DOUBLE);
+              break;
+            }
+            default:
+              return _URC_FAILURE;
+          }
+          break;
+        }
+        case 0xd0: {
+          if (byte & 0x08)
+            return _URC_FAILURE;
+          _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7),
+                          _UVRSD_DOUBLE);
+          break;
+        }
+        default:
+          return _URC_FAILURE;
+      }
+    }
+  }
+  if (!wrotePC) {
+    uint32_t lr;
+    _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr);
+    _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr);
+  }
+  return _URC_CONTINUE_UNWIND;
+}
+
+extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
+__aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp,
+                       _Unwind_Context *context) {
+  return unwindOneFrame(state, ucbp, context);
+}
+
+extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
+__aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp,
+                       _Unwind_Context *context) {
+  return unwindOneFrame(state, ucbp, context);
+}
+
+extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
+__aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp,
+                       _Unwind_Context *context) {
+  return unwindOneFrame(state, ucbp, context);
+}
+
+static _Unwind_Reason_Code
+unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
+  // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during
+  // phase 1 and then restoring it to the "primary VRS" for phase 2. The
+  // effect is phase 2 doesn't see any of the VRS manipulations from phase 1.
+  // In this implementation, the phases don't share the VRS backing store.
+  // Instead, they are passed the original |uc| and they create a new VRS
+  // from scratch thus achieving the same effect.
+  __unw_init_local(cursor, uc);
+
+  // Walk each frame looking for a place to stop.
+  for (bool handlerNotFound = true; handlerNotFound;) {
+
+    // See if frame has code to run (has personality routine).
+    unw_proc_info_t frameInfo;
+    if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): __unw_get_proc_info "
+          "failed => _URC_FATAL_PHASE1_ERROR",
+          static_cast<void *>(exception_object));
+      return _URC_FATAL_PHASE1_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionBuf[512];
+      const char *functionName = functionBuf;
+      unw_word_t offset;
+      if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
+                               &offset) != UNW_ESUCCESS) ||
+          (frameInfo.start_ip + offset > frameInfo.end_ip))
+        functionName = ".anonymous.";
+      unw_word_t pc;
+      __unw_get_reg(cursor, UNW_REG_IP, &pc);
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, "
+          "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
+          static_cast<void *>(exception_object), pc,
+          frameInfo.start_ip, functionName,
+          frameInfo.lsda, frameInfo.handler);
+    }
+
+    // If there is a personality routine, ask it if it will want to stop at
+    // this frame.
+    if (frameInfo.handler != 0) {
+      _Unwind_Personality_Fn p =
+          (_Unwind_Personality_Fn)(long)(frameInfo.handler);
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): calling personality function %p",
+          static_cast<void *>(exception_object),
+          reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p)));
+      struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor);
+      exception_object->pr_cache.fnstart = frameInfo.start_ip;
+      exception_object->pr_cache.ehtp =
+          (_Unwind_EHT_Header *)frameInfo.unwind_info;
+      exception_object->pr_cache.additional = frameInfo.flags;
+      _Unwind_Reason_Code personalityResult =
+          (*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context);
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p "
+          "additional %x",
+          static_cast<void *>(exception_object), personalityResult,
+          exception_object->pr_cache.fnstart,
+          static_cast<void *>(exception_object->pr_cache.ehtp),
+          exception_object->pr_cache.additional);
+      switch (personalityResult) {
+      case _URC_HANDLER_FOUND:
+        // found a catch clause or locals that need destructing in this frame
+        // stop search and remember stack pointer at the frame
+        handlerNotFound = false;
+        // p should have initialized barrier_cache. EHABI #7.3.5
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND",
+            static_cast<void *>(exception_object));
+        return _URC_NO_REASON;
+
+      case _URC_CONTINUE_UNWIND:
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",
+            static_cast<void *>(exception_object));
+        // continue unwinding
+        break;
+
+      // EHABI #7.3.3
+      case _URC_FAILURE:
+        return _URC_FAILURE;
+
+      default:
+        // something went wrong
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
+            static_cast<void *>(exception_object));
+        return _URC_FATAL_PHASE1_ERROR;
+      }
+    }
+  }
+  return _URC_NO_REASON;
+}
+
+static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor,
+                                         _Unwind_Exception *exception_object,
+                                         bool resume) {
+  // See comment at the start of unwind_phase1 regarding VRS integrity.
+  __unw_init_local(cursor, uc);
+
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
+                             static_cast<void *>(exception_object));
+  int frame_count = 0;
+
+  // Walk each frame until we reach where search phase said to stop.
+  while (true) {
+    // Ask libunwind to get next frame (skip over first which is
+    // _Unwind_RaiseException or _Unwind_Resume).
+    //
+    // Resume only ever makes sense for 1 frame.
+    _Unwind_State state =
+        resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING;
+    if (resume && frame_count == 1) {
+      // On a resume, first unwind the _Unwind_Resume() frame. The next frame
+      // is now the landing pad for the cleanup from a previous execution of
+      // phase2. To continue unwindingly correctly, replace VRS[15] with the
+      // IP of the frame that the previous run of phase2 installed the context
+      // for. After this, continue unwinding as if normal.
+      //
+      // See #7.4.6 for details.
+      __unw_set_reg(cursor, UNW_REG_IP,
+                    exception_object->unwinder_cache.reserved2);
+      resume = false;
+    }
+
+    // Get info about this frame.
+    unw_word_t sp;
+    unw_proc_info_t frameInfo;
+    __unw_get_reg(cursor, UNW_REG_SP, &sp);
+    if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2(ex_ojb=%p): __unw_get_proc_info "
+          "failed => _URC_FATAL_PHASE2_ERROR",
+          static_cast<void *>(exception_object));
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionBuf[512];
+      const char *functionName = functionBuf;
+      unw_word_t offset;
+      if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
+                               &offset) != UNW_ESUCCESS) ||
+          (frameInfo.start_ip + offset > frameInfo.end_ip))
+        functionName = ".anonymous.";
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", "
+          "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
+          static_cast<void *>(exception_object), frameInfo.start_ip,
+          functionName, sp, frameInfo.lsda,
+          frameInfo.handler);
+    }
+
+    // If there is a personality routine, tell it we are unwinding.
+    if (frameInfo.handler != 0) {
+      _Unwind_Personality_Fn p =
+          (_Unwind_Personality_Fn)(long)(frameInfo.handler);
+      struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor);
+      // EHABI #7.2
+      exception_object->pr_cache.fnstart = frameInfo.start_ip;
+      exception_object->pr_cache.ehtp =
+          (_Unwind_EHT_Header *)frameInfo.unwind_info;
+      exception_object->pr_cache.additional = frameInfo.flags;
+      _Unwind_Reason_Code personalityResult =
+          (*p)(state, exception_object, context);
+      switch (personalityResult) {
+      case _URC_CONTINUE_UNWIND:
+        // Continue unwinding
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
+            static_cast<void *>(exception_object));
+        // EHABI #7.2
+        if (sp == exception_object->barrier_cache.sp) {
+          // Phase 1 said we would stop at this frame, but we did not...
+          _LIBUNWIND_ABORT("during phase1 personality function said it would "
+                           "stop here, but now in phase2 it did not stop here");
+        }
+        break;
+      case _URC_INSTALL_CONTEXT:
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT",
+            static_cast<void *>(exception_object));
+        // Personality routine says to transfer control to landing pad.
+        // We may get control back if landing pad calls _Unwind_Resume().
+        if (_LIBUNWIND_TRACING_UNWINDING) {
+          unw_word_t pc;
+          __unw_get_reg(cursor, UNW_REG_IP, &pc);
+          __unw_get_reg(cursor, UNW_REG_SP, &sp);
+          _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
+                                     "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR,
+                                     static_cast<void *>(exception_object),
+                                     pc, sp);
+        }
+
+        {
+          // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume
+          // is called back, to find this same frame.
+          unw_word_t pc;
+          __unw_get_reg(cursor, UNW_REG_IP, &pc);
+          exception_object->unwinder_cache.reserved2 = (uint32_t)pc;
+        }
+        __unw_resume(cursor);
+        // __unw_resume() only returns if there was an error.
+        return _URC_FATAL_PHASE2_ERROR;
+
+      // # EHABI #7.4.3
+      case _URC_FAILURE:
+        abort();
+
+      default:
+        // Personality routine returned an unknown result code.
+        _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
+                      personalityResult);
+        return _URC_FATAL_PHASE2_ERROR;
+      }
+    }
+    frame_count++;
+  }
+
+  // Clean up phase did not resume at the frame that the search phase
+  // said it would...
+  return _URC_FATAL_PHASE2_ERROR;
+}
+
+/// Called by __cxa_throw.  Only returns if there is a fatal error.
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_RaiseException(_Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
+                       static_cast<void *>(exception_object));
+  unw_context_t uc;
+  unw_cursor_t cursor;
+  __unw_getcontext(&uc);
+
+  // This field for is for compatibility with GCC to say this isn't a forced
+  // unwind. EHABI #7.2
+  exception_object->unwinder_cache.reserved1 = 0;
+
+  // phase 1: the search phase
+  _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object);
+  if (phase1 != _URC_NO_REASON)
+    return phase1;
+
+  // phase 2: the clean up phase
+  return unwind_phase2(&uc, &cursor, exception_object, false);
+}
+
+_LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) {
+  // This is to be called when exception handling completes to give us a chance
+  // to perform any housekeeping. EHABI #7.2. But we have nothing to do here.
+  (void)exception_object;
+}
+
+/// When _Unwind_RaiseException() is in phase2, it hands control
+/// to the personality function at each frame.  The personality
+/// may force a jump to a landing pad in that function, the landing
+/// pad code may then call _Unwind_Resume() to continue with the
+/// unwinding.  Note: the call to _Unwind_Resume() is from compiler
+/// geneated user code.  All other _Unwind_* routines are called
+/// by the C++ runtime __cxa_* routines.
+///
+/// Note: re-throwing an exception (as opposed to continuing the unwind)
+/// is implemented by having the code call __cxa_rethrow() which
+/// in turn calls _Unwind_Resume_or_Rethrow().
+_LIBUNWIND_EXPORT void
+_Unwind_Resume(_Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)",
+                       static_cast<void *>(exception_object));
+  unw_context_t uc;
+  unw_cursor_t cursor;
+  __unw_getcontext(&uc);
+
+  // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,
+  // which is in the same position as private_1 below.
+  // TODO(ajwong): Who wronte the above? Why is it true?
+  unwind_phase2(&uc, &cursor, exception_object, true);
+
+  // Clients assume _Unwind_Resume() does not return, so all we can do is abort.
+  _LIBUNWIND_ABORT("_Unwind_Resume() can't return");
+}
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_proc_info_t frameInfo;
+  uintptr_t result = 0;
+  if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
+    result = (uintptr_t)frameInfo.lsda;
+  _LIBUNWIND_TRACE_API(
+      "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx",
+      static_cast<void *>(context), (long long)result);
+  return result;
+}
+
+static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation,
+                                  void* valuep) {
+  uint64_t value = 0;
+  switch (representation) {
+    case _UVRSD_UINT32:
+    case _UVRSD_FLOAT:
+      memcpy(&value, valuep, sizeof(uint32_t));
+      break;
+
+    case _UVRSD_VFPX:
+    case _UVRSD_UINT64:
+    case _UVRSD_DOUBLE:
+      memcpy(&value, valuep, sizeof(uint64_t));
+      break;
+  }
+  return value;
+}
+
+_LIBUNWIND_EXPORT _Unwind_VRS_Result
+_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+                uint32_t regno, _Unwind_VRS_DataRepresentation representation,
+                void *valuep) {
+  _LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, "
+                       "rep=%d, value=0x%llX)",
+                       static_cast<void *>(context), regclass, regno,
+                       representation,
+                       ValueAsBitPattern(representation, valuep));
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  switch (regclass) {
+    case _UVRSC_CORE:
+      if (representation != _UVRSD_UINT32 || regno > 15)
+        return _UVRSR_FAILED;
+      return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno),
+                           *(unw_word_t *)valuep) == UNW_ESUCCESS
+                 ? _UVRSR_OK
+                 : _UVRSR_FAILED;
+    case _UVRSC_VFP:
+      if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
+        return _UVRSR_FAILED;
+      if (representation == _UVRSD_VFPX) {
+        // Can only touch d0-15 with FSTMFDX.
+        if (regno > 15)
+          return _UVRSR_FAILED;
+        __unw_save_vfp_as_X(cursor);
+      } else {
+        if (regno > 31)
+          return _UVRSR_FAILED;
+      }
+      return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno),
+                             *(unw_fpreg_t *)valuep) == UNW_ESUCCESS
+                 ? _UVRSR_OK
+                 : _UVRSR_FAILED;
+#if defined(__ARM_WMMX)
+    case _UVRSC_WMMXC:
+      if (representation != _UVRSD_UINT32 || regno > 3)
+        return _UVRSR_FAILED;
+      return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
+                           *(unw_word_t *)valuep) == UNW_ESUCCESS
+                 ? _UVRSR_OK
+                 : _UVRSR_FAILED;
+    case _UVRSC_WMMXD:
+      if (representation != _UVRSD_DOUBLE || regno > 31)
+        return _UVRSR_FAILED;
+      return __unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno),
+                             *(unw_fpreg_t *)valuep) == UNW_ESUCCESS
+                 ? _UVRSR_OK
+                 : _UVRSR_FAILED;
+#else
+    case _UVRSC_WMMXC:
+    case _UVRSC_WMMXD:
+      break;
+#endif
+  }
+  _LIBUNWIND_ABORT("unsupported register class");
+}
+
+static _Unwind_VRS_Result
+_Unwind_VRS_Get_Internal(_Unwind_Context *context,
+                         _Unwind_VRS_RegClass regclass, uint32_t regno,
+                         _Unwind_VRS_DataRepresentation representation,
+                         void *valuep) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  switch (regclass) {
+    case _UVRSC_CORE:
+      if (representation != _UVRSD_UINT32 || regno > 15)
+        return _UVRSR_FAILED;
+      return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno),
+                           (unw_word_t *)valuep) == UNW_ESUCCESS
+                 ? _UVRSR_OK
+                 : _UVRSR_FAILED;
+    case _UVRSC_VFP:
+      if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
+        return _UVRSR_FAILED;
+      if (representation == _UVRSD_VFPX) {
+        // Can only touch d0-15 with FSTMFDX.
+        if (regno > 15)
+          return _UVRSR_FAILED;
+        __unw_save_vfp_as_X(cursor);
+      } else {
+        if (regno > 31)
+          return _UVRSR_FAILED;
+      }
+      return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno),
+                             (unw_fpreg_t *)valuep) == UNW_ESUCCESS
+                 ? _UVRSR_OK
+                 : _UVRSR_FAILED;
+#if defined(__ARM_WMMX)
+    case _UVRSC_WMMXC:
+      if (representation != _UVRSD_UINT32 || regno > 3)
+        return _UVRSR_FAILED;
+      return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
+                           (unw_word_t *)valuep) == UNW_ESUCCESS
+                 ? _UVRSR_OK
+                 : _UVRSR_FAILED;
+    case _UVRSC_WMMXD:
+      if (representation != _UVRSD_DOUBLE || regno > 31)
+        return _UVRSR_FAILED;
+      return __unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno),
+                             (unw_fpreg_t *)valuep) == UNW_ESUCCESS
+                 ? _UVRSR_OK
+                 : _UVRSR_FAILED;
+#else
+    case _UVRSC_WMMXC:
+    case _UVRSC_WMMXD:
+      break;
+#endif
+  }
+  _LIBUNWIND_ABORT("unsupported register class");
+}
+
+_LIBUNWIND_EXPORT _Unwind_VRS_Result
+_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+                uint32_t regno, _Unwind_VRS_DataRepresentation representation,
+                void *valuep) {
+  _Unwind_VRS_Result result =
+      _Unwind_VRS_Get_Internal(context, regclass, regno, representation,
+                               valuep);
+  _LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, "
+                       "rep=%d, value=0x%llX, result = %d)",
+                       static_cast<void *>(context), regclass, regno,
+                       representation,
+                       ValueAsBitPattern(representation, valuep), result);
+  return result;
+}
+
+_Unwind_VRS_Result
+_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+                uint32_t discriminator,
+                _Unwind_VRS_DataRepresentation representation) {
+  _LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, "
+                       "discriminator=%d, representation=%d)",
+                       static_cast<void *>(context), regclass, discriminator,
+                       representation);
+  switch (regclass) {
+    case _UVRSC_WMMXC:
+#if !defined(__ARM_WMMX)
+      break;
+#endif
+    case _UVRSC_CORE: {
+      if (representation != _UVRSD_UINT32)
+        return _UVRSR_FAILED;
+      // When popping SP from the stack, we don't want to override it from the
+      // computed new stack location. See EHABI #7.5.4 table 3.
+      bool poppedSP = false;
+      uint32_t* sp;
+      if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP,
+                          _UVRSD_UINT32, &sp) != _UVRSR_OK) {
+        return _UVRSR_FAILED;
+      }
+      for (uint32_t i = 0; i < 16; ++i) {
+        if (!(discriminator & static_cast<uint32_t>(1 << i)))
+          continue;
+        uint32_t value = *sp++;
+        if (regclass == _UVRSC_CORE && i == 13)
+          poppedSP = true;
+        if (_Unwind_VRS_Set(context, regclass, i,
+                            _UVRSD_UINT32, &value) != _UVRSR_OK) {
+          return _UVRSR_FAILED;
+        }
+      }
+      if (!poppedSP) {
+        return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP,
+                               _UVRSD_UINT32, &sp);
+      }
+      return _UVRSR_OK;
+    }
+    case _UVRSC_WMMXD:
+#if !defined(__ARM_WMMX)
+      break;
+#endif
+    case _UVRSC_VFP: {
+      if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
+        return _UVRSR_FAILED;
+      uint32_t first = discriminator >> 16;
+      uint32_t count = discriminator & 0xffff;
+      uint32_t end = first+count;
+      uint32_t* sp;
+      if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP,
+                          _UVRSD_UINT32, &sp) != _UVRSR_OK) {
+        return _UVRSR_FAILED;
+      }
+      // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard
+      // format 1", which is equivalent to FSTMD + a padding word.
+      for (uint32_t i = first; i < end; ++i) {
+        // SP is only 32-bit aligned so don't copy 64-bit at a time.
+        uint64_t w0 = *sp++;
+        uint64_t w1 = *sp++;
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+        uint64_t value = (w1 << 32) | w0;
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+        uint64_t value = (w0 << 32) | w1;
+#else
+#error "Unable to determine endianess"
+#endif
+        if (_Unwind_VRS_Set(context, regclass, i, representation, &value) !=
+            _UVRSR_OK)
+          return _UVRSR_FAILED;
+      }
+      if (representation == _UVRSD_VFPX)
+        ++sp;
+      return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
+                             &sp);
+    }
+  }
+  _LIBUNWIND_ABORT("unsupported register class");
+}
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_proc_info_t frameInfo;
+  uintptr_t result = 0;
+  if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
+    result = (uintptr_t)frameInfo.start_ip;
+  _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX",
+                       static_cast<void *>(context), (long long)result);
+  return result;
+}
+
+
+/// Called by personality handler during phase 2 if a foreign exception
+// is caught.
+_LIBUNWIND_EXPORT void
+_Unwind_DeleteException(_Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
+                       static_cast<void *>(exception_object));
+  if (exception_object->exception_cleanup != NULL)
+    (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
+                                           exception_object);
+}
+
+extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
+__gnu_unwind_frame(_Unwind_Exception *exception_object,
+                   struct _Unwind_Context *context) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  if (__unw_step(cursor) != UNW_STEP_SUCCESS)
+    return _URC_FAILURE;
+  return _URC_OK;
+}
+
+#endif  // defined(_LIBUNWIND_ARM_EHABI)

+ 50 - 0
llvm-libunwind/src/Unwind-EHABI.h

@@ -0,0 +1,50 @@
+//===------------------------- Unwind-EHABI.hpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_EHABI_H__
+#define __UNWIND_EHABI_H__
+
+#include <__libunwind_config.h>
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+
+#include <stdint.h>
+#include <unwind.h>
+
+// Unable to unwind in the ARM index table (section 5 EHABI).
+#define UNW_EXIDX_CANTUNWIND 0x1
+
+static inline uint32_t signExtendPrel31(uint32_t data) {
+  return data | ((data & 0x40000000u) << 1);
+}
+
+static inline uint32_t readPrel31(const uint32_t *data) {
+  return (((uint32_t)(uintptr_t)data) + signExtendPrel31(*data));
+}
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(
+    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(
+    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
+    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+#endif // defined(_LIBUNWIND_ARM_EHABI)
+
+#endif  // __UNWIND_EHABI_H__

+ 489 - 0
llvm-libunwind/src/Unwind-seh.cpp

@@ -0,0 +1,489 @@
+//===--------------------------- Unwind-seh.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  Implements SEH-based Itanium C++ exceptions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "config.h"
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+
+#include <unwind.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <windef.h>
+#include <excpt.h>
+#include <winnt.h>
+#include <ntstatus.h>
+
+#include "libunwind_ext.h"
+#include "UnwindCursor.hpp"
+
+using namespace libunwind;
+
+#define STATUS_USER_DEFINED (1u << 29)
+
+#define STATUS_GCC_MAGIC  (('G' << 16) | ('C' << 8) | 'C')
+
+#define MAKE_CUSTOM_STATUS(s, c) \
+  ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c)))
+#define MAKE_GCC_EXCEPTION(c) \
+  MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24))
+
+/// SEH exception raised by libunwind when the program calls
+/// \c _Unwind_RaiseException.
+#define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343
+/// SEH exception raised by libunwind to initiate phase 2 of exception
+/// handling.
+#define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343
+
+static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx);
+static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor);
+static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
+                                   DISPATCHER_CONTEXT *disp);
+
+/// Common implementation of SEH-style handler functions used by Itanium-
+/// style frames.  Depending on how and why it was called, it may do one of:
+///  a) Delegate to the given Itanium-style personality function; or
+///  b) Initiate a collided unwind to halt unwinding.
+_LIBUNWIND_EXPORT EXCEPTION_DISPOSITION
+_GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
+                      DISPATCHER_CONTEXT *disp, _Unwind_Personality_Fn pers) {
+  unw_cursor_t cursor;
+  _Unwind_Exception *exc;
+  _Unwind_Action action;
+  struct _Unwind_Context *ctx = nullptr;
+  _Unwind_Reason_Code urc;
+  uintptr_t retval, target;
+  bool ours = false;
+
+  _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010lx(%lx), %p)",
+                             ms_exc->ExceptionCode, ms_exc->ExceptionFlags,
+                             (void *)frame);
+  if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) {
+    if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) {
+      // Set up the upper return value (the lower one and the target PC
+      // were set in the call to RtlUnwindEx()) for the landing pad.
+#ifdef __x86_64__
+      disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3];
+#elif defined(__arm__)
+      disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3];
+#elif defined(__aarch64__)
+      disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3];
+#endif
+    }
+    // This is the collided unwind to the landing pad. Nothing to do.
+    return ExceptionContinueSearch;
+  }
+
+  if (ms_exc->ExceptionCode == STATUS_GCC_THROW) {
+    // This is (probably) a libunwind-controlled exception/unwind. Recover the
+    // parameters which we set below, and pass them to the personality function.
+    ours = true;
+    exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0];
+    if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) {
+      ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1];
+      action = (_Unwind_Action)ms_exc->ExceptionInformation[2];
+    }
+  } else {
+    // Foreign exception.
+    // We can't interact with them (we don't know the original target frame
+    // that we should pass on to RtlUnwindEx in _Unwind_Resume), so just
+    // pass without calling our destructors here.
+    return ExceptionContinueSearch;
+  }
+  if (!ctx) {
+    __unw_init_seh(&cursor, disp->ContextRecord);
+    __unw_seh_set_disp_ctx(&cursor, disp);
+    __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc - 1);
+    ctx = (struct _Unwind_Context *)&cursor;
+
+    if (!IS_UNWINDING(ms_exc->ExceptionFlags)) {
+      if (ours && ms_exc->NumberParameters > 1)
+        action =  (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND);
+      else
+        action = _UA_SEARCH_PHASE;
+    } else {
+      if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame)
+        action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
+      else
+        action = _UA_CLEANUP_PHASE;
+    }
+  }
+
+  _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality "
+                             "function %p(1, %d, %llx, %p, %p)",
+                             (void *)pers, action, exc->exception_class,
+                             (void *)exc, (void *)ctx);
+  urc = pers(1, action, exc->exception_class, exc, ctx);
+  _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc);
+  switch (urc) {
+  case _URC_CONTINUE_UNWIND:
+    // If we're in phase 2, and the personality routine said to continue
+    // at the target frame, we're in real trouble.
+    if (action & _UA_HANDLER_FRAME)
+      _LIBUNWIND_ABORT("Personality continued unwind at the target frame!");
+    return ExceptionContinueSearch;
+  case _URC_HANDLER_FOUND:
+    // If we were called by __libunwind_seh_personality(), indicate that
+    // a handler was found; otherwise, initiate phase 2 by unwinding.
+    if (ours && ms_exc->NumberParameters > 1)
+      return 4 /* ExecptionExecuteHandler in mingw */;
+    // This should never happen in phase 2.
+    if (IS_UNWINDING(ms_exc->ExceptionFlags))
+      _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!");
+    exc->private_[1] = (ULONG_PTR)frame;
+    if (ours) {
+      ms_exc->NumberParameters = 4;
+      ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame;
+    }
+    // FIXME: Indicate target frame in foreign case!
+    // phase 2: the clean up phase
+    RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable);
+    _LIBUNWIND_ABORT("RtlUnwindEx() failed");
+  case _URC_INSTALL_CONTEXT: {
+    // If we were called by __libunwind_seh_personality(), indicate that
+    // a handler was found; otherwise, it's time to initiate a collided
+    // unwind to the target.
+    if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1)
+      return 4 /* ExecptionExecuteHandler in mingw */;
+    // This should never happen in phase 1.
+    if (!IS_UNWINDING(ms_exc->ExceptionFlags))
+      _LIBUNWIND_ABORT("Personality installed context during phase 1!");
+#ifdef __x86_64__
+    exc->private_[2] = disp->TargetIp;
+    __unw_get_reg(&cursor, UNW_X86_64_RAX, &retval);
+    __unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]);
+#elif defined(__arm__)
+    exc->private_[2] = disp->TargetPc;
+    __unw_get_reg(&cursor, UNW_ARM_R0, &retval);
+    __unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]);
+#elif defined(__aarch64__)
+    exc->private_[2] = disp->TargetPc;
+    __unw_get_reg(&cursor, UNW_ARM64_X0, &retval);
+    __unw_get_reg(&cursor, UNW_ARM64_X1, &exc->private_[3]);
+#endif
+    __unw_get_reg(&cursor, UNW_REG_IP, &target);
+    ms_exc->ExceptionCode = STATUS_GCC_UNWIND;
+#ifdef __x86_64__
+    ms_exc->ExceptionInformation[2] = disp->TargetIp;
+#elif defined(__arm__) || defined(__aarch64__)
+    ms_exc->ExceptionInformation[2] = disp->TargetPc;
+#endif
+    ms_exc->ExceptionInformation[3] = exc->private_[3];
+    // Give NTRTL some scratch space to keep track of the collided unwind.
+    // Don't use the one that was passed in; we don't want to overwrite the
+    // context in the DISPATCHER_CONTEXT.
+    CONTEXT new_ctx;
+    RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable);
+    _LIBUNWIND_ABORT("RtlUnwindEx() failed");
+  }
+  // Anything else indicates a serious problem.
+  default: return ExceptionContinueExecution;
+  }
+}
+
+/// Personality function returned by \c __unw_get_proc_info() in SEH contexts.
+/// This is a wrapper that calls the real SEH handler function, which in
+/// turn (at least, for Itanium-style frames) calls the real Itanium
+/// personality function (see \c _GCC_specific_handler()).
+extern "C" _Unwind_Reason_Code
+__libunwind_seh_personality(int version, _Unwind_Action state,
+                            uint64_t klass, _Unwind_Exception *exc,
+                            struct _Unwind_Context *context) {
+  (void)version;
+  (void)klass;
+  EXCEPTION_RECORD ms_exc;
+  bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE;
+  ms_exc.ExceptionCode = STATUS_GCC_THROW;
+  ms_exc.ExceptionFlags = 0;
+  ms_exc.NumberParameters = 3;
+  ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc;
+  ms_exc.ExceptionInformation[1] = (ULONG_PTR)context;
+  ms_exc.ExceptionInformation[2] = state;
+  DISPATCHER_CONTEXT *disp_ctx =
+      __unw_seh_get_disp_ctx((unw_cursor_t *)context);
+  EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc,
+                                                           (PVOID)disp_ctx->EstablisherFrame,
+                                                           disp_ctx->ContextRecord,
+                                                           disp_ctx);
+  switch (ms_act) {
+  case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND;
+  case 4 /*ExceptionExecuteHandler*/:
+    return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND;
+  default:
+    return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR;
+  }
+}
+
+static _Unwind_Reason_Code
+unwind_phase2_forced(unw_context_t *uc,
+                     _Unwind_Exception *exception_object,
+                     _Unwind_Stop_Fn stop, void *stop_parameter) {
+  unw_cursor_t cursor2;
+  __unw_init_local(&cursor2, uc);
+
+  // Walk each frame until we reach where search phase said to stop
+  while (__unw_step(&cursor2) > 0) {
+
+    // Update info about this frame.
+    unw_proc_info_t frameInfo;
+    if (__unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step "
+                                 "failed => _URC_END_OF_STACK",
+                                 (void *)exception_object);
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionBuf[512];
+      const char *functionName = functionBuf;
+      unw_word_t offset;
+      if ((__unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf),
+                               &offset) != UNW_ESUCCESS) ||
+          (frameInfo.start_ip + offset > frameInfo.end_ip))
+        functionName = ".anonymous.";
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64
+          ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64,
+          (void *)exception_object, frameInfo.start_ip, functionName,
+          frameInfo.lsda, frameInfo.handler);
+    }
+
+    // Call stop function at each frame.
+    _Unwind_Action action =
+        (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
+    _Unwind_Reason_Code stopResult =
+        (*stop)(1, action, exception_object->exception_class, exception_object,
+                (struct _Unwind_Context *)(&cursor2), stop_parameter);
+    _LIBUNWIND_TRACE_UNWINDING(
+        "unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
+        (void *)exception_object, stopResult);
+    if (stopResult != _URC_NO_REASON) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
+          (void *)exception_object);
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // If there is a personality routine, tell it we are unwinding.
+    if (frameInfo.handler != 0) {
+      _Unwind_Personality_Fn p =
+          (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
+          (void *)exception_object, (void *)(uintptr_t)p);
+      _Unwind_Reason_Code personalityResult =
+          (*p)(1, action, exception_object->exception_class, exception_object,
+               (struct _Unwind_Context *)(&cursor2));
+      switch (personalityResult) {
+      case _URC_CONTINUE_UNWIND:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned "
+                                   "_URC_CONTINUE_UNWIND",
+                                   (void *)exception_object);
+        // Destructors called, continue unwinding
+        break;
+      case _URC_INSTALL_CONTEXT:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned "
+                                   "_URC_INSTALL_CONTEXT",
+                                   (void *)exception_object);
+        // We may get control back if landing pad calls _Unwind_Resume().
+        __unw_resume(&cursor2);
+        break;
+      default:
+        // Personality routine returned an unknown result code.
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned %d, "
+                                   "_URC_FATAL_PHASE2_ERROR",
+                                   (void *)exception_object, personalityResult);
+        return _URC_FATAL_PHASE2_ERROR;
+      }
+    }
+  }
+
+  // Call stop function one last time and tell it we've reached the end
+  // of the stack.
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
+                             "function with _UA_END_OF_STACK",
+                             (void *)exception_object);
+  _Unwind_Action lastAction =
+      (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
+  (*stop)(1, lastAction, exception_object->exception_class, exception_object,
+          (struct _Unwind_Context *)(&cursor2), stop_parameter);
+
+  // Clean up phase did not resume at the frame that the search phase said it
+  // would.
+  return _URC_FATAL_PHASE2_ERROR;
+}
+
+/// Called by \c __cxa_throw().  Only returns if there is a fatal error.
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_RaiseException(_Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
+                       (void *)exception_object);
+
+  // Mark that this is a non-forced unwind, so _Unwind_Resume()
+  // can do the right thing.
+  memset(exception_object->private_, 0, sizeof(exception_object->private_));
+
+  // phase 1: the search phase
+  // We'll let the system do that for us.
+  RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object);
+
+  // If we get here, either something went horribly wrong or we reached the
+  // top of the stack. Either way, let libc++abi call std::terminate().
+  return _URC_END_OF_STACK;
+}
+
+/// When \c _Unwind_RaiseException() is in phase2, it hands control
+/// to the personality function at each frame.  The personality
+/// may force a jump to a landing pad in that function; the landing
+/// pad code may then call \c _Unwind_Resume() to continue with the
+/// unwinding.  Note: the call to \c _Unwind_Resume() is from compiler
+/// geneated user code.  All other \c _Unwind_* routines are called
+/// by the C++ runtime \c __cxa_* routines.
+///
+/// Note: re-throwing an exception (as opposed to continuing the unwind)
+/// is implemented by having the code call \c __cxa_rethrow() which
+/// in turn calls \c _Unwind_Resume_or_Rethrow().
+_LIBUNWIND_EXPORT void
+_Unwind_Resume(_Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);
+
+  if (exception_object->private_[0] != 0) {
+    unw_context_t uc;
+
+    __unw_getcontext(&uc);
+    unwind_phase2_forced(&uc, exception_object,
+                         (_Unwind_Stop_Fn) exception_object->private_[0],
+                         (void *)exception_object->private_[4]);
+  } else {
+    // Recover the parameters for the unwind from the exception object
+    // so we can start unwinding again.
+    EXCEPTION_RECORD ms_exc;
+    CONTEXT ms_ctx;
+    UNWIND_HISTORY_TABLE hist;
+
+    memset(&ms_exc, 0, sizeof(ms_exc));
+    memset(&hist, 0, sizeof(hist));
+    ms_exc.ExceptionCode = STATUS_GCC_THROW;
+    ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
+    ms_exc.NumberParameters = 4;
+    ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object;
+    ms_exc.ExceptionInformation[1] = exception_object->private_[1];
+    ms_exc.ExceptionInformation[2] = exception_object->private_[2];
+    ms_exc.ExceptionInformation[3] = exception_object->private_[3];
+    RtlUnwindEx((PVOID)exception_object->private_[1],
+                (PVOID)exception_object->private_[2], &ms_exc,
+                exception_object, &ms_ctx, &hist);
+  }
+
+  // Clients assume _Unwind_Resume() does not return, so all we can do is abort.
+  _LIBUNWIND_ABORT("_Unwind_Resume() can't return");
+}
+
+/// Not used by C++.
+/// Unwinds stack, calling "stop" function at each frame.
+/// Could be used to implement \c longjmp().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
+                     _Unwind_Stop_Fn stop, void *stop_parameter) {
+  _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",
+                       (void *)exception_object, (void *)(uintptr_t)stop);
+  unw_context_t uc;
+  __unw_getcontext(&uc);
+
+  // Mark that this is a forced unwind, so _Unwind_Resume() can do
+  // the right thing.
+  exception_object->private_[0] = (uintptr_t) stop;
+  exception_object->private_[4] = (uintptr_t) stop_parameter;
+
+  // do it
+  return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
+}
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
+  uintptr_t result =
+      (uintptr_t)__unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData;
+  _LIBUNWIND_TRACE_API(
+      "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
+      (void *)context, result);
+  return result;
+}
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+  DISPATCHER_CONTEXT *disp = __unw_seh_get_disp_ctx((unw_cursor_t *)context);
+  uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase;
+  _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,
+                       (void *)context, result);
+  return result;
+}
+
+static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) {
+#ifdef _LIBUNWIND_TARGET_X86_64
+  new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor))
+      UnwindCursor<LocalAddressSpace, Registers_x86_64>(
+          context, LocalAddressSpace::sThisAddressSpace);
+  auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
+  co->setInfoBasedOnIPRegister();
+  return UNW_ESUCCESS;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+  new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor))
+      UnwindCursor<LocalAddressSpace, Registers_arm>(
+          context, LocalAddressSpace::sThisAddressSpace);
+  auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
+  co->setInfoBasedOnIPRegister();
+  return UNW_ESUCCESS;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor))
+      UnwindCursor<LocalAddressSpace, Registers_arm64>(
+          context, LocalAddressSpace::sThisAddressSpace);
+  auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
+  co->setInfoBasedOnIPRegister();
+  return UNW_ESUCCESS;
+#else
+  return UNW_EINVAL;
+#endif
+}
+
+static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor) {
+#ifdef _LIBUNWIND_TARGET_X86_64
+  return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext();
+#elif defined(_LIBUNWIND_TARGET_ARM)
+  return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext();
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->getDispatcherContext();
+#else
+  return nullptr;
+#endif
+}
+
+static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
+                                   DISPATCHER_CONTEXT *disp) {
+#ifdef _LIBUNWIND_TARGET_X86_64
+  reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp);
+#elif defined(_LIBUNWIND_TARGET_ARM)
+  reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp);
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp);
+#endif
+}
+
+#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)

+ 528 - 0
llvm-libunwind/src/Unwind-sjlj.c

@@ -0,0 +1,528 @@
+//===--------------------------- Unwind-sjlj.c ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Implements setjump-longjump based C++ exceptions
+//
+//===----------------------------------------------------------------------===//
+
+#include <unwind.h>
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+/// With SJLJ based exceptions, any function that has a catch clause or needs to
+/// do any clean up when an exception propagates through it, needs to call
+/// \c _Unwind_SjLj_Register at the start of the function and
+/// \c _Unwind_SjLj_Unregister at the end.  The register function is called with
+/// the address of a block of memory in the function's stack frame.  The runtime
+/// keeps a linked list (stack) of these blocks - one per thread.  The calling
+/// function also sets the personality and lsda fields of the block.
+
+#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
+
+struct _Unwind_FunctionContext {
+  // next function in stack of handlers
+  struct _Unwind_FunctionContext *prev;
+
+#if defined(__ve__)
+  // VE requires to store 64 bit pointers in the buffer for SjLj execption.
+  // We expand the size of values defined here.  This size must be matched
+  // to the size returned by TargetMachine::getSjLjDataSize().
+
+  // set by calling function before registering to be the landing pad
+  uint64_t                        resumeLocation;
+
+  // set by personality handler to be parameters passed to landing pad function
+  uint64_t                        resumeParameters[4];
+#else
+  // set by calling function before registering to be the landing pad
+  uint32_t                        resumeLocation;
+
+  // set by personality handler to be parameters passed to landing pad function
+  uint32_t                        resumeParameters[4];
+#endif
+
+  // set by calling function before registering
+  _Unwind_Personality_Fn personality;          // arm offset=24
+  uintptr_t                       lsda;        // arm offset=28
+
+  // variable length array, contains registers to restore
+  // 0 = r7, 1 = pc, 2 = sp
+  void                           *jbuf[];
+};
+
+#if defined(_LIBUNWIND_HAS_NO_THREADS)
+# define _LIBUNWIND_THREAD_LOCAL
+#else
+# if __STDC_VERSION__ >= 201112L
+#  define _LIBUNWIND_THREAD_LOCAL _Thread_local
+# elif defined(_MSC_VER)
+#  define _LIBUNWIND_THREAD_LOCAL __declspec(thread)
+# elif defined(__GNUC__) || defined(__clang__)
+#  define _LIBUNWIND_THREAD_LOCAL __thread
+# else
+#  error Unable to create thread local storage
+# endif
+#endif
+
+
+#if !defined(FOR_DYLD)
+
+#if defined(__APPLE__)
+#include <System/pthread_machdep.h>
+#else
+static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL;
+#endif
+
+static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
+#if defined(__APPLE__)
+  return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
+#else
+  return stack;
+#endif
+}
+
+static void
+__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
+#if defined(__APPLE__)
+  _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
+#else
+  stack = fc;
+#endif
+}
+
+#endif
+
+
+/// Called at start of each function that catches exceptions
+_LIBUNWIND_EXPORT void
+_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) {
+  fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
+  __Unwind_SjLj_SetTopOfFunctionStack(fc);
+}
+
+
+/// Called at end of each function that catches exceptions
+_LIBUNWIND_EXPORT void
+_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {
+  __Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase1(struct _Unwind_Exception *exception_object) {
+  _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p",
+                             (void *)c);
+
+  // walk each frame looking for a place to stop
+  for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
+
+    // check for no more frames
+    if (c == NULL) {
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
+                                 "bottom => _URC_END_OF_STACK",
+                                 (void *)exception_object);
+      return _URC_END_OF_STACK;
+    }
+
+    _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c);
+    // if there is a personality routine, ask it if it will want to stop at this
+    // frame
+    if (c->personality != NULL) {
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "
+                                 "personality function %p",
+                                 (void *)exception_object,
+                                 (void *)c->personality);
+      _Unwind_Reason_Code personalityResult = (*c->personality)(
+          1, _UA_SEARCH_PHASE, exception_object->exception_class,
+          exception_object, (struct _Unwind_Context *)c);
+      switch (personalityResult) {
+      case _URC_HANDLER_FOUND:
+        // found a catch clause or locals that need destructing in this frame
+        // stop search and remember function context
+        handlerNotFound = false;
+        exception_object->private_2 = (uintptr_t) c;
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
+                                   "_URC_HANDLER_FOUND",
+                                   (void *)exception_object);
+        return _URC_NO_REASON;
+
+      case _URC_CONTINUE_UNWIND:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
+                                   "_URC_CONTINUE_UNWIND",
+                                   (void *)exception_object);
+        // continue unwinding
+        break;
+
+      default:
+        // something went wrong
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
+            (void *)exception_object);
+        return _URC_FATAL_PHASE1_ERROR;
+      }
+    }
+  }
+  return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2(struct _Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
+                             (void *)exception_object);
+
+  // walk each frame until we reach where search phase said to stop
+  _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+  while (true) {
+    _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",
+                               (void *)exception_object, (void *)c);
+
+    // check for no more frames
+    if (c == NULL) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2(ex_ojb=%p): __unw_step() reached "
+          "bottom => _URC_END_OF_STACK",
+          (void *)exception_object);
+      return _URC_END_OF_STACK;
+    }
+
+    // if there is a personality routine, tell it we are unwinding
+    if (c->personality != NULL) {
+      _Unwind_Action action = _UA_CLEANUP_PHASE;
+      if ((uintptr_t) c == exception_object->private_2)
+        action = (_Unwind_Action)(
+            _UA_CLEANUP_PHASE |
+            _UA_HANDLER_FRAME); // tell personality this was the frame it marked
+                                // in phase 1
+      _Unwind_Reason_Code personalityResult =
+          (*c->personality)(1, action, exception_object->exception_class,
+                            exception_object, (struct _Unwind_Context *)c);
+      switch (personalityResult) {
+      case _URC_CONTINUE_UNWIND:
+        // continue unwinding
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
+            (void *)exception_object);
+        if ((uintptr_t) c == exception_object->private_2) {
+          // phase 1 said we would stop at this frame, but we did not...
+          _LIBUNWIND_ABORT("during phase1 personality function said it would "
+                           "stop here, but now if phase2 it did not stop here");
+        }
+        break;
+      case _URC_INSTALL_CONTEXT:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
+                                   "_URC_INSTALL_CONTEXT, will resume at "
+                                   "landing pad %p",
+                                   (void *)exception_object, c->jbuf[1]);
+        // personality routine says to transfer control to landing pad
+        // we may get control back if landing pad calls _Unwind_Resume()
+        __Unwind_SjLj_SetTopOfFunctionStack(c);
+        __builtin_longjmp(c->jbuf, 1);
+        // __unw_resume() only returns if there was an error
+        return _URC_FATAL_PHASE2_ERROR;
+      default:
+        // something went wrong
+        _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
+                      personalityResult);
+        return _URC_FATAL_PHASE2_ERROR;
+      }
+    }
+    c = c->prev;
+  }
+
+  // clean up phase did not resume at the frame that the search phase said it
+  // would
+  return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2_forced(struct _Unwind_Exception *exception_object,
+                     _Unwind_Stop_Fn stop, void *stop_parameter) {
+  // walk each frame until we reach where search phase said to stop
+  _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+  while (true) {
+
+    // get next frame (skip over first which is _Unwind_RaiseException)
+    if (c == NULL) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2(ex_ojb=%p): __unw_step() reached "
+          "bottom => _URC_END_OF_STACK",
+          (void *)exception_object);
+      return _URC_END_OF_STACK;
+    }
+
+    // call stop function at each frame
+    _Unwind_Action action =
+        (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
+    _Unwind_Reason_Code stopResult =
+        (*stop)(1, action, exception_object->exception_class, exception_object,
+                (struct _Unwind_Context *)c, stop_parameter);
+    _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                               "stop function returned %d",
+                               (void *)exception_object, stopResult);
+    if (stopResult != _URC_NO_REASON) {
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                 "stopped by stop function",
+                                 (void *)exception_object);
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // if there is a personality routine, tell it we are unwinding
+    if (c->personality != NULL) {
+      _Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality;
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                 "calling personality function %p",
+                                 (void *)exception_object, (void *)p);
+      _Unwind_Reason_Code personalityResult =
+          (*p)(1, action, exception_object->exception_class, exception_object,
+               (struct _Unwind_Context *)c);
+      switch (personalityResult) {
+      case _URC_CONTINUE_UNWIND:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p):  "
+                                   "personality returned _URC_CONTINUE_UNWIND",
+                                   (void *)exception_object);
+        // destructors called, continue unwinding
+        break;
+      case _URC_INSTALL_CONTEXT:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned _URC_INSTALL_CONTEXT",
+                                   (void *)exception_object);
+        // we may get control back if landing pad calls _Unwind_Resume()
+        __Unwind_SjLj_SetTopOfFunctionStack(c);
+        __builtin_longjmp(c->jbuf, 1);
+        break;
+      default:
+        // something went wrong
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned %d, "
+                                   "_URC_FATAL_PHASE2_ERROR",
+                                   (void *)exception_object, personalityResult);
+        return _URC_FATAL_PHASE2_ERROR;
+      }
+    }
+    c = c->prev;
+  }
+
+  // call stop function one last time and tell it we've reached the end of the
+  // stack
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
+                             "function with _UA_END_OF_STACK",
+                             (void *)exception_object);
+  _Unwind_Action lastAction =
+      (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
+  (*stop)(1, lastAction, exception_object->exception_class, exception_object,
+          (struct _Unwind_Context *)c, stop_parameter);
+
+  // clean up phase did not resume at the frame that the search phase said it
+  // would
+  return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+/// Called by __cxa_throw.  Only returns if there is a fatal error
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)",
+                       (void *)exception_object);
+
+  // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right
+  // thing
+  exception_object->private_1 = 0;
+  exception_object->private_2 = 0;
+
+  // phase 1: the search phase
+  _Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
+  if (phase1 != _URC_NO_REASON)
+    return phase1;
+
+  // phase 2: the clean up phase
+  return unwind_phase2(exception_object);
+}
+
+
+
+/// When _Unwind_RaiseException() is in phase2, it hands control
+/// to the personality function at each frame.  The personality
+/// may force a jump to a landing pad in that function, the landing
+/// pad code may then call _Unwind_Resume() to continue with the
+/// unwinding.  Note: the call to _Unwind_Resume() is from compiler
+/// geneated user code.  All other _Unwind_* routines are called
+/// by the C++ runtime __cxa_* routines.
+///
+/// Re-throwing an exception is implemented by having the code call
+/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
+_LIBUNWIND_EXPORT void
+_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)",
+                       (void *)exception_object);
+
+  if (exception_object->private_1 != 0)
+    unwind_phase2_forced(exception_object,
+                         (_Unwind_Stop_Fn) exception_object->private_1,
+                         (void *)exception_object->private_2);
+  else
+    unwind_phase2(exception_object);
+
+  // clients assume _Unwind_Resume() does not return, so all we can do is abort.
+  _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");
+}
+
+
+///  Called by __cxa_rethrow().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "
+                       "private_1=%" PRIuPTR,
+                       (void *)exception_object, exception_object->private_1);
+  // If this is non-forced and a stopping place was found, then this is a
+  // re-throw.
+  // Call _Unwind_RaiseException() as if this was a new exception.
+  if (exception_object->private_1 == 0) {
+    return _Unwind_SjLj_RaiseException(exception_object);
+    // should return if there is no catch clause, so that __cxa_rethrow can call
+    // std::terminate()
+  }
+
+  // Call through to _Unwind_Resume() which distiguishes between forced and
+  // regular exceptions.
+  _Unwind_SjLj_Resume(exception_object);
+  _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "
+                    "_Unwind_SjLj_Resume() which unexpectedly returned");
+}
+
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
+  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+  _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "
+                       "=> 0x%" PRIuPTR,
+                       (void *)context, ufc->lsda);
+  return ufc->lsda;
+}
+
+
+/// Called by personality handler during phase 2 to get register values.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
+                                          int index) {
+  _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context,
+                       index);
+  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+  return ufc->resumeParameters[index];
+}
+
+
+/// Called by personality handler during phase 2 to alter register values.
+_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
+                                     uintptr_t new_value) {
+  _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIuPTR
+                       ")",
+                       (void *)context, index, new_value);
+  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+  ufc->resumeParameters[index] = new_value;
+}
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
+  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+  _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIu32,
+                       (void *)context, ufc->resumeLocation + 1);
+  return ufc->resumeLocation + 1;
+}
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+/// ipBefore is a boolean that says if IP is already adjusted to be the call
+/// site address.  Normally IP is the return address.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
+                                              int *ipBefore) {
+  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+  *ipBefore = 0;
+  _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIu32,
+                       (void *)context, (void *)ipBefore,
+                       ufc->resumeLocation + 1);
+  return ufc->resumeLocation + 1;
+}
+
+
+/// Called by personality handler during phase 2 to alter instruction pointer.
+_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
+                                     uintptr_t new_value) {
+  _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIuPTR ")",
+                       (void *)context, new_value);
+  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+  ufc->resumeLocation = new_value - 1;
+}
+
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+  // Not supported or needed for sjlj based unwinding
+  (void)context;
+  _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context);
+  return 0;
+}
+
+
+/// Called by personality handler during phase 2 if a foreign exception
+/// is caught.
+_LIBUNWIND_EXPORT void
+_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
+                       (void *)exception_object);
+  if (exception_object->exception_cleanup != NULL)
+    (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
+                                           exception_object);
+}
+
+
+
+/// Called by personality handler during phase 2 to get base address for data
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
+  // Not supported or needed for sjlj based unwinding
+  (void)context;
+  _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
+  _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+
+/// Called by personality handler during phase 2 to get base address for text
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
+  // Not supported or needed for sjlj based unwinding
+  (void)context;
+  _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
+  _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+/// Called by personality handler to get "Call Frame Area" for current frame.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
+  _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context);
+  if (context != NULL) {
+    _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+    // Setjmp/longjmp based exceptions don't have a true CFA.
+    // Instead, the SP in the jmpbuf is the closest approximation.
+    return (uintptr_t) ufc->jbuf[2];
+  }
+  return 0;
+}
+
+#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)

+ 2128 - 0
llvm-libunwind/src/UnwindCursor.hpp

@@ -0,0 +1,2128 @@
+//===------------------------- UnwindCursor.hpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+// C++ interface to lower levels of libunwind
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWINDCURSOR_HPP__
+#define __UNWINDCURSOR_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unwind.h>
+
+#ifdef _WIN32
+  #include <windows.h>
+  #include <ntverp.h>
+#endif
+#ifdef __APPLE__
+  #include <mach-o/dyld.h>
+#endif
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+// Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and
+// earlier) SDKs.
+// MinGW-w64 has always provided this struct.
+  #if defined(_WIN32) && defined(_LIBUNWIND_TARGET_X86_64) && \
+      !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000
+struct _DISPATCHER_CONTEXT {
+  ULONG64 ControlPc;
+  ULONG64 ImageBase;
+  PRUNTIME_FUNCTION FunctionEntry;
+  ULONG64 EstablisherFrame;
+  ULONG64 TargetIp;
+  PCONTEXT ContextRecord;
+  PEXCEPTION_ROUTINE LanguageHandler;
+  PVOID HandlerData;
+  PUNWIND_HISTORY_TABLE HistoryTable;
+  ULONG ScopeIndex;
+  ULONG Fill0;
+};
+  #endif
+
+struct UNWIND_INFO {
+  uint8_t Version : 3;
+  uint8_t Flags : 5;
+  uint8_t SizeOfProlog;
+  uint8_t CountOfCodes;
+  uint8_t FrameRegister : 4;
+  uint8_t FrameOffset : 4;
+  uint16_t UnwindCodes[2];
+};
+
+extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
+    int, _Unwind_Action, uint64_t, _Unwind_Exception *,
+    struct _Unwind_Context *);
+
+#endif
+
+#include "config.h"
+
+#include "AddressSpace.hpp"
+#include "CompactUnwinder.hpp"
+#include "config.h"
+#include "DwarfInstructions.hpp"
+#include "EHHeaderParser.hpp"
+#include "libunwind.h"
+#include "Registers.hpp"
+#include "RWMutex.hpp"
+#include "Unwind-EHABI.h"
+
+namespace libunwind {
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+/// Cache of recently found FDEs.
+template <typename A>
+class _LIBUNWIND_HIDDEN DwarfFDECache {
+  typedef typename A::pint_t pint_t;
+public:
+  static constexpr pint_t kSearchAll = static_cast<pint_t>(-1);
+  static pint_t findFDE(pint_t mh, pint_t pc);
+  static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
+  static void removeAllIn(pint_t mh);
+  static void iterateCacheEntries(void (*func)(unw_word_t ip_start,
+                                               unw_word_t ip_end,
+                                               unw_word_t fde, unw_word_t mh));
+
+private:
+
+  struct entry {
+    pint_t mh;
+    pint_t ip_start;
+    pint_t ip_end;
+    pint_t fde;
+  };
+
+  // These fields are all static to avoid needing an initializer.
+  // There is only one instance of this class per process.
+  static RWMutex _lock;
+#ifdef __APPLE__
+  static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide);
+  static bool _registeredForDyldUnloads;
+#endif
+  static entry *_buffer;
+  static entry *_bufferUsed;
+  static entry *_bufferEnd;
+  static entry _initialBuffer[64];
+};
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_buffer = _initialBuffer;
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_bufferUsed = _initialBuffer;
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_bufferEnd = &_initialBuffer[64];
+
+template <typename A>
+typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64];
+
+template <typename A>
+RWMutex DwarfFDECache<A>::_lock;
+
+#ifdef __APPLE__
+template <typename A>
+bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
+#endif
+
+template <typename A>
+typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
+  pint_t result = 0;
+  _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared());
+  for (entry *p = _buffer; p < _bufferUsed; ++p) {
+    if ((mh == p->mh) || (mh == kSearchAll)) {
+      if ((p->ip_start <= pc) && (pc < p->ip_end)) {
+        result = p->fde;
+        break;
+      }
+    }
+  }
+  _LIBUNWIND_LOG_IF_FALSE(_lock.unlock_shared());
+  return result;
+}
+
+template <typename A>
+void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
+                           pint_t fde) {
+#if !defined(_LIBUNWIND_NO_HEAP)
+  _LIBUNWIND_LOG_IF_FALSE(_lock.lock());
+  if (_bufferUsed >= _bufferEnd) {
+    size_t oldSize = (size_t)(_bufferEnd - _buffer);
+    size_t newSize = oldSize * 4;
+    // Can't use operator new (we are below it).
+    entry *newBuffer = (entry *)malloc(newSize * sizeof(entry));
+    memcpy(newBuffer, _buffer, oldSize * sizeof(entry));
+    if (_buffer != _initialBuffer)
+      free(_buffer);
+    _buffer = newBuffer;
+    _bufferUsed = &newBuffer[oldSize];
+    _bufferEnd = &newBuffer[newSize];
+  }
+  _bufferUsed->mh = mh;
+  _bufferUsed->ip_start = ip_start;
+  _bufferUsed->ip_end = ip_end;
+  _bufferUsed->fde = fde;
+  ++_bufferUsed;
+#ifdef __APPLE__
+  if (!_registeredForDyldUnloads) {
+    _dyld_register_func_for_remove_image(&dyldUnloadHook);
+    _registeredForDyldUnloads = true;
+  }
+#endif
+  _LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
+#endif
+}
+
+template <typename A>
+void DwarfFDECache<A>::removeAllIn(pint_t mh) {
+  _LIBUNWIND_LOG_IF_FALSE(_lock.lock());
+  entry *d = _buffer;
+  for (const entry *s = _buffer; s < _bufferUsed; ++s) {
+    if (s->mh != mh) {
+      if (d != s)
+        *d = *s;
+      ++d;
+    }
+  }
+  _bufferUsed = d;
+  _LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
+}
+
+#ifdef __APPLE__
+template <typename A>
+void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) {
+  removeAllIn((pint_t) mh);
+}
+#endif
+
+template <typename A>
+void DwarfFDECache<A>::iterateCacheEntries(void (*func)(
+    unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
+  _LIBUNWIND_LOG_IF_FALSE(_lock.lock());
+  for (entry *p = _buffer; p < _bufferUsed; ++p) {
+    (*func)(p->ip_start, p->ip_end, p->fde, p->mh);
+  }
+  _LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
+}
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+
+#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
+
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+template <typename A> class UnwindSectionHeader {
+public:
+  UnwindSectionHeader(A &addressSpace, typename A::pint_t addr)
+      : _addressSpace(addressSpace), _addr(addr) {}
+
+  uint32_t version() const {
+    return _addressSpace.get32(_addr +
+                               offsetof(unwind_info_section_header, version));
+  }
+  uint32_t commonEncodingsArraySectionOffset() const {
+    return _addressSpace.get32(_addr +
+                               offsetof(unwind_info_section_header,
+                                        commonEncodingsArraySectionOffset));
+  }
+  uint32_t commonEncodingsArrayCount() const {
+    return _addressSpace.get32(_addr + offsetof(unwind_info_section_header,
+                                                commonEncodingsArrayCount));
+  }
+  uint32_t personalityArraySectionOffset() const {
+    return _addressSpace.get32(_addr + offsetof(unwind_info_section_header,
+                                                personalityArraySectionOffset));
+  }
+  uint32_t personalityArrayCount() const {
+    return _addressSpace.get32(
+        _addr + offsetof(unwind_info_section_header, personalityArrayCount));
+  }
+  uint32_t indexSectionOffset() const {
+    return _addressSpace.get32(
+        _addr + offsetof(unwind_info_section_header, indexSectionOffset));
+  }
+  uint32_t indexCount() const {
+    return _addressSpace.get32(
+        _addr + offsetof(unwind_info_section_header, indexCount));
+  }
+
+private:
+  A                     &_addressSpace;
+  typename A::pint_t     _addr;
+};
+
+template <typename A> class UnwindSectionIndexArray {
+public:
+  UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr)
+      : _addressSpace(addressSpace), _addr(addr) {}
+
+  uint32_t functionOffset(uint32_t index) const {
+    return _addressSpace.get32(
+        _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+                              functionOffset));
+  }
+  uint32_t secondLevelPagesSectionOffset(uint32_t index) const {
+    return _addressSpace.get32(
+        _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+                              secondLevelPagesSectionOffset));
+  }
+  uint32_t lsdaIndexArraySectionOffset(uint32_t index) const {
+    return _addressSpace.get32(
+        _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+                              lsdaIndexArraySectionOffset));
+  }
+
+private:
+  A                   &_addressSpace;
+  typename A::pint_t   _addr;
+};
+
+template <typename A> class UnwindSectionRegularPageHeader {
+public:
+  UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr)
+      : _addressSpace(addressSpace), _addr(addr) {}
+
+  uint32_t kind() const {
+    return _addressSpace.get32(
+        _addr + offsetof(unwind_info_regular_second_level_page_header, kind));
+  }
+  uint16_t entryPageOffset() const {
+    return _addressSpace.get16(
+        _addr + offsetof(unwind_info_regular_second_level_page_header,
+                         entryPageOffset));
+  }
+  uint16_t entryCount() const {
+    return _addressSpace.get16(
+        _addr +
+        offsetof(unwind_info_regular_second_level_page_header, entryCount));
+  }
+
+private:
+  A &_addressSpace;
+  typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionRegularArray {
+public:
+  UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr)
+      : _addressSpace(addressSpace), _addr(addr) {}
+
+  uint32_t functionOffset(uint32_t index) const {
+    return _addressSpace.get32(
+        _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index,
+                              functionOffset));
+  }
+  uint32_t encoding(uint32_t index) const {
+    return _addressSpace.get32(
+        _addr +
+        arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding));
+  }
+
+private:
+  A &_addressSpace;
+  typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionCompressedPageHeader {
+public:
+  UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr)
+      : _addressSpace(addressSpace), _addr(addr) {}
+
+  uint32_t kind() const {
+    return _addressSpace.get32(
+        _addr +
+        offsetof(unwind_info_compressed_second_level_page_header, kind));
+  }
+  uint16_t entryPageOffset() const {
+    return _addressSpace.get16(
+        _addr + offsetof(unwind_info_compressed_second_level_page_header,
+                         entryPageOffset));
+  }
+  uint16_t entryCount() const {
+    return _addressSpace.get16(
+        _addr +
+        offsetof(unwind_info_compressed_second_level_page_header, entryCount));
+  }
+  uint16_t encodingsPageOffset() const {
+    return _addressSpace.get16(
+        _addr + offsetof(unwind_info_compressed_second_level_page_header,
+                         encodingsPageOffset));
+  }
+  uint16_t encodingsCount() const {
+    return _addressSpace.get16(
+        _addr + offsetof(unwind_info_compressed_second_level_page_header,
+                         encodingsCount));
+  }
+
+private:
+  A &_addressSpace;
+  typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionCompressedArray {
+public:
+  UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr)
+      : _addressSpace(addressSpace), _addr(addr) {}
+
+  uint32_t functionOffset(uint32_t index) const {
+    return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(
+        _addressSpace.get32(_addr + index * sizeof(uint32_t)));
+  }
+  uint16_t encodingIndex(uint32_t index) const {
+    return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(
+        _addressSpace.get32(_addr + index * sizeof(uint32_t)));
+  }
+
+private:
+  A &_addressSpace;
+  typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionLsdaArray {
+public:
+  UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr)
+      : _addressSpace(addressSpace), _addr(addr) {}
+
+  uint32_t functionOffset(uint32_t index) const {
+    return _addressSpace.get32(
+        _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry,
+                              index, functionOffset));
+  }
+  uint32_t lsdaOffset(uint32_t index) const {
+    return _addressSpace.get32(
+        _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry,
+                              index, lsdaOffset));
+  }
+
+private:
+  A                   &_addressSpace;
+  typename A::pint_t   _addr;
+};
+#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+
+class _LIBUNWIND_HIDDEN AbstractUnwindCursor {
+public:
+  // NOTE: provide a class specific placement deallocation function (S5.3.4 p20)
+  // This avoids an unnecessary dependency to libc++abi.
+  void operator delete(void *, size_t) {}
+
+  virtual ~AbstractUnwindCursor() {}
+  virtual bool validReg(int) { _LIBUNWIND_ABORT("validReg not implemented"); }
+  virtual unw_word_t getReg(int) { _LIBUNWIND_ABORT("getReg not implemented"); }
+  virtual void setReg(int, unw_word_t) {
+    _LIBUNWIND_ABORT("setReg not implemented");
+  }
+  virtual bool validFloatReg(int) {
+    _LIBUNWIND_ABORT("validFloatReg not implemented");
+  }
+  virtual unw_fpreg_t getFloatReg(int) {
+    _LIBUNWIND_ABORT("getFloatReg not implemented");
+  }
+  virtual void setFloatReg(int, unw_fpreg_t) {
+    _LIBUNWIND_ABORT("setFloatReg not implemented");
+  }
+  virtual int step() { _LIBUNWIND_ABORT("step not implemented"); }
+  virtual void getInfo(unw_proc_info_t *) {
+    _LIBUNWIND_ABORT("getInfo not implemented");
+  }
+  virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); }
+  virtual bool isSignalFrame() {
+    _LIBUNWIND_ABORT("isSignalFrame not implemented");
+  }
+  virtual bool getFunctionName(char *, size_t, unw_word_t *) {
+    _LIBUNWIND_ABORT("getFunctionName not implemented");
+  }
+  virtual void setInfoBasedOnIPRegister(bool = false) {
+    _LIBUNWIND_ABORT("setInfoBasedOnIPRegister not implemented");
+  }
+  virtual const char *getRegisterName(int) {
+    _LIBUNWIND_ABORT("getRegisterName not implemented");
+  }
+#ifdef __arm__
+  virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); }
+#endif
+};
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
+
+/// \c UnwindCursor contains all state (including all register values) during
+/// an unwind.  This is normally stack-allocated inside a unw_cursor_t.
+template <typename A, typename R>
+class UnwindCursor : public AbstractUnwindCursor {
+  typedef typename A::pint_t pint_t;
+public:
+                      UnwindCursor(unw_context_t *context, A &as);
+                      UnwindCursor(CONTEXT *context, A &as);
+                      UnwindCursor(A &as, void *threadArg);
+  virtual             ~UnwindCursor() {}
+  virtual bool        validReg(int);
+  virtual unw_word_t  getReg(int);
+  virtual void        setReg(int, unw_word_t);
+  virtual bool        validFloatReg(int);
+  virtual unw_fpreg_t getFloatReg(int);
+  virtual void        setFloatReg(int, unw_fpreg_t);
+  virtual int         step();
+  virtual void        getInfo(unw_proc_info_t *);
+  virtual void        jumpto();
+  virtual bool        isSignalFrame();
+  virtual bool        getFunctionName(char *buf, size_t len, unw_word_t *off);
+  virtual void        setInfoBasedOnIPRegister(bool isReturnAddress = false);
+  virtual const char *getRegisterName(int num);
+#ifdef __arm__
+  virtual void        saveVFPAsX();
+#endif
+
+  DISPATCHER_CONTEXT *getDispatcherContext() { return &_dispContext; }
+  void setDispatcherContext(DISPATCHER_CONTEXT *disp) { _dispContext = *disp; }
+
+  // libunwind does not and should not depend on C++ library which means that we
+  // need our own defition of inline placement new.
+  static void *operator new(size_t, UnwindCursor<A, R> *p) { return p; }
+
+private:
+
+  pint_t getLastPC() const { return _dispContext.ControlPc; }
+  void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; }
+  RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) {
+    _dispContext.FunctionEntry = RtlLookupFunctionEntry(pc,
+                                                        &_dispContext.ImageBase,
+                                                        _dispContext.HistoryTable);
+    *base = _dispContext.ImageBase;
+    return _dispContext.FunctionEntry;
+  }
+  bool getInfoFromSEH(pint_t pc);
+  int stepWithSEHData() {
+    _dispContext.LanguageHandler = RtlVirtualUnwind(UNW_FLAG_UHANDLER,
+                                                    _dispContext.ImageBase,
+                                                    _dispContext.ControlPc,
+                                                    _dispContext.FunctionEntry,
+                                                    _dispContext.ContextRecord,
+                                                    &_dispContext.HandlerData,
+                                                    &_dispContext.EstablisherFrame,
+                                                    NULL);
+    // Update some fields of the unwind info now, since we have them.
+    _info.lsda = reinterpret_cast<unw_word_t>(_dispContext.HandlerData);
+    if (_dispContext.LanguageHandler) {
+      _info.handler = reinterpret_cast<unw_word_t>(__libunwind_seh_personality);
+    } else
+      _info.handler = 0;
+    return UNW_STEP_SUCCESS;
+  }
+
+  A                   &_addressSpace;
+  unw_proc_info_t      _info;
+  DISPATCHER_CONTEXT   _dispContext;
+  CONTEXT              _msContext;
+  UNWIND_HISTORY_TABLE _histTable;
+  bool                 _unwindInfoMissing;
+};
+
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
+    : _addressSpace(as), _unwindInfoMissing(false) {
+  static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit),
+                "UnwindCursor<> does not fit in unw_cursor_t");
+  static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
+                "UnwindCursor<> requires more alignment than unw_cursor_t");
+  memset(&_info, 0, sizeof(_info));
+  memset(&_histTable, 0, sizeof(_histTable));
+  _dispContext.ContextRecord = &_msContext;
+  _dispContext.HistoryTable = &_histTable;
+  // Initialize MS context from ours.
+  R r(context);
+  _msContext.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_FLOATING_POINT;
+#if defined(_LIBUNWIND_TARGET_X86_64)
+  _msContext.Rax = r.getRegister(UNW_X86_64_RAX);
+  _msContext.Rcx = r.getRegister(UNW_X86_64_RCX);
+  _msContext.Rdx = r.getRegister(UNW_X86_64_RDX);
+  _msContext.Rbx = r.getRegister(UNW_X86_64_RBX);
+  _msContext.Rsp = r.getRegister(UNW_X86_64_RSP);
+  _msContext.Rbp = r.getRegister(UNW_X86_64_RBP);
+  _msContext.Rsi = r.getRegister(UNW_X86_64_RSI);
+  _msContext.Rdi = r.getRegister(UNW_X86_64_RDI);
+  _msContext.R8 = r.getRegister(UNW_X86_64_R8);
+  _msContext.R9 = r.getRegister(UNW_X86_64_R9);
+  _msContext.R10 = r.getRegister(UNW_X86_64_R10);
+  _msContext.R11 = r.getRegister(UNW_X86_64_R11);
+  _msContext.R12 = r.getRegister(UNW_X86_64_R12);
+  _msContext.R13 = r.getRegister(UNW_X86_64_R13);
+  _msContext.R14 = r.getRegister(UNW_X86_64_R14);
+  _msContext.R15 = r.getRegister(UNW_X86_64_R15);
+  _msContext.Rip = r.getRegister(UNW_REG_IP);
+  union {
+    v128 v;
+    M128A m;
+  } t;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM0);
+  _msContext.Xmm0 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM1);
+  _msContext.Xmm1 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM2);
+  _msContext.Xmm2 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM3);
+  _msContext.Xmm3 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM4);
+  _msContext.Xmm4 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM5);
+  _msContext.Xmm5 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM6);
+  _msContext.Xmm6 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM7);
+  _msContext.Xmm7 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM8);
+  _msContext.Xmm8 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM9);
+  _msContext.Xmm9 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM10);
+  _msContext.Xmm10 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM11);
+  _msContext.Xmm11 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM12);
+  _msContext.Xmm12 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM13);
+  _msContext.Xmm13 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM14);
+  _msContext.Xmm14 = t.m;
+  t.v = r.getVectorRegister(UNW_X86_64_XMM15);
+  _msContext.Xmm15 = t.m;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+  _msContext.R0 = r.getRegister(UNW_ARM_R0);
+  _msContext.R1 = r.getRegister(UNW_ARM_R1);
+  _msContext.R2 = r.getRegister(UNW_ARM_R2);
+  _msContext.R3 = r.getRegister(UNW_ARM_R3);
+  _msContext.R4 = r.getRegister(UNW_ARM_R4);
+  _msContext.R5 = r.getRegister(UNW_ARM_R5);
+  _msContext.R6 = r.getRegister(UNW_ARM_R6);
+  _msContext.R7 = r.getRegister(UNW_ARM_R7);
+  _msContext.R8 = r.getRegister(UNW_ARM_R8);
+  _msContext.R9 = r.getRegister(UNW_ARM_R9);
+  _msContext.R10 = r.getRegister(UNW_ARM_R10);
+  _msContext.R11 = r.getRegister(UNW_ARM_R11);
+  _msContext.R12 = r.getRegister(UNW_ARM_R12);
+  _msContext.Sp = r.getRegister(UNW_ARM_SP);
+  _msContext.Lr = r.getRegister(UNW_ARM_LR);
+  _msContext.Pc = r.getRegister(UNW_ARM_IP);
+  for (int i = UNW_ARM_D0; i <= UNW_ARM_D31; ++i) {
+    union {
+      uint64_t w;
+      double d;
+    } d;
+    d.d = r.getFloatRegister(i);
+    _msContext.D[i - UNW_ARM_D0] = d.w;
+  }
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  for (int i = UNW_ARM64_X0; i <= UNW_ARM64_X30; ++i)
+    _msContext.X[i - UNW_ARM64_X0] = r.getRegister(i);
+  _msContext.Sp = r.getRegister(UNW_REG_SP);
+  _msContext.Pc = r.getRegister(UNW_REG_IP);
+  for (int i = UNW_ARM64_D0; i <= UNW_ARM64_D31; ++i)
+    _msContext.V[i - UNW_ARM64_D0].D[0] = r.getFloatRegister(i);
+#endif
+}
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(CONTEXT *context, A &as)
+    : _addressSpace(as), _unwindInfoMissing(false) {
+  static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit),
+                "UnwindCursor<> does not fit in unw_cursor_t");
+  memset(&_info, 0, sizeof(_info));
+  memset(&_histTable, 0, sizeof(_histTable));
+  _dispContext.ContextRecord = &_msContext;
+  _dispContext.HistoryTable = &_histTable;
+  _msContext = *context;
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validReg(int regNum) {
+  if (regNum == UNW_REG_IP || regNum == UNW_REG_SP) return true;
+#if defined(_LIBUNWIND_TARGET_X86_64)
+  if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+  if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  if (regNum >= UNW_ARM64_X0 && regNum <= UNW_ARM64_X30) return true;
+#endif
+  return false;
+}
+
+template <typename A, typename R>
+unw_word_t UnwindCursor<A, R>::getReg(int regNum) {
+  switch (regNum) {
+#if defined(_LIBUNWIND_TARGET_X86_64)
+  case UNW_REG_IP: return _msContext.Rip;
+  case UNW_X86_64_RAX: return _msContext.Rax;
+  case UNW_X86_64_RDX: return _msContext.Rdx;
+  case UNW_X86_64_RCX: return _msContext.Rcx;
+  case UNW_X86_64_RBX: return _msContext.Rbx;
+  case UNW_REG_SP:
+  case UNW_X86_64_RSP: return _msContext.Rsp;
+  case UNW_X86_64_RBP: return _msContext.Rbp;
+  case UNW_X86_64_RSI: return _msContext.Rsi;
+  case UNW_X86_64_RDI: return _msContext.Rdi;
+  case UNW_X86_64_R8: return _msContext.R8;
+  case UNW_X86_64_R9: return _msContext.R9;
+  case UNW_X86_64_R10: return _msContext.R10;
+  case UNW_X86_64_R11: return _msContext.R11;
+  case UNW_X86_64_R12: return _msContext.R12;
+  case UNW_X86_64_R13: return _msContext.R13;
+  case UNW_X86_64_R14: return _msContext.R14;
+  case UNW_X86_64_R15: return _msContext.R15;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+  case UNW_ARM_R0: return _msContext.R0;
+  case UNW_ARM_R1: return _msContext.R1;
+  case UNW_ARM_R2: return _msContext.R2;
+  case UNW_ARM_R3: return _msContext.R3;
+  case UNW_ARM_R4: return _msContext.R4;
+  case UNW_ARM_R5: return _msContext.R5;
+  case UNW_ARM_R6: return _msContext.R6;
+  case UNW_ARM_R7: return _msContext.R7;
+  case UNW_ARM_R8: return _msContext.R8;
+  case UNW_ARM_R9: return _msContext.R9;
+  case UNW_ARM_R10: return _msContext.R10;
+  case UNW_ARM_R11: return _msContext.R11;
+  case UNW_ARM_R12: return _msContext.R12;
+  case UNW_REG_SP:
+  case UNW_ARM_SP: return _msContext.Sp;
+  case UNW_ARM_LR: return _msContext.Lr;
+  case UNW_REG_IP:
+  case UNW_ARM_IP: return _msContext.Pc;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  case UNW_REG_SP: return _msContext.Sp;
+  case UNW_REG_IP: return _msContext.Pc;
+  default: return _msContext.X[regNum - UNW_ARM64_X0];
+#endif
+  }
+  _LIBUNWIND_ABORT("unsupported register");
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) {
+  switch (regNum) {
+#if defined(_LIBUNWIND_TARGET_X86_64)
+  case UNW_REG_IP: _msContext.Rip = value; break;
+  case UNW_X86_64_RAX: _msContext.Rax = value; break;
+  case UNW_X86_64_RDX: _msContext.Rdx = value; break;
+  case UNW_X86_64_RCX: _msContext.Rcx = value; break;
+  case UNW_X86_64_RBX: _msContext.Rbx = value; break;
+  case UNW_REG_SP:
+  case UNW_X86_64_RSP: _msContext.Rsp = value; break;
+  case UNW_X86_64_RBP: _msContext.Rbp = value; break;
+  case UNW_X86_64_RSI: _msContext.Rsi = value; break;
+  case UNW_X86_64_RDI: _msContext.Rdi = value; break;
+  case UNW_X86_64_R8: _msContext.R8 = value; break;
+  case UNW_X86_64_R9: _msContext.R9 = value; break;
+  case UNW_X86_64_R10: _msContext.R10 = value; break;
+  case UNW_X86_64_R11: _msContext.R11 = value; break;
+  case UNW_X86_64_R12: _msContext.R12 = value; break;
+  case UNW_X86_64_R13: _msContext.R13 = value; break;
+  case UNW_X86_64_R14: _msContext.R14 = value; break;
+  case UNW_X86_64_R15: _msContext.R15 = value; break;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+  case UNW_ARM_R0: _msContext.R0 = value; break;
+  case UNW_ARM_R1: _msContext.R1 = value; break;
+  case UNW_ARM_R2: _msContext.R2 = value; break;
+  case UNW_ARM_R3: _msContext.R3 = value; break;
+  case UNW_ARM_R4: _msContext.R4 = value; break;
+  case UNW_ARM_R5: _msContext.R5 = value; break;
+  case UNW_ARM_R6: _msContext.R6 = value; break;
+  case UNW_ARM_R7: _msContext.R7 = value; break;
+  case UNW_ARM_R8: _msContext.R8 = value; break;
+  case UNW_ARM_R9: _msContext.R9 = value; break;
+  case UNW_ARM_R10: _msContext.R10 = value; break;
+  case UNW_ARM_R11: _msContext.R11 = value; break;
+  case UNW_ARM_R12: _msContext.R12 = value; break;
+  case UNW_REG_SP:
+  case UNW_ARM_SP: _msContext.Sp = value; break;
+  case UNW_ARM_LR: _msContext.Lr = value; break;
+  case UNW_REG_IP:
+  case UNW_ARM_IP: _msContext.Pc = value; break;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  case UNW_REG_SP: _msContext.Sp = value; break;
+  case UNW_REG_IP: _msContext.Pc = value; break;
+  case UNW_ARM64_X0:
+  case UNW_ARM64_X1:
+  case UNW_ARM64_X2:
+  case UNW_ARM64_X3:
+  case UNW_ARM64_X4:
+  case UNW_ARM64_X5:
+  case UNW_ARM64_X6:
+  case UNW_ARM64_X7:
+  case UNW_ARM64_X8:
+  case UNW_ARM64_X9:
+  case UNW_ARM64_X10:
+  case UNW_ARM64_X11:
+  case UNW_ARM64_X12:
+  case UNW_ARM64_X13:
+  case UNW_ARM64_X14:
+  case UNW_ARM64_X15:
+  case UNW_ARM64_X16:
+  case UNW_ARM64_X17:
+  case UNW_ARM64_X18:
+  case UNW_ARM64_X19:
+  case UNW_ARM64_X20:
+  case UNW_ARM64_X21:
+  case UNW_ARM64_X22:
+  case UNW_ARM64_X23:
+  case UNW_ARM64_X24:
+  case UNW_ARM64_X25:
+  case UNW_ARM64_X26:
+  case UNW_ARM64_X27:
+  case UNW_ARM64_X28:
+  case UNW_ARM64_FP:
+  case UNW_ARM64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break;
+#endif
+  default:
+    _LIBUNWIND_ABORT("unsupported register");
+  }
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validFloatReg(int regNum) {
+#if defined(_LIBUNWIND_TARGET_ARM)
+  if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) return true;
+  if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) return true;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  if (regNum >= UNW_ARM64_D0 && regNum <= UNW_ARM64_D31) return true;
+#else
+  (void)regNum;
+#endif
+  return false;
+}
+
+template <typename A, typename R>
+unw_fpreg_t UnwindCursor<A, R>::getFloatReg(int regNum) {
+#if defined(_LIBUNWIND_TARGET_ARM)
+  if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) {
+    union {
+      uint32_t w;
+      float f;
+    } d;
+    d.w = _msContext.S[regNum - UNW_ARM_S0];
+    return d.f;
+  }
+  if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) {
+    union {
+      uint64_t w;
+      double d;
+    } d;
+    d.w = _msContext.D[regNum - UNW_ARM_D0];
+    return d.d;
+  }
+  _LIBUNWIND_ABORT("unsupported float register");
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  return _msContext.V[regNum - UNW_ARM64_D0].D[0];
+#else
+  (void)regNum;
+  _LIBUNWIND_ABORT("float registers unimplemented");
+#endif
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) {
+#if defined(_LIBUNWIND_TARGET_ARM)
+  if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) {
+    union {
+      uint32_t w;
+      float f;
+    } d;
+    d.f = value;
+    _msContext.S[regNum - UNW_ARM_S0] = d.w;
+  }
+  if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) {
+    union {
+      uint64_t w;
+      double d;
+    } d;
+    d.d = value;
+    _msContext.D[regNum - UNW_ARM_D0] = d.w;
+  }
+  _LIBUNWIND_ABORT("unsupported float register");
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+  _msContext.V[regNum - UNW_ARM64_D0].D[0] = value;
+#else
+  (void)regNum;
+  (void)value;
+  _LIBUNWIND_ABORT("float registers unimplemented");
+#endif
+}
+
+template <typename A, typename R> void UnwindCursor<A, R>::jumpto() {
+  RtlRestoreContext(&_msContext, nullptr);
+}
+
+#ifdef __arm__
+template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {}
+#endif
+
+template <typename A, typename R>
+const char *UnwindCursor<A, R>::getRegisterName(int regNum) {
+  return R::getRegisterName(regNum);
+}
+
+template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
+  return false;
+}
+
+#else  // !defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) || !defined(_WIN32)
+
+/// UnwindCursor contains all state (including all register values) during
+/// an unwind.  This is normally stack allocated inside a unw_cursor_t.
+template <typename A, typename R>
+class UnwindCursor : public AbstractUnwindCursor{
+  typedef typename A::pint_t pint_t;
+public:
+                      UnwindCursor(unw_context_t *context, A &as);
+                      UnwindCursor(A &as, void *threadArg);
+  virtual             ~UnwindCursor() {}
+  virtual bool        validReg(int);
+  virtual unw_word_t  getReg(int);
+  virtual void        setReg(int, unw_word_t);
+  virtual bool        validFloatReg(int);
+  virtual unw_fpreg_t getFloatReg(int);
+  virtual void        setFloatReg(int, unw_fpreg_t);
+  virtual int         step();
+  virtual void        getInfo(unw_proc_info_t *);
+  virtual void        jumpto();
+  virtual bool        isSignalFrame();
+  virtual bool        getFunctionName(char *buf, size_t len, unw_word_t *off);
+  virtual void        setInfoBasedOnIPRegister(bool isReturnAddress = false);
+  virtual const char *getRegisterName(int num);
+#ifdef __arm__
+  virtual void        saveVFPAsX();
+#endif
+
+  // libunwind does not and should not depend on C++ library which means that we
+  // need our own defition of inline placement new.
+  static void *operator new(size_t, UnwindCursor<A, R> *p) { return p; }
+
+private:
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+  bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections &sects);
+
+  int stepWithEHABI() {
+    size_t len = 0;
+    size_t off = 0;
+    // FIXME: Calling decode_eht_entry() here is violating the libunwind
+    // abstraction layer.
+    const uint32_t *ehtp =
+        decode_eht_entry(reinterpret_cast<const uint32_t *>(_info.unwind_info),
+                         &off, &len);
+    if (_Unwind_VRS_Interpret((_Unwind_Context *)this, ehtp, off, len) !=
+            _URC_CONTINUE_UNWIND)
+      return UNW_STEP_END;
+    return UNW_STEP_SUCCESS;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+  bool setInfoForSigReturn() {
+    R dummy;
+    return setInfoForSigReturn(dummy);
+  }
+  int stepThroughSigReturn() {
+    R dummy;
+    return stepThroughSigReturn(dummy);
+  }
+  bool setInfoForSigReturn(Registers_arm64 &);
+  int stepThroughSigReturn(Registers_arm64 &);
+  template <typename Registers> bool setInfoForSigReturn(Registers &) {
+    return false;
+  }
+  template <typename Registers> int stepThroughSigReturn(Registers &) {
+    return UNW_STEP_END;
+  }
+#endif
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+  bool getInfoFromFdeCie(const typename CFI_Parser<A>::FDE_Info &fdeInfo,
+                         const typename CFI_Parser<A>::CIE_Info &cieInfo,
+                         pint_t pc, uintptr_t dso_base);
+  bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
+                                            uint32_t fdeSectionOffsetHint=0);
+  int stepWithDwarfFDE() {
+    return DwarfInstructions<A, R>::stepWithDwarf(_addressSpace,
+                                              (pint_t)this->getReg(UNW_REG_IP),
+                                              (pint_t)_info.unwind_info,
+                                              _registers, _isSignalFrame);
+  }
+#endif
+
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+  bool getInfoFromCompactEncodingSection(pint_t pc,
+                                            const UnwindInfoSections &sects);
+  int stepWithCompactEncoding() {
+  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+    if ( compactSaysUseDwarf() )
+      return stepWithDwarfFDE();
+  #endif
+    R dummy;
+    return stepWithCompactEncoding(dummy);
+  }
+
+#if defined(_LIBUNWIND_TARGET_X86_64)
+  int stepWithCompactEncoding(Registers_x86_64 &) {
+    return CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
+        _info.format, _info.start_ip, _addressSpace, _registers);
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_I386)
+  int stepWithCompactEncoding(Registers_x86 &) {
+    return CompactUnwinder_x86<A>::stepWithCompactEncoding(
+        _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers);
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_PPC)
+  int stepWithCompactEncoding(Registers_ppc &) {
+    return UNW_EINVAL;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_PPC64)
+  int stepWithCompactEncoding(Registers_ppc64 &) {
+    return UNW_EINVAL;
+  }
+#endif
+
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+  int stepWithCompactEncoding(Registers_arm64 &) {
+    return CompactUnwinder_arm64<A>::stepWithCompactEncoding(
+        _info.format, _info.start_ip, _addressSpace, _registers);
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_O32)
+  int stepWithCompactEncoding(Registers_mips_o32 &) {
+    return UNW_EINVAL;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI)
+  int stepWithCompactEncoding(Registers_mips_newabi &) {
+    return UNW_EINVAL;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+  int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_RISCV)
+  int stepWithCompactEncoding(Registers_riscv &) {
+    return UNW_EINVAL;
+  }
+#endif
+
+  bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
+    R dummy;
+    return compactSaysUseDwarf(dummy, offset);
+  }
+
+#if defined(_LIBUNWIND_TARGET_X86_64)
+  bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const {
+    if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) {
+      if (offset)
+        *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+      return true;
+    }
+    return false;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_I386)
+  bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const {
+    if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) {
+      if (offset)
+        *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET);
+      return true;
+    }
+    return false;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_PPC)
+  bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const {
+    return true;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_PPC64)
+  bool compactSaysUseDwarf(Registers_ppc64 &, uint32_t *) const {
+    return true;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+  bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const {
+    if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) {
+      if (offset)
+        *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET);
+      return true;
+    }
+    return false;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_O32)
+  bool compactSaysUseDwarf(Registers_mips_o32 &, uint32_t *) const {
+    return true;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI)
+  bool compactSaysUseDwarf(Registers_mips_newabi &, uint32_t *) const {
+    return true;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+  bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_RISCV)
+  bool compactSaysUseDwarf(Registers_riscv &, uint32_t *) const {
+    return true;
+  }
+#endif
+
+#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+  compact_unwind_encoding_t dwarfEncoding() const {
+    R dummy;
+    return dwarfEncoding(dummy);
+  }
+
+#if defined(_LIBUNWIND_TARGET_X86_64)
+  compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const {
+    return UNWIND_X86_64_MODE_DWARF;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_I386)
+  compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const {
+    return UNWIND_X86_MODE_DWARF;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_PPC)
+  compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const {
+    return 0;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_PPC64)
+  compact_unwind_encoding_t dwarfEncoding(Registers_ppc64 &) const {
+    return 0;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+  compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const {
+    return UNWIND_ARM64_MODE_DWARF;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_ARM)
+  compact_unwind_encoding_t dwarfEncoding(Registers_arm &) const {
+    return 0;
+  }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_OR1K)
+  compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const {
+    return 0;
+  }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_HEXAGON)
+  compact_unwind_encoding_t dwarfEncoding(Registers_hexagon &) const {
+    return 0;
+  }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_MIPS_O32)
+  compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const {
+    return 0;
+  }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_MIPS_NEWABI)
+  compact_unwind_encoding_t dwarfEncoding(Registers_mips_newabi &) const {
+    return 0;
+  }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+  compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_RISCV)
+  compact_unwind_encoding_t dwarfEncoding(Registers_riscv &) const {
+    return 0;
+  }
+#endif
+
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+  // For runtime environments using SEH unwind data without Windows runtime
+  // support.
+  pint_t getLastPC() const { /* FIXME: Implement */ return 0; }
+  void setLastPC(pint_t pc) { /* FIXME: Implement */ }
+  RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) {
+    /* FIXME: Implement */
+    *base = 0;
+    return nullptr;
+  }
+  bool getInfoFromSEH(pint_t pc);
+  int stepWithSEHData() { /* FIXME: Implement */ return 0; }
+#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+
+
+  A               &_addressSpace;
+  R                _registers;
+  unw_proc_info_t  _info;
+  bool             _unwindInfoMissing;
+  bool             _isSignalFrame;
+#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+  bool             _isSigReturn = false;
+#endif
+};
+
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
+    : _addressSpace(as), _registers(context), _unwindInfoMissing(false),
+      _isSignalFrame(false) {
+  static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit),
+                "UnwindCursor<> does not fit in unw_cursor_t");
+  static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
+                "UnwindCursor<> requires more alignment than unw_cursor_t");
+  memset(&_info, 0, sizeof(_info));
+}
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(A &as, void *)
+    : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
+  memset(&_info, 0, sizeof(_info));
+  // FIXME
+  // fill in _registers from thread arg
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validReg(int regNum) {
+  return _registers.validRegister(regNum);
+}
+
+template <typename A, typename R>
+unw_word_t UnwindCursor<A, R>::getReg(int regNum) {
+  return _registers.getRegister(regNum);
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) {
+  _registers.setRegister(regNum, (typename A::pint_t)value);
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validFloatReg(int regNum) {
+  return _registers.validFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+unw_fpreg_t UnwindCursor<A, R>::getFloatReg(int regNum) {
+  return _registers.getFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) {
+  _registers.setFloatRegister(regNum, value);
+}
+
+template <typename A, typename R> void UnwindCursor<A, R>::jumpto() {
+  _registers.jumpto();
+}
+
+#ifdef __arm__
+template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {
+  _registers.saveVFPAsX();
+}
+#endif
+
+template <typename A, typename R>
+const char *UnwindCursor<A, R>::getRegisterName(int regNum) {
+  return _registers.getRegisterName(regNum);
+}
+
+template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
+  return _isSignalFrame;
+}
+
+#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+template<typename A>
+struct EHABISectionIterator {
+  typedef EHABISectionIterator _Self;
+
+  typedef typename A::pint_t value_type;
+  typedef typename A::pint_t* pointer;
+  typedef typename A::pint_t& reference;
+  typedef size_t size_type;
+  typedef size_t difference_type;
+
+  static _Self begin(A& addressSpace, const UnwindInfoSections& sects) {
+    return _Self(addressSpace, sects, 0);
+  }
+  static _Self end(A& addressSpace, const UnwindInfoSections& sects) {
+    return _Self(addressSpace, sects,
+                 sects.arm_section_length / sizeof(EHABIIndexEntry));
+  }
+
+  EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i)
+      : _i(i), _addressSpace(&addressSpace), _sects(&sects) {}
+
+  _Self& operator++() { ++_i; return *this; }
+  _Self& operator+=(size_t a) { _i += a; return *this; }
+  _Self& operator--() { assert(_i > 0); --_i; return *this; }
+  _Self& operator-=(size_t a) { assert(_i >= a); _i -= a; return *this; }
+
+  _Self operator+(size_t a) { _Self out = *this; out._i += a; return out; }
+  _Self operator-(size_t a) { assert(_i >= a); _Self out = *this; out._i -= a; return out; }
+
+  size_t operator-(const _Self& other) const { return _i - other._i; }
+
+  bool operator==(const _Self& other) const {
+    assert(_addressSpace == other._addressSpace);
+    assert(_sects == other._sects);
+    return _i == other._i;
+  }
+
+  bool operator!=(const _Self& other) const {
+    assert(_addressSpace == other._addressSpace);
+    assert(_sects == other._sects);
+    return _i != other._i;
+  }
+
+  typename A::pint_t operator*() const { return functionAddress(); }
+
+  typename A::pint_t functionAddress() const {
+    typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof(
+        EHABIIndexEntry, _i, functionOffset);
+    return indexAddr + signExtendPrel31(_addressSpace->get32(indexAddr));
+  }
+
+  typename A::pint_t dataAddress() {
+    typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof(
+        EHABIIndexEntry, _i, data);
+    return indexAddr;
+  }
+
+ private:
+  size_t _i;
+  A* _addressSpace;
+  const UnwindInfoSections* _sects;
+};
+
+namespace {
+
+template <typename A>
+EHABISectionIterator<A> EHABISectionUpperBound(
+    EHABISectionIterator<A> first,
+    EHABISectionIterator<A> last,
+    typename A::pint_t value) {
+  size_t len = last - first;
+  while (len > 0) {
+    size_t l2 = len / 2;
+    EHABISectionIterator<A> m = first + l2;
+    if (value < *m) {
+        len = l2;
+    } else {
+        first = ++m;
+        len -= l2 + 1;
+    }
+  }
+  return first;
+}
+
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromEHABISection(
+    pint_t pc,
+    const UnwindInfoSections &sects) {
+  EHABISectionIterator<A> begin =
+      EHABISectionIterator<A>::begin(_addressSpace, sects);
+  EHABISectionIterator<A> end =
+      EHABISectionIterator<A>::end(_addressSpace, sects);
+  if (begin == end)
+    return false;
+
+  EHABISectionIterator<A> itNextPC = EHABISectionUpperBound(begin, end, pc);
+  if (itNextPC == begin)
+    return false;
+  EHABISectionIterator<A> itThisPC = itNextPC - 1;
+
+  pint_t thisPC = itThisPC.functionAddress();
+  // If an exception is thrown from a function, corresponding to the last entry
+  // in the table, we don't really know the function extent and have to choose a
+  // value for nextPC. Choosing max() will allow the range check during trace to
+  // succeed.
+  pint_t nextPC = (itNextPC == end) ? UINTPTR_MAX : itNextPC.functionAddress();
+  pint_t indexDataAddr = itThisPC.dataAddress();
+
+  if (indexDataAddr == 0)
+    return false;
+
+  uint32_t indexData = _addressSpace.get32(indexDataAddr);
+  if (indexData == UNW_EXIDX_CANTUNWIND)
+    return false;
+
+  // If the high bit is set, the exception handling table entry is inline inside
+  // the index table entry on the second word (aka |indexDataAddr|). Otherwise,
+  // the table points at an offset in the exception handling table (section 5
+  // EHABI).
+  pint_t exceptionTableAddr;
+  uint32_t exceptionTableData;
+  bool isSingleWordEHT;
+  if (indexData & 0x80000000) {
+    exceptionTableAddr = indexDataAddr;
+    // TODO(ajwong): Should this data be 0?
+    exceptionTableData = indexData;
+    isSingleWordEHT = true;
+  } else {
+    exceptionTableAddr = indexDataAddr + signExtendPrel31(indexData);
+    exceptionTableData = _addressSpace.get32(exceptionTableAddr);
+    isSingleWordEHT = false;
+  }
+
+  // Now we know the 3 things:
+  //   exceptionTableAddr -- exception handler table entry.
+  //   exceptionTableData -- the data inside the first word of the eht entry.
+  //   isSingleWordEHT -- whether the entry is in the index.
+  unw_word_t personalityRoutine = 0xbadf00d;
+  bool scope32 = false;
+  uintptr_t lsda;
+
+  // If the high bit in the exception handling table entry is set, the entry is
+  // in compact form (section 6.3 EHABI).
+  if (exceptionTableData & 0x80000000) {
+    // Grab the index of the personality routine from the compact form.
+    uint32_t choice = (exceptionTableData & 0x0f000000) >> 24;
+    uint32_t extraWords = 0;
+    switch (choice) {
+      case 0:
+        personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr0;
+        extraWords = 0;
+        scope32 = false;
+        lsda = isSingleWordEHT ? 0 : (exceptionTableAddr + 4);
+        break;
+      case 1:
+        personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr1;
+        extraWords = (exceptionTableData & 0x00ff0000) >> 16;
+        scope32 = false;
+        lsda = exceptionTableAddr + (extraWords + 1) * 4;
+        break;
+      case 2:
+        personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr2;
+        extraWords = (exceptionTableData & 0x00ff0000) >> 16;
+        scope32 = true;
+        lsda = exceptionTableAddr + (extraWords + 1) * 4;
+        break;
+      default:
+        _LIBUNWIND_ABORT("unknown personality routine");
+        return false;
+    }
+
+    if (isSingleWordEHT) {
+      if (extraWords != 0) {
+        _LIBUNWIND_ABORT("index inlined table detected but pr function "
+                         "requires extra words");
+        return false;
+      }
+    }
+  } else {
+    pint_t personalityAddr =
+        exceptionTableAddr + signExtendPrel31(exceptionTableData);
+    personalityRoutine = personalityAddr;
+
+    // ARM EHABI # 6.2, # 9.2
+    //
+    //  +---- ehtp
+    //  v
+    // +--------------------------------------+
+    // | +--------+--------+--------+-------+ |
+    // | |0| prel31 to personalityRoutine   | |
+    // | +--------+--------+--------+-------+ |
+    // | |      N |      unwind opcodes     | |  <-- UnwindData
+    // | +--------+--------+--------+-------+ |
+    // | | Word 2        unwind opcodes     | |
+    // | +--------+--------+--------+-------+ |
+    // | ...                                  |
+    // | +--------+--------+--------+-------+ |
+    // | | Word N        unwind opcodes     | |
+    // | +--------+--------+--------+-------+ |
+    // | | LSDA                             | |  <-- lsda
+    // | | ...                              | |
+    // | +--------+--------+--------+-------+ |
+    // +--------------------------------------+
+
+    uint32_t *UnwindData = reinterpret_cast<uint32_t*>(exceptionTableAddr) + 1;
+    uint32_t FirstDataWord = *UnwindData;
+    size_t N = ((FirstDataWord >> 24) & 0xff);
+    size_t NDataWords = N + 1;
+    lsda = reinterpret_cast<uintptr_t>(UnwindData + NDataWords);
+  }
+
+  _info.start_ip = thisPC;
+  _info.end_ip = nextPC;
+  _info.handler = personalityRoutine;
+  _info.unwind_info = exceptionTableAddr;
+  _info.lsda = lsda;
+  // flags is pr_cache.additional. See EHABI #7.2 for definition of bit 0.
+  _info.flags = (isSingleWordEHT ? 1 : 0) | (scope32 ? 0x2 : 0);  // Use enum?
+
+  return true;
+}
+#endif
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromFdeCie(
+    const typename CFI_Parser<A>::FDE_Info &fdeInfo,
+    const typename CFI_Parser<A>::CIE_Info &cieInfo, pint_t pc,
+    uintptr_t dso_base) {
+  typename CFI_Parser<A>::PrologInfo prolog;
+  if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
+                                          R::getArch(), &prolog)) {
+    // Save off parsed FDE info
+    _info.start_ip          = fdeInfo.pcStart;
+    _info.end_ip            = fdeInfo.pcEnd;
+    _info.lsda              = fdeInfo.lsda;
+    _info.handler           = cieInfo.personality;
+    // Some frameless functions need SP altered when resuming in function, so
+    // propagate spExtraArgSize.
+    _info.gp                = prolog.spExtraArgSize;
+    _info.flags             = 0;
+    _info.format            = dwarfEncoding();
+    _info.unwind_info       = fdeInfo.fdeStart;
+    _info.unwind_info_size  = static_cast<uint32_t>(fdeInfo.fdeLength);
+    _info.extra             = static_cast<unw_word_t>(dso_base);
+    return true;
+  }
+  return false;
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
+                                                const UnwindInfoSections &sects,
+                                                uint32_t fdeSectionOffsetHint) {
+  typename CFI_Parser<A>::FDE_Info fdeInfo;
+  typename CFI_Parser<A>::CIE_Info cieInfo;
+  bool foundFDE = false;
+  bool foundInCache = false;
+  // If compact encoding table gave offset into dwarf section, go directly there
+  if (fdeSectionOffsetHint != 0) {
+    foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+                                    sects.dwarf_section_length,
+                                    sects.dwarf_section + fdeSectionOffsetHint,
+                                    &fdeInfo, &cieInfo);
+  }
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+  if (!foundFDE && (sects.dwarf_index_section != 0)) {
+    foundFDE = EHHeaderParser<A>::findFDE(
+        _addressSpace, pc, sects.dwarf_index_section,
+        (uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo);
+  }
+#endif
+  if (!foundFDE) {
+    // otherwise, search cache of previously found FDEs.
+    pint_t cachedFDE = DwarfFDECache<A>::findFDE(sects.dso_base, pc);
+    if (cachedFDE != 0) {
+      foundFDE =
+          CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+                                 sects.dwarf_section_length,
+                                 cachedFDE, &fdeInfo, &cieInfo);
+      foundInCache = foundFDE;
+    }
+  }
+  if (!foundFDE) {
+    // Still not found, do full scan of __eh_frame section.
+    foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+                                      sects.dwarf_section_length, 0,
+                                      &fdeInfo, &cieInfo);
+  }
+  if (foundFDE) {
+    if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, sects.dso_base)) {
+      // Add to cache (to make next lookup faster) if we had no hint
+      // and there was no index.
+      if (!foundInCache && (fdeSectionOffsetHint == 0)) {
+  #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+        if (sects.dwarf_index_section == 0)
+  #endif
+        DwarfFDECache<A>::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd,
+                              fdeInfo.fdeStart);
+      }
+      return true;
+    }
+  }
+  //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc);
+  return false;
+}
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
+                                              const UnwindInfoSections &sects) {
+  const bool log = false;
+  if (log)
+    fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n",
+            (uint64_t)pc, (uint64_t)sects.dso_base);
+
+  const UnwindSectionHeader<A> sectionHeader(_addressSpace,
+                                                sects.compact_unwind_section);
+  if (sectionHeader.version() != UNWIND_SECTION_VERSION)
+    return false;
+
+  // do a binary search of top level index to find page with unwind info
+  pint_t targetFunctionOffset = pc - sects.dso_base;
+  const UnwindSectionIndexArray<A> topIndex(_addressSpace,
+                                           sects.compact_unwind_section
+                                         + sectionHeader.indexSectionOffset());
+  uint32_t low = 0;
+  uint32_t high = sectionHeader.indexCount();
+  uint32_t last = high - 1;
+  while (low < high) {
+    uint32_t mid = (low + high) / 2;
+    //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n",
+    //mid, low, high, topIndex.functionOffset(mid));
+    if (topIndex.functionOffset(mid) <= targetFunctionOffset) {
+      if ((mid == last) ||
+          (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) {
+        low = mid;
+        break;
+      } else {
+        low = mid + 1;
+      }
+    } else {
+      high = mid;
+    }
+  }
+  const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low);
+  const uint32_t firstLevelNextPageFunctionOffset =
+      topIndex.functionOffset(low + 1);
+  const pint_t secondLevelAddr =
+      sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low);
+  const pint_t lsdaArrayStartAddr =
+      sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low);
+  const pint_t lsdaArrayEndAddr =
+      sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1);
+  if (log)
+    fprintf(stderr, "\tfirst level search for result index=%d "
+                    "to secondLevelAddr=0x%llX\n",
+                    low, (uint64_t) secondLevelAddr);
+  // do a binary search of second level page index
+  uint32_t encoding = 0;
+  pint_t funcStart = 0;
+  pint_t funcEnd = 0;
+  pint_t lsda = 0;
+  pint_t personality = 0;
+  uint32_t pageKind = _addressSpace.get32(secondLevelAddr);
+  if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) {
+    // regular page
+    UnwindSectionRegularPageHeader<A> pageHeader(_addressSpace,
+                                                 secondLevelAddr);
+    UnwindSectionRegularArray<A> pageIndex(
+        _addressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+    // binary search looks for entry with e where index[e].offset <= pc <
+    // index[e+1].offset
+    if (log)
+      fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in "
+                      "regular page starting at secondLevelAddr=0x%llX\n",
+              (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr);
+    low = 0;
+    high = pageHeader.entryCount();
+    while (low < high) {
+      uint32_t mid = (low + high) / 2;
+      if (pageIndex.functionOffset(mid) <= targetFunctionOffset) {
+        if (mid == (uint32_t)(pageHeader.entryCount() - 1)) {
+          // at end of table
+          low = mid;
+          funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base;
+          break;
+        } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) {
+          // next is too big, so we found it
+          low = mid;
+          funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base;
+          break;
+        } else {
+          low = mid + 1;
+        }
+      } else {
+        high = mid;
+      }
+    }
+    encoding = pageIndex.encoding(low);
+    funcStart = pageIndex.functionOffset(low) + sects.dso_base;
+    if (pc < funcStart) {
+      if (log)
+        fprintf(
+            stderr,
+            "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n",
+            (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd);
+      return false;
+    }
+    if (pc > funcEnd) {
+      if (log)
+        fprintf(
+            stderr,
+            "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n",
+            (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd);
+      return false;
+    }
+  } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) {
+    // compressed page
+    UnwindSectionCompressedPageHeader<A> pageHeader(_addressSpace,
+                                                    secondLevelAddr);
+    UnwindSectionCompressedArray<A> pageIndex(
+        _addressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+    const uint32_t targetFunctionPageOffset =
+        (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset);
+    // binary search looks for entry with e where index[e].offset <= pc <
+    // index[e+1].offset
+    if (log)
+      fprintf(stderr, "\tbinary search of compressed page starting at "
+                      "secondLevelAddr=0x%llX\n",
+              (uint64_t) secondLevelAddr);
+    low = 0;
+    last = pageHeader.entryCount() - 1;
+    high = pageHeader.entryCount();
+    while (low < high) {
+      uint32_t mid = (low + high) / 2;
+      if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) {
+        if ((mid == last) ||
+            (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) {
+          low = mid;
+          break;
+        } else {
+          low = mid + 1;
+        }
+      } else {
+        high = mid;
+      }
+    }
+    funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset
+                                                              + sects.dso_base;
+    if (low < last)
+      funcEnd =
+          pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset
+                                                              + sects.dso_base;
+    else
+      funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base;
+    if (pc < funcStart) {
+      _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second  "
+                           "level compressed unwind table. funcStart=0x%llX",
+                            (uint64_t) pc, (uint64_t) funcStart);
+      return false;
+    }
+    if (pc > funcEnd) {
+      _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second  "
+                          "level compressed unwind table. funcEnd=0x%llX",
+                           (uint64_t) pc, (uint64_t) funcEnd);
+      return false;
+    }
+    uint16_t encodingIndex = pageIndex.encodingIndex(low);
+    if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) {
+      // encoding is in common table in section header
+      encoding = _addressSpace.get32(
+          sects.compact_unwind_section +
+          sectionHeader.commonEncodingsArraySectionOffset() +
+          encodingIndex * sizeof(uint32_t));
+    } else {
+      // encoding is in page specific table
+      uint16_t pageEncodingIndex =
+          encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount();
+      encoding = _addressSpace.get32(secondLevelAddr +
+                                     pageHeader.encodingsPageOffset() +
+                                     pageEncodingIndex * sizeof(uint32_t));
+    }
+  } else {
+    _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second "
+                         "level page",
+                          (uint64_t) sects.compact_unwind_section);
+    return false;
+  }
+
+  // look up LSDA, if encoding says function has one
+  if (encoding & UNWIND_HAS_LSDA) {
+    UnwindSectionLsdaArray<A> lsdaIndex(_addressSpace, lsdaArrayStartAddr);
+    uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base);
+    low = 0;
+    high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) /
+                    sizeof(unwind_info_section_header_lsda_index_entry);
+    // binary search looks for entry with exact match for functionOffset
+    if (log)
+      fprintf(stderr,
+              "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n",
+              funcStartOffset);
+    while (low < high) {
+      uint32_t mid = (low + high) / 2;
+      if (lsdaIndex.functionOffset(mid) == funcStartOffset) {
+        lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base;
+        break;
+      } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) {
+        low = mid + 1;
+      } else {
+        high = mid;
+      }
+    }
+    if (lsda == 0) {
+      _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for "
+                    "pc=0x%0llX, but lsda table has no entry",
+                    encoding, (uint64_t) pc);
+      return false;
+    }
+  }
+
+  // extract personality routine, if encoding says function has one
+  uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >>
+                              (__builtin_ctz(UNWIND_PERSONALITY_MASK));
+  if (personalityIndex != 0) {
+    --personalityIndex; // change 1-based to zero-based index
+    if (personalityIndex >= sectionHeader.personalityArrayCount()) {
+      _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d,  "
+                            "but personality table has only %d entries",
+                            encoding, personalityIndex,
+                            sectionHeader.personalityArrayCount());
+      return false;
+    }
+    int32_t personalityDelta = (int32_t)_addressSpace.get32(
+        sects.compact_unwind_section +
+        sectionHeader.personalityArraySectionOffset() +
+        personalityIndex * sizeof(uint32_t));
+    pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
+    personality = _addressSpace.getP(personalityPointer);
+    if (log)
+      fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
+                      "personalityDelta=0x%08X, personality=0x%08llX\n",
+              (uint64_t) pc, personalityDelta, (uint64_t) personality);
+  }
+
+  if (log)
+    fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
+                    "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n",
+            (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart);
+  _info.start_ip = funcStart;
+  _info.end_ip = funcEnd;
+  _info.lsda = lsda;
+  _info.handler = personality;
+  _info.gp = 0;
+  _info.flags = 0;
+  _info.format = encoding;
+  _info.unwind_info = 0;
+  _info.unwind_info_size = 0;
+  _info.extra = sects.dso_base;
+  return true;
+}
+#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) {
+  pint_t base;
+  RUNTIME_FUNCTION *unwindEntry = lookUpSEHUnwindInfo(pc, &base);
+  if (!unwindEntry) {
+    _LIBUNWIND_DEBUG_LOG("\tpc not in table, pc=0x%llX", (uint64_t) pc);
+    return false;
+  }
+  _info.gp = 0;
+  _info.flags = 0;
+  _info.format = 0;
+  _info.unwind_info_size = sizeof(RUNTIME_FUNCTION);
+  _info.unwind_info = reinterpret_cast<unw_word_t>(unwindEntry);
+  _info.extra = base;
+  _info.start_ip = base + unwindEntry->BeginAddress;
+#ifdef _LIBUNWIND_TARGET_X86_64
+  _info.end_ip = base + unwindEntry->EndAddress;
+  // Only fill in the handler and LSDA if they're stale.
+  if (pc != getLastPC()) {
+    UNWIND_INFO *xdata = reinterpret_cast<UNWIND_INFO *>(base + unwindEntry->UnwindData);
+    if (xdata->Flags & (UNW_FLAG_EHANDLER|UNW_FLAG_UHANDLER)) {
+      // The personality is given in the UNWIND_INFO itself. The LSDA immediately
+      // follows the UNWIND_INFO. (This follows how both Clang and MSVC emit
+      // these structures.)
+      // N.B. UNWIND_INFO structs are DWORD-aligned.
+      uint32_t lastcode = (xdata->CountOfCodes + 1) & ~1;
+      const uint32_t *handler = reinterpret_cast<uint32_t *>(&xdata->UnwindCodes[lastcode]);
+      _info.lsda = reinterpret_cast<unw_word_t>(handler+1);
+      if (*handler) {
+        _info.handler = reinterpret_cast<unw_word_t>(__libunwind_seh_personality);
+      } else
+        _info.handler = 0;
+    } else {
+      _info.lsda = 0;
+      _info.handler = 0;
+    }
+  }
+#elif defined(_LIBUNWIND_TARGET_ARM)
+  _info.end_ip = _info.start_ip + unwindEntry->FunctionLength;
+  _info.lsda = 0; // FIXME
+  _info.handler = 0; // FIXME
+#endif
+  setLastPC(pc);
+  return true;
+}
+#endif
+
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
+#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+  _isSigReturn = false;
+#endif
+
+  pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+#if defined(_LIBUNWIND_ARM_EHABI)
+  // Remove the thumb bit so the IP represents the actual instruction address.
+  // This matches the behaviour of _Unwind_GetIP on arm.
+  pc &= (pint_t)~0x1;
+#endif
+
+  // Exit early if at the top of the stack.
+  if (pc == 0) {
+    _unwindInfoMissing = true;
+    return;
+  }
+
+  // If the last line of a function is a "throw" the compiler sometimes
+  // emits no instructions after the call to __cxa_throw.  This means
+  // the return address is actually the start of the next function.
+  // To disambiguate this, back up the pc when we know it is a return
+  // address.
+  if (isReturnAddress)
+    --pc;
+
+  // Ask address space object to find unwind sections for this pc.
+  UnwindInfoSections sects;
+  if (_addressSpace.findUnwindSections(pc, sects)) {
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+    // If there is a compact unwind encoding table, look there first.
+    if (sects.compact_unwind_section != 0) {
+      if (this->getInfoFromCompactEncodingSection(pc, sects)) {
+  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+        // Found info in table, done unless encoding says to use dwarf.
+        uint32_t dwarfOffset;
+        if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) {
+          if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) {
+            // found info in dwarf, done
+            return;
+          }
+        }
+  #endif
+        // If unwind table has entry, but entry says there is no unwind info,
+        // record that we have no unwind info.
+        if (_info.format == 0)
+          _unwindInfoMissing = true;
+        return;
+      }
+    }
+#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+    // If there is SEH unwind info, look there next.
+    if (this->getInfoFromSEH(pc))
+      return;
+#endif
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+    // If there is dwarf unwind info, look there next.
+    if (sects.dwarf_section != 0) {
+      if (this->getInfoFromDwarfSection(pc, sects)) {
+        // found info in dwarf, done
+        return;
+      }
+    }
+#endif
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+    // If there is ARM EHABI unwind info, look there next.
+    if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects))
+      return;
+#endif
+  }
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+  // There is no static unwind info for this pc. Look to see if an FDE was
+  // dynamically registered for it.
+  pint_t cachedFDE = DwarfFDECache<A>::findFDE(DwarfFDECache<A>::kSearchAll,
+                                               pc);
+  if (cachedFDE != 0) {
+    typename CFI_Parser<A>::FDE_Info fdeInfo;
+    typename CFI_Parser<A>::CIE_Info cieInfo;
+    if (!CFI_Parser<A>::decodeFDE(_addressSpace, cachedFDE, &fdeInfo, &cieInfo))
+      if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0))
+        return;
+  }
+
+  // Lastly, ask AddressSpace object about platform specific ways to locate
+  // other FDEs.
+  pint_t fde;
+  if (_addressSpace.findOtherFDE(pc, fde)) {
+    typename CFI_Parser<A>::FDE_Info fdeInfo;
+    typename CFI_Parser<A>::CIE_Info cieInfo;
+    if (!CFI_Parser<A>::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) {
+      // Double check this FDE is for a function that includes the pc.
+      if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd))
+        if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0))
+          return;
+    }
+  }
+#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+  if (setInfoForSigReturn())
+    return;
+#endif
+
+  // no unwind info, flag that we can't reliably unwind
+  _unwindInfoMissing = true;
+}
+
+#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
+  // Look for the sigreturn trampoline. The trampoline's body is two
+  // specific instructions (see below). Typically the trampoline comes from the
+  // vDSO[1] (i.e. the __kernel_rt_sigreturn function). A libc might provide its
+  // own restorer function, though, or user-mode QEMU might write a trampoline
+  // onto the stack.
+  //
+  // This special code path is a fallback that is only used if the trampoline
+  // lacks proper (e.g. DWARF) unwind info. On AArch64, a new DWARF register
+  // constant for the PC needs to be defined before DWARF can handle a signal
+  // trampoline. This code may segfault if the target PC is unreadable, e.g.:
+  //  - The PC points at a function compiled without unwind info, and which is
+  //    part of an execute-only mapping (e.g. using -Wl,--execute-only).
+  //  - The PC is invalid and happens to point to unreadable or unmapped memory.
+  //
+  // [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
+  const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+  // Look for instructions: mov x8, #0x8b; svc #0x0
+  if (_addressSpace.get32(pc) == 0xd2801168 &&
+      _addressSpace.get32(pc + 4) == 0xd4000001) {
+    _info = {};
+    _isSigReturn = true;
+    return true;
+  }
+  return false;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
+  // In the signal trampoline frame, sp points to an rt_sigframe[1], which is:
+  //  - 128-byte siginfo struct
+  //  - ucontext struct:
+  //     - 8-byte long (uc_flags)
+  //     - 8-byte pointer (uc_link)
+  //     - 24-byte stack_t
+  //     - 128-byte signal set
+  //     - 8 bytes of padding because sigcontext has 16-byte alignment
+  //     - sigcontext/mcontext_t
+  // [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c
+  const pint_t kOffsetSpToSigcontext = (128 + 8 + 8 + 24 + 128 + 8); // 304
+
+  // Offsets from sigcontext to each register.
+  const pint_t kOffsetGprs = 8; // offset to "__u64 regs[31]" field
+  const pint_t kOffsetSp = 256; // offset to "__u64 sp" field
+  const pint_t kOffsetPc = 264; // offset to "__u64 pc" field
+
+  pint_t sigctx = _registers.getSP() + kOffsetSpToSigcontext;
+
+  for (int i = 0; i <= 30; ++i) {
+    uint64_t value = _addressSpace.get64(sigctx + kOffsetGprs +
+                                         static_cast<pint_t>(i * 8));
+    _registers.setRegister(UNW_ARM64_X0 + i, value);
+  }
+  _registers.setSP(_addressSpace.get64(sigctx + kOffsetSp));
+  _registers.setIP(_addressSpace.get64(sigctx + kOffsetPc));
+  _isSignalFrame = true;
+  return UNW_STEP_SUCCESS;
+}
+#endif // defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+
+template <typename A, typename R>
+int UnwindCursor<A, R>::step() {
+  // Bottom of stack is defined is when unwind info cannot be found.
+  if (_unwindInfoMissing)
+    return UNW_STEP_END;
+
+  // Use unwinding info to modify register set as if function returned.
+  int result;
+#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+  if (_isSigReturn) {
+    result = this->stepThroughSigReturn();
+  } else
+#endif
+  {
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+    result = this->stepWithCompactEncoding();
+#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+    result = this->stepWithSEHData();
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+    result = this->stepWithDwarfFDE();
+#elif defined(_LIBUNWIND_ARM_EHABI)
+    result = this->stepWithEHABI();
+#else
+  #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \
+              _LIBUNWIND_SUPPORT_SEH_UNWIND or \
+              _LIBUNWIND_SUPPORT_DWARF_UNWIND or \
+              _LIBUNWIND_ARM_EHABI
+#endif
+  }
+
+  // update info based on new PC
+  if (result == UNW_STEP_SUCCESS) {
+    this->setInfoBasedOnIPRegister(true);
+    if (_unwindInfoMissing)
+      return UNW_STEP_END;
+  }
+
+  return result;
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
+  if (_unwindInfoMissing)
+    memset(info, 0, sizeof(*info));
+  else
+    *info = _info;
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
+                                                           unw_word_t *offset) {
+  return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP),
+                                         buf, bufLen, offset);
+}
+
+} // namespace libunwind
+
+#endif // __UNWINDCURSOR_HPP__

+ 326 - 0
llvm-libunwind/src/UnwindLevel1-gcc-ext.c

@@ -0,0 +1,326 @@
+//===--------------------- UnwindLevel1-gcc-ext.c -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Implements gcc extensions to the C++ ABI Exception Handling Level 1.
+//
+//===----------------------------------------------------------------------===//
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "libunwind_ext.h"
+#include "libunwind.h"
+#include "Unwind-EHABI.h"
+#include "unwind.h"
+
+#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+#define private_1 private_[0]
+#endif
+
+///  Called by __cxa_rethrow().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
+#if defined(_LIBUNWIND_ARM_EHABI)
+  _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld",
+                       (void *)exception_object,
+                       (long)exception_object->unwinder_cache.reserved1);
+#else
+  _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR,
+                       (void *)exception_object,
+                       (intptr_t)exception_object->private_1);
+#endif
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+  // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,
+  // which is in the same position as private_1 below.
+  return _Unwind_RaiseException(exception_object);
+#else
+  // If this is non-forced and a stopping place was found, then this is a
+  // re-throw.
+  // Call _Unwind_RaiseException() as if this was a new exception
+  if (exception_object->private_1 == 0) {
+    return _Unwind_RaiseException(exception_object);
+    // Will return if there is no catch clause, so that __cxa_rethrow can call
+    // std::terminate().
+  }
+
+  // Call through to _Unwind_Resume() which distiguishes between forced and
+  // regular exceptions.
+  _Unwind_Resume(exception_object);
+  _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"
+                   " which unexpectedly returned");
+#endif
+}
+
+
+/// Called by personality handler during phase 2 to get base address for data
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
+  (void)context;
+  _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
+  _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+
+/// Called by personality handler during phase 2 to get base address for text
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
+  (void)context;
+  _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
+  _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+/// Scans unwind information to find the function that contains the
+/// specified code address "pc".
+_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
+  _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);
+  // This is slow, but works.
+  // We create an unwind cursor then alter the IP to be pc
+  unw_cursor_t cursor;
+  unw_context_t uc;
+  unw_proc_info_t info;
+  __unw_getcontext(&uc);
+  __unw_init_local(&cursor, &uc);
+  __unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc);
+  if (__unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
+    return (void *)(intptr_t) info.start_ip;
+  else
+    return NULL;
+}
+
+/// Walk every frame and call trace function at each one.  If trace function
+/// returns anything other than _URC_NO_REASON, then walk is terminated.
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
+  unw_cursor_t cursor;
+  unw_context_t uc;
+  __unw_getcontext(&uc);
+  __unw_init_local(&cursor, &uc);
+
+  _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",
+                       (void *)(uintptr_t)callback);
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+  // Create a mock exception object for force unwinding.
+  _Unwind_Exception ex;
+  memset(&ex, '\0', sizeof(ex));
+  ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0
+#endif
+
+  // walk each frame
+  while (true) {
+    _Unwind_Reason_Code result;
+
+#if !defined(_LIBUNWIND_ARM_EHABI)
+    // ask libunwind to get next frame (skip over first frame which is
+    // _Unwind_Backtrace())
+    if (__unw_step(&cursor) <= 0) {
+      _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "
+                                 "bottom of stack, returning %d",
+                                 _URC_END_OF_STACK);
+      return _URC_END_OF_STACK;
+    }
+#else
+    // Get the information for this frame.
+    unw_proc_info_t frameInfo;
+    if (__unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {
+      return _URC_END_OF_STACK;
+    }
+
+    // Update the pr_cache in the mock exception object.
+    const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;
+    ex.pr_cache.fnstart = frameInfo.start_ip;
+    ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
+    ex.pr_cache.additional= frameInfo.flags;
+
+    struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
+    // Get and call the personality function to unwind the frame.
+    _Unwind_Personality_Fn handler = (_Unwind_Personality_Fn)frameInfo.handler;
+    if (handler == NULL) {
+      return _URC_END_OF_STACK;
+    }
+    if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
+            _URC_CONTINUE_UNWIND) {
+      return _URC_END_OF_STACK;
+    }
+#endif // defined(_LIBUNWIND_ARM_EHABI)
+
+    // debugging
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionName[512];
+      unw_proc_info_t frame;
+      unw_word_t offset;
+      __unw_get_proc_name(&cursor, functionName, 512, &offset);
+      __unw_get_proc_info(&cursor, &frame);
+      _LIBUNWIND_TRACE_UNWINDING(
+          " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p",
+          frame.start_ip, functionName, frame.lsda,
+          (void *)&cursor);
+    }
+
+    // call trace function with this frame
+    result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
+    if (result != _URC_NO_REASON) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          " _backtrace: ended because callback returned %d", result);
+      return result;
+    }
+  }
+}
+
+
+/// Find DWARF unwind info for an address 'pc' in some function.
+_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
+                                               struct dwarf_eh_bases *bases) {
+  // This is slow, but works.
+  // We create an unwind cursor then alter the IP to be pc
+  unw_cursor_t cursor;
+  unw_context_t uc;
+  unw_proc_info_t info;
+  __unw_getcontext(&uc);
+  __unw_init_local(&cursor, &uc);
+  __unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t)pc);
+  __unw_get_proc_info(&cursor, &info);
+  bases->tbase = (uintptr_t)info.extra;
+  bases->dbase = 0; // dbase not used on Mac OS X
+  bases->func = (uintptr_t)info.start_ip;
+  _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc,
+                  (void *)(intptr_t) info.unwind_info);
+  return (void *)(intptr_t) info.unwind_info;
+}
+
+/// Returns the CFA (call frame area, or stack pointer at start of function)
+/// for the current context.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_word_t result;
+  __unw_get_reg(cursor, UNW_REG_SP, &result);
+  _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,
+                       (void *)context, result);
+  return (uintptr_t)result;
+}
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+/// ipBefore is a boolean that says if IP is already adjusted to be the call
+/// site address.  Normally IP is the return address.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
+                                              int *ipBefore) {
+  _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context);
+  int isSignalFrame = __unw_is_signal_frame((unw_cursor_t *)context);
+  // Negative means some kind of error (probably UNW_ENOINFO), but we have no
+  // good way to report that, and this maintains backward compatibility with the
+  // implementation that hard-coded zero in every case, even signal frames.
+  if (isSignalFrame <= 0)
+    *ipBefore = 0;
+  else
+    *ipBefore = 1;
+  return _Unwind_GetIP(context);
+}
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+/// Called by programs with dynamic code generators that want
+/// to register a dynamically generated FDE.
+/// This function has existed on Mac OS X since 10.4, but
+/// was broken until 10.6.
+_LIBUNWIND_EXPORT void __register_frame(const void *fde) {
+  _LIBUNWIND_TRACE_API("__register_frame(%p)", fde);
+  __unw_add_dynamic_fde((unw_word_t)(uintptr_t)fde);
+}
+
+
+/// Called by programs with dynamic code generators that want
+/// to unregister a dynamically generated FDE.
+/// This function has existed on Mac OS X since 10.4, but
+/// was broken until 10.6.
+_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {
+  _LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde);
+  __unw_remove_dynamic_fde((unw_word_t)(uintptr_t)fde);
+}
+
+
+// The following register/deregister functions are gcc extensions.
+// They have existed on Mac OS X, but have never worked because Mac OS X
+// before 10.6 used keymgr to track known FDEs, but these functions
+// never got updated to use keymgr.
+// For now, we implement these as do-nothing functions to keep any existing
+// applications working.  We also add the not in 10.6 symbol so that nwe
+// application won't be able to use them.
+
+#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
+_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
+                                                   void *tb, void *db) {
+  (void)fde;
+  (void)ob;
+  (void)tb;
+  (void)db;
+ _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)",
+                            fde, ob, tb, db);
+  // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) {
+  (void)fde;
+  (void)ob;
+  _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob);
+  // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde,
+                                                         void *ob, void *tb,
+                                                         void *db) {
+  (void)fde;
+  (void)ob;
+  (void)tb;
+  (void)db;
+  _LIBUNWIND_TRACE_API("__register_frame_info_table_bases"
+                             "(%p,%p, %p, %p)", fde, ob, tb, db);
+  // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) {
+  (void)fde;
+  (void)ob;
+  _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob);
+  // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) {
+  (void)fde;
+  _LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde);
+  // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) {
+  (void)fde;
+  _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde);
+  // do nothing, this function never worked in Mac OS X
+  return NULL;
+}
+
+_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {
+  (void)fde;
+  _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde);
+  // do nothing, this function never worked in Mac OS X
+  return NULL;
+}
+#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
+
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)

+ 513 - 0
llvm-libunwind/src/UnwindLevel1.c

@@ -0,0 +1,513 @@
+//===------------------------- UnwindLevel1.c -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+// Implements C++ ABI Exception Handling Level 1 as documented at:
+//      https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
+// using libunwind
+//
+//===----------------------------------------------------------------------===//
+
+// ARM EHABI does not specify _Unwind_{Get,Set}{GR,IP}().  Thus, we are
+// defining inline functions to delegate the function calls to
+// _Unwind_VRS_{Get,Set}().  However, some applications might declare the
+// function protetype directly (instead of including <unwind.h>), thus we need
+// to export these functions from libunwind.so as well.
+#define _LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE 1
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+#include "libunwind.h"
+#include "libunwind_ext.h"
+#include "unwind.h"
+
+#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
+
+#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND
+
+static _Unwind_Reason_Code
+unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
+  __unw_init_local(cursor, uc);
+
+  // Walk each frame looking for a place to stop.
+  while (true) {
+    // Ask libunwind to get next frame (skip over first which is
+    // _Unwind_RaiseException).
+    int stepResult = __unw_step(cursor);
+    if (stepResult == 0) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): __unw_step() reached "
+          "bottom => _URC_END_OF_STACK",
+          (void *)exception_object);
+      return _URC_END_OF_STACK;
+    } else if (stepResult < 0) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): __unw_step failed => "
+          "_URC_FATAL_PHASE1_ERROR",
+          (void *)exception_object);
+      return _URC_FATAL_PHASE1_ERROR;
+    }
+
+    // See if frame has code to run (has personality routine).
+    unw_proc_info_t frameInfo;
+    unw_word_t sp;
+    if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): __unw_get_proc_info "
+          "failed => _URC_FATAL_PHASE1_ERROR",
+          (void *)exception_object);
+      return _URC_FATAL_PHASE1_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionBuf[512];
+      const char *functionName = functionBuf;
+      unw_word_t offset;
+      if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
+                               &offset) != UNW_ESUCCESS) ||
+          (frameInfo.start_ip + offset > frameInfo.end_ip))
+        functionName = ".anonymous.";
+      unw_word_t pc;
+      __unw_get_reg(cursor, UNW_REG_IP, &pc);
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR
+          ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
+          (void *)exception_object, pc, frameInfo.start_ip, functionName,
+          frameInfo.lsda, frameInfo.handler);
+    }
+
+    // If there is a personality routine, ask it if it will want to stop at
+    // this frame.
+    if (frameInfo.handler != 0) {
+      _Unwind_Personality_Fn p =
+          (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase1(ex_ojb=%p): calling personality function %p",
+          (void *)exception_object, (void *)(uintptr_t)p);
+      _Unwind_Reason_Code personalityResult =
+          (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
+               exception_object, (struct _Unwind_Context *)(cursor));
+      switch (personalityResult) {
+      case _URC_HANDLER_FOUND:
+        // found a catch clause or locals that need destructing in this frame
+        // stop search and remember stack pointer at the frame
+        __unw_get_reg(cursor, UNW_REG_SP, &sp);
+        exception_object->private_2 = (uintptr_t)sp;
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND",
+            (void *)exception_object);
+        return _URC_NO_REASON;
+
+      case _URC_CONTINUE_UNWIND:
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",
+            (void *)exception_object);
+        // continue unwinding
+        break;
+
+      default:
+        // something went wrong
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
+            (void *)exception_object);
+        return _URC_FATAL_PHASE1_ERROR;
+      }
+    }
+  }
+  return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
+  __unw_init_local(cursor, uc);
+
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
+                             (void *)exception_object);
+
+  // Walk each frame until we reach where search phase said to stop.
+  while (true) {
+
+    // Ask libunwind to get next frame (skip over first which is
+    // _Unwind_RaiseException).
+    int stepResult = __unw_step(cursor);
+    if (stepResult == 0) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2(ex_ojb=%p): __unw_step() reached "
+          "bottom => _URC_END_OF_STACK",
+          (void *)exception_object);
+      return _URC_END_OF_STACK;
+    } else if (stepResult < 0) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2(ex_ojb=%p): __unw_step failed => "
+          "_URC_FATAL_PHASE1_ERROR",
+          (void *)exception_object);
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // Get info about this frame.
+    unw_word_t sp;
+    unw_proc_info_t frameInfo;
+    __unw_get_reg(cursor, UNW_REG_SP, &sp);
+    if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2(ex_ojb=%p): __unw_get_proc_info "
+          "failed => _URC_FATAL_PHASE1_ERROR",
+          (void *)exception_object);
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionBuf[512];
+      const char *functionName = functionBuf;
+      unw_word_t offset;
+      if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
+                               &offset) != UNW_ESUCCESS) ||
+          (frameInfo.start_ip + offset > frameInfo.end_ip))
+        functionName = ".anonymous.";
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR
+                                 ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR
+                                 ", personality=0x%" PRIxPTR,
+                                 (void *)exception_object, frameInfo.start_ip,
+                                 functionName, sp, frameInfo.lsda,
+                                 frameInfo.handler);
+    }
+
+    // If there is a personality routine, tell it we are unwinding.
+    if (frameInfo.handler != 0) {
+      _Unwind_Personality_Fn p =
+          (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
+      _Unwind_Action action = _UA_CLEANUP_PHASE;
+      if (sp == exception_object->private_2) {
+        // Tell personality this was the frame it marked in phase 1.
+        action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
+      }
+       _Unwind_Reason_Code personalityResult =
+          (*p)(1, action, exception_object->exception_class, exception_object,
+               (struct _Unwind_Context *)(cursor));
+      switch (personalityResult) {
+      case _URC_CONTINUE_UNWIND:
+        // Continue unwinding
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
+            (void *)exception_object);
+        if (sp == exception_object->private_2) {
+          // Phase 1 said we would stop at this frame, but we did not...
+          _LIBUNWIND_ABORT("during phase1 personality function said it would "
+                           "stop here, but now in phase2 it did not stop here");
+        }
+        break;
+      case _URC_INSTALL_CONTEXT:
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT",
+            (void *)exception_object);
+        // Personality routine says to transfer control to landing pad.
+        // We may get control back if landing pad calls _Unwind_Resume().
+        if (_LIBUNWIND_TRACING_UNWINDING) {
+          unw_word_t pc;
+          __unw_get_reg(cursor, UNW_REG_IP, &pc);
+          __unw_get_reg(cursor, UNW_REG_SP, &sp);
+          _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
+                                     "user code with ip=0x%" PRIxPTR
+                                     ", sp=0x%" PRIxPTR,
+                                     (void *)exception_object, pc, sp);
+        }
+        __unw_resume(cursor);
+        // __unw_resume() only returns if there was an error.
+        return _URC_FATAL_PHASE2_ERROR;
+      default:
+        // Personality routine returned an unknown result code.
+        _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
+                             personalityResult);
+        return _URC_FATAL_PHASE2_ERROR;
+      }
+    }
+  }
+
+  // Clean up phase did not resume at the frame that the search phase
+  // said it would...
+  return _URC_FATAL_PHASE2_ERROR;
+}
+
+static _Unwind_Reason_Code
+unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
+                     _Unwind_Exception *exception_object,
+                     _Unwind_Stop_Fn stop, void *stop_parameter) {
+  __unw_init_local(cursor, uc);
+
+  // Walk each frame until we reach where search phase said to stop
+  while (__unw_step(cursor) > 0) {
+
+    // Update info about this frame.
+    unw_proc_info_t frameInfo;
+    if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step "
+                                 "failed => _URC_END_OF_STACK",
+                                 (void *)exception_object);
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionBuf[512];
+      const char *functionName = functionBuf;
+      unw_word_t offset;
+      if ((__unw_get_proc_name(cursor, functionBuf, sizeof(functionBuf),
+                               &offset) != UNW_ESUCCESS) ||
+          (frameInfo.start_ip + offset > frameInfo.end_ip))
+        functionName = ".anonymous.";
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
+          ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
+          (void *)exception_object, frameInfo.start_ip, functionName,
+          frameInfo.lsda, frameInfo.handler);
+    }
+
+    // Call stop function at each frame.
+    _Unwind_Action action =
+        (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
+    _Unwind_Reason_Code stopResult =
+        (*stop)(1, action, exception_object->exception_class, exception_object,
+                (struct _Unwind_Context *)(cursor), stop_parameter);
+    _LIBUNWIND_TRACE_UNWINDING(
+        "unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
+        (void *)exception_object, stopResult);
+    if (stopResult != _URC_NO_REASON) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
+          (void *)exception_object);
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // If there is a personality routine, tell it we are unwinding.
+    if (frameInfo.handler != 0) {
+      _Unwind_Personality_Fn p =
+          (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
+          (void *)exception_object, (void *)(uintptr_t)p);
+      _Unwind_Reason_Code personalityResult =
+          (*p)(1, action, exception_object->exception_class, exception_object,
+               (struct _Unwind_Context *)(cursor));
+      switch (personalityResult) {
+      case _URC_CONTINUE_UNWIND:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned "
+                                   "_URC_CONTINUE_UNWIND",
+                                   (void *)exception_object);
+        // Destructors called, continue unwinding
+        break;
+      case _URC_INSTALL_CONTEXT:
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned "
+                                   "_URC_INSTALL_CONTEXT",
+                                   (void *)exception_object);
+        // We may get control back if landing pad calls _Unwind_Resume().
+        __unw_resume(cursor);
+        break;
+      default:
+        // Personality routine returned an unknown result code.
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+                                   "personality returned %d, "
+                                   "_URC_FATAL_PHASE2_ERROR",
+                                   (void *)exception_object, personalityResult);
+        return _URC_FATAL_PHASE2_ERROR;
+      }
+    }
+  }
+
+  // Call stop function one last time and tell it we've reached the end
+  // of the stack.
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
+                             "function with _UA_END_OF_STACK",
+                             (void *)exception_object);
+  _Unwind_Action lastAction =
+      (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
+  (*stop)(1, lastAction, exception_object->exception_class, exception_object,
+          (struct _Unwind_Context *)(cursor), stop_parameter);
+
+  // Clean up phase did not resume at the frame that the search phase said it
+  // would.
+  return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+/// Called by __cxa_throw.  Only returns if there is a fatal error.
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_RaiseException(_Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
+                       (void *)exception_object);
+  unw_context_t uc;
+  unw_cursor_t cursor;
+  __unw_getcontext(&uc);
+
+  // Mark that this is a non-forced unwind, so _Unwind_Resume()
+  // can do the right thing.
+  exception_object->private_1 = 0;
+  exception_object->private_2 = 0;
+
+  // phase 1: the search phase
+  _Unwind_Reason_Code phase1 = unwind_phase1(&uc, &cursor, exception_object);
+  if (phase1 != _URC_NO_REASON)
+    return phase1;
+
+  // phase 2: the clean up phase
+  return unwind_phase2(&uc, &cursor, exception_object);
+}
+
+
+
+/// When _Unwind_RaiseException() is in phase2, it hands control
+/// to the personality function at each frame.  The personality
+/// may force a jump to a landing pad in that function, the landing
+/// pad code may then call _Unwind_Resume() to continue with the
+/// unwinding.  Note: the call to _Unwind_Resume() is from compiler
+/// geneated user code.  All other _Unwind_* routines are called
+/// by the C++ runtime __cxa_* routines.
+///
+/// Note: re-throwing an exception (as opposed to continuing the unwind)
+/// is implemented by having the code call __cxa_rethrow() which
+/// in turn calls _Unwind_Resume_or_Rethrow().
+_LIBUNWIND_EXPORT void
+_Unwind_Resume(_Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);
+  unw_context_t uc;
+  unw_cursor_t cursor;
+  __unw_getcontext(&uc);
+
+  if (exception_object->private_1 != 0)
+    unwind_phase2_forced(&uc, &cursor, exception_object,
+                         (_Unwind_Stop_Fn) exception_object->private_1,
+                         (void *)exception_object->private_2);
+  else
+    unwind_phase2(&uc, &cursor, exception_object);
+
+  // Clients assume _Unwind_Resume() does not return, so all we can do is abort.
+  _LIBUNWIND_ABORT("_Unwind_Resume() can't return");
+}
+
+
+
+/// Not used by C++.
+/// Unwinds stack, calling "stop" function at each frame.
+/// Could be used to implement longjmp().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
+                     _Unwind_Stop_Fn stop, void *stop_parameter) {
+  _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",
+                       (void *)exception_object, (void *)(uintptr_t)stop);
+  unw_context_t uc;
+  unw_cursor_t cursor;
+  __unw_getcontext(&uc);
+
+  // Mark that this is a forced unwind, so _Unwind_Resume() can do
+  // the right thing.
+  exception_object->private_1 = (uintptr_t) stop;
+  exception_object->private_2 = (uintptr_t) stop_parameter;
+
+  // do it
+  return unwind_phase2_forced(&uc, &cursor, exception_object, stop, stop_parameter);
+}
+
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_proc_info_t frameInfo;
+  uintptr_t result = 0;
+  if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
+    result = (uintptr_t)frameInfo.lsda;
+  _LIBUNWIND_TRACE_API(
+      "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
+      (void *)context, result);
+  if (result != 0) {
+    if (*((uint8_t *)result) != 0xFF)
+      _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF",
+                           result);
+  }
+  return result;
+}
+
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_proc_info_t frameInfo;
+  uintptr_t result = 0;
+  if (__unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
+    result = (uintptr_t)frameInfo.start_ip;
+  _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,
+                       (void *)context, result);
+  return result;
+}
+
+#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND
+
+/// Called by personality handler during phase 2 if a foreign exception
+// is caught.
+_LIBUNWIND_EXPORT void
+_Unwind_DeleteException(_Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
+                       (void *)exception_object);
+  if (exception_object->exception_cleanup != NULL)
+    (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
+                                           exception_object);
+}
+
+/// Called by personality handler during phase 2 to get register values.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetGR(struct _Unwind_Context *context, int index) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_word_t result;
+  __unw_get_reg(cursor, index, &result);
+  _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR,
+                       (void *)context, index, result);
+  return (uintptr_t)result;
+}
+
+/// Called by personality handler during phase 2 to alter register values.
+_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
+                                     uintptr_t value) {
+  _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR
+                       ")",
+                       (void *)context, index, value);
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  __unw_set_reg(cursor, index, value);
+}
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_word_t result;
+  __unw_get_reg(cursor, UNW_REG_IP, &result);
+  _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
+                       (void *)context, result);
+  return (uintptr_t)result;
+}
+
+/// Called by personality handler during phase 2 to alter instruction pointer,
+/// such as setting where the landing pad is, so _Unwind_Resume() will
+/// start executing in the landing pad.
+_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
+                                     uintptr_t value) {
+  _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")",
+                       (void *)context, value);
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  __unw_set_reg(cursor, UNW_REG_IP, value);
+}
+
+#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)

+ 1161 - 0
llvm-libunwind/src/UnwindRegistersRestore.S

@@ -0,0 +1,1161 @@
+//===-------------------- UnwindRegistersRestore.S ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "assembly.h"
+
+  .text
+
+#if !defined(__USING_SJLJ_EXCEPTIONS__)
+
+#if defined(__i386__)
+DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
+#
+# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
+#
+# On entry:
+#  +                       +
+#  +-----------------------+
+#  + thread_state pointer  +
+#  +-----------------------+
+#  + return address        +
+#  +-----------------------+   <-- SP
+#  +                       +
+  movl   4(%esp), %eax
+  # set up eax and ret on new stack location
+  movl  28(%eax), %edx # edx holds new stack pointer
+  subl  $8,%edx
+  movl  %edx, 28(%eax)
+  movl  0(%eax), %ebx
+  movl  %ebx, 0(%edx)
+  movl  40(%eax), %ebx
+  movl  %ebx, 4(%edx)
+  # we now have ret and eax pushed onto where new stack will be
+  # restore all registers
+  movl   4(%eax), %ebx
+  movl   8(%eax), %ecx
+  movl  12(%eax), %edx
+  movl  16(%eax), %edi
+  movl  20(%eax), %esi
+  movl  24(%eax), %ebp
+  movl  28(%eax), %esp
+  # skip ss
+  # skip eflags
+  pop    %eax  # eax was already pushed on new stack
+  ret        # eip was already pushed on new stack
+  # skip cs
+  # skip ds
+  # skip es
+  # skip fs
+  # skip gs
+
+#elif defined(__x86_64__)
+
+DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
+#
+# extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);
+#
+#if defined(_WIN64)
+# On entry, thread_state pointer is in rcx; move it into rdi
+# to share restore code below. Since this routine restores and
+# overwrites all registers, we can use the same registers for
+# pointers and temporaries as on unix even though win64 normally
+# mustn't clobber some of them.
+  movq  %rcx, %rdi
+#else
+# On entry, thread_state pointer is in rdi
+#endif
+
+  movq  56(%rdi), %rax # rax holds new stack pointer
+  subq  $16, %rax
+  movq  %rax, 56(%rdi)
+  movq  32(%rdi), %rbx  # store new rdi on new stack
+  movq  %rbx, 0(%rax)
+  movq  128(%rdi), %rbx # store new rip on new stack
+  movq  %rbx, 8(%rax)
+  # restore all registers
+  movq    0(%rdi), %rax
+  movq    8(%rdi), %rbx
+  movq   16(%rdi), %rcx
+  movq   24(%rdi), %rdx
+  # restore rdi later
+  movq   40(%rdi), %rsi
+  movq   48(%rdi), %rbp
+  # restore rsp later
+  movq   64(%rdi), %r8
+  movq   72(%rdi), %r9
+  movq   80(%rdi), %r10
+  movq   88(%rdi), %r11
+  movq   96(%rdi), %r12
+  movq  104(%rdi), %r13
+  movq  112(%rdi), %r14
+  movq  120(%rdi), %r15
+  # skip rflags
+  # skip cs
+  # skip fs
+  # skip gs
+
+#if defined(_WIN64)
+  movdqu 176(%rdi),%xmm0
+  movdqu 192(%rdi),%xmm1
+  movdqu 208(%rdi),%xmm2
+  movdqu 224(%rdi),%xmm3
+  movdqu 240(%rdi),%xmm4
+  movdqu 256(%rdi),%xmm5
+  movdqu 272(%rdi),%xmm6
+  movdqu 288(%rdi),%xmm7
+  movdqu 304(%rdi),%xmm8
+  movdqu 320(%rdi),%xmm9
+  movdqu 336(%rdi),%xmm10
+  movdqu 352(%rdi),%xmm11
+  movdqu 368(%rdi),%xmm12
+  movdqu 384(%rdi),%xmm13
+  movdqu 400(%rdi),%xmm14
+  movdqu 416(%rdi),%xmm15
+#endif
+  movq  56(%rdi), %rsp  # cut back rsp to new location
+  pop    %rdi      # rdi was saved here earlier
+  ret            # rip was saved here
+
+
+#elif defined(__powerpc64__)
+
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
+//
+// void libunwind::Registers_ppc64::jumpto()
+//
+// On entry:
+//  thread_state pointer is in r3
+//
+
+// load register (GPR)
+#define PPC64_LR(n) \
+  ld    n, (8 * (n + 2))(3)
+
+  // restore integral registers
+  // skip r0 for now
+  // skip r1 for now
+  PPC64_LR(2)
+  // skip r3 for now
+  // skip r4 for now
+  // skip r5 for now
+  PPC64_LR(6)
+  PPC64_LR(7)
+  PPC64_LR(8)
+  PPC64_LR(9)
+  PPC64_LR(10)
+  PPC64_LR(11)
+  PPC64_LR(12)
+  PPC64_LR(13)
+  PPC64_LR(14)
+  PPC64_LR(15)
+  PPC64_LR(16)
+  PPC64_LR(17)
+  PPC64_LR(18)
+  PPC64_LR(19)
+  PPC64_LR(20)
+  PPC64_LR(21)
+  PPC64_LR(22)
+  PPC64_LR(23)
+  PPC64_LR(24)
+  PPC64_LR(25)
+  PPC64_LR(26)
+  PPC64_LR(27)
+  PPC64_LR(28)
+  PPC64_LR(29)
+  PPC64_LR(30)
+  PPC64_LR(31)
+
+#if defined(__VSX__)
+
+  // restore VS registers
+  // (note that this also restores floating point registers and V registers,
+  // because part of VS is mapped to these registers)
+
+  addi  4, 3, PPC64_OFFS_FP
+
+// load VS register
+#define PPC64_LVS(n)         \
+  lxvd2x  n, 0, 4           ;\
+  addi    4, 4, 16
+
+  // restore the first 32 VS regs (and also all floating point regs)
+  PPC64_LVS(0)
+  PPC64_LVS(1)
+  PPC64_LVS(2)
+  PPC64_LVS(3)
+  PPC64_LVS(4)
+  PPC64_LVS(5)
+  PPC64_LVS(6)
+  PPC64_LVS(7)
+  PPC64_LVS(8)
+  PPC64_LVS(9)
+  PPC64_LVS(10)
+  PPC64_LVS(11)
+  PPC64_LVS(12)
+  PPC64_LVS(13)
+  PPC64_LVS(14)
+  PPC64_LVS(15)
+  PPC64_LVS(16)
+  PPC64_LVS(17)
+  PPC64_LVS(18)
+  PPC64_LVS(19)
+  PPC64_LVS(20)
+  PPC64_LVS(21)
+  PPC64_LVS(22)
+  PPC64_LVS(23)
+  PPC64_LVS(24)
+  PPC64_LVS(25)
+  PPC64_LVS(26)
+  PPC64_LVS(27)
+  PPC64_LVS(28)
+  PPC64_LVS(29)
+  PPC64_LVS(30)
+  PPC64_LVS(31)
+
+  // use VRSAVE to conditionally restore the remaining VS regs,
+  // that are where the V regs are mapped
+
+  ld    5, PPC64_OFFS_VRSAVE(3)   // test VRsave
+  cmpwi 5, 0
+  beq   Lnovec
+
+// conditionally load VS
+#define PPC64_CLVS_BOTTOM(n)               \
+  beq    Ldone##n                         ;\
+  addi   4, 3, PPC64_OFFS_FP + n * 16     ;\
+  lxvd2x n, 0, 4                          ;\
+Ldone##n:
+
+#define PPC64_CLVSl(n)                    \
+  andis. 0, 5, (1 PPC_LEFT_SHIFT(47-n))  ;\
+PPC64_CLVS_BOTTOM(n)
+
+#define PPC64_CLVSh(n)                    \
+  andi.  0, 5, (1 PPC_LEFT_SHIFT(63-n))  ;\
+PPC64_CLVS_BOTTOM(n)
+
+  PPC64_CLVSl(32)
+  PPC64_CLVSl(33)
+  PPC64_CLVSl(34)
+  PPC64_CLVSl(35)
+  PPC64_CLVSl(36)
+  PPC64_CLVSl(37)
+  PPC64_CLVSl(38)
+  PPC64_CLVSl(39)
+  PPC64_CLVSl(40)
+  PPC64_CLVSl(41)
+  PPC64_CLVSl(42)
+  PPC64_CLVSl(43)
+  PPC64_CLVSl(44)
+  PPC64_CLVSl(45)
+  PPC64_CLVSl(46)
+  PPC64_CLVSl(47)
+  PPC64_CLVSh(48)
+  PPC64_CLVSh(49)
+  PPC64_CLVSh(50)
+  PPC64_CLVSh(51)
+  PPC64_CLVSh(52)
+  PPC64_CLVSh(53)
+  PPC64_CLVSh(54)
+  PPC64_CLVSh(55)
+  PPC64_CLVSh(56)
+  PPC64_CLVSh(57)
+  PPC64_CLVSh(58)
+  PPC64_CLVSh(59)
+  PPC64_CLVSh(60)
+  PPC64_CLVSh(61)
+  PPC64_CLVSh(62)
+  PPC64_CLVSh(63)
+
+#else
+
+// load FP register
+#define PPC64_LF(n) \
+  lfd   n, (PPC64_OFFS_FP + n * 16)(3)
+
+  // restore float registers
+  PPC64_LF(0)
+  PPC64_LF(1)
+  PPC64_LF(2)
+  PPC64_LF(3)
+  PPC64_LF(4)
+  PPC64_LF(5)
+  PPC64_LF(6)
+  PPC64_LF(7)
+  PPC64_LF(8)
+  PPC64_LF(9)
+  PPC64_LF(10)
+  PPC64_LF(11)
+  PPC64_LF(12)
+  PPC64_LF(13)
+  PPC64_LF(14)
+  PPC64_LF(15)
+  PPC64_LF(16)
+  PPC64_LF(17)
+  PPC64_LF(18)
+  PPC64_LF(19)
+  PPC64_LF(20)
+  PPC64_LF(21)
+  PPC64_LF(22)
+  PPC64_LF(23)
+  PPC64_LF(24)
+  PPC64_LF(25)
+  PPC64_LF(26)
+  PPC64_LF(27)
+  PPC64_LF(28)
+  PPC64_LF(29)
+  PPC64_LF(30)
+  PPC64_LF(31)
+
+#if defined(__ALTIVEC__)
+  // restore vector registers if any are in use
+  ld    5, PPC64_OFFS_VRSAVE(3)   // test VRsave
+  cmpwi 5, 0
+  beq   Lnovec
+
+  subi  4, 1, 16
+  // r4 is now a 16-byte aligned pointer into the red zone
+  // the _vectorScalarRegisters may not be 16-byte aligned
+  // so copy via red zone temp buffer
+
+#define PPC64_CLV_UNALIGNED_BOTTOM(n)            \
+  beq    Ldone##n                               ;\
+  ld     0, (PPC64_OFFS_V + n * 16)(3)          ;\
+  std    0, 0(4)                                ;\
+  ld     0, (PPC64_OFFS_V + n * 16 + 8)(3)      ;\
+  std    0, 8(4)                                ;\
+  lvx    n, 0, 4                                ;\
+Ldone  ## n:
+
+#define PPC64_CLV_UNALIGNEDl(n)                 \
+  andis. 0, 5, (1 PPC_LEFT_SHIFT(15-n))        ;\
+PPC64_CLV_UNALIGNED_BOTTOM(n)
+
+#define PPC64_CLV_UNALIGNEDh(n)                \
+  andi.  0, 5, (1 PPC_LEFT_SHIFT(31-n))       ;\
+PPC64_CLV_UNALIGNED_BOTTOM(n)
+
+  PPC64_CLV_UNALIGNEDl(0)
+  PPC64_CLV_UNALIGNEDl(1)
+  PPC64_CLV_UNALIGNEDl(2)
+  PPC64_CLV_UNALIGNEDl(3)
+  PPC64_CLV_UNALIGNEDl(4)
+  PPC64_CLV_UNALIGNEDl(5)
+  PPC64_CLV_UNALIGNEDl(6)
+  PPC64_CLV_UNALIGNEDl(7)
+  PPC64_CLV_UNALIGNEDl(8)
+  PPC64_CLV_UNALIGNEDl(9)
+  PPC64_CLV_UNALIGNEDl(10)
+  PPC64_CLV_UNALIGNEDl(11)
+  PPC64_CLV_UNALIGNEDl(12)
+  PPC64_CLV_UNALIGNEDl(13)
+  PPC64_CLV_UNALIGNEDl(14)
+  PPC64_CLV_UNALIGNEDl(15)
+  PPC64_CLV_UNALIGNEDh(16)
+  PPC64_CLV_UNALIGNEDh(17)
+  PPC64_CLV_UNALIGNEDh(18)
+  PPC64_CLV_UNALIGNEDh(19)
+  PPC64_CLV_UNALIGNEDh(20)
+  PPC64_CLV_UNALIGNEDh(21)
+  PPC64_CLV_UNALIGNEDh(22)
+  PPC64_CLV_UNALIGNEDh(23)
+  PPC64_CLV_UNALIGNEDh(24)
+  PPC64_CLV_UNALIGNEDh(25)
+  PPC64_CLV_UNALIGNEDh(26)
+  PPC64_CLV_UNALIGNEDh(27)
+  PPC64_CLV_UNALIGNEDh(28)
+  PPC64_CLV_UNALIGNEDh(29)
+  PPC64_CLV_UNALIGNEDh(30)
+  PPC64_CLV_UNALIGNEDh(31)
+
+#endif
+#endif
+
+Lnovec:
+  ld    0, PPC64_OFFS_CR(3)
+  mtcr  0
+  ld    0, PPC64_OFFS_SRR0(3)
+  mtctr 0
+
+  PPC64_LR(0)
+  PPC64_LR(5)
+  PPC64_LR(4)
+  PPC64_LR(1)
+  PPC64_LR(3)
+  bctr
+
+#elif defined(__ppc__)
+
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
+//
+// void libunwind::Registers_ppc::jumpto()
+//
+// On entry:
+//  thread_state pointer is in r3
+//
+
+  // restore integral registerrs
+  // skip r0 for now
+  // skip r1 for now
+  lwz     2,  16(3)
+  // skip r3 for now
+  // skip r4 for now
+  // skip r5 for now
+  lwz     6,  32(3)
+  lwz     7,  36(3)
+  lwz     8,  40(3)
+  lwz     9,  44(3)
+  lwz     10, 48(3)
+  lwz     11, 52(3)
+  lwz     12, 56(3)
+  lwz     13, 60(3)
+  lwz     14, 64(3)
+  lwz     15, 68(3)
+  lwz     16, 72(3)
+  lwz     17, 76(3)
+  lwz     18, 80(3)
+  lwz     19, 84(3)
+  lwz     20, 88(3)
+  lwz     21, 92(3)
+  lwz     22, 96(3)
+  lwz     23,100(3)
+  lwz     24,104(3)
+  lwz     25,108(3)
+  lwz     26,112(3)
+  lwz     27,116(3)
+  lwz     28,120(3)
+  lwz     29,124(3)
+  lwz     30,128(3)
+  lwz     31,132(3)
+
+#ifndef __NO_FPRS__
+  // restore float registers
+  lfd     0, 160(3)
+  lfd     1, 168(3)
+  lfd     2, 176(3)
+  lfd     3, 184(3)
+  lfd     4, 192(3)
+  lfd     5, 200(3)
+  lfd     6, 208(3)
+  lfd     7, 216(3)
+  lfd     8, 224(3)
+  lfd     9, 232(3)
+  lfd     10,240(3)
+  lfd     11,248(3)
+  lfd     12,256(3)
+  lfd     13,264(3)
+  lfd     14,272(3)
+  lfd     15,280(3)
+  lfd     16,288(3)
+  lfd     17,296(3)
+  lfd     18,304(3)
+  lfd     19,312(3)
+  lfd     20,320(3)
+  lfd     21,328(3)
+  lfd     22,336(3)
+  lfd     23,344(3)
+  lfd     24,352(3)
+  lfd     25,360(3)
+  lfd     26,368(3)
+  lfd     27,376(3)
+  lfd     28,384(3)
+  lfd     29,392(3)
+  lfd     30,400(3)
+  lfd     31,408(3)
+#endif
+
+#if defined(__ALTIVEC__)
+  // restore vector registers if any are in use
+  lwz     5, 156(3)       // test VRsave
+  cmpwi   5, 0
+  beq     Lnovec
+
+  subi    4, 1, 16
+  rlwinm  4, 4, 0, 0, 27  // mask low 4-bits
+  // r4 is now a 16-byte aligned pointer into the red zone
+  // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
+
+
+#define LOAD_VECTOR_UNALIGNEDl(_index)          \
+  andis.  0, 5, (1 PPC_LEFT_SHIFT(15-_index)) SEPARATOR \
+  beq     Ldone ## _index             SEPARATOR \
+  lwz     0, 424+_index*16(3)         SEPARATOR \
+  stw     0, 0(%r4)                   SEPARATOR \
+  lwz     0, 424+_index*16+4(%r3)     SEPARATOR \
+  stw     0, 4(%r4)                   SEPARATOR \
+  lwz     0, 424+_index*16+8(%r3)     SEPARATOR \
+  stw     0, 8(%r4)                   SEPARATOR \
+  lwz     0, 424+_index*16+12(%r3)    SEPARATOR \
+  stw     0, 12(%r4)                  SEPARATOR \
+  lvx     _index, 0, 4                SEPARATOR \
+  Ldone ## _index:
+
+#define LOAD_VECTOR_UNALIGNEDh(_index)          \
+  andi.   0, 5, (1 PPC_LEFT_SHIFT(31-_index)) SEPARATOR \
+  beq     Ldone ## _index             SEPARATOR \
+  lwz     0, 424+_index*16(3)         SEPARATOR \
+  stw     0, 0(4)                     SEPARATOR \
+  lwz     0, 424+_index*16+4(3)       SEPARATOR \
+  stw     0, 4(4)                     SEPARATOR \
+  lwz     0, 424+_index*16+8(3)       SEPARATOR \
+  stw     0, 8(%r4)                   SEPARATOR \
+  lwz     0, 424+_index*16+12(3)      SEPARATOR \
+  stw     0, 12(4)                    SEPARATOR \
+  lvx     _index, 0, 4                SEPARATOR \
+  Ldone ## _index:
+
+
+  LOAD_VECTOR_UNALIGNEDl(0)
+  LOAD_VECTOR_UNALIGNEDl(1)
+  LOAD_VECTOR_UNALIGNEDl(2)
+  LOAD_VECTOR_UNALIGNEDl(3)
+  LOAD_VECTOR_UNALIGNEDl(4)
+  LOAD_VECTOR_UNALIGNEDl(5)
+  LOAD_VECTOR_UNALIGNEDl(6)
+  LOAD_VECTOR_UNALIGNEDl(7)
+  LOAD_VECTOR_UNALIGNEDl(8)
+  LOAD_VECTOR_UNALIGNEDl(9)
+  LOAD_VECTOR_UNALIGNEDl(10)
+  LOAD_VECTOR_UNALIGNEDl(11)
+  LOAD_VECTOR_UNALIGNEDl(12)
+  LOAD_VECTOR_UNALIGNEDl(13)
+  LOAD_VECTOR_UNALIGNEDl(14)
+  LOAD_VECTOR_UNALIGNEDl(15)
+  LOAD_VECTOR_UNALIGNEDh(16)
+  LOAD_VECTOR_UNALIGNEDh(17)
+  LOAD_VECTOR_UNALIGNEDh(18)
+  LOAD_VECTOR_UNALIGNEDh(19)
+  LOAD_VECTOR_UNALIGNEDh(20)
+  LOAD_VECTOR_UNALIGNEDh(21)
+  LOAD_VECTOR_UNALIGNEDh(22)
+  LOAD_VECTOR_UNALIGNEDh(23)
+  LOAD_VECTOR_UNALIGNEDh(24)
+  LOAD_VECTOR_UNALIGNEDh(25)
+  LOAD_VECTOR_UNALIGNEDh(26)
+  LOAD_VECTOR_UNALIGNEDh(27)
+  LOAD_VECTOR_UNALIGNEDh(28)
+  LOAD_VECTOR_UNALIGNEDh(29)
+  LOAD_VECTOR_UNALIGNEDh(30)
+  LOAD_VECTOR_UNALIGNEDh(31)
+#endif
+
+Lnovec:
+  lwz     0, 136(3)   // __cr
+  mtcr    0
+  lwz     0, 148(3)   // __ctr
+  mtctr   0
+  lwz     0,   0(3)   // __ssr0
+  mtctr   0
+  lwz     0,   8(3)   // do r0 now
+  lwz     5,  28(3)   // do r5 now
+  lwz     4,  24(3)   // do r4 now
+  lwz     1,  12(3)   // do sp now
+  lwz     3,  20(3)   // do r3 last
+  bctr
+
+#elif defined(__aarch64__)
+
+//
+// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
+//
+// On entry:
+//  thread_state pointer is in x0
+//
+  .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
+  // skip restore of x0,x1 for now
+  ldp    x2, x3,  [x0, #0x010]
+  ldp    x4, x5,  [x0, #0x020]
+  ldp    x6, x7,  [x0, #0x030]
+  ldp    x8, x9,  [x0, #0x040]
+  ldp    x10,x11, [x0, #0x050]
+  ldp    x12,x13, [x0, #0x060]
+  ldp    x14,x15, [x0, #0x070]
+  // x16 and x17 were clobbered by the call into the unwinder, so no point in
+  // restoring them.
+  ldp    x18,x19, [x0, #0x090]
+  ldp    x20,x21, [x0, #0x0A0]
+  ldp    x22,x23, [x0, #0x0B0]
+  ldp    x24,x25, [x0, #0x0C0]
+  ldp    x26,x27, [x0, #0x0D0]
+  ldp    x28,x29, [x0, #0x0E0]
+  ldr    x30,     [x0, #0x100]  // restore pc into lr
+
+  ldp    d0, d1,  [x0, #0x110]
+  ldp    d2, d3,  [x0, #0x120]
+  ldp    d4, d5,  [x0, #0x130]
+  ldp    d6, d7,  [x0, #0x140]
+  ldp    d8, d9,  [x0, #0x150]
+  ldp    d10,d11, [x0, #0x160]
+  ldp    d12,d13, [x0, #0x170]
+  ldp    d14,d15, [x0, #0x180]
+  ldp    d16,d17, [x0, #0x190]
+  ldp    d18,d19, [x0, #0x1A0]
+  ldp    d20,d21, [x0, #0x1B0]
+  ldp    d22,d23, [x0, #0x1C0]
+  ldp    d24,d25, [x0, #0x1D0]
+  ldp    d26,d27, [x0, #0x1E0]
+  ldp    d28,d29, [x0, #0x1F0]
+  ldr    d30,     [x0, #0x200]
+  ldr    d31,     [x0, #0x208]
+
+  // Finally, restore sp. This must be done after the the last read from the
+  // context struct, because it is allocated on the stack, and an exception
+  // could clobber the de-allocated portion of the stack after sp has been
+  // restored.
+  ldr    x16,     [x0, #0x0F8]
+  ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
+  mov    sp,x16                 // restore sp
+  ret    x30                    // jump to pc
+
+#elif defined(__arm__) && !defined(__APPLE__)
+
+#if !defined(__ARM_ARCH_ISA_ARM)
+#if (__ARM_ARCH_ISA_THUMB == 2)
+  .syntax unified
+#endif
+  .thumb
+#endif
+
+@
+@ void libunwind::Registers_arm::restoreCoreAndJumpTo()
+@
+@ On entry:
+@  thread_state pointer is in r0
+@
+  .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
+#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
+  @ r8-r11: ldm into r1-r4, then mov to r8-r11
+  adds r0, #0x20
+  ldm r0!, {r1-r4}
+  subs r0, #0x30
+  mov r8, r1
+  mov r9, r2
+  mov r10, r3
+  mov r11, r4
+  @ r12 does not need loading, it it the intra-procedure-call scratch register
+  ldr r2, [r0, #0x34]
+  ldr r3, [r0, #0x3c]
+  mov sp, r2
+  mov lr, r3         @ restore pc into lr
+  ldm r0, {r0-r7}
+#else
+  @ Use lr as base so that r0 can be restored.
+  mov lr, r0
+  @ 32bit thumb-2 restrictions for ldm:
+  @ . the sp (r13) cannot be in the list
+  @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
+  ldm lr, {r0-r12}
+  ldr sp, [lr, #52]
+  ldr lr, [lr, #60]  @ restore pc into lr
+#endif
+  JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .fpu vfpv3-d16
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPv)
+  @ VFP and iwMMX instructions are only available when compiling with the flags
+  @ that enable them. We do not want to do that in the library (because we do not
+  @ want the compiler to generate instructions that access those) but this is
+  @ only accessed if the personality routine needs these registers. Use of
+  @ these registers implies they are, actually, available on the target, so
+  @ it's ok to execute.
+  @ So, generate the instruction using the corresponding coprocessor mnemonic.
+  vldmia r0, {d0-d15}
+  JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .fpu vfpv3-d16
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPv)
+  vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
+  JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .fpu vfpv3
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPv)
+  vldmia r0, {d16-d31}
+  JMP(lr)
+
+#if defined(__ARM_WMMX)
+
+@
+@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .arch armv5te
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPv)
+  ldcl p1, cr0, [r0], #8  @ wldrd wR0, [r0], #8
+  ldcl p1, cr1, [r0], #8  @ wldrd wR1, [r0], #8
+  ldcl p1, cr2, [r0], #8  @ wldrd wR2, [r0], #8
+  ldcl p1, cr3, [r0], #8  @ wldrd wR3, [r0], #8
+  ldcl p1, cr4, [r0], #8  @ wldrd wR4, [r0], #8
+  ldcl p1, cr5, [r0], #8  @ wldrd wR5, [r0], #8
+  ldcl p1, cr6, [r0], #8  @ wldrd wR6, [r0], #8
+  ldcl p1, cr7, [r0], #8  @ wldrd wR7, [r0], #8
+  ldcl p1, cr8, [r0], #8  @ wldrd wR8, [r0], #8
+  ldcl p1, cr9, [r0], #8  @ wldrd wR9, [r0], #8
+  ldcl p1, cr10, [r0], #8  @ wldrd wR10, [r0], #8
+  ldcl p1, cr11, [r0], #8  @ wldrd wR11, [r0], #8
+  ldcl p1, cr12, [r0], #8  @ wldrd wR12, [r0], #8
+  ldcl p1, cr13, [r0], #8  @ wldrd wR13, [r0], #8
+  ldcl p1, cr14, [r0], #8  @ wldrd wR14, [r0], #8
+  ldcl p1, cr15, [r0], #8  @ wldrd wR15, [r0], #8
+  JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .arch armv5te
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj)
+  ldc2 p1, cr8, [r0], #4  @ wldrw wCGR0, [r0], #4
+  ldc2 p1, cr9, [r0], #4  @ wldrw wCGR1, [r0], #4
+  ldc2 p1, cr10, [r0], #4  @ wldrw wCGR2, [r0], #4
+  ldc2 p1, cr11, [r0], #4  @ wldrw wCGR3, [r0], #4
+  JMP(lr)
+
+#endif
+
+#elif defined(__or1k__)
+
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
+#
+# void libunwind::Registers_or1k::jumpto()
+#
+# On entry:
+#  thread_state pointer is in r3
+#
+
+  # restore integral registers
+  l.lwz     r0,  0(r3)
+  l.lwz     r1,  4(r3)
+  l.lwz     r2,  8(r3)
+  # skip r3 for now
+  l.lwz     r4, 16(r3)
+  l.lwz     r5, 20(r3)
+  l.lwz     r6, 24(r3)
+  l.lwz     r7, 28(r3)
+  l.lwz     r8, 32(r3)
+  # skip r9
+  l.lwz    r10, 40(r3)
+  l.lwz    r11, 44(r3)
+  l.lwz    r12, 48(r3)
+  l.lwz    r13, 52(r3)
+  l.lwz    r14, 56(r3)
+  l.lwz    r15, 60(r3)
+  l.lwz    r16, 64(r3)
+  l.lwz    r17, 68(r3)
+  l.lwz    r18, 72(r3)
+  l.lwz    r19, 76(r3)
+  l.lwz    r20, 80(r3)
+  l.lwz    r21, 84(r3)
+  l.lwz    r22, 88(r3)
+  l.lwz    r23, 92(r3)
+  l.lwz    r24, 96(r3)
+  l.lwz    r25,100(r3)
+  l.lwz    r26,104(r3)
+  l.lwz    r27,108(r3)
+  l.lwz    r28,112(r3)
+  l.lwz    r29,116(r3)
+  l.lwz    r30,120(r3)
+  l.lwz    r31,124(r3)
+
+  # at last, restore r3
+  l.lwz    r3,  12(r3)
+
+  # load new pc into ra
+  l.lwz    r9, 128(r3)
+  # jump to pc
+  l.jr     r9
+   l.nop
+
+#elif defined(__hexagon__)
+# On entry:
+#  thread_state pointer is in r2
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_hexagon6jumptoEv)
+#
+# void libunwind::Registers_hexagon::jumpto()
+#
+  r8 = memw(r0+#32)
+  r9 = memw(r0+#36)
+  r10 = memw(r0+#40)
+  r11 = memw(r0+#44)
+
+  r12 = memw(r0+#48)
+  r13 = memw(r0+#52)
+  r14 = memw(r0+#56)
+  r15 = memw(r0+#60)
+
+  r16 = memw(r0+#64)
+  r17 = memw(r0+#68)
+  r18 = memw(r0+#72)
+  r19 = memw(r0+#76)
+
+  r20 = memw(r0+#80)
+  r21 = memw(r0+#84)
+  r22 = memw(r0+#88)
+  r23 = memw(r0+#92)
+
+  r24 = memw(r0+#96)
+  r25 = memw(r0+#100)
+  r26 = memw(r0+#104)
+  r27 = memw(r0+#108)
+
+  r28 = memw(r0+#112)
+  r29 = memw(r0+#116)
+  r30 = memw(r0+#120)
+  r31 = memw(r0+#132)
+
+  r1 = memw(r0+#128)
+  c4 = r1   // Predicate register
+  r1 = memw(r0+#4)
+  r0 = memw(r0)
+  jumpr r31
+#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
+
+//
+// void libunwind::Registers_mips_o32::jumpto()
+//
+// On entry:
+//  thread state pointer is in a0 ($4)
+//
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
+  .set push
+  .set noat
+  .set noreorder
+  .set nomacro
+#ifdef __mips_hard_float
+#if __mips_fpr != 64
+  ldc1  $f0, (4 * 36 + 8 * 0)($4)
+  ldc1  $f2, (4 * 36 + 8 * 2)($4)
+  ldc1  $f4, (4 * 36 + 8 * 4)($4)
+  ldc1  $f6, (4 * 36 + 8 * 6)($4)
+  ldc1  $f8, (4 * 36 + 8 * 8)($4)
+  ldc1  $f10, (4 * 36 + 8 * 10)($4)
+  ldc1  $f12, (4 * 36 + 8 * 12)($4)
+  ldc1  $f14, (4 * 36 + 8 * 14)($4)
+  ldc1  $f16, (4 * 36 + 8 * 16)($4)
+  ldc1  $f18, (4 * 36 + 8 * 18)($4)
+  ldc1  $f20, (4 * 36 + 8 * 20)($4)
+  ldc1  $f22, (4 * 36 + 8 * 22)($4)
+  ldc1  $f24, (4 * 36 + 8 * 24)($4)
+  ldc1  $f26, (4 * 36 + 8 * 26)($4)
+  ldc1  $f28, (4 * 36 + 8 * 28)($4)
+  ldc1  $f30, (4 * 36 + 8 * 30)($4)
+#else
+  ldc1  $f0, (4 * 36 + 8 * 0)($4)
+  ldc1  $f1, (4 * 36 + 8 * 1)($4)
+  ldc1  $f2, (4 * 36 + 8 * 2)($4)
+  ldc1  $f3, (4 * 36 + 8 * 3)($4)
+  ldc1  $f4, (4 * 36 + 8 * 4)($4)
+  ldc1  $f5, (4 * 36 + 8 * 5)($4)
+  ldc1  $f6, (4 * 36 + 8 * 6)($4)
+  ldc1  $f7, (4 * 36 + 8 * 7)($4)
+  ldc1  $f8, (4 * 36 + 8 * 8)($4)
+  ldc1  $f9, (4 * 36 + 8 * 9)($4)
+  ldc1  $f10, (4 * 36 + 8 * 10)($4)
+  ldc1  $f11, (4 * 36 + 8 * 11)($4)
+  ldc1  $f12, (4 * 36 + 8 * 12)($4)
+  ldc1  $f13, (4 * 36 + 8 * 13)($4)
+  ldc1  $f14, (4 * 36 + 8 * 14)($4)
+  ldc1  $f15, (4 * 36 + 8 * 15)($4)
+  ldc1  $f16, (4 * 36 + 8 * 16)($4)
+  ldc1  $f17, (4 * 36 + 8 * 17)($4)
+  ldc1  $f18, (4 * 36 + 8 * 18)($4)
+  ldc1  $f19, (4 * 36 + 8 * 19)($4)
+  ldc1  $f20, (4 * 36 + 8 * 20)($4)
+  ldc1  $f21, (4 * 36 + 8 * 21)($4)
+  ldc1  $f22, (4 * 36 + 8 * 22)($4)
+  ldc1  $f23, (4 * 36 + 8 * 23)($4)
+  ldc1  $f24, (4 * 36 + 8 * 24)($4)
+  ldc1  $f25, (4 * 36 + 8 * 25)($4)
+  ldc1  $f26, (4 * 36 + 8 * 26)($4)
+  ldc1  $f27, (4 * 36 + 8 * 27)($4)
+  ldc1  $f28, (4 * 36 + 8 * 28)($4)
+  ldc1  $f29, (4 * 36 + 8 * 29)($4)
+  ldc1  $f30, (4 * 36 + 8 * 30)($4)
+  ldc1  $f31, (4 * 36 + 8 * 31)($4)
+#endif
+#endif
+  // restore hi and lo
+  lw    $8, (4 * 33)($4)
+  mthi  $8
+  lw    $8, (4 * 34)($4)
+  mtlo  $8
+  // r0 is zero
+  lw    $1, (4 * 1)($4)
+  lw    $2, (4 * 2)($4)
+  lw    $3, (4 * 3)($4)
+  // skip a0 for now
+  lw    $5, (4 * 5)($4)
+  lw    $6, (4 * 6)($4)
+  lw    $7, (4 * 7)($4)
+  lw    $8, (4 * 8)($4)
+  lw    $9, (4 * 9)($4)
+  lw    $10, (4 * 10)($4)
+  lw    $11, (4 * 11)($4)
+  lw    $12, (4 * 12)($4)
+  lw    $13, (4 * 13)($4)
+  lw    $14, (4 * 14)($4)
+  lw    $15, (4 * 15)($4)
+  lw    $16, (4 * 16)($4)
+  lw    $17, (4 * 17)($4)
+  lw    $18, (4 * 18)($4)
+  lw    $19, (4 * 19)($4)
+  lw    $20, (4 * 20)($4)
+  lw    $21, (4 * 21)($4)
+  lw    $22, (4 * 22)($4)
+  lw    $23, (4 * 23)($4)
+  lw    $24, (4 * 24)($4)
+  lw    $25, (4 * 25)($4)
+  lw    $26, (4 * 26)($4)
+  lw    $27, (4 * 27)($4)
+  lw    $28, (4 * 28)($4)
+  lw    $29, (4 * 29)($4)
+  lw    $30, (4 * 30)($4)
+  // load new pc into ra
+  lw    $31, (4 * 32)($4)
+  // jump to ra, load a0 in the delay slot
+  jr    $31
+  lw    $4, (4 * 4)($4)
+  .set pop
+
+#elif defined(__mips64)
+
+//
+// void libunwind::Registers_mips_newabi::jumpto()
+//
+// On entry:
+//  thread state pointer is in a0 ($4)
+//
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
+  .set push
+  .set noat
+  .set noreorder
+  .set nomacro
+#ifdef __mips_hard_float
+  ldc1  $f0, (8 * 35)($4)
+  ldc1  $f1, (8 * 36)($4)
+  ldc1  $f2, (8 * 37)($4)
+  ldc1  $f3, (8 * 38)($4)
+  ldc1  $f4, (8 * 39)($4)
+  ldc1  $f5, (8 * 40)($4)
+  ldc1  $f6, (8 * 41)($4)
+  ldc1  $f7, (8 * 42)($4)
+  ldc1  $f8, (8 * 43)($4)
+  ldc1  $f9, (8 * 44)($4)
+  ldc1  $f10, (8 * 45)($4)
+  ldc1  $f11, (8 * 46)($4)
+  ldc1  $f12, (8 * 47)($4)
+  ldc1  $f13, (8 * 48)($4)
+  ldc1  $f14, (8 * 49)($4)
+  ldc1  $f15, (8 * 50)($4)
+  ldc1  $f16, (8 * 51)($4)
+  ldc1  $f17, (8 * 52)($4)
+  ldc1  $f18, (8 * 53)($4)
+  ldc1  $f19, (8 * 54)($4)
+  ldc1  $f20, (8 * 55)($4)
+  ldc1  $f21, (8 * 56)($4)
+  ldc1  $f22, (8 * 57)($4)
+  ldc1  $f23, (8 * 58)($4)
+  ldc1  $f24, (8 * 59)($4)
+  ldc1  $f25, (8 * 60)($4)
+  ldc1  $f26, (8 * 61)($4)
+  ldc1  $f27, (8 * 62)($4)
+  ldc1  $f28, (8 * 63)($4)
+  ldc1  $f29, (8 * 64)($4)
+  ldc1  $f30, (8 * 65)($4)
+  ldc1  $f31, (8 * 66)($4)
+#endif
+  // restore hi and lo
+  ld    $8, (8 * 33)($4)
+  mthi  $8
+  ld    $8, (8 * 34)($4)
+  mtlo  $8
+  // r0 is zero
+  ld    $1, (8 * 1)($4)
+  ld    $2, (8 * 2)($4)
+  ld    $3, (8 * 3)($4)
+  // skip a0 for now
+  ld    $5, (8 * 5)($4)
+  ld    $6, (8 * 6)($4)
+  ld    $7, (8 * 7)($4)
+  ld    $8, (8 * 8)($4)
+  ld    $9, (8 * 9)($4)
+  ld    $10, (8 * 10)($4)
+  ld    $11, (8 * 11)($4)
+  ld    $12, (8 * 12)($4)
+  ld    $13, (8 * 13)($4)
+  ld    $14, (8 * 14)($4)
+  ld    $15, (8 * 15)($4)
+  ld    $16, (8 * 16)($4)
+  ld    $17, (8 * 17)($4)
+  ld    $18, (8 * 18)($4)
+  ld    $19, (8 * 19)($4)
+  ld    $20, (8 * 20)($4)
+  ld    $21, (8 * 21)($4)
+  ld    $22, (8 * 22)($4)
+  ld    $23, (8 * 23)($4)
+  ld    $24, (8 * 24)($4)
+  ld    $25, (8 * 25)($4)
+  ld    $26, (8 * 26)($4)
+  ld    $27, (8 * 27)($4)
+  ld    $28, (8 * 28)($4)
+  ld    $29, (8 * 29)($4)
+  ld    $30, (8 * 30)($4)
+  // load new pc into ra
+  ld    $31, (8 * 32)($4)
+  // jump to ra, load a0 in the delay slot
+  jr    $31
+  ld    $4, (8 * 4)($4)
+  .set pop
+
+#elif defined(__sparc__)
+
+//
+// void libunwind::Registers_sparc_o32::jumpto()
+//
+// On entry:
+//  thread_state pointer is in o0
+//
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
+  ta 3
+  ldd [%o0 + 64],  %l0
+  ldd [%o0 + 72],  %l2
+  ldd [%o0 + 80],  %l4
+  ldd [%o0 + 88],  %l6
+  ldd [%o0 + 96],  %i0
+  ldd [%o0 + 104], %i2
+  ldd [%o0 + 112], %i4
+  ldd [%o0 + 120], %i6
+  ld  [%o0 + 60],  %o7
+  jmp %o7
+   nop
+
+#elif defined(__riscv)
+
+//
+// void libunwind::Registers_riscv::jumpto()
+//
+// On entry:
+//  thread_state pointer is in a0
+//
+  .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
+# if defined(__riscv_flen)
+  FLOAD    f0, (RISCV_FOFFSET + RISCV_FSIZE * 0)(a0)
+  FLOAD    f1, (RISCV_FOFFSET + RISCV_FSIZE * 1)(a0)
+  FLOAD    f2, (RISCV_FOFFSET + RISCV_FSIZE * 2)(a0)
+  FLOAD    f3, (RISCV_FOFFSET + RISCV_FSIZE * 3)(a0)
+  FLOAD    f4, (RISCV_FOFFSET + RISCV_FSIZE * 4)(a0)
+  FLOAD    f5, (RISCV_FOFFSET + RISCV_FSIZE * 5)(a0)
+  FLOAD    f6, (RISCV_FOFFSET + RISCV_FSIZE * 6)(a0)
+  FLOAD    f7, (RISCV_FOFFSET + RISCV_FSIZE * 7)(a0)
+  FLOAD    f8, (RISCV_FOFFSET + RISCV_FSIZE * 8)(a0)
+  FLOAD    f9, (RISCV_FOFFSET + RISCV_FSIZE * 9)(a0)
+  FLOAD    f10, (RISCV_FOFFSET + RISCV_FSIZE * 10)(a0)
+  FLOAD    f11, (RISCV_FOFFSET + RISCV_FSIZE * 11)(a0)
+  FLOAD    f12, (RISCV_FOFFSET + RISCV_FSIZE * 12)(a0)
+  FLOAD    f13, (RISCV_FOFFSET + RISCV_FSIZE * 13)(a0)
+  FLOAD    f14, (RISCV_FOFFSET + RISCV_FSIZE * 14)(a0)
+  FLOAD    f15, (RISCV_FOFFSET + RISCV_FSIZE * 15)(a0)
+  FLOAD    f16, (RISCV_FOFFSET + RISCV_FSIZE * 16)(a0)
+  FLOAD    f17, (RISCV_FOFFSET + RISCV_FSIZE * 17)(a0)
+  FLOAD    f18, (RISCV_FOFFSET + RISCV_FSIZE * 18)(a0)
+  FLOAD    f19, (RISCV_FOFFSET + RISCV_FSIZE * 19)(a0)
+  FLOAD    f20, (RISCV_FOFFSET + RISCV_FSIZE * 20)(a0)
+  FLOAD    f21, (RISCV_FOFFSET + RISCV_FSIZE * 21)(a0)
+  FLOAD    f22, (RISCV_FOFFSET + RISCV_FSIZE * 22)(a0)
+  FLOAD    f23, (RISCV_FOFFSET + RISCV_FSIZE * 23)(a0)
+  FLOAD    f24, (RISCV_FOFFSET + RISCV_FSIZE * 24)(a0)
+  FLOAD    f25, (RISCV_FOFFSET + RISCV_FSIZE * 25)(a0)
+  FLOAD    f26, (RISCV_FOFFSET + RISCV_FSIZE * 26)(a0)
+  FLOAD    f27, (RISCV_FOFFSET + RISCV_FSIZE * 27)(a0)
+  FLOAD    f28, (RISCV_FOFFSET + RISCV_FSIZE * 28)(a0)
+  FLOAD    f29, (RISCV_FOFFSET + RISCV_FSIZE * 29)(a0)
+  FLOAD    f30, (RISCV_FOFFSET + RISCV_FSIZE * 30)(a0)
+  FLOAD    f31, (RISCV_FOFFSET + RISCV_FSIZE * 31)(a0)
+# endif
+
+  // x0 is zero
+  ILOAD    x1, (RISCV_ISIZE * 0)(a0) // restore pc into ra
+  ILOAD    x2, (RISCV_ISIZE * 2)(a0)
+  ILOAD    x3, (RISCV_ISIZE * 3)(a0)
+  ILOAD    x4, (RISCV_ISIZE * 4)(a0)
+  ILOAD    x5, (RISCV_ISIZE * 5)(a0)
+  ILOAD    x6, (RISCV_ISIZE * 6)(a0)
+  ILOAD    x7, (RISCV_ISIZE * 7)(a0)
+  ILOAD    x8, (RISCV_ISIZE * 8)(a0)
+  ILOAD    x9, (RISCV_ISIZE * 9)(a0)
+  // skip a0 for now
+  ILOAD    x11, (RISCV_ISIZE * 11)(a0)
+  ILOAD    x12, (RISCV_ISIZE * 12)(a0)
+  ILOAD    x13, (RISCV_ISIZE * 13)(a0)
+  ILOAD    x14, (RISCV_ISIZE * 14)(a0)
+  ILOAD    x15, (RISCV_ISIZE * 15)(a0)
+  ILOAD    x16, (RISCV_ISIZE * 16)(a0)
+  ILOAD    x17, (RISCV_ISIZE * 17)(a0)
+  ILOAD    x18, (RISCV_ISIZE * 18)(a0)
+  ILOAD    x19, (RISCV_ISIZE * 19)(a0)
+  ILOAD    x20, (RISCV_ISIZE * 20)(a0)
+  ILOAD    x21, (RISCV_ISIZE * 21)(a0)
+  ILOAD    x22, (RISCV_ISIZE * 22)(a0)
+  ILOAD    x23, (RISCV_ISIZE * 23)(a0)
+  ILOAD    x24, (RISCV_ISIZE * 24)(a0)
+  ILOAD    x25, (RISCV_ISIZE * 25)(a0)
+  ILOAD    x26, (RISCV_ISIZE * 26)(a0)
+  ILOAD    x27, (RISCV_ISIZE * 27)(a0)
+  ILOAD    x28, (RISCV_ISIZE * 28)(a0)
+  ILOAD    x29, (RISCV_ISIZE * 29)(a0)
+  ILOAD    x30, (RISCV_ISIZE * 30)(a0)
+  ILOAD    x31, (RISCV_ISIZE * 31)(a0)
+  ILOAD    x10, (RISCV_ISIZE * 10)(a0)   // restore a0
+
+  ret                       // jump to ra
+
+#endif
+
+#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
+
+NO_EXEC_STACK_DIRECTIVE
+

+ 1114 - 0
llvm-libunwind/src/UnwindRegistersSave.S

@@ -0,0 +1,1114 @@
+//===------------------------ UnwindRegistersSave.S -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "assembly.h"
+
+    .text
+
+#if !defined(__USING_SJLJ_EXCEPTIONS__)
+
+#if defined(__i386__)
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#   +                       +
+#   +-----------------------+
+#   + thread_state pointer  +
+#   +-----------------------+
+#   + return address        +
+#   +-----------------------+   <-- SP
+#   +                       +
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  push  %eax
+  movl  8(%esp), %eax
+  movl  %ebx,  4(%eax)
+  movl  %ecx,  8(%eax)
+  movl  %edx, 12(%eax)
+  movl  %edi, 16(%eax)
+  movl  %esi, 20(%eax)
+  movl  %ebp, 24(%eax)
+  movl  %esp, %edx
+  addl  $8, %edx
+  movl  %edx, 28(%eax)  # store what sp was at call site as esp
+  # skip ss
+  # skip eflags
+  movl  4(%esp), %edx
+  movl  %edx, 40(%eax)  # store return address as eip
+  # skip cs
+  # skip ds
+  # skip es
+  # skip fs
+  # skip gs
+  movl  (%esp), %edx
+  movl  %edx, (%eax)  # store original eax
+  popl  %eax
+  xorl  %eax, %eax    # return UNW_ESUCCESS
+  ret
+
+#elif defined(__x86_64__)
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in rdi
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+#if defined(_WIN64)
+#define PTR %rcx
+#define TMP %rdx
+#else
+#define PTR %rdi
+#define TMP %rsi
+#endif
+
+  movq  %rax,   (PTR)
+  movq  %rbx,  8(PTR)
+  movq  %rcx, 16(PTR)
+  movq  %rdx, 24(PTR)
+  movq  %rdi, 32(PTR)
+  movq  %rsi, 40(PTR)
+  movq  %rbp, 48(PTR)
+  movq  %rsp, 56(PTR)
+  addq  $8,   56(PTR)
+  movq  %r8,  64(PTR)
+  movq  %r9,  72(PTR)
+  movq  %r10, 80(PTR)
+  movq  %r11, 88(PTR)
+  movq  %r12, 96(PTR)
+  movq  %r13,104(PTR)
+  movq  %r14,112(PTR)
+  movq  %r15,120(PTR)
+  movq  (%rsp),TMP
+  movq  TMP,128(PTR) # store return address as rip
+  # skip rflags
+  # skip cs
+  # skip fs
+  # skip gs
+
+#if defined(_WIN64)
+  movdqu %xmm0,176(PTR)
+  movdqu %xmm1,192(PTR)
+  movdqu %xmm2,208(PTR)
+  movdqu %xmm3,224(PTR)
+  movdqu %xmm4,240(PTR)
+  movdqu %xmm5,256(PTR)
+  movdqu %xmm6,272(PTR)
+  movdqu %xmm7,288(PTR)
+  movdqu %xmm8,304(PTR)
+  movdqu %xmm9,320(PTR)
+  movdqu %xmm10,336(PTR)
+  movdqu %xmm11,352(PTR)
+  movdqu %xmm12,368(PTR)
+  movdqu %xmm13,384(PTR)
+  movdqu %xmm14,400(PTR)
+  movdqu %xmm15,416(PTR)
+#endif
+  xorl  %eax, %eax    # return UNW_ESUCCESS
+  ret
+
+#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in a0 ($4)
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  .set push
+  .set noat
+  .set noreorder
+  .set nomacro
+  sw    $1, (4 * 1)($4)
+  sw    $2, (4 * 2)($4)
+  sw    $3, (4 * 3)($4)
+  sw    $4, (4 * 4)($4)
+  sw    $5, (4 * 5)($4)
+  sw    $6, (4 * 6)($4)
+  sw    $7, (4 * 7)($4)
+  sw    $8, (4 * 8)($4)
+  sw    $9, (4 * 9)($4)
+  sw    $10, (4 * 10)($4)
+  sw    $11, (4 * 11)($4)
+  sw    $12, (4 * 12)($4)
+  sw    $13, (4 * 13)($4)
+  sw    $14, (4 * 14)($4)
+  sw    $15, (4 * 15)($4)
+  sw    $16, (4 * 16)($4)
+  sw    $17, (4 * 17)($4)
+  sw    $18, (4 * 18)($4)
+  sw    $19, (4 * 19)($4)
+  sw    $20, (4 * 20)($4)
+  sw    $21, (4 * 21)($4)
+  sw    $22, (4 * 22)($4)
+  sw    $23, (4 * 23)($4)
+  sw    $24, (4 * 24)($4)
+  sw    $25, (4 * 25)($4)
+  sw    $26, (4 * 26)($4)
+  sw    $27, (4 * 27)($4)
+  sw    $28, (4 * 28)($4)
+  sw    $29, (4 * 29)($4)
+  sw    $30, (4 * 30)($4)
+  sw    $31, (4 * 31)($4)
+  # Store return address to pc
+  sw    $31, (4 * 32)($4)
+  # hi and lo
+  mfhi  $8
+  sw    $8,  (4 * 33)($4)
+  mflo  $8
+  sw    $8,  (4 * 34)($4)
+#ifdef __mips_hard_float
+#if __mips_fpr != 64
+  sdc1  $f0, (4 * 36 + 8 * 0)($4)
+  sdc1  $f2, (4 * 36 + 8 * 2)($4)
+  sdc1  $f4, (4 * 36 + 8 * 4)($4)
+  sdc1  $f6, (4 * 36 + 8 * 6)($4)
+  sdc1  $f8, (4 * 36 + 8 * 8)($4)
+  sdc1  $f10, (4 * 36 + 8 * 10)($4)
+  sdc1  $f12, (4 * 36 + 8 * 12)($4)
+  sdc1  $f14, (4 * 36 + 8 * 14)($4)
+  sdc1  $f16, (4 * 36 + 8 * 16)($4)
+  sdc1  $f18, (4 * 36 + 8 * 18)($4)
+  sdc1  $f20, (4 * 36 + 8 * 20)($4)
+  sdc1  $f22, (4 * 36 + 8 * 22)($4)
+  sdc1  $f24, (4 * 36 + 8 * 24)($4)
+  sdc1  $f26, (4 * 36 + 8 * 26)($4)
+  sdc1  $f28, (4 * 36 + 8 * 28)($4)
+  sdc1  $f30, (4 * 36 + 8 * 30)($4)
+#else
+  sdc1  $f0, (4 * 36 + 8 * 0)($4)
+  sdc1  $f1, (4 * 36 + 8 * 1)($4)
+  sdc1  $f2, (4 * 36 + 8 * 2)($4)
+  sdc1  $f3, (4 * 36 + 8 * 3)($4)
+  sdc1  $f4, (4 * 36 + 8 * 4)($4)
+  sdc1  $f5, (4 * 36 + 8 * 5)($4)
+  sdc1  $f6, (4 * 36 + 8 * 6)($4)
+  sdc1  $f7, (4 * 36 + 8 * 7)($4)
+  sdc1  $f8, (4 * 36 + 8 * 8)($4)
+  sdc1  $f9, (4 * 36 + 8 * 9)($4)
+  sdc1  $f10, (4 * 36 + 8 * 10)($4)
+  sdc1  $f11, (4 * 36 + 8 * 11)($4)
+  sdc1  $f12, (4 * 36 + 8 * 12)($4)
+  sdc1  $f13, (4 * 36 + 8 * 13)($4)
+  sdc1  $f14, (4 * 36 + 8 * 14)($4)
+  sdc1  $f15, (4 * 36 + 8 * 15)($4)
+  sdc1  $f16, (4 * 36 + 8 * 16)($4)
+  sdc1  $f17, (4 * 36 + 8 * 17)($4)
+  sdc1  $f18, (4 * 36 + 8 * 18)($4)
+  sdc1  $f19, (4 * 36 + 8 * 19)($4)
+  sdc1  $f20, (4 * 36 + 8 * 20)($4)
+  sdc1  $f21, (4 * 36 + 8 * 21)($4)
+  sdc1  $f22, (4 * 36 + 8 * 22)($4)
+  sdc1  $f23, (4 * 36 + 8 * 23)($4)
+  sdc1  $f24, (4 * 36 + 8 * 24)($4)
+  sdc1  $f25, (4 * 36 + 8 * 25)($4)
+  sdc1  $f26, (4 * 36 + 8 * 26)($4)
+  sdc1  $f27, (4 * 36 + 8 * 27)($4)
+  sdc1  $f28, (4 * 36 + 8 * 28)($4)
+  sdc1  $f29, (4 * 36 + 8 * 29)($4)
+  sdc1  $f30, (4 * 36 + 8 * 30)($4)
+  sdc1  $f31, (4 * 36 + 8 * 31)($4)
+#endif
+#endif
+  jr	$31
+  # return UNW_ESUCCESS
+  or    $2, $0, $0
+  .set pop
+
+#elif defined(__mips64)
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in a0 ($4)
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  .set push
+  .set noat
+  .set noreorder
+  .set nomacro
+  sd    $1, (8 * 1)($4)
+  sd    $2, (8 * 2)($4)
+  sd    $3, (8 * 3)($4)
+  sd    $4, (8 * 4)($4)
+  sd    $5, (8 * 5)($4)
+  sd    $6, (8 * 6)($4)
+  sd    $7, (8 * 7)($4)
+  sd    $8, (8 * 8)($4)
+  sd    $9, (8 * 9)($4)
+  sd    $10, (8 * 10)($4)
+  sd    $11, (8 * 11)($4)
+  sd    $12, (8 * 12)($4)
+  sd    $13, (8 * 13)($4)
+  sd    $14, (8 * 14)($4)
+  sd    $15, (8 * 15)($4)
+  sd    $16, (8 * 16)($4)
+  sd    $17, (8 * 17)($4)
+  sd    $18, (8 * 18)($4)
+  sd    $19, (8 * 19)($4)
+  sd    $20, (8 * 20)($4)
+  sd    $21, (8 * 21)($4)
+  sd    $22, (8 * 22)($4)
+  sd    $23, (8 * 23)($4)
+  sd    $24, (8 * 24)($4)
+  sd    $25, (8 * 25)($4)
+  sd    $26, (8 * 26)($4)
+  sd    $27, (8 * 27)($4)
+  sd    $28, (8 * 28)($4)
+  sd    $29, (8 * 29)($4)
+  sd    $30, (8 * 30)($4)
+  sd    $31, (8 * 31)($4)
+  # Store return address to pc
+  sd    $31, (8 * 32)($4)
+  # hi and lo
+  mfhi  $8
+  sd    $8,  (8 * 33)($4)
+  mflo  $8
+  sd    $8,  (8 * 34)($4)
+#ifdef __mips_hard_float
+  sdc1  $f0, (8 * 35)($4)
+  sdc1  $f1, (8 * 36)($4)
+  sdc1  $f2, (8 * 37)($4)
+  sdc1  $f3, (8 * 38)($4)
+  sdc1  $f4, (8 * 39)($4)
+  sdc1  $f5, (8 * 40)($4)
+  sdc1  $f6, (8 * 41)($4)
+  sdc1  $f7, (8 * 42)($4)
+  sdc1  $f8, (8 * 43)($4)
+  sdc1  $f9, (8 * 44)($4)
+  sdc1  $f10, (8 * 45)($4)
+  sdc1  $f11, (8 * 46)($4)
+  sdc1  $f12, (8 * 47)($4)
+  sdc1  $f13, (8 * 48)($4)
+  sdc1  $f14, (8 * 49)($4)
+  sdc1  $f15, (8 * 50)($4)
+  sdc1  $f16, (8 * 51)($4)
+  sdc1  $f17, (8 * 52)($4)
+  sdc1  $f18, (8 * 53)($4)
+  sdc1  $f19, (8 * 54)($4)
+  sdc1  $f20, (8 * 55)($4)
+  sdc1  $f21, (8 * 56)($4)
+  sdc1  $f22, (8 * 57)($4)
+  sdc1  $f23, (8 * 58)($4)
+  sdc1  $f24, (8 * 59)($4)
+  sdc1  $f25, (8 * 60)($4)
+  sdc1  $f26, (8 * 61)($4)
+  sdc1  $f27, (8 * 62)($4)
+  sdc1  $f28, (8 * 63)($4)
+  sdc1  $f29, (8 * 64)($4)
+  sdc1  $f30, (8 * 65)($4)
+  sdc1  $f31, (8 * 66)($4)
+#endif
+  jr	$31
+  # return UNW_ESUCCESS
+  or    $2, $0, $0
+  .set pop
+
+# elif defined(__mips__)
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# Just trap for the time being.
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  teq $0, $0
+
+#elif defined(__powerpc64__)
+
+//
+// extern int __unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+//  thread_state pointer is in r3
+//
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+
+// store register (GPR)
+#define PPC64_STR(n) \
+  std   n, (8 * (n + 2))(3)
+
+  // save GPRs
+  PPC64_STR(0)
+  mflr  0
+  std   0, PPC64_OFFS_SRR0(3) // store lr as ssr0
+  PPC64_STR(1)
+  PPC64_STR(2)
+  PPC64_STR(3)
+  PPC64_STR(4)
+  PPC64_STR(5)
+  PPC64_STR(6)
+  PPC64_STR(7)
+  PPC64_STR(8)
+  PPC64_STR(9)
+  PPC64_STR(10)
+  PPC64_STR(11)
+  PPC64_STR(12)
+  PPC64_STR(13)
+  PPC64_STR(14)
+  PPC64_STR(15)
+  PPC64_STR(16)
+  PPC64_STR(17)
+  PPC64_STR(18)
+  PPC64_STR(19)
+  PPC64_STR(20)
+  PPC64_STR(21)
+  PPC64_STR(22)
+  PPC64_STR(23)
+  PPC64_STR(24)
+  PPC64_STR(25)
+  PPC64_STR(26)
+  PPC64_STR(27)
+  PPC64_STR(28)
+  PPC64_STR(29)
+  PPC64_STR(30)
+  PPC64_STR(31)
+
+  mfcr  0
+  std   0,  PPC64_OFFS_CR(3)
+  mfxer 0
+  std   0,  PPC64_OFFS_XER(3)
+  mflr  0
+  std   0,  PPC64_OFFS_LR(3)
+  mfctr 0
+  std   0,  PPC64_OFFS_CTR(3)
+  mfvrsave    0
+  std   0,  PPC64_OFFS_VRSAVE(3)
+
+#if defined(__VSX__)
+  // save VS registers
+  // (note that this also saves floating point registers and V registers,
+  // because part of VS is mapped to these registers)
+
+  addi  4, 3, PPC64_OFFS_FP
+
+// store VS register
+#define PPC64_STVS(n)      \
+  stxvd2x n, 0, 4         ;\
+  addi    4, 4, 16
+
+  PPC64_STVS(0)
+  PPC64_STVS(1)
+  PPC64_STVS(2)
+  PPC64_STVS(3)
+  PPC64_STVS(4)
+  PPC64_STVS(5)
+  PPC64_STVS(6)
+  PPC64_STVS(7)
+  PPC64_STVS(8)
+  PPC64_STVS(9)
+  PPC64_STVS(10)
+  PPC64_STVS(11)
+  PPC64_STVS(12)
+  PPC64_STVS(13)
+  PPC64_STVS(14)
+  PPC64_STVS(15)
+  PPC64_STVS(16)
+  PPC64_STVS(17)
+  PPC64_STVS(18)
+  PPC64_STVS(19)
+  PPC64_STVS(20)
+  PPC64_STVS(21)
+  PPC64_STVS(22)
+  PPC64_STVS(23)
+  PPC64_STVS(24)
+  PPC64_STVS(25)
+  PPC64_STVS(26)
+  PPC64_STVS(27)
+  PPC64_STVS(28)
+  PPC64_STVS(29)
+  PPC64_STVS(30)
+  PPC64_STVS(31)
+  PPC64_STVS(32)
+  PPC64_STVS(33)
+  PPC64_STVS(34)
+  PPC64_STVS(35)
+  PPC64_STVS(36)
+  PPC64_STVS(37)
+  PPC64_STVS(38)
+  PPC64_STVS(39)
+  PPC64_STVS(40)
+  PPC64_STVS(41)
+  PPC64_STVS(42)
+  PPC64_STVS(43)
+  PPC64_STVS(44)
+  PPC64_STVS(45)
+  PPC64_STVS(46)
+  PPC64_STVS(47)
+  PPC64_STVS(48)
+  PPC64_STVS(49)
+  PPC64_STVS(50)
+  PPC64_STVS(51)
+  PPC64_STVS(52)
+  PPC64_STVS(53)
+  PPC64_STVS(54)
+  PPC64_STVS(55)
+  PPC64_STVS(56)
+  PPC64_STVS(57)
+  PPC64_STVS(58)
+  PPC64_STVS(59)
+  PPC64_STVS(60)
+  PPC64_STVS(61)
+  PPC64_STVS(62)
+  PPC64_STVS(63)
+
+#else
+
+// store FP register
+#define PPC64_STF(n) \
+  stfd  n, (PPC64_OFFS_FP + n * 16)(3)
+
+  // save float registers
+  PPC64_STF(0)
+  PPC64_STF(1)
+  PPC64_STF(2)
+  PPC64_STF(3)
+  PPC64_STF(4)
+  PPC64_STF(5)
+  PPC64_STF(6)
+  PPC64_STF(7)
+  PPC64_STF(8)
+  PPC64_STF(9)
+  PPC64_STF(10)
+  PPC64_STF(11)
+  PPC64_STF(12)
+  PPC64_STF(13)
+  PPC64_STF(14)
+  PPC64_STF(15)
+  PPC64_STF(16)
+  PPC64_STF(17)
+  PPC64_STF(18)
+  PPC64_STF(19)
+  PPC64_STF(20)
+  PPC64_STF(21)
+  PPC64_STF(22)
+  PPC64_STF(23)
+  PPC64_STF(24)
+  PPC64_STF(25)
+  PPC64_STF(26)
+  PPC64_STF(27)
+  PPC64_STF(28)
+  PPC64_STF(29)
+  PPC64_STF(30)
+  PPC64_STF(31)
+
+#if defined(__ALTIVEC__)
+  // save vector registers
+
+  // Use 16-bytes below the stack pointer as an
+  // aligned buffer to save each vector register.
+  // Note that the stack pointer is always 16-byte aligned.
+  subi  4, 1, 16
+
+#define PPC64_STV_UNALIGNED(n)             \
+  stvx  n, 0, 4                           ;\
+  ld    5, 0(4)                           ;\
+  std   5, (PPC64_OFFS_V + n * 16)(3)     ;\
+  ld    5, 8(4)                           ;\
+  std   5, (PPC64_OFFS_V + n * 16 + 8)(3)
+
+  PPC64_STV_UNALIGNED(0)
+  PPC64_STV_UNALIGNED(1)
+  PPC64_STV_UNALIGNED(2)
+  PPC64_STV_UNALIGNED(3)
+  PPC64_STV_UNALIGNED(4)
+  PPC64_STV_UNALIGNED(5)
+  PPC64_STV_UNALIGNED(6)
+  PPC64_STV_UNALIGNED(7)
+  PPC64_STV_UNALIGNED(8)
+  PPC64_STV_UNALIGNED(9)
+  PPC64_STV_UNALIGNED(10)
+  PPC64_STV_UNALIGNED(11)
+  PPC64_STV_UNALIGNED(12)
+  PPC64_STV_UNALIGNED(13)
+  PPC64_STV_UNALIGNED(14)
+  PPC64_STV_UNALIGNED(15)
+  PPC64_STV_UNALIGNED(16)
+  PPC64_STV_UNALIGNED(17)
+  PPC64_STV_UNALIGNED(18)
+  PPC64_STV_UNALIGNED(19)
+  PPC64_STV_UNALIGNED(20)
+  PPC64_STV_UNALIGNED(21)
+  PPC64_STV_UNALIGNED(22)
+  PPC64_STV_UNALIGNED(23)
+  PPC64_STV_UNALIGNED(24)
+  PPC64_STV_UNALIGNED(25)
+  PPC64_STV_UNALIGNED(26)
+  PPC64_STV_UNALIGNED(27)
+  PPC64_STV_UNALIGNED(28)
+  PPC64_STV_UNALIGNED(29)
+  PPC64_STV_UNALIGNED(30)
+  PPC64_STV_UNALIGNED(31)
+
+#endif
+#endif
+
+  li    3,  0   // return UNW_ESUCCESS
+  blr
+
+
+#elif defined(__ppc__)
+
+//
+// extern int unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+//  thread_state pointer is in r3
+//
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  stw     0,   8(3)
+  mflr    0
+  stw     0,   0(3) // store lr as ssr0
+  stw     1,  12(3)
+  stw     2,  16(3)
+  stw     3,  20(3)
+  stw     4,  24(3)
+  stw     5,  28(3)
+  stw     6,  32(3)
+  stw     7,  36(3)
+  stw     8,  40(3)
+  stw     9,  44(3)
+  stw     10, 48(3)
+  stw     11, 52(3)
+  stw     12, 56(3)
+  stw     13, 60(3)
+  stw     14, 64(3)
+  stw     15, 68(3)
+  stw     16, 72(3)
+  stw     17, 76(3)
+  stw     18, 80(3)
+  stw     19, 84(3)
+  stw     20, 88(3)
+  stw     21, 92(3)
+  stw     22, 96(3)
+  stw     23,100(3)
+  stw     24,104(3)
+  stw     25,108(3)
+  stw     26,112(3)
+  stw     27,116(3)
+  stw     28,120(3)
+  stw     29,124(3)
+  stw     30,128(3)
+  stw     31,132(3)
+
+  // save VRSave register
+  mfspr   0, 256
+  stw     0, 156(3)
+  // save CR registers
+  mfcr    0
+  stw     0, 136(3)
+  // save CTR register
+  mfctr   0
+  stw     0, 148(3)
+
+#if !defined(__NO_FPRS__)
+  // save float registers
+  stfd    0, 160(3)
+  stfd    1, 168(3)
+  stfd    2, 176(3)
+  stfd    3, 184(3)
+  stfd    4, 192(3)
+  stfd    5, 200(3)
+  stfd    6, 208(3)
+  stfd    7, 216(3)
+  stfd    8, 224(3)
+  stfd    9, 232(3)
+  stfd    10,240(3)
+  stfd    11,248(3)
+  stfd    12,256(3)
+  stfd    13,264(3)
+  stfd    14,272(3)
+  stfd    15,280(3)
+  stfd    16,288(3)
+  stfd    17,296(3)
+  stfd    18,304(3)
+  stfd    19,312(3)
+  stfd    20,320(3)
+  stfd    21,328(3)
+  stfd    22,336(3)
+  stfd    23,344(3)
+  stfd    24,352(3)
+  stfd    25,360(3)
+  stfd    26,368(3)
+  stfd    27,376(3)
+  stfd    28,384(3)
+  stfd    29,392(3)
+  stfd    30,400(3)
+  stfd    31,408(3)
+#endif
+
+#if defined(__ALTIVEC__)
+  // save vector registers
+
+  subi    4, 1, 16
+  rlwinm  4, 4, 0, 0, 27  // mask low 4-bits
+  // r4 is now a 16-byte aligned pointer into the red zone
+
+#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
+  stvx    _vec, 0, 4               SEPARATOR \
+  lwz     5, 0(4)                  SEPARATOR \
+  stw     5, _offset(3)            SEPARATOR \
+  lwz     5, 4(4)                  SEPARATOR \
+  stw     5, _offset+4(3)          SEPARATOR \
+  lwz     5, 8(4)                  SEPARATOR \
+  stw     5, _offset+8(3)          SEPARATOR \
+  lwz     5, 12(4)                 SEPARATOR \
+  stw     5, _offset+12(3)
+
+  SAVE_VECTOR_UNALIGNED( 0, 424+0x000)
+  SAVE_VECTOR_UNALIGNED( 1, 424+0x010)
+  SAVE_VECTOR_UNALIGNED( 2, 424+0x020)
+  SAVE_VECTOR_UNALIGNED( 3, 424+0x030)
+  SAVE_VECTOR_UNALIGNED( 4, 424+0x040)
+  SAVE_VECTOR_UNALIGNED( 5, 424+0x050)
+  SAVE_VECTOR_UNALIGNED( 6, 424+0x060)
+  SAVE_VECTOR_UNALIGNED( 7, 424+0x070)
+  SAVE_VECTOR_UNALIGNED( 8, 424+0x080)
+  SAVE_VECTOR_UNALIGNED( 9, 424+0x090)
+  SAVE_VECTOR_UNALIGNED(10, 424+0x0A0)
+  SAVE_VECTOR_UNALIGNED(11, 424+0x0B0)
+  SAVE_VECTOR_UNALIGNED(12, 424+0x0C0)
+  SAVE_VECTOR_UNALIGNED(13, 424+0x0D0)
+  SAVE_VECTOR_UNALIGNED(14, 424+0x0E0)
+  SAVE_VECTOR_UNALIGNED(15, 424+0x0F0)
+  SAVE_VECTOR_UNALIGNED(16, 424+0x100)
+  SAVE_VECTOR_UNALIGNED(17, 424+0x110)
+  SAVE_VECTOR_UNALIGNED(18, 424+0x120)
+  SAVE_VECTOR_UNALIGNED(19, 424+0x130)
+  SAVE_VECTOR_UNALIGNED(20, 424+0x140)
+  SAVE_VECTOR_UNALIGNED(21, 424+0x150)
+  SAVE_VECTOR_UNALIGNED(22, 424+0x160)
+  SAVE_VECTOR_UNALIGNED(23, 424+0x170)
+  SAVE_VECTOR_UNALIGNED(24, 424+0x180)
+  SAVE_VECTOR_UNALIGNED(25, 424+0x190)
+  SAVE_VECTOR_UNALIGNED(26, 424+0x1A0)
+  SAVE_VECTOR_UNALIGNED(27, 424+0x1B0)
+  SAVE_VECTOR_UNALIGNED(28, 424+0x1C0)
+  SAVE_VECTOR_UNALIGNED(29, 424+0x1D0)
+  SAVE_VECTOR_UNALIGNED(30, 424+0x1E0)
+  SAVE_VECTOR_UNALIGNED(31, 424+0x1F0)
+#endif
+
+  li      3, 0  // return UNW_ESUCCESS
+  blr
+
+
+#elif defined(__aarch64__)
+
+//
+// extern int __unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+//  thread_state pointer is in x0
+//
+  .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  stp    x0, x1,  [x0, #0x000]
+  stp    x2, x3,  [x0, #0x010]
+  stp    x4, x5,  [x0, #0x020]
+  stp    x6, x7,  [x0, #0x030]
+  stp    x8, x9,  [x0, #0x040]
+  stp    x10,x11, [x0, #0x050]
+  stp    x12,x13, [x0, #0x060]
+  stp    x14,x15, [x0, #0x070]
+  stp    x16,x17, [x0, #0x080]
+  stp    x18,x19, [x0, #0x090]
+  stp    x20,x21, [x0, #0x0A0]
+  stp    x22,x23, [x0, #0x0B0]
+  stp    x24,x25, [x0, #0x0C0]
+  stp    x26,x27, [x0, #0x0D0]
+  stp    x28,x29, [x0, #0x0E0]
+  str    x30,     [x0, #0x0F0]
+  mov    x1,sp
+  str    x1,      [x0, #0x0F8]
+  str    x30,     [x0, #0x100]    // store return address as pc
+  // skip cpsr
+  stp    d0, d1,  [x0, #0x110]
+  stp    d2, d3,  [x0, #0x120]
+  stp    d4, d5,  [x0, #0x130]
+  stp    d6, d7,  [x0, #0x140]
+  stp    d8, d9,  [x0, #0x150]
+  stp    d10,d11, [x0, #0x160]
+  stp    d12,d13, [x0, #0x170]
+  stp    d14,d15, [x0, #0x180]
+  stp    d16,d17, [x0, #0x190]
+  stp    d18,d19, [x0, #0x1A0]
+  stp    d20,d21, [x0, #0x1B0]
+  stp    d22,d23, [x0, #0x1C0]
+  stp    d24,d25, [x0, #0x1D0]
+  stp    d26,d27, [x0, #0x1E0]
+  stp    d28,d29, [x0, #0x1F0]
+  str    d30,     [x0, #0x200]
+  str    d31,     [x0, #0x208]
+  mov    x0, #0                   // return UNW_ESUCCESS
+  ret
+
+#elif defined(__arm__) && !defined(__APPLE__)
+
+#if !defined(__ARM_ARCH_ISA_ARM)
+#if (__ARM_ARCH_ISA_THUMB == 2)
+  .syntax unified
+#endif
+  .thumb
+#endif
+
+@
+@ extern int __unw_getcontext(unw_context_t* thread_state)
+@
+@ On entry:
+@  thread_state pointer is in r0
+@ 
+@ Per EHABI #4.7 this only saves the core integer registers.
+@ EHABI #7.4.5 notes that in general all VRS registers should be restored
+@ however this is very hard to do for VFP registers because it is unknown
+@ to the library how many registers are implemented by the architecture.
+@ Instead, VFP registers are demand saved by logic external to __unw_getcontext.
+@
+  .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
+  stm r0!, {r0-r7}
+  mov r1, r8
+  mov r2, r9
+  mov r3, r10
+  stm r0!, {r1-r3}
+  mov r1, r11
+  mov r2, sp
+  mov r3, lr
+  str r1, [r0, #0]   @ r11
+  @ r12 does not need storing, it it the intra-procedure-call scratch register
+  str r2, [r0, #8]   @ sp
+  str r3, [r0, #12]  @ lr
+  str r3, [r0, #16]  @ store return address as pc
+  @ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
+  @ It is safe to use here though because we are about to return, and cpsr is
+  @ not expected to be preserved.
+  movs r0, #0        @ return UNW_ESUCCESS
+#else
+  @ 32bit thumb-2 restrictions for stm:
+  @ . the sp (r13) cannot be in the list
+  @ . the pc (r15) cannot be in the list in an STM instruction
+  stm r0, {r0-r12}
+  str sp, [r0, #52]
+  str lr, [r0, #56]
+  str lr, [r0, #60]  @ store return address as pc
+  mov r0, #0         @ return UNW_ESUCCESS
+#endif
+  JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .fpu vfpv3-d16
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPv)
+  vstmia r0, {d0-d15}
+  JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .fpu vfpv3-d16
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPv)
+  vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
+  JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .fpu vfpv3
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPv)
+  @ VFP and iwMMX instructions are only available when compiling with the flags
+  @ that enable them. We do not want to do that in the library (because we do not
+  @ want the compiler to generate instructions that access those) but this is
+  @ only accessed if the personality routine needs these registers. Use of
+  @ these registers implies they are, actually, available on the target, so
+  @ it's ok to execute.
+  @ So, generate the instructions using the corresponding coprocessor mnemonic.
+  vstmia r0, {d16-d31}
+  JMP(lr)
+
+#if defined(_LIBUNWIND_ARM_WMMX)
+
+@
+@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .arch armv5te
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPv)
+  stcl p1, cr0, [r0], #8  @ wstrd wR0, [r0], #8
+  stcl p1, cr1, [r0], #8  @ wstrd wR1, [r0], #8
+  stcl p1, cr2, [r0], #8  @ wstrd wR2, [r0], #8
+  stcl p1, cr3, [r0], #8  @ wstrd wR3, [r0], #8
+  stcl p1, cr4, [r0], #8  @ wstrd wR4, [r0], #8
+  stcl p1, cr5, [r0], #8  @ wstrd wR5, [r0], #8
+  stcl p1, cr6, [r0], #8  @ wstrd wR6, [r0], #8
+  stcl p1, cr7, [r0], #8  @ wstrd wR7, [r0], #8
+  stcl p1, cr8, [r0], #8  @ wstrd wR8, [r0], #8
+  stcl p1, cr9, [r0], #8  @ wstrd wR9, [r0], #8
+  stcl p1, cr10, [r0], #8  @ wstrd wR10, [r0], #8
+  stcl p1, cr11, [r0], #8  @ wstrd wR11, [r0], #8
+  stcl p1, cr12, [r0], #8  @ wstrd wR12, [r0], #8
+  stcl p1, cr13, [r0], #8  @ wstrd wR13, [r0], #8
+  stcl p1, cr14, [r0], #8  @ wstrd wR14, [r0], #8
+  stcl p1, cr15, [r0], #8  @ wstrd wR15, [r0], #8
+  JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values)
+@
+@ On entry:
+@  values pointer is in r0
+@
+  .p2align 2
+#if defined(__ELF__)
+  .arch armv5te
+#endif
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
+  stc2 p1, cr8, [r0], #4  @ wstrw wCGR0, [r0], #4
+  stc2 p1, cr9, [r0], #4  @ wstrw wCGR1, [r0], #4
+  stc2 p1, cr10, [r0], #4  @ wstrw wCGR2, [r0], #4
+  stc2 p1, cr11, [r0], #4  @ wstrw wCGR3, [r0], #4
+  JMP(lr)
+
+#endif
+
+#elif defined(__or1k__)
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in r3
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  l.sw       0(r3), r0
+  l.sw       4(r3), r1
+  l.sw       8(r3), r2
+  l.sw      12(r3), r3
+  l.sw      16(r3), r4
+  l.sw      20(r3), r5
+  l.sw      24(r3), r6
+  l.sw      28(r3), r7
+  l.sw      32(r3), r8
+  l.sw      36(r3), r9
+  l.sw      40(r3), r10
+  l.sw      44(r3), r11
+  l.sw      48(r3), r12
+  l.sw      52(r3), r13
+  l.sw      56(r3), r14
+  l.sw      60(r3), r15
+  l.sw      64(r3), r16
+  l.sw      68(r3), r17
+  l.sw      72(r3), r18
+  l.sw      76(r3), r19
+  l.sw      80(r3), r20
+  l.sw      84(r3), r21
+  l.sw      88(r3), r22
+  l.sw      92(r3), r23
+  l.sw      96(r3), r24
+  l.sw     100(r3), r25
+  l.sw     104(r3), r26
+  l.sw     108(r3), r27
+  l.sw     112(r3), r28
+  l.sw     116(r3), r29
+  l.sw     120(r3), r30
+  l.sw     124(r3), r31
+  # store ra to pc
+  l.sw     128(r3), r9
+  # zero epcr
+  l.sw     132(r3), r0
+
+#elif defined(__hexagon__)
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in r0
+#
+#define OFFSET(offset) (offset/4)
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  memw(r0+#32) = r8
+  memw(r0+#36) = r9
+  memw(r0+#40) = r10
+  memw(r0+#44) = r11
+
+  memw(r0+#48) = r12
+  memw(r0+#52) = r13
+  memw(r0+#56) = r14
+  memw(r0+#60) = r15
+
+  memw(r0+#64) = r16
+  memw(r0+#68) = r17
+  memw(r0+#72) = r18
+  memw(r0+#76) = r19
+
+  memw(r0+#80) = r20
+  memw(r0+#84) = r21
+  memw(r0+#88) = r22
+  memw(r0+#92) = r23
+
+  memw(r0+#96) = r24
+  memw(r0+#100) = r25
+  memw(r0+#104) = r26
+  memw(r0+#108) = r27
+
+  memw(r0+#112) = r28
+  memw(r0+#116) = r29
+  memw(r0+#120) = r30
+  memw(r0+#124) = r31
+  r1 = c4   // Predicate register
+  memw(r0+#128) = r1
+  r1 = memw(r30)           // *FP == Saved FP
+  r1 = r31
+  memw(r0+#132) = r1
+
+  jumpr r31
+
+#elif defined(__sparc__)
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in o0
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  ta 3
+  add %o7, 8, %o7
+  std %g0, [%o0 +   0]
+  std %g2, [%o0 +   8]
+  std %g4, [%o0 +  16]
+  std %g6, [%o0 +  24]
+  std %o0, [%o0 +  32]
+  std %o2, [%o0 +  40]
+  std %o4, [%o0 +  48]
+  std %o6, [%o0 +  56]
+  std %l0, [%o0 +  64]
+  std %l2, [%o0 +  72]
+  std %l4, [%o0 +  80]
+  std %l6, [%o0 +  88]
+  std %i0, [%o0 +  96]
+  std %i2, [%o0 + 104]
+  std %i4, [%o0 + 112]
+  std %i6, [%o0 + 120]
+  jmp %o7
+   clr %o0                   // return UNW_ESUCCESS
+
+#elif defined(__riscv)
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in a0
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  ISTORE    x1, (RISCV_ISIZE * 0)(a0) // store ra as pc
+  ISTORE    x1, (RISCV_ISIZE * 1)(a0)
+  ISTORE    x2, (RISCV_ISIZE * 2)(a0)
+  ISTORE    x3, (RISCV_ISIZE * 3)(a0)
+  ISTORE    x4, (RISCV_ISIZE * 4)(a0)
+  ISTORE    x5, (RISCV_ISIZE * 5)(a0)
+  ISTORE    x6, (RISCV_ISIZE * 6)(a0)
+  ISTORE    x7, (RISCV_ISIZE * 7)(a0)
+  ISTORE    x8, (RISCV_ISIZE * 8)(a0)
+  ISTORE    x9, (RISCV_ISIZE * 9)(a0)
+  ISTORE    x10, (RISCV_ISIZE * 10)(a0)
+  ISTORE    x11, (RISCV_ISIZE * 11)(a0)
+  ISTORE    x12, (RISCV_ISIZE * 12)(a0)
+  ISTORE    x13, (RISCV_ISIZE * 13)(a0)
+  ISTORE    x14, (RISCV_ISIZE * 14)(a0)
+  ISTORE    x15, (RISCV_ISIZE * 15)(a0)
+  ISTORE    x16, (RISCV_ISIZE * 16)(a0)
+  ISTORE    x17, (RISCV_ISIZE * 17)(a0)
+  ISTORE    x18, (RISCV_ISIZE * 18)(a0)
+  ISTORE    x19, (RISCV_ISIZE * 19)(a0)
+  ISTORE    x20, (RISCV_ISIZE * 20)(a0)
+  ISTORE    x21, (RISCV_ISIZE * 21)(a0)
+  ISTORE    x22, (RISCV_ISIZE * 22)(a0)
+  ISTORE    x23, (RISCV_ISIZE * 23)(a0)
+  ISTORE    x24, (RISCV_ISIZE * 24)(a0)
+  ISTORE    x25, (RISCV_ISIZE * 25)(a0)
+  ISTORE    x26, (RISCV_ISIZE * 26)(a0)
+  ISTORE    x27, (RISCV_ISIZE * 27)(a0)
+  ISTORE    x28, (RISCV_ISIZE * 28)(a0)
+  ISTORE    x29, (RISCV_ISIZE * 29)(a0)
+  ISTORE    x30, (RISCV_ISIZE * 30)(a0)
+  ISTORE    x31, (RISCV_ISIZE * 31)(a0)
+
+# if defined(__riscv_flen)
+  FSTORE    f0, (RISCV_FOFFSET + RISCV_FSIZE * 0)(a0)
+  FSTORE    f1, (RISCV_FOFFSET + RISCV_FSIZE * 1)(a0)
+  FSTORE    f2, (RISCV_FOFFSET + RISCV_FSIZE * 2)(a0)
+  FSTORE    f3, (RISCV_FOFFSET + RISCV_FSIZE * 3)(a0)
+  FSTORE    f4, (RISCV_FOFFSET + RISCV_FSIZE * 4)(a0)
+  FSTORE    f5, (RISCV_FOFFSET + RISCV_FSIZE * 5)(a0)
+  FSTORE    f6, (RISCV_FOFFSET + RISCV_FSIZE * 6)(a0)
+  FSTORE    f7, (RISCV_FOFFSET + RISCV_FSIZE * 7)(a0)
+  FSTORE    f8, (RISCV_FOFFSET + RISCV_FSIZE * 8)(a0)
+  FSTORE    f9, (RISCV_FOFFSET + RISCV_FSIZE * 9)(a0)
+  FSTORE    f10, (RISCV_FOFFSET + RISCV_FSIZE * 10)(a0)
+  FSTORE    f11, (RISCV_FOFFSET + RISCV_FSIZE * 11)(a0)
+  FSTORE    f12, (RISCV_FOFFSET + RISCV_FSIZE * 12)(a0)
+  FSTORE    f13, (RISCV_FOFFSET + RISCV_FSIZE * 13)(a0)
+  FSTORE    f14, (RISCV_FOFFSET + RISCV_FSIZE * 14)(a0)
+  FSTORE    f15, (RISCV_FOFFSET + RISCV_FSIZE * 15)(a0)
+  FSTORE    f16, (RISCV_FOFFSET + RISCV_FSIZE * 16)(a0)
+  FSTORE    f17, (RISCV_FOFFSET + RISCV_FSIZE * 17)(a0)
+  FSTORE    f18, (RISCV_FOFFSET + RISCV_FSIZE * 18)(a0)
+  FSTORE    f19, (RISCV_FOFFSET + RISCV_FSIZE * 19)(a0)
+  FSTORE    f20, (RISCV_FOFFSET + RISCV_FSIZE * 20)(a0)
+  FSTORE    f21, (RISCV_FOFFSET + RISCV_FSIZE * 21)(a0)
+  FSTORE    f22, (RISCV_FOFFSET + RISCV_FSIZE * 22)(a0)
+  FSTORE    f23, (RISCV_FOFFSET + RISCV_FSIZE * 23)(a0)
+  FSTORE    f24, (RISCV_FOFFSET + RISCV_FSIZE * 24)(a0)
+  FSTORE    f25, (RISCV_FOFFSET + RISCV_FSIZE * 25)(a0)
+  FSTORE    f26, (RISCV_FOFFSET + RISCV_FSIZE * 26)(a0)
+  FSTORE    f27, (RISCV_FOFFSET + RISCV_FSIZE * 27)(a0)
+  FSTORE    f28, (RISCV_FOFFSET + RISCV_FSIZE * 28)(a0)
+  FSTORE    f29, (RISCV_FOFFSET + RISCV_FSIZE * 29)(a0)
+  FSTORE    f30, (RISCV_FOFFSET + RISCV_FSIZE * 30)(a0)
+  FSTORE    f31, (RISCV_FOFFSET + RISCV_FSIZE * 31)(a0)
+# endif
+
+  li     a0, 0  // return UNW_ESUCCESS
+  ret           // jump to ra
+#endif
+
+  WEAK_ALIAS(__unw_getcontext, unw_getcontext)
+
+#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
+
+NO_EXEC_STACK_DIRECTIVE

+ 113 - 0
llvm-libunwind/src/Unwind_AppleExtras.cpp

@@ -0,0 +1,113 @@
+//===--------------------- Unwind_AppleExtras.cpp -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "config.h"
+
+
+// static linker symbols to prevent wrong two level namespace for _Unwind symbols
+#if defined(__arm__)
+   #define NOT_HERE_BEFORE_5_0(sym)     \
+       extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); \
+       __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \
+       extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \
+       extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym );\
+           __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \
+       extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \
+       extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \
+       extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \
+       extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp43 = 0;
+#elif defined(__aarch64__)
+  #define NOT_HERE_BEFORE_10_6(sym)
+  #define NEVER_HERE(sym)
+#else
+  #define NOT_HERE_BEFORE_10_6(sym) \
+    extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+    extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+  #define NEVER_HERE(sym) \
+    extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+    extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+    extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
+          __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#endif
+
+
+#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
+
+//
+// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in
+// earlier versions
+//
+NOT_HERE_BEFORE_10_6(_Unwind_DeleteException)
+NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE)
+NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind)
+NOT_HERE_BEFORE_10_6(_Unwind_GetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIP)
+NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData)
+NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart)
+NOT_HERE_BEFORE_10_6(_Unwind_RaiseException)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume)
+NOT_HERE_BEFORE_10_6(_Unwind_SetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_SetIP)
+NOT_HERE_BEFORE_10_6(_Unwind_Backtrace)
+NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction)
+NOT_HERE_BEFORE_10_6(_Unwind_GetCFA)
+NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo)
+NOT_HERE_BEFORE_10_6(__register_frame)
+NOT_HERE_BEFORE_10_6(__deregister_frame)
+
+//
+// symbols in libSystem.dylib for compatibility, but we don't want any new code
+// using them
+//
+NEVER_HERE(__register_frame_info_bases)
+NEVER_HERE(__register_frame_info)
+NEVER_HERE(__register_frame_info_table_bases)
+NEVER_HERE(__register_frame_info_table)
+NEVER_HERE(__register_frame_table)
+NEVER_HERE(__deregister_frame_info)
+NEVER_HERE(__deregister_frame_info_bases)
+
+#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
+
+
+
+
+#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
+//
+// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in
+// earlier versions
+//
+NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData)
+NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart)
+NOT_HERE_BEFORE_5_0(_Unwind_GetIP)
+NOT_HERE_BEFORE_5_0(_Unwind_SetGR)
+NOT_HERE_BEFORE_5_0(_Unwind_SetIP)
+NOT_HERE_BEFORE_5_0(_Unwind_DeleteException)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register)
+NOT_HERE_BEFORE_5_0(_Unwind_GetGR)
+NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo)
+NOT_HERE_BEFORE_5_0(_Unwind_GetCFA)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
+
+#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)

+ 223 - 0
llvm-libunwind/src/assembly.h

@@ -0,0 +1,223 @@
+/* ===-- assembly.h - libUnwind assembler support macros -------------------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file defines macros for use in libUnwind assembler source.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef UNWIND_ASSEMBLY_H
+#define UNWIND_ASSEMBLY_H
+
+#if defined(__powerpc64__)
+#define SEPARATOR ;
+#define PPC64_OFFS_SRR0   0
+#define PPC64_OFFS_CR     272
+#define PPC64_OFFS_XER    280
+#define PPC64_OFFS_LR     288
+#define PPC64_OFFS_CTR    296
+#define PPC64_OFFS_VRSAVE 304
+#define PPC64_OFFS_FP     312
+#define PPC64_OFFS_V      824
+#elif defined(__APPLE__) && defined(__aarch64__)
+#define SEPARATOR %%
+#elif defined(__riscv)
+# define RISCV_ISIZE (__riscv_xlen / 8)
+# define RISCV_FOFFSET (RISCV_ISIZE * 32)
+# if defined(__riscv_flen)
+#  define RISCV_FSIZE (__riscv_flen / 8)
+# endif
+
+# if __riscv_xlen == 64
+#  define ILOAD ld
+#  define ISTORE sd
+# elif __riscv_xlen == 32
+#  define ILOAD lw
+#  define ISTORE sw
+# else
+#  error "Unsupported __riscv_xlen"
+# endif
+
+# if defined(__riscv_flen)
+#  if __riscv_flen == 64
+#   define FLOAD fld
+#   define FSTORE fsd
+#  elif __riscv_flen == 32
+#   define FLOAD flw
+#   define FSTORE fsw
+#  else
+#   error "Unsupported __riscv_flen"
+#  endif
+# endif
+# define SEPARATOR ;
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
+#define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR
+#define PPC64_OPD2 SEPARATOR \
+  .p2align 3 SEPARATOR \
+  .quad .Lfunc_begin0 SEPARATOR \
+  .quad .TOC.@tocbase SEPARATOR \
+  .quad 0 SEPARATOR \
+  .text SEPARATOR \
+.Lfunc_begin0:
+#else
+#define PPC64_OPD1
+#define PPC64_OPD2
+#endif
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+  .pushsection ".note.gnu.property", "a" SEPARATOR                             \
+  .balign 8 SEPARATOR                                                          \
+  .long 4 SEPARATOR                                                            \
+  .long 0x10 SEPARATOR                                                         \
+  .long 0x5 SEPARATOR                                                          \
+  .asciz "GNU" SEPARATOR                                                       \
+  .long 0xc0000000 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */          \
+  .long 4 SEPARATOR                                                            \
+  .long 3 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_BTI AND */               \
+                    /* GNU_PROPERTY_AARCH64_FEATURE_1_PAC */                   \
+  .long 0 SEPARATOR                                                            \
+  .popsection SEPARATOR
+#define AARCH64_BTI  bti c
+#else
+#define AARCH64_BTI
+#endif
+
+#define GLUE2(a, b) a ## b
+#define GLUE(a, b) GLUE2(a, b)
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#if defined(__APPLE__)
+
+#define SYMBOL_IS_FUNC(name)
+#define HIDDEN_SYMBOL(name) .private_extern name
+#if defined(_LIBUNWIND_HIDE_SYMBOLS)
+#define EXPORT_SYMBOL(name) HIDDEN_SYMBOL(name)
+#else
+#define EXPORT_SYMBOL(name)
+#endif
+#define WEAK_ALIAS(name, aliasname)                                            \
+  .globl SYMBOL_NAME(aliasname) SEPARATOR                                      \
+  EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR                              \
+  SYMBOL_NAME(aliasname) = SYMBOL_NAME(name)
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#elif defined(__ELF__)
+
+#if defined(__arm__)
+#define SYMBOL_IS_FUNC(name) .type name,%function
+#else
+#define SYMBOL_IS_FUNC(name) .type name,@function
+#endif
+#define HIDDEN_SYMBOL(name) .hidden name
+#if defined(_LIBUNWIND_HIDE_SYMBOLS)
+#define EXPORT_SYMBOL(name) HIDDEN_SYMBOL(name)
+#else
+#define EXPORT_SYMBOL(name)
+#endif
+#define WEAK_SYMBOL(name) .weak name
+
+#if defined(__hexagon__)
+#define WEAK_ALIAS(name, aliasname)                                            \
+  EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR                              \
+  WEAK_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR                                \
+  .equiv SYMBOL_NAME(aliasname), SYMBOL_NAME(name)
+#else
+#define WEAK_ALIAS(name, aliasname)                                            \
+  EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR                              \
+  WEAK_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR                                \
+  SYMBOL_NAME(aliasname) = SYMBOL_NAME(name)
+#endif
+
+#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
+    defined(__linux__)
+#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
+#else
+#define NO_EXEC_STACK_DIRECTIVE
+#endif
+
+#elif defined(_WIN32)
+
+#define SYMBOL_IS_FUNC(name)                                                   \
+  .def name SEPARATOR                                                          \
+    .scl 2 SEPARATOR                                                           \
+    .type 32 SEPARATOR                                                         \
+  .endef
+#define EXPORT_SYMBOL2(name)                                                   \
+  .section .drectve,"yn" SEPARATOR                                             \
+  .ascii "-export:", #name, "\0" SEPARATOR                                     \
+  .text
+#if defined(_LIBUNWIND_HIDE_SYMBOLS)
+#define EXPORT_SYMBOL(name)
+#else
+#define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name)
+#endif
+#define HIDDEN_SYMBOL(name)
+
+#if defined(__MINGW32__)
+#define WEAK_ALIAS(name, aliasname)                                            \
+  .globl SYMBOL_NAME(aliasname) SEPARATOR                                      \
+  EXPORT_SYMBOL(aliasname) SEPARATOR                                           \
+  SYMBOL_NAME(aliasname) = SYMBOL_NAME(name)
+#else
+#define WEAK_ALIAS3(name, aliasname)                                           \
+  .section .drectve,"yn" SEPARATOR                                             \
+  .ascii "-alternatename:", #aliasname, "=", #name, "\0" SEPARATOR             \
+  .text
+#define WEAK_ALIAS2(name, aliasname)                                           \
+  WEAK_ALIAS3(name, aliasname)
+#define WEAK_ALIAS(name, aliasname)                                            \
+  EXPORT_SYMBOL(SYMBOL_NAME(aliasname)) SEPARATOR                              \
+  WEAK_ALIAS2(SYMBOL_NAME(name), SYMBOL_NAME(aliasname))
+#endif
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#elif defined(__sparc__)
+
+#else
+
+#error Unsupported target
+
+#endif
+
+#define DEFINE_LIBUNWIND_FUNCTION(name)                                        \
+  .globl SYMBOL_NAME(name) SEPARATOR                                           \
+  HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR                                   \
+  SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR                                  \
+  PPC64_OPD1                                                                   \
+  SYMBOL_NAME(name):                                                           \
+  PPC64_OPD2                                                                   \
+  AARCH64_BTI
+
+#if defined(__arm__)
+#if !defined(__ARM_ARCH)
+#define __ARM_ARCH 4
+#endif
+
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+
+#ifdef ARM_HAS_BX
+#define JMP(r) bx r
+#else
+#define JMP(r) mov pc, r
+#endif
+#endif /* __arm__ */
+
+#if defined(__ppc__) || defined(__powerpc64__)
+#define PPC_LEFT_SHIFT(index) << (index)
+#endif
+
+#endif /* UNWIND_ASSEMBLY_H */

+ 241 - 0
llvm-libunwind/src/config.h

@@ -0,0 +1,241 @@
+//===----------------------------- config.h -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Defines macros used within libunwind project.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LIBUNWIND_CONFIG_H
+#define LIBUNWIND_CONFIG_H
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <__libunwind_config.h>
+
+// Platform specific configuration defines.
+#ifdef __APPLE__
+  #if defined(FOR_DYLD)
+    #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
+  #else
+    #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
+    #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
+  #endif
+#elif defined(_WIN32)
+  #ifdef __SEH__
+    #define _LIBUNWIND_SUPPORT_SEH_UNWIND 1
+  #else
+    #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
+  #endif
+#elif defined(_LIBUNWIND_IS_BAREMETAL)
+  #if !defined(_LIBUNWIND_ARM_EHABI)
+    #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
+    #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
+  #endif
+#elif defined(__BIONIC__) && defined(_LIBUNWIND_ARM_EHABI)
+  // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
+  // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
+  #define _LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX 1
+#else
+  // Assume an ELF system with a dl_iterate_phdr function.
+  #define _LIBUNWIND_USE_DL_ITERATE_PHDR 1
+  #if !defined(_LIBUNWIND_ARM_EHABI)
+    #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
+    #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
+  #endif
+#endif
+
+#if defined(_LIBUNWIND_HIDE_SYMBOLS)
+  // The CMake file passes -fvisibility=hidden to control ELF/Mach-O visibility.
+  #define _LIBUNWIND_EXPORT
+  #define _LIBUNWIND_HIDDEN
+#else
+  #if !defined(__ELF__) && !defined(__MACH__)
+    #define _LIBUNWIND_EXPORT __declspec(dllexport)
+    #define _LIBUNWIND_HIDDEN
+  #else
+    #define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
+    #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
+  #endif
+#endif
+
+#define STR(a) #a
+#define XSTR(a) STR(a)
+#define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name
+
+#if defined(__APPLE__)
+#if defined(_LIBUNWIND_HIDE_SYMBOLS)
+#define _LIBUNWIND_ALIAS_VISIBILITY(name) __asm__(".private_extern " name)
+#else
+#define _LIBUNWIND_ALIAS_VISIBILITY(name)
+#endif
+#define _LIBUNWIND_WEAK_ALIAS(name, aliasname)                                 \
+  __asm__(".globl " SYMBOL_NAME(aliasname));                                   \
+  __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name));                     \
+  _LIBUNWIND_ALIAS_VISIBILITY(SYMBOL_NAME(aliasname));
+#elif defined(__ELF__)
+#define _LIBUNWIND_WEAK_ALIAS(name, aliasname)                                 \
+  extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname                        \
+      __attribute__((weak, alias(#name)));
+#elif defined(_WIN32)
+#if defined(__MINGW32__)
+#define _LIBUNWIND_WEAK_ALIAS(name, aliasname)                                 \
+  extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname                        \
+      __attribute__((alias(#name)));
+#else
+#define _LIBUNWIND_WEAK_ALIAS(name, aliasname)                                 \
+  __pragma(comment(linker, "/alternatename:" SYMBOL_NAME(aliasname) "="        \
+                                             SYMBOL_NAME(name)))               \
+  extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname;
+#endif
+#else
+#error Unsupported target
+#endif
+
+// Apple/armv7k defaults to DWARF/Compact unwinding, but its libunwind also
+// needs to include the SJLJ APIs.
+#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__)
+#define _LIBUNWIND_BUILD_SJLJ_APIS
+#endif
+
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__)
+#define _LIBUNWIND_SUPPORT_FRAME_APIS
+#endif
+
+#if defined(__i386__) || defined(__x86_64__) ||                                \
+    defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) ||        \
+    (!defined(__APPLE__) && defined(__arm__)) ||                               \
+    defined(__aarch64__) ||                                                    \
+    defined(__mips__) ||                                                       \
+    defined(__riscv) ||                                                        \
+    defined(__hexagon__)
+#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
+#define _LIBUNWIND_BUILD_ZERO_COST_APIS
+#endif
+#endif
+
+#ifndef _LIBUNWIND_REMEMBER_HEAP_ALLOC
+#if defined(_LIBUNWIND_REMEMBER_STACK_ALLOC) || defined(__APPLE__) ||          \
+    defined(__linux__) || defined(__ANDROID__) || defined(__MINGW32__) ||      \
+    defined(_LIBUNWIND_IS_BAREMETAL)
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) alloca(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr)                                         \
+  do {                                                                         \
+  } while (0)
+#elif defined(_WIN32)
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) _malloca(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) _freea(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
+#else
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
+#endif
+#else /* _LIBUNWIND_REMEMBER_HEAP_ALLOC */
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
+#endif
+
+#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
+#define _LIBUNWIND_ABORT(msg)                                                  \
+  do {                                                                         \
+    abort();                                                                   \
+  } while (0)
+#else
+#define _LIBUNWIND_ABORT(msg)                                                  \
+  do {                                                                         \
+    fprintf(stderr, "libunwind: %s - %s\n", __func__, msg);                    \
+    fflush(stderr);                                                            \
+    abort();                                                                   \
+  } while (0)
+#endif
+
+#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
+#define _LIBUNWIND_LOG0(msg)
+#define _LIBUNWIND_LOG(msg, ...)
+#else
+#define _LIBUNWIND_LOG0(msg)                                               \
+  fprintf(stderr, "libunwind: " msg "\n")
+#define _LIBUNWIND_LOG(msg, ...)                                               \
+  fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__)
+#endif
+
+#if defined(NDEBUG)
+  #define _LIBUNWIND_LOG_IF_FALSE(x) x
+#else
+  #define _LIBUNWIND_LOG_IF_FALSE(x)                                           \
+    do {                                                                       \
+      bool _ret = x;                                                           \
+      if (!_ret)                                                               \
+        _LIBUNWIND_LOG("" #x " failed in %s", __FUNCTION__);                   \
+    } while (0)
+#endif
+
+// Macros that define away in non-Debug builds
+#ifdef NDEBUG
+  #define _LIBUNWIND_DEBUG_LOG(msg, ...)
+  #define _LIBUNWIND_TRACE_API(msg, ...)
+  #define _LIBUNWIND_TRACING_UNWINDING (0)
+  #define _LIBUNWIND_TRACING_DWARF (0)
+  #define _LIBUNWIND_TRACE_UNWINDING(msg, ...)
+  #define _LIBUNWIND_TRACE_DWARF(...)
+#else
+  #ifdef __cplusplus
+    extern "C" {
+  #endif
+    extern  bool logAPIs();
+    extern  bool logUnwinding();
+    extern  bool logDWARF();
+  #ifdef __cplusplus
+    }
+  #endif
+  #define _LIBUNWIND_DEBUG_LOG(msg, ...)  _LIBUNWIND_LOG(msg, __VA_ARGS__)
+  #define _LIBUNWIND_TRACE_API(msg, ...)                                       \
+    do {                                                                       \
+      if (logAPIs())                                                           \
+        _LIBUNWIND_LOG(msg, __VA_ARGS__);                                      \
+    } while (0)
+  #define _LIBUNWIND_TRACING_UNWINDING logUnwinding()
+  #define _LIBUNWIND_TRACING_DWARF logDWARF()
+  #define _LIBUNWIND_TRACE_UNWINDING(msg, ...)                                 \
+    do {                                                                       \
+      if (logUnwinding())                                                      \
+        _LIBUNWIND_LOG(msg, __VA_ARGS__);                                      \
+    } while (0)
+  #define _LIBUNWIND_TRACE_DWARF(...)                                          \
+    do {                                                                       \
+      if (logDWARF())                                                          \
+        fprintf(stderr, __VA_ARGS__);                                          \
+    } while (0)
+#endif
+
+#ifdef __cplusplus
+// Used to fit UnwindCursor and Registers_xxx types against unw_context_t /
+// unw_cursor_t sized memory blocks.
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+# define COMP_OP ==
+#else
+# define COMP_OP <=
+#endif
+template <typename _Type, typename _Mem>
+struct check_fit {
+  template <typename T>
+  struct blk_count {
+    static const size_t count =
+      (sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t);
+  };
+  static const bool does_fit =
+    (blk_count<_Type>::count COMP_OP blk_count<_Mem>::count);
+};
+#undef COMP_OP
+#endif // __cplusplus
+
+#endif // LIBUNWIND_CONFIG_H

+ 239 - 0
llvm-libunwind/src/dwarf2.h

@@ -0,0 +1,239 @@
+//===------------------------------- dwarf2.h -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+/*
+   These constants were taken from version 3 of the DWARF standard,
+   which is Copyright (c) 2005 Free Standards Group, and
+   Copyright (c) 1992, 1993 UNIX International, Inc.
+*/
+
+#ifndef __DWARF2__
+#define __DWARF2__
+
+// DWARF unwind instructions
+enum {
+  DW_CFA_nop                 = 0x0,
+  DW_CFA_set_loc             = 0x1,
+  DW_CFA_advance_loc1        = 0x2,
+  DW_CFA_advance_loc2        = 0x3,
+  DW_CFA_advance_loc4        = 0x4,
+  DW_CFA_offset_extended     = 0x5,
+  DW_CFA_restore_extended    = 0x6,
+  DW_CFA_undefined           = 0x7,
+  DW_CFA_same_value          = 0x8,
+  DW_CFA_register            = 0x9,
+  DW_CFA_remember_state      = 0xA,
+  DW_CFA_restore_state       = 0xB,
+  DW_CFA_def_cfa             = 0xC,
+  DW_CFA_def_cfa_register    = 0xD,
+  DW_CFA_def_cfa_offset      = 0xE,
+  DW_CFA_def_cfa_expression  = 0xF,
+  DW_CFA_expression         = 0x10,
+  DW_CFA_offset_extended_sf = 0x11,
+  DW_CFA_def_cfa_sf         = 0x12,
+  DW_CFA_def_cfa_offset_sf  = 0x13,
+  DW_CFA_val_offset         = 0x14,
+  DW_CFA_val_offset_sf      = 0x15,
+  DW_CFA_val_expression     = 0x16,
+  DW_CFA_advance_loc        = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
+  DW_CFA_offset             = 0x80, // high 2 bits are 0x2, lower 6 bits are register
+  DW_CFA_restore            = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
+
+  // GNU extensions
+  DW_CFA_GNU_window_save              = 0x2D,
+  DW_CFA_GNU_args_size                = 0x2E,
+  DW_CFA_GNU_negative_offset_extended = 0x2F,
+
+  // AARCH64 extensions
+  DW_CFA_AARCH64_negate_ra_state      = 0x2D
+};
+
+
+// FSF exception handling Pointer-Encoding constants
+// Used in CFI augmentation by GCC
+enum {
+  DW_EH_PE_ptr       = 0x00,
+  DW_EH_PE_uleb128   = 0x01,
+  DW_EH_PE_udata2    = 0x02,
+  DW_EH_PE_udata4    = 0x03,
+  DW_EH_PE_udata8    = 0x04,
+  DW_EH_PE_signed    = 0x08,
+  DW_EH_PE_sleb128   = 0x09,
+  DW_EH_PE_sdata2    = 0x0A,
+  DW_EH_PE_sdata4    = 0x0B,
+  DW_EH_PE_sdata8    = 0x0C,
+  DW_EH_PE_absptr    = 0x00,
+  DW_EH_PE_pcrel     = 0x10,
+  DW_EH_PE_textrel   = 0x20,
+  DW_EH_PE_datarel   = 0x30,
+  DW_EH_PE_funcrel   = 0x40,
+  DW_EH_PE_aligned   = 0x50,
+  DW_EH_PE_indirect  = 0x80,
+  DW_EH_PE_omit      = 0xFF
+};
+
+
+// DWARF expressions
+enum {
+  DW_OP_addr               = 0x03, // constant address (size target specific)
+  DW_OP_deref              = 0x06,
+  DW_OP_const1u            = 0x08, // 1-byte constant
+  DW_OP_const1s            = 0x09, // 1-byte constant
+  DW_OP_const2u            = 0x0A, // 2-byte constant
+  DW_OP_const2s            = 0x0B, // 2-byte constant
+  DW_OP_const4u            = 0x0C, // 4-byte constant
+  DW_OP_const4s            = 0x0D, // 4-byte constant
+  DW_OP_const8u            = 0x0E, // 8-byte constant
+  DW_OP_const8s            = 0x0F, // 8-byte constant
+  DW_OP_constu             = 0x10, // ULEB128 constant
+  DW_OP_consts             = 0x11, // SLEB128 constant
+  DW_OP_dup                = 0x12,
+  DW_OP_drop               = 0x13,
+  DW_OP_over               = 0x14,
+  DW_OP_pick               = 0x15, // 1-byte stack index
+  DW_OP_swap               = 0x16,
+  DW_OP_rot                = 0x17,
+  DW_OP_xderef             = 0x18,
+  DW_OP_abs                = 0x19,
+  DW_OP_and                = 0x1A,
+  DW_OP_div                = 0x1B,
+  DW_OP_minus              = 0x1C,
+  DW_OP_mod                = 0x1D,
+  DW_OP_mul                = 0x1E,
+  DW_OP_neg                = 0x1F,
+  DW_OP_not                = 0x20,
+  DW_OP_or                 = 0x21,
+  DW_OP_plus               = 0x22,
+  DW_OP_plus_uconst        = 0x23, // ULEB128 addend
+  DW_OP_shl                = 0x24,
+  DW_OP_shr                = 0x25,
+  DW_OP_shra               = 0x26,
+  DW_OP_xor                = 0x27,
+  DW_OP_skip               = 0x2F, // signed 2-byte constant
+  DW_OP_bra                = 0x28, // signed 2-byte constant
+  DW_OP_eq                 = 0x29,
+  DW_OP_ge                 = 0x2A,
+  DW_OP_gt                 = 0x2B,
+  DW_OP_le                 = 0x2C,
+  DW_OP_lt                 = 0x2D,
+  DW_OP_ne                 = 0x2E,
+  DW_OP_lit0               = 0x30, // Literal 0
+  DW_OP_lit1               = 0x31, // Literal 1
+  DW_OP_lit2               = 0x32, // Literal 2
+  DW_OP_lit3               = 0x33, // Literal 3
+  DW_OP_lit4               = 0x34, // Literal 4
+  DW_OP_lit5               = 0x35, // Literal 5
+  DW_OP_lit6               = 0x36, // Literal 6
+  DW_OP_lit7               = 0x37, // Literal 7
+  DW_OP_lit8               = 0x38, // Literal 8
+  DW_OP_lit9               = 0x39, // Literal 9
+  DW_OP_lit10              = 0x3A, // Literal 10
+  DW_OP_lit11              = 0x3B, // Literal 11
+  DW_OP_lit12              = 0x3C, // Literal 12
+  DW_OP_lit13              = 0x3D, // Literal 13
+  DW_OP_lit14              = 0x3E, // Literal 14
+  DW_OP_lit15              = 0x3F, // Literal 15
+  DW_OP_lit16              = 0x40, // Literal 16
+  DW_OP_lit17              = 0x41, // Literal 17
+  DW_OP_lit18              = 0x42, // Literal 18
+  DW_OP_lit19              = 0x43, // Literal 19
+  DW_OP_lit20              = 0x44, // Literal 20
+  DW_OP_lit21              = 0x45, // Literal 21
+  DW_OP_lit22              = 0x46, // Literal 22
+  DW_OP_lit23              = 0x47, // Literal 23
+  DW_OP_lit24              = 0x48, // Literal 24
+  DW_OP_lit25              = 0x49, // Literal 25
+  DW_OP_lit26              = 0x4A, // Literal 26
+  DW_OP_lit27              = 0x4B, // Literal 27
+  DW_OP_lit28              = 0x4C, // Literal 28
+  DW_OP_lit29              = 0x4D, // Literal 29
+  DW_OP_lit30              = 0x4E, // Literal 30
+  DW_OP_lit31              = 0x4F, // Literal 31
+  DW_OP_reg0               = 0x50, // Contents of reg0
+  DW_OP_reg1               = 0x51, // Contents of reg1
+  DW_OP_reg2               = 0x52, // Contents of reg2
+  DW_OP_reg3               = 0x53, // Contents of reg3
+  DW_OP_reg4               = 0x54, // Contents of reg4
+  DW_OP_reg5               = 0x55, // Contents of reg5
+  DW_OP_reg6               = 0x56, // Contents of reg6
+  DW_OP_reg7               = 0x57, // Contents of reg7
+  DW_OP_reg8               = 0x58, // Contents of reg8
+  DW_OP_reg9               = 0x59, // Contents of reg9
+  DW_OP_reg10              = 0x5A, // Contents of reg10
+  DW_OP_reg11              = 0x5B, // Contents of reg11
+  DW_OP_reg12              = 0x5C, // Contents of reg12
+  DW_OP_reg13              = 0x5D, // Contents of reg13
+  DW_OP_reg14              = 0x5E, // Contents of reg14
+  DW_OP_reg15              = 0x5F, // Contents of reg15
+  DW_OP_reg16              = 0x60, // Contents of reg16
+  DW_OP_reg17              = 0x61, // Contents of reg17
+  DW_OP_reg18              = 0x62, // Contents of reg18
+  DW_OP_reg19              = 0x63, // Contents of reg19
+  DW_OP_reg20              = 0x64, // Contents of reg20
+  DW_OP_reg21              = 0x65, // Contents of reg21
+  DW_OP_reg22              = 0x66, // Contents of reg22
+  DW_OP_reg23              = 0x67, // Contents of reg23
+  DW_OP_reg24              = 0x68, // Contents of reg24
+  DW_OP_reg25              = 0x69, // Contents of reg25
+  DW_OP_reg26              = 0x6A, // Contents of reg26
+  DW_OP_reg27              = 0x6B, // Contents of reg27
+  DW_OP_reg28              = 0x6C, // Contents of reg28
+  DW_OP_reg29              = 0x6D, // Contents of reg29
+  DW_OP_reg30              = 0x6E, // Contents of reg30
+  DW_OP_reg31              = 0x6F, // Contents of reg31
+  DW_OP_breg0              = 0x70, // base register 0 + SLEB128 offset
+  DW_OP_breg1              = 0x71, // base register 1 + SLEB128 offset
+  DW_OP_breg2              = 0x72, // base register 2 + SLEB128 offset
+  DW_OP_breg3              = 0x73, // base register 3 + SLEB128 offset
+  DW_OP_breg4              = 0x74, // base register 4 + SLEB128 offset
+  DW_OP_breg5              = 0x75, // base register 5 + SLEB128 offset
+  DW_OP_breg6              = 0x76, // base register 6 + SLEB128 offset
+  DW_OP_breg7              = 0x77, // base register 7 + SLEB128 offset
+  DW_OP_breg8              = 0x78, // base register 8 + SLEB128 offset
+  DW_OP_breg9              = 0x79, // base register 9 + SLEB128 offset
+  DW_OP_breg10             = 0x7A, // base register 10 + SLEB128 offset
+  DW_OP_breg11             = 0x7B, // base register 11 + SLEB128 offset
+  DW_OP_breg12             = 0x7C, // base register 12 + SLEB128 offset
+  DW_OP_breg13             = 0x7D, // base register 13 + SLEB128 offset
+  DW_OP_breg14             = 0x7E, // base register 14 + SLEB128 offset
+  DW_OP_breg15             = 0x7F, // base register 15 + SLEB128 offset
+  DW_OP_breg16             = 0x80, // base register 16 + SLEB128 offset
+  DW_OP_breg17             = 0x81, // base register 17 + SLEB128 offset
+  DW_OP_breg18             = 0x82, // base register 18 + SLEB128 offset
+  DW_OP_breg19             = 0x83, // base register 19 + SLEB128 offset
+  DW_OP_breg20             = 0x84, // base register 20 + SLEB128 offset
+  DW_OP_breg21             = 0x85, // base register 21 + SLEB128 offset
+  DW_OP_breg22             = 0x86, // base register 22 + SLEB128 offset
+  DW_OP_breg23             = 0x87, // base register 23 + SLEB128 offset
+  DW_OP_breg24             = 0x88, // base register 24 + SLEB128 offset
+  DW_OP_breg25             = 0x89, // base register 25 + SLEB128 offset
+  DW_OP_breg26             = 0x8A, // base register 26 + SLEB128 offset
+  DW_OP_breg27             = 0x8B, // base register 27 + SLEB128 offset
+  DW_OP_breg28             = 0x8C, // base register 28 + SLEB128 offset
+  DW_OP_breg29             = 0x8D, // base register 29 + SLEB128 offset
+  DW_OP_breg30             = 0x8E, // base register 30 + SLEB128 offset
+  DW_OP_breg31             = 0x8F, // base register 31 + SLEB128 offset
+  DW_OP_regx               = 0x90, // ULEB128 register
+  DW_OP_fbreg              = 0x91, // SLEB128 offset
+  DW_OP_bregx              = 0x92, // ULEB128 register followed by SLEB128 offset
+  DW_OP_piece              = 0x93, // ULEB128 size of piece addressed
+  DW_OP_deref_size         = 0x94, // 1-byte size of data retrieved
+  DW_OP_xderef_size        = 0x95, // 1-byte size of data retrieved
+  DW_OP_nop                = 0x96,
+  DW_OP_push_object_addres = 0x97,
+  DW_OP_call2              = 0x98, // 2-byte offset of DIE
+  DW_OP_call4              = 0x99, // 4-byte offset of DIE
+  DW_OP_call_ref           = 0x9A, // 4- or 8-byte offset of DIE
+  DW_OP_lo_user            = 0xE0,
+  DW_OP_APPLE_uninit       = 0xF0,
+  DW_OP_hi_user            = 0xFF
+};
+
+
+#endif

+ 328 - 0
llvm-libunwind/src/libunwind.cpp

@@ -0,0 +1,328 @@
+//===--------------------------- libunwind.cpp ----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Implements unw_* functions from <libunwind.h>
+//
+//===----------------------------------------------------------------------===//
+
+#include <libunwind.h>
+
+#include "libunwind_ext.h"
+#include "config.h"
+
+#include <stdlib.h>
+
+
+#if !defined(__USING_SJLJ_EXCEPTIONS__)
+#include "AddressSpace.hpp"
+#include "UnwindCursor.hpp"
+
+using namespace libunwind;
+
+/// internal object to represent this processes address space
+LocalAddressSpace LocalAddressSpace::sThisAddressSpace;
+
+_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
+    (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace;
+
+/// Create a cursor of a thread in this process given 'context' recorded by
+/// __unw_getcontext().
+_LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
+                                       unw_context_t *context) {
+  _LIBUNWIND_TRACE_API("__unw_init_local(cursor=%p, context=%p)",
+                       static_cast<void *>(cursor),
+                       static_cast<void *>(context));
+#if defined(__i386__)
+# define REGISTER_KIND Registers_x86
+#elif defined(__x86_64__)
+# define REGISTER_KIND Registers_x86_64
+#elif defined(__powerpc64__)
+# define REGISTER_KIND Registers_ppc64
+#elif defined(__ppc__)
+# define REGISTER_KIND Registers_ppc
+#elif defined(__aarch64__)
+# define REGISTER_KIND Registers_arm64
+#elif defined(__arm__)
+# define REGISTER_KIND Registers_arm
+#elif defined(__or1k__)
+# define REGISTER_KIND Registers_or1k
+#elif defined(__hexagon__)
+# define REGISTER_KIND Registers_hexagon
+#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
+# define REGISTER_KIND Registers_mips_o32
+#elif defined(__mips64)
+# define REGISTER_KIND Registers_mips_newabi
+#elif defined(__mips__)
+# warning The MIPS architecture is not supported with this ABI and environment!
+#elif defined(__sparc__)
+# define REGISTER_KIND Registers_sparc
+#elif defined(__riscv)
+# define REGISTER_KIND Registers_riscv
+#elif defined(__ve__)
+# define REGISTER_KIND Registers_ve
+#else
+# error Architecture not supported
+#endif
+  // Use "placement new" to allocate UnwindCursor in the cursor buffer.
+  new (reinterpret_cast<UnwindCursor<LocalAddressSpace, REGISTER_KIND> *>(cursor))
+      UnwindCursor<LocalAddressSpace, REGISTER_KIND>(
+          context, LocalAddressSpace::sThisAddressSpace);
+#undef REGISTER_KIND
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  co->setInfoBasedOnIPRegister();
+
+  return UNW_ESUCCESS;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_init_local, unw_init_local)
+
+/// Get value of specified register at cursor position in stack frame.
+_LIBUNWIND_HIDDEN int __unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
+                                    unw_word_t *value) {
+  _LIBUNWIND_TRACE_API("__unw_get_reg(cursor=%p, regNum=%d, &value=%p)",
+                       static_cast<void *>(cursor), regNum,
+                       static_cast<void *>(value));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  if (co->validReg(regNum)) {
+    *value = co->getReg(regNum);
+    return UNW_ESUCCESS;
+  }
+  return UNW_EBADREG;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_get_reg, unw_get_reg)
+
+/// Set value of specified register at cursor position in stack frame.
+_LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
+                                    unw_word_t value) {
+  _LIBUNWIND_TRACE_API("__unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR
+                       ")",
+                       static_cast<void *>(cursor), regNum, value);
+  typedef LocalAddressSpace::pint_t pint_t;
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  if (co->validReg(regNum)) {
+    co->setReg(regNum, (pint_t)value);
+    // specical case altering IP to re-find info (being called by personality
+    // function)
+    if (regNum == UNW_REG_IP) {
+      unw_proc_info_t info;
+      // First, get the FDE for the old location and then update it.
+      co->getInfo(&info);
+      co->setInfoBasedOnIPRegister(false);
+      // If the original call expects stack adjustment, perform this now.
+      // Normal frame unwinding would have included the offset already in the
+      // CFA computation.
+      // Note: for PA-RISC and other platforms where the stack grows up,
+      // this should actually be - info.gp. LLVM doesn't currently support
+      // any such platforms and Clang doesn't export a macro for them.
+      if (info.gp)
+        co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
+    }
+    return UNW_ESUCCESS;
+  }
+  return UNW_EBADREG;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_set_reg, unw_set_reg)
+
+/// Get value of specified float register at cursor position in stack frame.
+_LIBUNWIND_HIDDEN int __unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
+                                      unw_fpreg_t *value) {
+  _LIBUNWIND_TRACE_API("__unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)",
+                       static_cast<void *>(cursor), regNum,
+                       static_cast<void *>(value));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  if (co->validFloatReg(regNum)) {
+    *value = co->getFloatReg(regNum);
+    return UNW_ESUCCESS;
+  }
+  return UNW_EBADREG;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_get_fpreg, unw_get_fpreg)
+
+/// Set value of specified float register at cursor position in stack frame.
+_LIBUNWIND_HIDDEN int __unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
+                                      unw_fpreg_t value) {
+#if defined(_LIBUNWIND_ARM_EHABI)
+  _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)",
+                       static_cast<void *>(cursor), regNum, value);
+#else
+  _LIBUNWIND_TRACE_API("__unw_set_fpreg(cursor=%p, regNum=%d, value=%g)",
+                       static_cast<void *>(cursor), regNum, value);
+#endif
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  if (co->validFloatReg(regNum)) {
+    co->setFloatReg(regNum, value);
+    return UNW_ESUCCESS;
+  }
+  return UNW_EBADREG;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_set_fpreg, unw_set_fpreg)
+
+/// Move cursor to next frame.
+_LIBUNWIND_HIDDEN int __unw_step(unw_cursor_t *cursor) {
+  _LIBUNWIND_TRACE_API("__unw_step(cursor=%p)", static_cast<void *>(cursor));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  return co->step();
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step)
+
+/// Get unwind info at cursor position in stack frame.
+_LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor,
+                                          unw_proc_info_t *info) {
+  _LIBUNWIND_TRACE_API("__unw_get_proc_info(cursor=%p, &info=%p)",
+                       static_cast<void *>(cursor), static_cast<void *>(info));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  co->getInfo(info);
+  if (info->end_ip == 0)
+    return UNW_ENOINFO;
+  return UNW_ESUCCESS;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_info, unw_get_proc_info)
+
+/// Resume execution at cursor position (aka longjump).
+_LIBUNWIND_HIDDEN int __unw_resume(unw_cursor_t *cursor) {
+  _LIBUNWIND_TRACE_API("__unw_resume(cursor=%p)", static_cast<void *>(cursor));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  co->jumpto();
+  return UNW_EUNSPEC;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_resume, unw_resume)
+
+/// Get name of function at cursor position in stack frame.
+_LIBUNWIND_HIDDEN int __unw_get_proc_name(unw_cursor_t *cursor, char *buf,
+                                          size_t bufLen, unw_word_t *offset) {
+  _LIBUNWIND_TRACE_API("__unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)",
+                       static_cast<void *>(cursor), static_cast<void *>(buf),
+                       static_cast<unsigned long>(bufLen));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  if (co->getFunctionName(buf, bufLen, offset))
+    return UNW_ESUCCESS;
+  return UNW_EUNSPEC;
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_get_proc_name, unw_get_proc_name)
+
+/// Checks if a register is a floating-point register.
+_LIBUNWIND_HIDDEN int __unw_is_fpreg(unw_cursor_t *cursor,
+                                     unw_regnum_t regNum) {
+  _LIBUNWIND_TRACE_API("__unw_is_fpreg(cursor=%p, regNum=%d)",
+                       static_cast<void *>(cursor), regNum);
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  return co->validFloatReg(regNum);
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_is_fpreg, unw_is_fpreg)
+
+/// Checks if a register is a floating-point register.
+_LIBUNWIND_HIDDEN const char *__unw_regname(unw_cursor_t *cursor,
+                                            unw_regnum_t regNum) {
+  _LIBUNWIND_TRACE_API("__unw_regname(cursor=%p, regNum=%d)",
+                       static_cast<void *>(cursor), regNum);
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  return co->getRegisterName(regNum);
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_regname, unw_regname)
+
+/// Checks if current frame is signal trampoline.
+_LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) {
+  _LIBUNWIND_TRACE_API("__unw_is_signal_frame(cursor=%p)",
+                       static_cast<void *>(cursor));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  return co->isSignalFrame();
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame)
+
+#ifdef __arm__
+// Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD
+_LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) {
+  _LIBUNWIND_TRACE_API("__unw_get_fpreg_save_vfp_as_X(cursor=%p)",
+                       static_cast<void *>(cursor));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  return co->saveVFPAsX();
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_save_vfp_as_X, unw_save_vfp_as_X)
+#endif
+
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+/// SPI: walks cached DWARF entries
+_LIBUNWIND_HIDDEN void __unw_iterate_dwarf_unwind_cache(void (*func)(
+    unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
+  _LIBUNWIND_TRACE_API("__unw_iterate_dwarf_unwind_cache(func=%p)",
+                       reinterpret_cast<void *>(func));
+  DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_iterate_dwarf_unwind_cache,
+                      unw_iterate_dwarf_unwind_cache)
+
+/// IPI: for __register_frame()
+void __unw_add_dynamic_fde(unw_word_t fde) {
+  CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+  CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+  const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
+                           LocalAddressSpace::sThisAddressSpace,
+                          (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
+  if (message == NULL) {
+    // dynamically registered FDEs don't have a mach_header group they are in.
+    // Use fde as mh_group
+    unw_word_t mh_group = fdeInfo.fdeStart;
+    DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
+                                          fdeInfo.pcStart, fdeInfo.pcEnd,
+                                          fdeInfo.fdeStart);
+  } else {
+    _LIBUNWIND_DEBUG_LOG("__unw_add_dynamic_fde: bad fde: %s", message);
+  }
+}
+
+/// IPI: for __deregister_frame()
+void __unw_remove_dynamic_fde(unw_word_t fde) {
+  // fde is own mh_group
+  DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
+}
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+#endif // !defined(__USING_SJLJ_EXCEPTIONS__)
+
+
+
+// Add logging hooks in Debug builds only
+#ifndef NDEBUG
+#include <stdlib.h>
+
+_LIBUNWIND_HIDDEN
+bool logAPIs() {
+  // do manual lock to avoid use of _cxa_guard_acquire or initializers
+  static bool checked = false;
+  static bool log = false;
+  if (!checked) {
+    log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
+    checked = true;
+  }
+  return log;
+}
+
+_LIBUNWIND_HIDDEN
+bool logUnwinding() {
+  // do manual lock to avoid use of _cxa_guard_acquire or initializers
+  static bool checked = false;
+  static bool log = false;
+  if (!checked) {
+    log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
+    checked = true;
+  }
+  return log;
+}
+
+_LIBUNWIND_HIDDEN
+bool logDWARF() {
+  // do manual lock to avoid use of _cxa_guard_acquire or initializers
+  static bool checked = false;
+  static bool log = false;
+  if (!checked) {
+    log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL);
+    checked = true;
+  }
+  return log;
+}
+
+#endif // NDEBUG
+

+ 65 - 0
llvm-libunwind/src/libunwind_ext.h

@@ -0,0 +1,65 @@
+//===------------------------ libunwind_ext.h -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//  Extensions to libunwind API.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LIBUNWIND_EXT__
+#define __LIBUNWIND_EXT__
+
+#include "config.h"
+#include <libunwind.h>
+#include <unwind.h>
+
+#define UNW_STEP_SUCCESS 1
+#define UNW_STEP_END     0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int __unw_getcontext(unw_context_t *);
+extern int __unw_init_local(unw_cursor_t *, unw_context_t *);
+extern int __unw_step(unw_cursor_t *);
+extern int __unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *);
+extern int __unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *);
+extern int __unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t);
+extern int __unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t);
+extern int __unw_resume(unw_cursor_t *);
+
+#ifdef __arm__
+/* Save VFP registers in FSTMX format (instead of FSTMD). */
+extern void __unw_save_vfp_as_X(unw_cursor_t *);
+#endif
+
+extern const char *__unw_regname(unw_cursor_t *, unw_regnum_t);
+extern int __unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *);
+extern int __unw_is_fpreg(unw_cursor_t *, unw_regnum_t);
+extern int __unw_is_signal_frame(unw_cursor_t *);
+extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *);
+
+// SPI
+extern void __unw_iterate_dwarf_unwind_cache(void (*func)(
+    unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
+
+// IPI
+extern void __unw_add_dynamic_fde(unw_word_t fde);
+extern void __unw_remove_dynamic_fde(unw_word_t fde);
+
+#if defined(_LIBUNWIND_ARM_EHABI)
+extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*);
+extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context,
+                                                 const uint32_t *data,
+                                                 size_t offset, size_t len);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LIBUNWIND_EXT__

+ 35 - 0
llvm-libunwind/test/CMakeLists.txt

@@ -0,0 +1,35 @@
+include(AddLLVM) # for add_lit_testsuite
+macro(pythonize_bool var)
+  if (${var})
+    set(${var} True)
+  else()
+    set(${var} False)
+  endif()
+endmacro()
+
+if (NOT DEFINED LIBCXX_ENABLE_SHARED)
+  set(LIBCXX_ENABLE_SHARED ON)
+endif()
+
+pythonize_bool(LIBUNWIND_BUILD_32_BITS)
+pythonize_bool(LIBCXX_ENABLE_SHARED)
+pythonize_bool(LIBUNWIND_ENABLE_SHARED)
+pythonize_bool(LIBUNWIND_ENABLE_THREADS)
+pythonize_bool(LIBUNWIND_USES_ARM_EHABI)
+pythonize_bool(LIBUNWIND_USE_COMPILER_RT)
+pythonize_bool(LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY)
+set(LIBUNWIND_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING
+    "TargetInfo to use when setting up test environment.")
+set(LIBUNWIND_EXECUTOR "${Python3_EXECUTABLE} ${LIBUNWIND_LIBCXX_PATH}/utils/run.py" CACHE STRING
+    "Executor to use when running tests.")
+
+set(AUTO_GEN_COMMENT "## Autogenerated by libunwind configuration.\n# Do not edit!")
+configure_lit_site_cfg(
+  "${LIBUNWIND_TEST_CONFIG}"
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+  MAIN_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py")
+
+add_lit_testsuite(check-unwind "Running libunwind tests"
+  ${CMAKE_CURRENT_BINARY_DIR}
+  DEPENDS unwind ${LIBUNWIND_TEST_DEPS}
+  PARAMS "${LIBUNWIND_TEST_PARAMS}")

+ 24 - 0
llvm-libunwind/test/alignment.compile.pass.cpp

@@ -0,0 +1,24 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// The Itanium ABI requires that _Unwind_Exception objects are "double-word
+// aligned".
+
+#include <unwind.h>
+
+// EHABI  : 8-byte aligned
+// itanium: largest supported alignment for the system
+#if defined(_LIBUNWIND_ARM_EHABI)
+static_assert(alignof(_Unwind_Control_Block) == 8,
+              "_Unwind_Control_Block must be double-word aligned");
+#else
+struct MaxAligned {} __attribute__((__aligned__));
+static_assert(alignof(_Unwind_Exception) == alignof(MaxAligned),
+              "_Unwind_Exception must be maximally aligned");
+#endif

+ 72 - 0
llvm-libunwind/test/frameheadercache_test.pass.cpp

@@ -0,0 +1,72 @@
+// The other libunwind tests don't test internal interfaces, so the include path
+// is a little wonky.
+#include "../src/config.h"
+
+// Only run this test under supported configurations.
+
+#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) &&                                 \
+    defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
+
+#include <link.h>
+#include <stdio.h>
+
+// This file defines several of the data structures needed here,
+// and includes FrameHeaderCache.hpp as well.
+#include "../src/AddressSpace.hpp"
+
+#define kBaseAddr 0xFFF000
+#define kTextSegmentLength 0xFF
+
+using namespace libunwind;
+
+int main(int, char**) {
+  FrameHeaderCache FHC;
+  struct dl_phdr_info PInfo;
+  memset(&PInfo, 0, sizeof(PInfo));
+  // The cache itself should only care about these two fields--they
+  // tell the cache to invalidate or not; everything else is handled
+  // by AddressSpace.hpp.
+  PInfo.dlpi_adds = 6;
+  PInfo.dlpi_subs = 7;
+
+  UnwindInfoSections UIS;
+  UIS.dso_base = kBaseAddr;
+  UIS.text_segment_length = kTextSegmentLength;
+  dl_iterate_cb_data CBData;
+  // Unused by the cache.
+  CBData.addressSpace = nullptr;
+  CBData.sects = &UIS;
+  CBData.targetAddr = kBaseAddr + 1;
+
+  // Nothing present, shouldn't find.
+  if (FHC.find(&PInfo, 0, &CBData))
+    abort();
+  FHC.add(&UIS);
+  // Just added. Should find.
+  if (!FHC.find(&PInfo, 0, &CBData))
+    abort();
+  // Cache is invalid. Shouldn't find.
+  PInfo.dlpi_adds++;
+  if (FHC.find(&PInfo, 0, &CBData))
+    abort();
+
+  FHC.add(&UIS);
+  CBData.targetAddr = kBaseAddr - 1;
+  // Shouldn't find something outside of the addresses.
+  if (FHC.find(&PInfo, 0, &CBData))
+    abort();
+  // Add enough things to the cache that the entry is evicted.
+  for (int i = 0; i < 9; i++) {
+    UIS.dso_base = kBaseAddr + (kTextSegmentLength * i);
+    FHC.add(&UIS);
+  }
+  CBData.targetAddr = kBaseAddr;
+  // Should have been evicted.
+  if (FHC.find(&PInfo, 0, &CBData))
+    abort();
+  return 0;
+}
+
+#else
+int main(int, char**) { return 0;}
+#endif

+ 0 - 0
llvm-libunwind/test/libunwind/__init__.py


+ 0 - 0
llvm-libunwind/test/libunwind/test/__init__.py


+ 69 - 0
llvm-libunwind/test/libunwind/test/config.py

@@ -0,0 +1,69 @@
+#===----------------------------------------------------------------------===##
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+#===----------------------------------------------------------------------===##
+import os
+import sys
+
+from libcxx.test.config import Configuration as LibcxxConfiguration
+
+
+class Configuration(LibcxxConfiguration):
+    # pylint: disable=redefined-outer-name
+    def __init__(self, lit_config, config):
+        super(Configuration, self).__init__(lit_config, config)
+        self.libunwind_src_root = None
+        self.libunwind_obj_root = None
+        self.abi_library_root = None
+        self.libcxx_src_root = None
+
+    def configure_src_root(self):
+        self.libunwind_src_root = (self.get_lit_conf('libunwind_src_root')
+            or os.path.dirname(self.config.test_source_root))
+        self.libcxx_src_root = (self.get_lit_conf('libcxx_src_root')
+            or os.path.join(self.libunwind_src_root, '..', 'libcxx'))
+
+    def configure_obj_root(self):
+        self.libunwind_obj_root = self.get_lit_conf('libunwind_obj_root')
+        super(Configuration, self).configure_obj_root()
+
+    def has_cpp_feature(self, feature, required_value):
+        return int(self.cxx.dumpMacros().get('__cpp_' + feature, 0)) >= required_value
+
+    def configure_features(self):
+        super(Configuration, self).configure_features()
+        if self.get_lit_bool('arm_ehabi', False):
+            self.config.available_features.add('libunwind-arm-ehabi')
+
+    def configure_compile_flags(self):
+        self.cxx.compile_flags += ['-DLIBUNWIND_NO_TIMER']
+        # Stack unwinding tests need unwinding tables and these are not
+        # generated by default on all Targets.
+        self.cxx.compile_flags += ['-funwind-tables']
+        # Make symbols available in the tests.
+        if 'linux' in self.config.target_triple:
+            self.cxx.link_flags += ['-Wl,--export-dynamic']
+        if not self.get_lit_bool('enable_threads', True):
+            self.cxx.compile_flags += ['-D_LIBUNWIND_HAS_NO_THREADS']
+            self.config.available_features.add('libunwind-no-threads')
+        super(Configuration, self).configure_compile_flags()
+
+    def configure_compile_flags_header_includes(self):
+        libunwind_headers = self.get_lit_conf(
+            'libunwind_headers',
+            os.path.join(self.libunwind_src_root, 'include'))
+        if not os.path.isdir(libunwind_headers):
+            self.lit_config.fatal("libunwind_headers='%s' is not a directory."
+                                  % libunwind_headers)
+        self.cxx.compile_flags += ['-I' + libunwind_headers]
+
+    def configure_link_flags_cxx_library(self):
+        # libunwind tests should not link with libc++
+        pass
+
+    def configure_link_flags_abi_library(self):
+        # libunwind tests should not link with libc++abi
+        pass

+ 64 - 0
llvm-libunwind/test/libunwind_01.pass.cpp

@@ -0,0 +1,64 @@
+#include <libunwind.h>
+#include <stdlib.h>
+
+void backtrace(int lower_bound) {
+  unw_context_t context;
+  unw_getcontext(&context);
+
+  unw_cursor_t cursor;
+  unw_init_local(&cursor, &context);
+
+  int n = 0;
+  do {
+    ++n;
+    if (n > 100) {
+      abort();
+    }
+  } while (unw_step(&cursor) > 0);
+
+  if (n < lower_bound) {
+    abort();
+  }
+}
+
+void test1(int i) {
+  backtrace(i);
+}
+
+void test2(int i, int j) {
+  backtrace(i);
+  test1(j);
+}
+
+void test3(int i, int j, int k) {
+  backtrace(i);
+  test2(j, k);
+}
+
+void test_no_info() {
+  unw_context_t context;
+  unw_getcontext(&context);
+
+  unw_cursor_t cursor;
+  unw_init_local(&cursor, &context);
+
+  unw_proc_info_t info;
+  int ret = unw_get_proc_info(&cursor, &info);
+  if (ret != UNW_ESUCCESS)
+    abort();
+
+  // Set the IP to an address clearly outside any function.
+  unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)0);
+
+  ret = unw_get_proc_info(&cursor, &info);
+  if (ret != UNW_ENOINFO)
+    abort();
+}
+
+int main(int, char**) {
+  test1(1);
+  test2(1, 2);
+  test3(1, 2, 3);
+  test_no_info();
+  return 0;
+}

+ 39 - 0
llvm-libunwind/test/libunwind_02.pass.cpp

@@ -0,0 +1,39 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <unwind.h>
+
+#define EXPECTED_NUM_FRAMES 50
+#define NUM_FRAMES_UPPER_BOUND 100
+
+_Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) {
+  (void)context;
+  int *i = (int *)cnt;
+  ++*i;
+  if (*i > NUM_FRAMES_UPPER_BOUND) {
+    abort();
+  }
+  return _URC_NO_REASON;
+}
+
+void test_backtrace() {
+  int n = 0;
+  _Unwind_Backtrace(&callback, &n);
+  if (n < EXPECTED_NUM_FRAMES) {
+    abort();
+  }
+}
+
+int test(int i) {
+  if (i == 0) {
+    test_backtrace();
+    return 0;
+  } else {
+    return i + test(i - 1);
+  }
+}
+
+int main(int, char**) {
+  int total = test(50);
+  assert(total == 1275);
+  return 0;
+}

+ 10 - 0
llvm-libunwind/test/lit.cfg.py

@@ -0,0 +1,10 @@
+# All the Lit configuration is handled in the site configs -- this file is only
+# left as a canary to catch invocations of Lit that do not go through llvm-lit.
+#
+# Invocations that go through llvm-lit will automatically use the right Lit
+# site configuration inside the build directory.
+
+lit_config.fatal(
+    "You seem to be running Lit directly -- you should be running Lit through "
+    "<build>/bin/llvm-lit, which will ensure that the right Lit configuration "
+    "file is used.")

+ 58 - 0
llvm-libunwind/test/lit.site.cfg.in

@@ -0,0 +1,58 @@
+@AUTO_GEN_COMMENT@
+
+import os
+import site
+
+config.cxx_under_test           = "@CMAKE_CXX_COMPILER@"
+config.project_obj_root         = "@CMAKE_BINARY_DIR@"
+config.libunwind_src_root       = "@LIBUNWIND_SOURCE_DIR@"
+config.libunwind_obj_root       = "@LIBUNWIND_BINARY_DIR@"
+config.abi_library_root         = "@LIBUNWIND_LIBRARY_DIR@"
+config.libcxx_src_root          = "@LIBUNWIND_LIBCXX_PATH@"
+config.libunwind_headers        = "@LIBUNWIND_SOURCE_DIR@/include"
+config.cxx_library_root         = "@LIBUNWIND_LIBCXX_LIBRARY_PATH@"
+config.llvm_unwinder            = True
+config.builtins_library         = "@LIBUNWIND_BUILTINS_LIBRARY@"
+config.enable_threads           = @LIBUNWIND_ENABLE_THREADS@
+config.use_sanitizer            = "@LLVM_USE_SANITIZER@"
+config.enable_32bit             = @LIBUNWIND_BUILD_32_BITS@
+config.target_info              = "@LIBUNWIND_TARGET_INFO@"
+config.test_linker_flags        = "@LIBUNWIND_TEST_LINKER_FLAGS@"
+config.test_compiler_flags      = "@LIBUNWIND_TEST_COMPILER_FLAGS@"
+config.executor                 = "@LIBUNWIND_EXECUTOR@"
+config.libunwind_shared         = @LIBUNWIND_ENABLE_SHARED@
+config.enable_shared            = @LIBCXX_ENABLE_SHARED@
+config.arm_ehabi                = @LIBUNWIND_USES_ARM_EHABI@
+config.host_triple              = "@LLVM_HOST_TRIPLE@"
+if "@TARGET_TRIPLE@":
+    config.target_triple        = "@TARGET_TRIPLE@"
+config.sysroot                  = "@LIBUNWIND_SYSROOT@"
+config.gcc_toolchain            = "@LIBUNWIND_GCC_TOOLCHAIN@"
+config.cxx_ext_threads          = @LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY@
+
+site.addsitedir(os.path.join(config.libunwind_src_root, 'test'))
+site.addsitedir(os.path.join(config.libcxx_src_root, 'utils'))
+
+# name: The name of this test suite.
+config.name = 'libunwind'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.cpp', '.s']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.join(config.libunwind_src_root, 'test')
+
+# Allow expanding substitutions that are based on other substitutions
+config.recursiveExpansionLimit = 10
+
+# Infer the test_exec_root from the build directory.
+config.test_exec_root = os.path.join(config.libunwind_obj_root, 'test')
+
+import libcxx.test.format
+config.test_format = libcxx.test.format.CxxStandardLibraryTest()
+
+lit_config.note('Using configuration variant: libunwind')
+import libunwind.test.config
+configuration = libunwind.test.config.Configuration(lit_config, config)
+configuration.configure()
+configuration.print_config_info()

+ 56 - 0
llvm-libunwind/test/remember_state_leak.pass.sh.s

@@ -0,0 +1,56 @@
+# REQUIRES: x86, linux
+# RUN: %{build} -target x86_64-unknown-linux-gnu
+# RUN: %{run}
+
+# The following assembly is a translation of this code:
+#
+#   _Unwind_Reason_Code callback(int, _Unwind_Action, long unsigned int,
+#                                _Unwind_Exception*, _Unwind_Context*, void*) {
+#     return _Unwind_Reason_Code(0);
+#   }
+#
+#   int main() {
+#     asm(".cfi_remember_state\n\t");
+#     _Unwind_Exception exc;
+#     _Unwind_ForcedUnwind(&exc, callback, 0);
+#     asm(".cfi_restore_state\n\t");
+#   }
+#
+# When unwinding, the CFI parser will stop parsing opcodes after the current PC,
+# so in this case the DW_CFA_restore_state opcode will never be processed and,
+# if the library doesn't clean up properly, the store allocated by
+# DW_CFA_remember_state will be leaked.
+#
+# This test will fail when linked with an asan-enabled libunwind if the
+# remembered state is leaked.
+
+    SIZEOF_UNWIND_EXCEPTION = 32
+
+    .text
+callback:
+    xorl    %eax, %eax
+    retq
+
+    .globl    main                    # -- Begin function main
+    .p2align    4, 0x90
+    .type    main,@function
+main:                                   # @main
+    .cfi_startproc
+    subq    $8, %rsp   # Adjust stack alignment
+    subq    $SIZEOF_UNWIND_EXCEPTION, %rsp
+    .cfi_def_cfa_offset 48
+    .cfi_remember_state
+    movq    %rsp, %rdi
+    movabsq $callback, %rsi
+    xorl    %edx, %edx
+    callq    _Unwind_ForcedUnwind
+    .cfi_restore_state
+    xorl    %eax, %eax
+    addq    $SIZEOF_UNWIND_EXCEPTION, %rsp
+    addq    $8, %rsp   # Undo stack alignment adjustment
+    .cfi_def_cfa_offset 8
+    retq
+.Lfunc_end1:
+    .size    main, .Lfunc_end1-main
+    .cfi_endproc
+                                        # -- End function

+ 31 - 0
llvm-libunwind/test/signal_frame.pass.cpp

@@ -0,0 +1,31 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Ensure that functions marked as signal frames are reported as such.
+
+// UNSUPPORTED: libunwind-arm-ehabi
+
+#include <assert.h>
+#include <stdlib.h>
+#include <libunwind.h>
+
+void test() {
+  asm(".cfi_signal_frame");
+  unw_cursor_t cursor;
+  unw_context_t uc;
+  unw_getcontext(&uc);
+  unw_init_local(&cursor, &uc);
+  assert(unw_step(&cursor) > 0);
+  assert(unw_is_signal_frame(&cursor));
+}
+
+int main(int, char**) {
+  test();
+  return 0;
+}

+ 46 - 0
llvm-libunwind/test/signal_unwind.pass.cpp

@@ -0,0 +1,46 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Ensure that the unwinder can cope with the signal handler.
+// REQUIRES: linux && (target-aarch64 || target-x86_64)
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <unwind.h>
+
+_Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) {
+  (void)arg;
+  Dl_info info = { 0, 0, 0, 0 };
+
+  // Unwind util the main is reached, above frames depend on the platform and
+  // architecture.
+  if (dladdr(reinterpret_cast<void *>(_Unwind_GetIP(ctx)), &info) &&
+      info.dli_sname && !strcmp("main", info.dli_sname)) {
+    _Exit(0);
+  }
+  return _URC_NO_REASON;
+}
+
+void signal_handler(int signum) {
+  (void)signum;
+  _Unwind_Backtrace(frame_handler, NULL);
+  _Exit(-1);
+}
+
+int main(int, char**) {
+  signal(SIGUSR1, signal_handler);
+  kill(getpid(), SIGUSR1);
+  return -2;
+}

+ 9 - 0
llvm-libunwind/test/unw_getcontext.pass.cpp

@@ -0,0 +1,9 @@
+#include <assert.h>
+#include <libunwind.h>
+
+int main(int, char**) {
+  unw_context_t context;
+  int ret = unw_getcontext(&context);
+  assert(ret == UNW_ESUCCESS);
+  return 0;
+}

+ 51 - 0
llvm-libunwind/test/unwind_leaffunction.pass.cpp

@@ -0,0 +1,51 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Ensure that leaf function can be unwund.
+// REQUIRES: linux && (target-aarch64 || target-x86_64)
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <unwind.h>
+
+_Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) {
+  (void)arg;
+  Dl_info info = { 0, 0, 0, 0 };
+
+  // Unwind util the main is reached, above frames deeped on the platfrom and architecture.
+  if (dladdr(reinterpret_cast<void *>(_Unwind_GetIP(ctx)), &info) &&
+      info.dli_sname && !strcmp("main", info.dli_sname)) {
+    _Exit(0);
+  }
+  return _URC_NO_REASON;
+}
+
+void signal_handler(int signum) {
+  (void)signum;
+  _Unwind_Backtrace(frame_handler, NULL);
+  _Exit(-1);
+}
+
+int* faultyPointer = NULL;
+
+__attribute__((noinline)) void crashing_leaf_func(void) {
+  *faultyPointer = 0;
+}
+
+int main(int, char**) {
+  signal(SIGSEGV, signal_handler);
+  crashing_leaf_func();
+  return -2;
+}

+ 40 - 0
src/aarch64.rs

@@ -0,0 +1,40 @@
+use crate::uw;
+
+/// Register context from which to capture a backtrace.
+#[derive(Copy, Clone, Debug)]
+pub struct Context {
+    /// Program counter
+    pub pc: u64,
+
+    /// Stack pointer
+    pub sp: u64,
+
+    /// General-purpose registers (excluding the stack pointer)
+    pub regs: [u64; 31],
+
+    /// FP/SIMD registers
+    pub vregs: [u128; 32],
+}
+
+impl Context {
+    pub(crate) unsafe fn apply(&self, cursor: *mut uw::unw_cursor_t) {
+        uw::unw_set_reg(cursor, uw::UNW_REG_IP, self.pc as usize);
+        uw::unw_set_reg(cursor, uw::UNW_REG_SP, self.sp as usize);
+        for i in 0..31 {
+            uw::unw_set_reg(
+                cursor,
+                (uw::UNW_ARM64_X0 + i) as i32,
+                self.regs[i as usize] as usize,
+            );
+        }
+        for i in 0..32 {
+            // libunwind doesn't track the upper bits of SIMD registers
+            let fval = f64::from_bits(self.vregs[i as usize] as u64);
+            uw::unw_set_fpreg(cursor, (uw::UNW_ARM64_D0 + i) as i32, fval);
+        }
+    }
+
+    pub(crate) fn ip(&self) -> usize {
+        self.pc as usize
+    }
+}

+ 292 - 0
src/lib.rs

@@ -0,0 +1,292 @@
+//! This crate provides backtrace support for `no_std` and embedded programs.
+//!
+//! This is done through by compiling LLVM's libunwind with certain flags to remove
+//! all OS dependencies, including libc and any memory allocations.
+//!
+//! # Usage
+//!
+//! ### Setup
+//!
+//! There are two prerequisites for using this crate:
+//!
+//! 1. Unwind tables must be built into the binary, even with unwinding is set to
+//!    abort. This can be done with the `-C force-unwind-tables` flag.
+//!
+//! 2. Several `__eh_frame_*` symbols need to be defined by the linker so that the
+//!    the unwinding tables can be located by libunwind. This can be done by
+//!    including the [`eh_frame.ld`] linker script fragment.
+//!
+//! Both of these can be done by setting `RUSTFLAGS`:
+//!
+//! ```sh
+//! export RUSTFLAGS="-Cforce-unwind-tables -Clink-arg=-Wl,eh_frame.ld"
+//! ```
+//!
+//! Note that these flags also apply to build-dependencies and proc
+//! macros by default. This can be worked around by explicitly
+//! specifying a target when invoking cargo:
+//!
+//! ```sh
+//! # Applies RUSTFLAGS to everything
+//! cargo build
+//!
+//! # Doesn't apply RUSTFLAGS to build dependencies and proc macros
+//! cargo build --target x86_64-unknown-linux-gnu
+//! ```
+//!
+//! [`eh_frame.ld`]: https://github.com/Amanieu/mini-backtrace/blob/master/eh_frame.ld
+//!
+//! ### Capturing backtraces
+//!
+//! Add the `mini-backtrace` crate as a dependency to your program:
+//!
+//! ```toml
+//! [dependencies]
+//! mini-backtrace = "0.1"
+//! ```
+//!
+//! You can capture a backtrace by using the `Backtrace` type which returns a list
+//! of frames as an `ArrayVec` of instruction pointer addresses.
+//!
+//! ```rust
+//! use mini_backtrace::Backtrace;
+//!
+//! // Capture up to 16 frames. This is returned using an ArrayVec that doesn't
+//! // perform any dynamic memory allocation.
+//! let bt = Backtrace::<16>::capture();
+//! println!("Backtrace:");
+//! for frame in bt.frames {
+//!     println!("  {:#x}", frame);
+//! }
+//! if bt.frames_omitted {
+//!     println!(" ... <frames omitted>");
+//! }
+//! ```
+//!
+//! This will output:
+//!
+//! ```text
+//! Backtrace:
+//!   0x5587058c3eb1
+//!   0x5587058c3cdb
+//!   0x5587058c491e
+//!   0x5587058c38b1
+//!   0x5587058daf1a
+//!   0x5587058c3890
+//!   0x5587058c414c
+//! ```
+//!
+//! ### Position-independent code
+//!
+//! If your code is executing at a different address than the one it is linked at
+//! then you will need to fix up the frame pointer addresses to be relative to the
+//! module base address. This can be done with the following function:
+//!
+//! ```rust
+//! fn adjust_for_pic(ip: usize) -> usize {
+//!     extern "C" {
+//!         // Symbol defined by the linker
+//!         static __executable_start: [u8; 0];
+//!     }
+//!     let base = unsafe { __executable_start.as_ptr() as usize };
+//!     ip - base
+//! }
+//! ```
+//!
+//! After post-processing, the output should look like this:
+//!
+//! ```text
+//! Backtrace:
+//!   0x8eb1
+//!   0x8cdb
+//!   0x999e
+//!   0x88b1
+//!   0x1ffba
+//!   0x8890
+//!   0x91cc
+//! ```
+//!
+//! Have a look at `examples/backtrace.rs` for a complete example.
+//!
+//! Note that `adjust_for_pic` should *only* be called for position-independent
+//! binaries. Statically-linked binaries should emit unadjusted addresses so that
+//! the backtraces can be correctly resolved.
+//!
+//! ### Resolving backtraces
+//!
+//! The addresses generated by `Backtrace` can be converted to human-readable
+//! function names, filenames and line numbers by using the `addr2line` tool from
+//! LLVM or binutils with [rustfilt] to demangle Rust symbol names.
+//!
+//! Simply run `addr2line -fipe /path/to/binary | rustfilt` in a terminal and then
+//! paste the addresses from the backtrace:
+//!
+//! ```text
+//! $ llvm-addr2line -fipe target/x86_64-unknown-linux-gnu/debug/examples/backtrace | rustfilt
+//!   0x8ed1
+//!   0x8ea6
+//!   0x8e96
+//!   0x8cdb
+//!   0x99be
+//!   0x88b1
+//!   0x1ffda
+//!   0x8890
+//!   0x91ec
+//! backtrace::bar at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:15
+//! backtrace::foo at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:10
+//! backtrace::main at /home/amanieu/code/mini-backtrace/examples/backtrace.rs:5
+//! core::ops::function::FnOnce::call_once at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
+//! std::sys_common::backtrace::__rust_begin_short_backtrace at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:128
+//! std::rt::lang_start::{{closure}} at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:49
+//! std::panicking::try at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/panicking.rs:344
+//!  (inlined by) std::panic::catch_unwind at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/panic.rs:431
+//!  (inlined by) std::rt::lang_start_internal at /rustc/676ee14729462585b969bbc52f32c307403f4126/library/std/src/rt.rs:34
+//! std::rt::lang_start at /home/amanieu/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:48
+//! main at ??:0
+//! ```
+//!
+//! [rustfilt]: https://github.com/luser/rustfilt
+//!
+//! ### Backtraces from signal/interrupt handlers
+//!
+//! The libunwind unwinder used by this crate is usually unable to unwind past
+//! signal handler or interrupt handler frames. Instead, you can use
+//! `Backtrace::capture_from_context` and pass in the register state at the point
+//! where the exception occurred. In a signal handler this can be obtained through
+//! the `uc_mcontext` field of `ucontext_t`.
+//!
+//! This is currently only implemented for:
+//! - AArch64
+//! - RISC-V (RV32 & RV64)
+
+#![no_std]
+
+use arrayvec::ArrayVec;
+use core::mem::MaybeUninit;
+
+#[allow(non_upper_case_globals)]
+#[allow(non_camel_case_types)]
+#[allow(non_snake_case)]
+#[allow(dead_code)]
+mod uw {
+    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+}
+
+cfg_if::cfg_if! {
+    if #[cfg(target_arch = "aarch64")] {
+        mod aarch64;
+        pub use aarch64::Context;
+    } else if #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] {
+        mod riscv;
+        pub use riscv::Context;
+    }
+}
+
+/// A backtrace consisting of a list of instruction pointer addresses.
+///
+/// The backtrace does not allocate any memory, which allows it to be used in
+/// environments where dynamic allocation cannot be used such as signal handlers
+/// or interrupt handlers.
+///
+/// The `N` generic constant controls the maximum number of entries that should
+/// be included in the backtrace. Usually 16 frames are enough to get sufficient
+/// context from a crash.
+#[derive(Clone, Debug, Default)]
+pub struct Backtrace<const N: usize> {
+    /// List of instruction pointer addresses in each frame, from most recent to
+    /// oldest.
+    ///
+    /// These are not precise return address: the addresses are adjusted so that
+    /// they point within the bounds of the caller function. This avoids issues
+    /// when a call instruction is the last instruction in a function, which
+    /// would otherwise result in a return address pointing at the start of the
+    /// next function.
+    pub frames: ArrayVec<usize, N>,
+
+    /// Whether any frames have been omitted due to exceeding the capacity of
+    /// the `ArrayVec`.
+    pub frames_omitted: bool,
+}
+
+impl<const N: usize> Backtrace<N> {
+    /// Captures a backtrace from the current call point.
+    ///
+    /// The first frame of the backtrace is the caller of `Backtrace::capture`.
+    #[inline(never)]
+    pub fn capture() -> Self {
+        unsafe {
+            let mut unw_context = MaybeUninit::uninit();
+            let mut unw_cursor = MaybeUninit::uninit();
+            uw::unw_getcontext(unw_context.as_mut_ptr());
+            uw::unw_init_local(unw_cursor.as_mut_ptr(), unw_context.as_mut_ptr());
+
+            let mut result = Self::default();
+            result.fill_from_cursor(unw_cursor.as_mut_ptr());
+            result
+        }
+    }
+
+    /// Captures a backtrace from the given register context.
+    ///
+    /// The first frame of the backtrace is the instruction pointer address in
+    /// the register context.
+    ///
+    /// This function is useful for capturing backtraces from signal handlers
+    /// since the unwinder may not be able to unwind past the signal frame.
+    ///
+    /// If no unwinding information is found for the instruction pointer address
+    /// in the context then `None` is returned.
+    #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
+    pub fn capture_from_context(ctx: &Context) -> Option<Self> {
+        unsafe {
+            let mut unw_context = MaybeUninit::uninit();
+            let mut unw_cursor = MaybeUninit::uninit();
+            uw::unw_getcontext(unw_context.as_mut_ptr());
+            uw::unw_init_local(unw_cursor.as_mut_ptr(), unw_context.as_mut_ptr());
+
+            // Apply the register state to the cursor.
+            ctx.apply(unw_cursor.as_mut_ptr());
+
+            // Check if we actually have unwind info for the fault address. We
+            // don't generate a backtrace if the fault happened outside our
+            // executable.
+            let mut unw_proc_info = MaybeUninit::uninit();
+            if uw::unw_get_proc_info(unw_cursor.as_mut_ptr(), unw_proc_info.as_mut_ptr())
+                != uw::UNW_ESUCCESS
+            {
+                return None;
+            }
+
+            // Add the instruction pointer address from the context as the first
+            // frame of the backtrace.
+            let mut result = Self::default();
+            result.frames.push(ctx.ip());
+            result.fill_from_cursor(unw_cursor.as_mut_ptr());
+            Some(result)
+        }
+    }
+
+    unsafe fn fill_from_cursor(&mut self, cursor: *mut uw::unw_cursor_t) {
+        while uw::unw_step(cursor) > 0 {
+            let mut ip = 0;
+            uw::unw_get_reg(cursor, uw::UNW_REG_IP, &mut ip);
+
+            // Adjust the IP to point within the function symbol. This should
+            // only be done if the frame is not a signal frame.
+            if uw::unw_is_signal_frame(cursor) > 0 {
+                ip -= 1;
+            }
+
+            if self.frames.try_push(ip).is_err() {
+                self.frames_omitted = true;
+                break;
+            }
+        }
+    }
+}
+
+#[test]
+fn capture() {
+    let bt = Backtrace::<16>::capture();
+    assert!(bt.frames.len() > 1);
+}

+ 31 - 0
src/riscv.rs

@@ -0,0 +1,31 @@
+use crate::uw;
+
+/// Register context from which to capture a backtrace.
+#[derive(Copy, Clone, Debug)]
+pub struct Context {
+    /// Program counter
+    pub pc: usize,
+
+    /// General-purpose registers, starting from x1
+    pub regs: [usize; 31],
+
+    /// Floating-point registers
+    pub fregs: [u64; 32],
+}
+
+impl Context {
+    pub(crate) unsafe fn apply(&self, cursor: *mut uw::unw_cursor_t) {
+        uw::unw_set_reg(cursor, uw::UNW_REG_IP, self.pc);
+        for i in 0..31 {
+            uw::unw_set_reg(cursor, (uw::UNW_RISCV_X1 + i) as i32, self.regs[i as usize]);
+        }
+        for i in 0..32 {
+            let fval = f64::from_bits(self.fregs[i as usize]);
+            uw::unw_set_fpreg(cursor, (uw::UNW_RISCV_F0 + i) as i32, fval);
+        }
+    }
+
+    pub(crate) fn ip(&self) -> usize {
+        self.pc
+    }
+}