diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs
new file mode 100644
index 00000000000..2b360cb85a6
--- /dev/null
+++ b/src/shims/backtrace.rs
@@ -0,0 +1,110 @@
+use crate::*;
+use helpers::check_arg_count;
+use rustc_middle::ty::TypeAndMut;
+use rustc_ast::ast::Mutability;
+use rustc_span::BytePos;
+use rustc_target::abi::Size;
+use std::convert::TryInto as _;
+use crate::rustc_target::abi::LayoutOf as _;
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
+
+    fn handle_miri_get_backtrace(
+        &mut self,
+        args: &[OpTy<'tcx, Tag>],
+        dest: PlaceTy<'tcx, Tag>
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let tcx = this.tcx;
+        let &[flags] = check_arg_count(args)?;
+
+        let flags = this.read_scalar(flags)?.to_u64()?;
+        if flags != 0 {
+            throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags);
+        }
+
+        let mut data = Vec::new();
+        for frame in this.active_thread_stack().iter().rev() {
+            data.push((frame.instance, frame.current_span().lo()));
+        }
+
+        let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| {
+            let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance));
+            fn_ptr.offset = Size::from_bytes(pos.0);
+            Scalar::Ptr(fn_ptr)
+        }).collect();
+
+        let len = ptrs.len();
+
+        let ptr_ty = tcx.mk_ptr(TypeAndMut {
+            ty: tcx.types.unit,
+            mutbl: Mutability::Mut
+        });
+
+        let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap());
+
+        // Write pointers into array
+        let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into());
+        for (i, ptr) in ptrs.into_iter().enumerate() {
+            let place = this.mplace_index(alloc, i as u64)?;
+            this.write_immediate_to_mplace(ptr.into(), place)?;
+        }
+
+        this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?;
+        Ok(())
+    }
+
+    fn handle_miri_resolve_frame(
+        &mut self,
+        args: &[OpTy<'tcx, Tag>],
+        dest: PlaceTy<'tcx, Tag>
+    ) -> InterpResult<'tcx> {
+        let this = self.eval_context_mut();
+        let tcx = this.tcx;
+        let &[ptr, flags] = check_arg_count(args)?;
+
+        let flags = this.read_scalar(flags)?.to_u64()?;
+        if flags != 0 {
+            throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags);
+        }
+
+        let ptr = match this.read_scalar(ptr)?.check_init()? {
+            Scalar::Ptr(ptr) => ptr,
+            Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr)
+        };
+
+        let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) {
+            instance
+        } else {
+            throw_ub_format!("expected function pointer, found {:?}", ptr);
+        };
+
+        if dest.layout.layout.fields.count() != 4 {
+            throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields");
+        }
+
+        let pos = BytePos(ptr.offset.bytes().try_into().unwrap());
+        let name = fn_instance.to_string();
+
+        let lo = tcx.sess.source_map().lookup_char_pos(pos);
+
+        let filename = lo.file.name.to_string();
+        let lineno: u32 = lo.line as u32;
+        // `lo.col` is 0-based - add 1 to make it 1-based for the caller.
+        let colno: u32 = lo.col.0 as u32 + 1;
+
+        let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into());
+        let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into());
+        let lineno_alloc = Scalar::from_u32(lineno);
+        let colno_alloc = Scalar::from_u32(colno);
+
+        let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0;
+
+        this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?;
+        this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?;
+        this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?;
+        this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?;
+        Ok(())
+    }
+}
diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs
index b1a02a8eb65..7118fbda240 100644
--- a/src/shims/foreign_items.rs
+++ b/src/shims/foreign_items.rs
@@ -5,13 +5,12 @@ use log::trace;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir;
 use rustc_target::{abi::{Align, Size}, spec::PanicStrategy};
-use rustc_middle::ty::{self, ParamEnv, TypeAndMut};
-use rustc_ast::ast::Mutability;
+use rustc_middle::ty;
 use rustc_apfloat::Float;
 use rustc_span::symbol::sym;
-use rustc_span::BytePos;
 
 use crate::*;
+use super::backtrace::EvalContextExt as _;
 use helpers::check_arg_count;
 
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
@@ -216,84 +215,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
 
             // Obtains a Miri backtrace. See the README for details.
             "miri_get_backtrace" => {
-                let tcx = this.tcx;
-                let mut data = Vec::new();
-                for frame in this.active_thread_stack().iter().rev() {
-                    data.push((frame.instance, frame.current_span().lo()));
-                }
-
-                let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| {
-                    let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance));
-                    fn_ptr.offset = Size::from_bytes(pos.0);
-                    Scalar::Ptr(fn_ptr)
-                }).collect();
-
-                let len = ptrs.len();
-
-                let ptr_ty = tcx.mk_ptr(TypeAndMut {
-                    ty: tcx.types.unit,
-                    mutbl: Mutability::Mut
-                });
-
-                let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap());
-                let array_ty_and_env = ParamEnv::empty().and(array_ty);
-
-                // Write pointers into array
-                let alloc = this.allocate(tcx.layout_of(array_ty_and_env).unwrap(), MiriMemoryKind::Rust.into());
-                for (i, ptr) in ptrs.into_iter().enumerate() {
-                    let place = this.mplace_index(alloc, i as u64)?;
-                    this.write_immediate_to_mplace(ptr.into(), place)?;
-                }
-
-                this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?;
+                this.handle_miri_get_backtrace(args, dest)?;
             }
 
             // Resolves a Miri backtrace frame. See the README for details.
             "miri_resolve_frame" => {
-                let tcx = this.tcx;
-                let &[ptr, flags] = check_arg_count(args)?;
-
-                let flags = this.read_scalar(flags)?.to_u64()?;
-                if flags != 0 {
-                    throw_ub_format!("Unknown `miri_resolve_frame` flags {}", flags);
-                }
-
-                let ptr = match this.read_scalar(ptr)?.check_init()? {
-                    Scalar::Ptr(ptr) => ptr,
-                    Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr)
-                };
-
-                let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) {
-                    instance
-                } else {
-                    throw_ub_format!("Expect function pointer, found {:?}", ptr);
-                };
-
-                if dest.layout.layout.fields.count() != 4 {
-                    throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields");
-                }
-
-                let pos = BytePos(ptr.offset.bytes().try_into().unwrap());
-                let name = fn_instance.to_string();
-
-                let lo = tcx.sess.source_map().lookup_char_pos(pos);
-
-                let filename = lo.file.name.to_string();
-                let lineno: u32 = lo.line as u32;
-                // `lo.col` is 0-based - add 1 to make it 1-based for the caller.
-                let colno: u32 = lo.col.0 as u32 + 1;
-
-                let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into());
-                let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into());
-                let lineno_alloc = Scalar::from_u32(lineno);
-                let colno_alloc = Scalar::from_u32(colno);
-
-                let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0;
-
-                this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?;
-                this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?;
-                this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?;
-                this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?;
+                this.handle_miri_resolve_frame(args, dest)?;
             }
 
 
diff --git a/src/shims/mod.rs b/src/shims/mod.rs
index eab27496cb2..90dcc4d8ff1 100644
--- a/src/shims/mod.rs
+++ b/src/shims/mod.rs
@@ -1,4 +1,4 @@
-
+mod backtrace;
 pub mod foreign_items;
 pub mod intrinsics;
 pub mod posix;
diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs
index c55a1c6d380..bccc7063af7 100644
--- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs
+++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs
@@ -1,10 +1,10 @@
 extern "Rust" {
-    fn miri_get_backtrace() -> Box<[*mut ()]>;
+    fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
     fn miri_resolve_frame(ptr: *mut (), flags: u64);
 }
 
 fn main() {
-    let frames = unsafe { miri_get_backtrace() };
+    let frames = unsafe { miri_get_backtrace(0) };
     for frame in frames.into_iter() {
         unsafe {
             miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields
diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs
index d6743ae8fff..4579b5d0ade 100644
--- a/tests/compile-fail/backtrace/bad-backtrace-version.rs
+++ b/tests/compile-fail/backtrace/bad-backtrace-version.rs
@@ -4,6 +4,6 @@ extern "Rust" {
 
 fn main() {
     unsafe {
-        miri_resolve_frame(0 as *mut _, 1); //~ ERROR  Undefined Behavior: Unknown `miri_resolve_frame` flags 1
+        miri_resolve_frame(0 as *mut _, 1); //~ ERROR  unsupported operation: unknown `miri_resolve_frame` flags 1
     }
 }
diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs
index 73a3f6242d5..655a52c7fc7 100644
--- a/tests/run-pass/backtrace-api.rs
+++ b/tests/run-pass/backtrace-api.rs
@@ -2,7 +2,7 @@
 // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL "
 
 extern "Rust" {
-    fn miri_get_backtrace() -> Box<[*mut ()]>;
+    fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
     fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
 }
 
@@ -16,7 +16,7 @@ struct MiriFrame {
 
 fn func_a() -> Box<[*mut ()]> { func_b::<u8>() }
 fn func_b<T>() -> Box<[*mut ()]> { func_c() }
-fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace() } }
+fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } }
 
 fn main() {
     let mut seen_main = false;