diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h
index bfa99de81ea4..7b11f480e97c 100644
--- a/lldb/include/lldb/Core/Disassembler.h
+++ b/lldb/include/lldb/Core/Disassembler.h
@@ -182,6 +182,37 @@ public:
     
     uint32_t
     GetData (DataExtractor &data);
+    
+    struct Operand
+    {
+        enum class Type {
+            Invalid = 0,
+            Register,
+            Immediate,
+            Dereference,
+            Sum,
+            Product
+        } m_type = Type::Invalid;
+        std::vector<const Operand> m_children;
+        lldb::addr_t m_immediate = 0;
+        ConstString m_register;
+        bool m_negative = false;
+        bool m_clobbered = false;
+        
+        bool IsValid() { return m_type != Type::Invalid; }
+    };
+    
+    virtual bool
+    ParseOperands (llvm::SmallVectorImpl<Operand> &operands)
+    {
+        return false;
+    }
+    
+    virtual bool
+    IsCall ()
+    {
+        return false;
+    }
 
 protected:
     Address m_address; // The section offset address of this instruction
diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h
index d984a419c5c9..af3df8cab926 100644
--- a/lldb/include/lldb/Expression/DWARFExpression.h
+++ b/lldb/include/lldb/Expression/DWARFExpression.h
@@ -435,7 +435,15 @@ public:
                            const DWARFCompileUnit* cu,
                            const DataExtractor& debug_loc_data,
                            lldb::offset_t offset);
-
+    
+    bool
+    IsRegister(StackFrame &frame,
+               const RegisterInfo *&register_info);
+    
+    bool
+    IsDereferenceOfRegister(StackFrame &frame,
+                            const RegisterInfo *&register_info,
+                            int64_t &offset);
 protected:
     //------------------------------------------------------------------
     /// Pretty-prints the location expression to a stream
@@ -475,6 +483,11 @@ protected:
                                      lldb::offset_t* offset_ptr,
                                      lldb::addr_t& low_pc,
                                      lldb::addr_t& high_pc);
+    
+    bool
+    GetOpAndEndOffsets(StackFrame &frame,
+                       lldb::offset_t &op_offset,
+                       lldb::offset_t &end_offset);
 
     //------------------------------------------------------------------
     /// Classes that inherit from DWARFExpression can see and modify these
diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h
index cd0b57e61ff8..6d82af0cd934 100644
--- a/lldb/include/lldb/Target/ABI.h
+++ b/lldb/include/lldb/Target/ABI.h
@@ -147,6 +147,12 @@ public:
     GetRegisterInfoByKind (lldb::RegisterKind reg_kind, 
                            uint32_t reg_num, 
                            RegisterInfo &info);
+    
+    virtual bool
+    GetPointerReturnRegister (const char *&name)
+    {
+        return false;
+    }
 
     static lldb::ABISP
     FindPlugin (const ArchSpec &arch);
diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h
index b3cc57f176ca..907e88905f02 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -218,6 +218,21 @@ public:
     //------------------------------------------------------------------
     bool
     GetFrameBaseValue(Scalar &value, Error *error_ptr);
+    
+    //------------------------------------------------------------------
+    /// Get the DWARFExpression corresponding to the Canonical Frame Address.
+    ///
+    /// Often a register (bp), but sometimes a register + offset.
+    ///
+    /// @param [out] error_ptr
+    ///   If there is an error determining the CFA address, this may contain a
+    ///   string explaining the failure.
+    ///
+    /// @return
+    ///   Returns the corresponding DWARF expression, or NULL.
+    //------------------------------------------------------------------
+    DWARFExpression *
+    GetFrameBaseExpression(Error *error_ptr);
 
     //------------------------------------------------------------------
     /// Get the current lexical scope block for this StackFrame, if possible.
@@ -484,6 +499,37 @@ public:
     lldb::LanguageType
     GuessLanguage ();
     
+    //------------------------------------------------------------------
+    /// Attempt to econstruct the ValueObject for a given raw address touched by
+    /// the current instruction.  The ExpressionPath should indicate how to get
+    /// to this value using "frame variable."
+    ///
+    /// @params [in] addr
+    ///   The raw address.
+    ///
+    /// @return
+    ///   The ValueObject if found.  If valid, it has a valid ExpressionPath.
+    //------------------------------------------------------------------
+    lldb::ValueObjectSP
+    GuessValueForAddress(lldb::addr_t addr);
+    
+    //------------------------------------------------------------------
+    /// Attempt to reconstruct the ValueObject for the address contained in a
+    /// given register plus an offset.  The ExpressionPath should indicate how to
+    /// get to this value using "frame variable."
+    ///
+    /// @params [in] reg
+    ///   The name of the register.
+    ///
+    /// @params [in] offset
+    ///   The offset from the register.  Particularly important for sp...
+    ///
+    /// @return
+    ///   The ValueObject if found.  If valid, it has a valid ExpressionPath.
+    //------------------------------------------------------------------
+    lldb::ValueObjectSP
+    GuessValueForRegisterAndOffset(ConstString reg, int64_t offset);
+    
     //------------------------------------------------------------------
     // lldb::ExecutionContextScope pure virtual functions
     //------------------------------------------------------------------
@@ -501,7 +547,7 @@ public:
 
     void
     CalculateExecutionContext(ExecutionContext &exe_ctx) override;
-
+    
 protected:
     friend class StackFrameList;
 
@@ -516,7 +562,7 @@ protected:
 
     bool
     HasCachedData () const;
-    
+        
 private:
     //------------------------------------------------------------------
     // For StackFrame only
diff --git a/lldb/include/lldb/Target/StopInfo.h b/lldb/include/lldb/Target/StopInfo.h
index dfc9860b604a..7fc071174012 100644
--- a/lldb/include/lldb/Target/StopInfo.h
+++ b/lldb/include/lldb/Target/StopInfo.h
@@ -185,6 +185,9 @@ public:
 
     static lldb::ExpressionVariableSP
     GetExpressionVariable (lldb::StopInfoSP &stop_info_sp);
+    
+    static lldb::ValueObjectSP
+    GetCrashingDereference (lldb::StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address = nullptr);
 
 protected:
     // Perform any action that is associated with this stop.  This is done as the
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/Makefile
new file mode 100644
index 000000000000..b09a579159d4
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/TestArray.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/TestArray.py
new file mode 100644
index 000000000000..0f1c109676cd
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/TestArray.py
@@ -0,0 +1,25 @@
+"""
+Test the output of `frame diagnose` for an array access
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestArray(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_array(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", substrs=["a[10]"])
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/main.c b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/main.c
new file mode 100644
index 000000000000..95c6515e5f54
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/main.c
@@ -0,0 +1,9 @@
+struct Foo {
+  int b;
+  int c;
+};
+
+int main() {
+  struct Foo *a = 0;
+  return a[10].c;
+}
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/Makefile
new file mode 100644
index 000000000000..314f1cb2f077
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/TestBadReference.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/TestBadReference.py
new file mode 100644
index 000000000000..e90e8668f7f9
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/TestBadReference.py
@@ -0,0 +1,25 @@
+"""
+Test the output of `frame diagnose` for dereferencing a bad reference
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestBadReference(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_bad_reference(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", "f->b") 
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/main.cpp
new file mode 100644
index 000000000000..2f61152e3985
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/main.cpp
@@ -0,0 +1,22 @@
+struct Bar {
+  int c;
+  int d;
+};
+
+struct Foo {
+  int a;
+  struct Bar &b;
+};
+
+struct Foo *GetAFoo() {
+  static struct Foo f = { 0, *((Bar*)0) };
+  return &f;
+}
+
+int GetSum(struct Foo *f) {
+  return f->a + f->b.d;
+}
+
+int main() {
+  return GetSum(GetAFoo());
+}
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/Makefile
new file mode 100644
index 000000000000..b09a579159d4
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/TestComplicatedExpression.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/TestComplicatedExpression.py
new file mode 100644
index 000000000000..bd25a29fab01
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/TestComplicatedExpression.py
@@ -0,0 +1,25 @@
+"""
+Test the output of `frame diagnose` for a subexpression of a complicated expression
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestDiagnoseDereferenceArgument(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_diagnose_dereference_argument(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", "f->b->d") 
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/main.c b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/main.c
new file mode 100644
index 000000000000..147aae946140
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/main.c
@@ -0,0 +1,26 @@
+struct Bar {
+  int c;
+  int d;
+};
+
+struct Foo {
+  int a;
+  struct Bar *b;
+};
+
+struct Foo *GetAFoo() {
+  static struct Foo f = { 0, 0 };
+  return &f;
+}
+
+int SumTwoIntegers(int x, int y) {
+  return x + y;
+}
+
+int GetSum(struct Foo *f) {
+  return SumTwoIntegers(f->a, f->b->d ? 0 : 1);
+}
+
+int main() {
+  return GetSum(GetAFoo());
+}
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/Makefile
new file mode 100644
index 000000000000..b09a579159d4
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/TestDiagnoseDereferenceArgument.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/TestDiagnoseDereferenceArgument.py
new file mode 100644
index 000000000000..28872929b916
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/TestDiagnoseDereferenceArgument.py
@@ -0,0 +1,25 @@
+"""
+Test the output of `frame diagnose` for dereferencing a function argument
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestDiagnoseDereferenceArgument(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_diagnose_dereference_argument(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", "f->b->d") 
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/main.c b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/main.c
new file mode 100644
index 000000000000..0ec23b13be16
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/main.c
@@ -0,0 +1,22 @@
+struct Bar {
+  int c;
+  int d;
+};
+
+struct Foo {
+  int a;
+  struct Bar *b;
+};
+
+struct Foo *GetAFoo() {
+  static struct Foo f = { 0, 0 };
+  return &f;
+}
+
+int GetSum(struct Foo *f) {
+  return f->a + f->b->d;
+}
+
+int main() {
+  return GetSum(GetAFoo());
+}
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/Makefile
new file mode 100644
index 000000000000..314f1cb2f077
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/TestDiagnoseDereferenceFunctionReturn.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/TestDiagnoseDereferenceFunctionReturn.py
new file mode 100644
index 000000000000..597ced3c0d9b
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/TestDiagnoseDereferenceFunctionReturn.py
@@ -0,0 +1,26 @@
+"""
+Test the output of `frame diagnose` for dereferencing a function's return value
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestDiagnoseDereferenceFunctionReturn(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_diagnose_dereference_function_return(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", substrs = ["GetAFoo", "->b"]) 
+
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/main.c b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/main.c
new file mode 100644
index 000000000000..420e6f21de6b
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/main.c
@@ -0,0 +1,12 @@
+struct Foo {
+  int a;
+  int b;
+};
+
+struct Foo *GetAFoo() {
+  return 0;
+}
+
+int main() {
+  return GetAFoo()->b;
+}
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/Makefile
new file mode 100644
index 000000000000..314f1cb2f077
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/TestDiagnoseDereferenceThis.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/TestDiagnoseDereferenceThis.py
new file mode 100644
index 000000000000..fe71e528d8f8
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/TestDiagnoseDereferenceThis.py
@@ -0,0 +1,25 @@
+"""
+Test the output of `frame diagnose` for dereferencing `this`
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestDiagnoseDereferenceThis(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_diagnose_dereference_this(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", "this->a") 
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/main.cpp
new file mode 100644
index 000000000000..1f177230ed90
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/main.cpp
@@ -0,0 +1,15 @@
+struct Foo {
+  int a;
+  int b;
+  int Sum() { return a + b; }
+};
+
+struct Foo *GetAFoo() {
+  return (struct Foo*)0;
+}
+
+int main() {
+  struct Foo *foo = GetAFoo();
+  return foo->Sum();
+}
+
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/Makefile
new file mode 100644
index 000000000000..314f1cb2f077
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/TestDiagnoseInheritance.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/TestDiagnoseInheritance.py
new file mode 100644
index 000000000000..1438747c1a1c
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/TestDiagnoseInheritance.py
@@ -0,0 +1,25 @@
+"""
+Test the output of `frame diagnose` for calling virtual methods
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestDiagnoseInheritance(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_diagnose_inheritance(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", "d") 
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/main.cpp
new file mode 100644
index 000000000000..78cac2c89653
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/main.cpp
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <stdint.h>
+
+class A
+{
+public:
+    A(int a) : 
+        m_a(a)
+    {
+    }
+    virtual ~A(){}
+    virtual int get2() const { return m_a; }
+    virtual int get() const { return m_a; }
+protected:
+    int m_a;    
+};
+
+class B : public A
+{
+public:
+    B(int a, int b) : 
+        A(a),
+        m_b(b)
+    {
+    }
+
+    ~B() override
+    {
+    }
+
+    int get2() const override
+    {
+        return m_b;
+    }
+    int get() const override
+    {
+        return m_b;
+    }   
+            
+protected:
+    int m_b;
+};
+
+struct C
+{
+    C(int c) : m_c(c){}
+    virtual ~C(){}
+    int m_c;
+};
+
+class D : public C, public B
+{
+public:
+    D(int a, int b, int c, int d) : 
+        C(c),
+        B(a, b),
+        m_d(d)
+    {
+    }
+protected:
+    int m_d;
+};
+int main (int argc, char const *argv[], char const *envp[])
+{
+    D *good_d = new D(1, 2, 3, 4);
+    D *d = nullptr;
+    return d->get();
+}
+
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/Makefile
new file mode 100644
index 000000000000..b09a579159d4
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/TestLocalVariable.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/TestLocalVariable.py
new file mode 100644
index 000000000000..cdddd8483a6b
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/TestLocalVariable.py
@@ -0,0 +1,25 @@
+"""
+Test the output of `frame diagnose` for dereferencing a local variable
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestLocalVariable(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_local_variable(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", "myInt") 
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/main.c b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/main.c
new file mode 100644
index 000000000000..33307beb0703
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/main.c
@@ -0,0 +1,4 @@
+int main() {
+  int *myInt = 0;
+  return *myInt;
+}
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/Makefile
new file mode 100644
index 000000000000..314f1cb2f077
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/TestDiagnoseDereferenceVirtualMethodCall.py b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/TestDiagnoseDereferenceVirtualMethodCall.py
new file mode 100644
index 000000000000..6f7e55b46296
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/TestDiagnoseDereferenceVirtualMethodCall.py
@@ -0,0 +1,25 @@
+"""
+Test the output of `frame diagnose` for calling virtual methods
+"""
+
+from __future__ import print_function
+
+import os
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestDiagnoseVirtualMethodCall(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_diagnose_virtual_method_call(self):
+        TestBase.setUp(self)
+        self.build()
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        self.runCmd("run", RUN_SUCCEEDED)
+        self.expect("thread list", "Thread should be stopped",
+            substrs = ['stopped'])
+        self.expect("frame diagnose", "Crash diagnosis was accurate", "foo") 
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/main.cpp
new file mode 100644
index 000000000000..2a03dc11bf29
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/main.cpp
@@ -0,0 +1,16 @@
+class Foo {
+public:
+  int a;
+  int b;
+  virtual int Sum() { return a + b; }
+};
+
+struct Foo *GetAFoo() {
+  return (struct Foo*)0;
+}
+
+int main() {
+  struct Foo *foo = GetAFoo();
+  return foo->Sum();
+}
+
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 935fee80a6af..d508bf486347 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -43,12 +43,214 @@
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StopInfo.h"
 #include "lldb/Target/Thread.h"
 #include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBAssert.h"
 
 using namespace lldb;
 using namespace lldb_private;
 
+#pragma mark CommandObjectFrameDiagnose
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameInfo
+//-------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameDiagnose
+//-------------------------------------------------------------------------
+
+class CommandObjectFrameDiagnose : public CommandObjectParsed
+{
+public:
+    class CommandOptions : public Options
+    {
+    public:
+        CommandOptions() :
+        Options()
+        {
+            OptionParsingStarting(nullptr);
+        }
+        
+        ~CommandOptions() override = default;
+        
+        Error
+        SetOptionValue(uint32_t option_idx, const char *option_arg,
+                       ExecutionContext *execution_context) override
+        {
+            Error error;
+            const int short_option = m_getopt_table[option_idx].val;
+            switch (short_option)
+            {
+            case 'r':
+                reg = ConstString(option_arg);
+                break;
+
+            case 'a':
+                {
+                    bool success = false;
+
+                    address = StringConvert::ToUInt64 (option_arg, 0, 0, &success);
+                    if (!success)
+                    {
+                        address.reset();
+                        error.SetErrorStringWithFormat ("invalid address argument '%s'", option_arg);
+                    }
+                }
+                break;
+        
+            case 'o':
+                {
+                    bool success = false;
+                    
+                    offset = StringConvert::ToSInt64 (option_arg, 0, 0, &success);
+                    if (!success)
+                    {
+                        offset.reset();
+                        error.SetErrorStringWithFormat ("invalid offset argument '%s'", option_arg);
+                    }
+                }
+                break;
+                
+            default:
+                error.SetErrorStringWithFormat ("invalid short option character '%c'", short_option);
+                break;
+            }
+            
+            return error;
+        }
+        
+        void
+        OptionParsingStarting(ExecutionContext *execution_context) override
+        {
+            address.reset();
+            reg.reset();
+            offset.reset();
+        }
+        
+        const OptionDefinition*
+        GetDefinitions () override
+        {
+            return g_option_table;
+        }
+        
+        // Options table: Required for subclasses of Options.
+        static OptionDefinition g_option_table[];
+        
+        // Options.
+        llvm::Optional<lldb::addr_t> address;
+        llvm::Optional<ConstString> reg;
+        llvm::Optional<int64_t> offset;
+    };
+    
+    CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
+        : CommandObjectParsed(interpreter, "frame diagnose",
+                              "Try to determine what path path the current stop location used to get to a register or address",
+                              nullptr, eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
+                              eCommandProcessMustBePaused),
+          m_options()
+    {
+        CommandArgumentEntry arg;
+        CommandArgumentData index_arg;
+        
+        // Define the first (and only) variant of this arg.
+        index_arg.arg_type = eArgTypeFrameIndex;
+        index_arg.arg_repetition = eArgRepeatOptional;
+        
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg.push_back (index_arg);
+        
+        // Push the data for the first argument into the m_arguments vector.
+        m_arguments.push_back (arg);
+    }
+    
+    ~CommandObjectFrameDiagnose() override = default;
+    
+    Options *
+    GetOptions () override
+    {
+        return &m_options;
+    }
+    
+protected:
+    bool
+    DoExecute (Args& command, CommandReturnObject &result) override
+    {
+        Thread *thread = m_exe_ctx.GetThreadPtr();
+        StackFrameSP frame_sp = thread->GetSelectedFrame();
+        
+        ValueObjectSP valobj_sp;
+        
+        if (m_options.address.hasValue())
+        {
+            if (m_options.reg.hasValue() || m_options.offset.hasValue())
+            {
+                result.AppendError("`frame diagnose --address` is incompatible with other arguments.");
+                result.SetStatus(eReturnStatusFailed);
+                return false;
+            }
+            valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
+        }
+        else if (m_options.reg.hasValue())
+        {
+            valobj_sp = frame_sp->GuessValueForRegisterAndOffset(m_options.reg.getValue(), m_options.offset.getValueOr(0));
+        }
+        else
+        {
+            StopInfoSP stop_info_sp = thread->GetStopInfo();
+            if (!stop_info_sp)
+            {
+                result.AppendError("No arguments provided, and no stop info.");
+                result.SetStatus(eReturnStatusFailed);
+                return false;
+            }
+
+            valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
+        }
+        
+        if (!valobj_sp)
+        {
+            result.AppendError("No diagnosis available.");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        const bool qualify_cxx_base_classes = false;
+
+        DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](ConstString type,
+                                                                         ConstString var,
+                                                                         const DumpValueObjectOptions &opts,
+                                                                         Stream &stream) -> bool {
+            const ValueObject::GetExpressionPathFormat format = ValueObject::GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
+            valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
+            stream.PutCString(" =");
+            return true;
+        };
+
+        DumpValueObjectOptions options;
+        options.SetDeclPrintingHelper(helper);
+        ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), options);
+        printer.PrintValueObject();
+        
+        return true;
+    }
+    
+protected:
+    CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectFrameDiagnose::CommandOptions::g_option_table[] =
+{
+    // clang-format off
+    {LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegisterName,    "A register to diagnose."},
+    {LLDB_OPT_SET_1, false, "address",  'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddress,         "An address to diagnose."},
+    {LLDB_OPT_SET_1, false, "offset",   'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset,          "An optional offset.  Requires --register."},
+    {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
+    // clang-format on
+};
+
 #pragma mark CommandObjectFrameInfo
 
 //-------------------------------------------------------------------------
@@ -612,6 +814,7 @@ CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(CommandInterpreter &int
                              "Commands for selecting and examing the current thread's stack frames.",
                              "frame <subcommand> [<subcommand-options>]")
 {
+    LoadSubCommand ("diagnose", CommandObjectSP (new CommandObjectFrameDiagnose (interpreter)));
     LoadSubCommand ("info",   CommandObjectSP (new CommandObjectFrameInfo (interpreter)));
     LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter)));
     LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter)));
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index b81d60e9b065..23a922c491b2 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -30,6 +30,8 @@
 #include "lldb/Host/Endian.h"
 #include "lldb/Host/Host.h"
 
+#include "lldb/Symbol/Function.h"
+
 #include "lldb/Target/ABI.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
@@ -3336,3 +3338,149 @@ DWARFExpression::PrintDWARFLocationList(Stream &s,
         offset += loc_length;
     }
 }
+
+bool
+DWARFExpression::GetOpAndEndOffsets(StackFrame &frame, lldb::offset_t &op_offset, lldb::offset_t &end_offset)
+{
+    SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction);
+    if (!sc.function)
+    {
+        return false;
+    }
+
+    addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+    if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
+    {
+        return false;
+    }
+    
+    addr_t pc_file_addr = frame.GetFrameCodeAddress().GetFileAddress();
+    lldb::offset_t opcodes_offset, opcodes_length;
+    if (!GetLocation(loclist_base_file_addr, pc_file_addr, opcodes_offset, opcodes_length))
+    {
+        return false;
+    }
+    
+    if (opcodes_length == 0)
+    {
+        return false;
+    }
+    
+    op_offset = opcodes_offset;
+    end_offset = opcodes_offset + opcodes_length;
+    return true;
+}
+
+bool
+DWARFExpression::IsRegister(StackFrame &frame,
+                            const RegisterInfo *&register_info)
+{
+    lldb::offset_t op_offset;
+    lldb::offset_t end_offset;
+    if (!GetOpAndEndOffsets(frame, op_offset, end_offset))
+    {
+        return false;
+    }
+
+    if (!m_data.ValidOffset(op_offset) || op_offset >= end_offset)
+    {
+        return false;
+    }
+    
+    RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
+    if (!reg_ctx_sp)
+    {
+        return false;
+    }
+    
+    DataExtractor opcodes = m_data;
+    uint8_t opcode = opcodes.GetU8(&op_offset);
+    
+    if (opcode >= DW_OP_reg0 && opcode <= DW_OP_breg31)
+    {
+        register_info = reg_ctx_sp->GetRegisterInfo(m_reg_kind, opcode - DW_OP_reg0);
+        return register_info != nullptr;
+    }
+    switch (opcode)
+    {
+        default:
+            return false;
+        case DW_OP_regx:
+        {
+            uint32_t reg_num = m_data.GetULEB128(&op_offset);
+            register_info = reg_ctx_sp->GetRegisterInfo(m_reg_kind, reg_num);
+            return register_info != nullptr;
+        }
+    }
+}
+
+bool
+DWARFExpression::IsDereferenceOfRegister(StackFrame &frame,
+                                         const RegisterInfo *&register_info,
+                                         int64_t &offset)
+{
+    lldb::offset_t op_offset;
+    lldb::offset_t end_offset;
+    if (!GetOpAndEndOffsets(frame, op_offset, end_offset))
+    {
+        return false;
+    }
+    
+    if (!m_data.ValidOffset(op_offset) || op_offset >= end_offset)
+    {
+        return false;
+    }
+    
+    RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
+    if (!reg_ctx_sp)
+    {
+        return false;
+    }
+    
+    DataExtractor opcodes = m_data;
+    uint8_t opcode = opcodes.GetU8(&op_offset);
+
+    switch (opcode)
+    {
+    default:
+        return false;
+    case DW_OP_bregx:
+        {
+            uint32_t reg_num = static_cast<uint32_t>(opcodes.GetULEB128(&op_offset));
+            int64_t breg_offset = opcodes.GetSLEB128(&op_offset);
+
+            const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfo(m_reg_kind, reg_num);
+            if (!reg_info)
+            {
+                return false;
+            }
+            
+            register_info = reg_info;
+            offset = breg_offset;
+            return true;
+        }
+    case DW_OP_fbreg:
+        {
+            int64_t fbreg_offset = opcodes.GetSLEB128(&op_offset);
+
+            DWARFExpression *dwarf_expression = frame.GetFrameBaseExpression(nullptr);
+            
+            if (!dwarf_expression)
+            {
+                return false;
+            }
+            
+            const RegisterInfo *fbr_info;
+            
+            if (!dwarf_expression->IsRegister(frame, fbr_info))
+            {
+                return false;
+            }
+            
+            register_info = fbr_info;
+            offset = fbreg_offset;
+            return true;
+        }
+    }
+}
+
diff --git a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
index ac5151afdee5..32dc28e2c7dc 100644
--- a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
+++ b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp
@@ -204,6 +204,13 @@ ABISysV_arm64::GetRegisterInfoArray (uint32_t &count)
     return g_register_infos;
 }
 
+bool
+ABISysV_arm64::GetPointerReturnRegister (const char *&name)
+{
+    name = "x0";
+    return true;
+}
+
 size_t
 ABISysV_arm64::GetRedZoneSize () const
 {
diff --git a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
index e36f87e744f4..548d42a87802 100644
--- a/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
+++ b/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h
@@ -81,6 +81,9 @@ public:
 
     const lldb_private::RegisterInfo *
     GetRegisterInfoArray (uint32_t &count) override;
+    
+    bool
+    GetPointerReturnRegister (const char *&name) override;
 
     //------------------------------------------------------------------
     // Static Functions
diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
index cc568d6f6359..89b39a1a7527 100644
--- a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
+++ b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -211,6 +211,13 @@ ABISysV_x86_64::GetRegisterInfoArray (uint32_t &count)
     return g_register_infos;
 }
 
+bool
+ABISysV_x86_64::GetPointerReturnRegister (const char *&name)
+{
+    name = "rax";
+    return true;
+}
+
 size_t
 ABISysV_x86_64::GetRedZoneSize () const
 {
diff --git a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
index 07b57abaf57c..2adf22d109ce 100644
--- a/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
+++ b/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -84,7 +84,10 @@ public:
 
     const lldb_private::RegisterInfo *
     GetRegisterInfoArray(uint32_t &count) override;
-
+    
+    bool
+    GetPointerReturnRegister (const char *&name) override;
+    
     //------------------------------------------------------------------
     // Static Functions
     //------------------------------------------------------------------
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
index 4d24cf1ab6de..61a57ef3fcdd 100644
--- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -31,6 +31,7 @@
 
 #include "lldb/Core/Address.h"
 #include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Stream.h"
 #include "lldb/Symbol/SymbolContext.h"
@@ -56,6 +57,7 @@ public:
         m_disasm_wp (std::static_pointer_cast<DisassemblerLLVMC>(disasm.shared_from_this())),
         m_does_branch (eLazyBoolCalculate),
         m_has_delay_slot (eLazyBoolCalculate),
+        m_is_call (eLazyBoolCalculate),
         m_is_valid (false),
         m_using_file_addr (false)
     {
@@ -467,11 +469,569 @@ public:
     {
         return m_disasm_wp.lock();
     }
+    
+    static llvm::StringRef::const_iterator
+    ConsumeWhitespace(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+    {
+        while (osi != ose)
+        {
+            switch (*osi) {
+            default:
+                return osi;
+            case ' ': case '\t':
+                break;
+            }
+            ++osi;
+        }
+        
+        return osi;
+    }
+    
+    static std::pair<bool, llvm::StringRef::const_iterator>
+    ConsumeChar(llvm::StringRef::const_iterator osi, const char c, llvm::StringRef::const_iterator ose)
+    {
+        bool found = false;
+        
+        osi = ConsumeWhitespace(osi, ose);
+        if (osi != ose && *osi == c)
+        {
+            found = true;
+            ++osi;
+        }
+        
+        return std::make_pair(found, osi);
+    }
+    
+    static std::pair<Operand, llvm::StringRef::const_iterator>
+    ParseRegisterName(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+    {
+        Operand ret;
+        ret.m_type = Operand::Type::Register;
+        std::string str;
+        
+        osi = ConsumeWhitespace(osi, ose);
+        
+        while (osi != ose)
+        {
+            if (*osi >= '0' && *osi <= '9')
+            {
+                if (str.empty())
+                {
+                    return std::make_pair(Operand(), osi);
+                }
+                else
+                {
+                    str.push_back(*osi);
+                }
+            }
+            else if (*osi >= 'a' && *osi <= 'z')
+            {
+                str.push_back(*osi);
+            }
+            else
+            {
+                switch (*osi)
+                {
+                default:
+                    if (str.empty())
+                    {
+                        return std::make_pair(Operand(), osi);
+                    }
+                    else
+                    {
+                        ret.m_register = ConstString(str);
+                        return std::make_pair(ret, osi);
+                    }
+                case '%':
+                    if (!str.empty())
+                    {
+                        return std::make_pair(Operand(), osi);
+                    }
+                    break;
+                }
+            }
+            ++osi;
+        }
+    
+        ret.m_register = ConstString(str);
+        return std::make_pair(ret, osi);
+    }
+    
+    static std::pair<Operand, llvm::StringRef::const_iterator>
+    ParseImmediate(llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+    {
+        Operand ret;
+        ret.m_type = Operand::Type::Immediate;
+        std::string str;
+        bool is_hex = false;
+        
+        osi = ConsumeWhitespace(osi, ose);
+        
+        while (osi != ose)
+        {
+            if (*osi >= '0' && *osi <= '9')
+            {
+                str.push_back(*osi);
+            }
+            else if (*osi >= 'a' && *osi <= 'f')
+            {
+                if (is_hex)
+                {
+                    str.push_back(*osi);
+                }
+                else
+                {
+                    return std::make_pair(Operand(), osi);
+                }
+            }
+            else
+            {
+                switch (*osi)
+                {
+                default:
+                    if (str.empty())
+                    {
+                        return std::make_pair(Operand(), osi);
+                    }
+                    else
+                    {
+                        ret.m_immediate = std::stoull(str, nullptr, 0);
+                        return std::make_pair(ret, osi);
+                    }
+                case 'x':
+                    if (!str.compare("0"))
+                    {
+                        is_hex = true;
+                        str.push_back(*osi);
+                    }
+                    else
+                    {
+                        return std::make_pair(Operand(), osi);
+                    }
+                    break;
+                case '#': case '$':
+                    if (!str.empty())
+                    {
+                        return std::make_pair(Operand(), osi);
+                    }
+                    break;
+                case '-':
+                    if (str.empty())
+                    {
+                        ret.m_negative = true;
+                    }
+                    else
+                    {
+                        return std::make_pair(Operand(), osi);
+                    }
+                }
+            }
+            ++osi;
+        }
+        
+        ret.m_immediate = std::stoull(str, nullptr, 0);
+        return std::make_pair(ret, osi);
+    }
+
+    // -0x5(%rax,%rax,2)
+    static std::pair<Operand, llvm::StringRef::const_iterator>
+    ParseIntelIndexedAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+    {
+        std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+        if (offset_and_iterator.first.IsValid())
+        {
+            osi = offset_and_iterator.second;
+        }
+        
+        bool found = false;
+        std::tie(found, osi) = ConsumeChar(osi, '(', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+        if (base_and_iterator.first.IsValid())
+        {
+            osi = base_and_iterator.second;
+        }
+        else
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::pair<Operand, llvm::StringRef::const_iterator> index_and_iterator = ParseRegisterName(osi, ose);
+        if (index_and_iterator.first.IsValid())
+        {
+            osi = index_and_iterator.second;
+        }
+        else
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+
+        std::pair<Operand, llvm::StringRef::const_iterator> multiplier_and_iterator = ParseImmediate(osi, ose);
+        if (index_and_iterator.first.IsValid())
+        {
+            osi = index_and_iterator.second;
+        }
+        else
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::tie(found, osi) = ConsumeChar(osi, ')', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        Operand product;
+        product.m_type = Operand::Type::Product;
+        product.m_children.push_back(index_and_iterator.first);
+        product.m_children.push_back(multiplier_and_iterator.first);
+        
+        Operand index;
+        index.m_type = Operand::Type::Sum;
+        index.m_children.push_back(base_and_iterator.first);
+        index.m_children.push_back(product);
+        
+        if (offset_and_iterator.first.IsValid())
+        {
+            Operand offset;
+            offset.m_type = Operand::Type::Sum;
+            offset.m_children.push_back(offset_and_iterator.first);
+            offset.m_children.push_back(index);
+            
+            Operand deref;
+            deref.m_type = Operand::Type::Dereference;
+            deref.m_children.push_back(offset);
+            return std::make_pair(deref, osi);
+        }
+        else
+        {
+            Operand deref;
+            deref.m_type = Operand::Type::Dereference;
+            deref.m_children.push_back(index);
+            return std::make_pair(deref, osi);
+        }
+    }
+    
+    // -0x10(%rbp)
+    static std::pair<Operand, llvm::StringRef::const_iterator>
+    ParseIntelDerefAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+    {
+        std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+        if (offset_and_iterator.first.IsValid())
+        {
+            osi = offset_and_iterator.second;
+        }
+        
+        bool found = false;
+        std::tie(found, osi) = ConsumeChar(osi, '(', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+        if (base_and_iterator.first.IsValid())
+        {
+            osi = base_and_iterator.second;
+        }
+        else
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::tie(found, osi) = ConsumeChar(osi, ')', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        if (offset_and_iterator.first.IsValid())
+        {
+            Operand offset;
+            offset.m_type = Operand::Type::Sum;
+            offset.m_children.push_back(offset_and_iterator.first);
+            offset.m_children.push_back(base_and_iterator.first);
+            
+            Operand deref;
+            deref.m_type = Operand::Type::Dereference;
+            deref.m_children.push_back(offset);
+            return std::make_pair(deref, osi);
+        }
+        else
+        {
+            Operand deref;
+            deref.m_type = Operand::Type::Dereference;
+            deref.m_children.push_back(base_and_iterator.first);
+            return std::make_pair(deref, osi);
+        }
+    }
+    
+    // [sp, #8]!
+    static std::pair<Operand, llvm::StringRef::const_iterator>
+    ParseARMOffsetAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+    {
+        bool found = false;
+        std::tie(found, osi) = ConsumeChar(osi, '[', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+        if (base_and_iterator.first.IsValid())
+        {
+            osi = base_and_iterator.second;
+        }
+        else
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::tie(found, osi) = ConsumeChar(osi, ',', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::pair<Operand, llvm::StringRef::const_iterator> offset_and_iterator = ParseImmediate(osi, ose);
+        if (offset_and_iterator.first.IsValid())
+        {
+            osi = offset_and_iterator.second;
+        }
+        
+        std::tie(found, osi) = ConsumeChar(osi, ']', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        Operand offset;
+        offset.m_type = Operand::Type::Sum;
+        offset.m_children.push_back(offset_and_iterator.first);
+        offset.m_children.push_back(base_and_iterator.first);
+        
+        Operand deref;
+        deref.m_type = Operand::Type::Dereference;
+        deref.m_children.push_back(offset);
+        return std::make_pair(deref, osi);
+    }
+    
+    // [sp]
+    static std::pair<Operand, llvm::StringRef::const_iterator>
+    ParseARMDerefAccess (llvm::StringRef::const_iterator osi, llvm::StringRef::const_iterator ose)
+    {
+        bool found = false;
+        std::tie(found, osi) = ConsumeChar(osi, '[', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::pair<Operand, llvm::StringRef::const_iterator> base_and_iterator = ParseRegisterName(osi, ose);
+        if (base_and_iterator.first.IsValid())
+        {
+            osi = base_and_iterator.second;
+        }
+        else
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        std::tie(found, osi) = ConsumeChar(osi, ']', ose);
+        if (!found)
+        {
+            return std::make_pair(Operand(), osi);
+        }
+        
+        Operand deref;
+        deref.m_type = Operand::Type::Dereference;
+        deref.m_children.push_back(base_and_iterator.first);
+        return std::make_pair(deref, osi);
+    }
+    
+    static void
+    DumpOperand(const Operand &op, Stream &s)
+    {
+        switch (op.m_type)
+        {
+        case Operand::Type::Dereference:
+            s.PutCString("*");
+            DumpOperand(op.m_children[0], s);
+            break;
+        case Operand::Type::Immediate:
+            if (op.m_negative)
+            {
+                s.PutCString("-");
+            }
+            s.PutCString(std::to_string(op.m_immediate).c_str());
+            break;
+        case Operand::Type::Invalid:
+            s.PutCString("Invalid");
+            break;
+        case Operand::Type::Product:
+            s.PutCString("(");
+            DumpOperand(op.m_children[0], s);
+            s.PutCString("*");
+            DumpOperand(op.m_children[1], s);
+            s.PutCString(")");
+            break;
+        case Operand::Type::Register:
+            s.PutCString(op.m_register.AsCString());
+            break;
+        case Operand::Type::Sum:
+            s.PutCString("(");
+            DumpOperand(op.m_children[0], s);
+            s.PutCString("+");
+            DumpOperand(op.m_children[1], s);
+            s.PutCString(")");
+            break;
+        }
+    }
+    
+    bool
+    ParseOperands (llvm::SmallVectorImpl<Instruction::Operand> &operands) override
+    {
+        const char *operands_string = GetOperands(nullptr);
+        
+        if (!operands_string)
+        {
+            return false;
+        }
+        
+        llvm::StringRef operands_ref(operands_string);
+        
+        llvm::StringRef::const_iterator osi = operands_ref.begin();
+        llvm::StringRef::const_iterator ose = operands_ref.end();
+        
+        while (osi != ose)
+        {
+            Operand operand;
+            llvm::StringRef::const_iterator iter;
+            
+            if ((std::tie(operand, iter) = ParseIntelIndexedAccess(osi, ose), operand.IsValid()) ||
+                (std::tie(operand, iter) = ParseIntelDerefAccess(osi, ose), operand.IsValid()) ||
+                (std::tie(operand, iter) = ParseARMOffsetAccess(osi, ose), operand.IsValid()) ||
+                (std::tie(operand, iter) = ParseARMDerefAccess(osi, ose), operand.IsValid()) ||
+                (std::tie(operand, iter) = ParseRegisterName(osi, ose), operand.IsValid()) ||
+                (std::tie(operand, iter) = ParseImmediate(osi, ose), operand.IsValid()))
+            {
+                osi = iter;
+                operands.push_back(operand);
+            }
+            else
+            {
+                return false;
+            }
+            
+            std::pair<bool, llvm::StringRef::const_iterator> found_and_iter = ConsumeChar(osi, ',', ose);
+            if (found_and_iter.first)
+            {
+                osi = found_and_iter.second;
+            }
+            
+            osi = ConsumeWhitespace(osi, ose);
+        }
+        
+        DisassemblerSP disasm_sp = m_disasm_wp.lock();
+        
+        if (disasm_sp && operands.size() > 1)
+        {
+            // TODO tie this into the MC Disassembler's notion of clobbers.
+            switch (disasm_sp->GetArchitecture().GetMachine())
+            {
+            default:
+                break;
+            case llvm::Triple::x86:
+            case llvm::Triple::x86_64:
+                operands[operands.size() - 1].m_clobbered = true;
+                break;
+            case llvm::Triple::arm:
+                operands[0].m_clobbered = true;
+                break;
+            }
+        }
+        
+        if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS))
+        {
+            StreamString ss;
+            
+            ss.Printf("[%s] expands to %zu operands:\n", operands_string, operands.size());
+            for (const Operand &operand : operands) {
+                ss.PutCString("  ");
+                DumpOperand(operand, ss);
+                ss.PutCString("\n");
+            }
+            
+            log->PutCString(ss.GetData());
+        }
+        
+        return true;
+    }
+    
+    bool
+    IsCall () override
+    {
+        if (m_is_call == eLazyBoolCalculate)
+        {
+            std::shared_ptr<DisassemblerLLVMC> disasm_sp(GetDisassembler());
+            if (disasm_sp)
+            {
+                disasm_sp->Lock(this, NULL);
+                DataExtractor data;
+                if (m_opcode.GetData(data))
+                {
+                    bool is_alternate_isa;
+                    lldb::addr_t pc = m_address.GetFileAddress();
+                    
+                    DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
+                    const uint8_t *opcode_data = data.GetDataStart();
+                    const size_t opcode_data_len = data.GetByteSize();
+                    llvm::MCInst inst;
+                    const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
+                                                                       opcode_data_len,
+                                                                       pc,
+                                                                       inst);
+                    if (inst_size == 0)
+                    {
+                        m_is_call = eLazyBoolNo;
+                    }
+                    else
+                    {
+                        if (mc_disasm_ptr->IsCall(inst))
+                            m_is_call = eLazyBoolYes;
+                        else
+                            m_is_call = eLazyBoolNo;
+                    }
+                }
+                disasm_sp->Unlock();
+            }
+        }
+        return m_is_call == eLazyBoolYes;
+    }
+    
 protected:
 
     std::weak_ptr<DisassemblerLLVMC> m_disasm_wp;
     LazyBool                m_does_branch;
     LazyBool                m_has_delay_slot;
+    LazyBool                m_is_call;
     bool                    m_is_valid;
     bool                    m_using_file_addr;
 };
@@ -611,6 +1171,12 @@ DisassemblerLLVMC::LLVMCDisassembler::HasDelaySlot (llvm::MCInst &mc_inst)
     return m_instr_info_ap->get(mc_inst.getOpcode()).hasDelaySlot();
 }
 
+bool
+DisassemblerLLVMC::LLVMCDisassembler::IsCall (llvm::MCInst &mc_inst)
+{
+    return m_instr_info_ap->get(mc_inst.getOpcode()).isCall();
+}
+
 DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_string) :
     Disassembler(arch, flavor_string),
     m_exe_ctx (NULL),
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
index e8f09a4d3abb..f2f54d393990 100644
--- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
@@ -55,6 +55,7 @@ class DisassemblerLLVMC : public lldb_private::Disassembler
         void     SetStyle (bool use_hex_immed, HexImmediateStyle hex_style);
         bool     CanBranch (llvm::MCInst &mc_inst);
         bool     HasDelaySlot (llvm::MCInst &mc_inst);
+        bool     IsCall (llvm::MCInst &mc_inst);
         bool     IsValid()
         {
             return m_is_valid;
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index f5f8660a1225..b40502995b65 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -1150,6 +1150,7 @@ Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
             }
             else
             {
+                StopInfoSP curr_thread_stop_info_sp;
                 // Lock the thread list so it doesn't change on us, this is the scope for the locker:
                 {
                     ThreadList &thread_list = process_sp->GetThreadList();
@@ -1159,7 +1160,10 @@ Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
                     ThreadSP thread;
                     StopReason curr_thread_stop_reason = eStopReasonInvalid;
                     if (curr_thread)
+                    {
                         curr_thread_stop_reason = curr_thread->GetStopReason();
+                        curr_thread_stop_info_sp = curr_thread->GetStopInfo();
+                    }
                     if (!curr_thread ||
                         !curr_thread->IsValid() ||
                         curr_thread_stop_reason == eStopReasonInvalid ||
@@ -1244,6 +1248,20 @@ Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
                                                      start_frame,
                                                      num_frames,
                                                      num_frames_with_source);
+                        if (curr_thread_stop_info_sp)
+                        {
+                            lldb::addr_t crashing_address;
+                            ValueObjectSP valobj_sp = StopInfo::GetCrashingDereference(curr_thread_stop_info_sp, &crashing_address);
+                            if (valobj_sp)
+                            {
+                                const bool qualify_cxx_base_classes = false;
+                                
+                                const ValueObject::GetExpressionPathFormat format = ValueObject::GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
+                                stream->PutCString("Likely cause: ");
+                                valobj_sp->GetExpressionPath(*stream, qualify_cxx_base_classes, format);
+                                stream->Printf(" accessed 0x%llx\n", crashing_address);
+                            }
+                        }
                     }
                     else
                     {
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 7110051d28e4..aaf0a4d7ac7d 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -20,12 +20,14 @@
 #include "lldb/Core/Value.h"
 #include "lldb/Core/ValueObjectVariable.h"
 #include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectMemory.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/Symbol.h"
 #include "lldb/Symbol/SymbolContextScope.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/RegisterContext.h"
@@ -1236,6 +1238,21 @@ StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
     return m_frame_base_error.Success();
 }
 
+DWARFExpression *
+StackFrame::GetFrameBaseExpression(Error *error_ptr)
+{
+    if (!m_sc.function)
+    {
+        if (error_ptr)
+        {
+            error_ptr->SetErrorString ("No function in symbol context.");
+        }
+        return nullptr;
+    }
+
+    return &m_sc.function->GetFrameBaseExpression();
+}
+
 RegisterContextSP
 StackFrame::GetRegisterContext ()
 {
@@ -1354,6 +1371,572 @@ StackFrame::GuessLanguage ()
     return lang_type;
 }
 
+namespace
+{
+    std::pair<const Instruction::Operand *, int64_t>
+    GetBaseExplainingValue(const Instruction::Operand &operand,
+                           RegisterContext &register_context,
+                           lldb::addr_t value)
+    {
+        switch(operand.m_type)
+        {
+        case Instruction::Operand::Type::Dereference:
+        case Instruction::Operand::Type::Immediate:
+        case Instruction::Operand::Type::Invalid:
+        case Instruction::Operand::Type::Product:
+            // These are not currently interesting
+            return std::make_pair(nullptr, 0);
+        case Instruction::Operand::Type::Sum:
+            {
+                const Instruction::Operand *immediate_child = nullptr;
+                const Instruction::Operand *variable_child = nullptr;
+                if (operand.m_children[0].m_type == Instruction::Operand::Type::Immediate)
+                {
+                    immediate_child = &operand.m_children[0];
+                    variable_child = &operand.m_children[1];
+                }
+                else if (operand.m_children[1].m_type == Instruction::Operand::Type::Immediate)
+                {
+                    immediate_child = &operand.m_children[1];
+                    variable_child = &operand.m_children[0];
+                }
+                if (!immediate_child)
+                {
+                    return std::make_pair(nullptr, 0);
+                }
+                lldb::addr_t adjusted_value = value;
+                if (immediate_child->m_negative)
+                {
+                    adjusted_value += immediate_child->m_immediate;
+                }
+                else
+                {
+                    adjusted_value -= immediate_child->m_immediate;
+                }
+                std::pair<const Instruction::Operand *, int64_t> base_and_offset = GetBaseExplainingValue(*variable_child, register_context, adjusted_value);
+                if (!base_and_offset.first)
+                {
+                    return std::make_pair(nullptr, 0);
+                }
+                if (immediate_child->m_negative)
+                {
+                    base_and_offset.second -= immediate_child->m_immediate;
+                }
+                else
+                {
+                    base_and_offset.second += immediate_child->m_immediate;
+                }
+                return base_and_offset;
+            }
+        case Instruction::Operand::Type::Register:
+            {
+                const RegisterInfo *info = register_context.GetRegisterInfoByName(operand.m_register.AsCString());
+                if (!info)
+                {
+                    return std::make_pair(nullptr, 0);
+                }
+                RegisterValue reg_value;
+                if (!register_context.ReadRegister(info, reg_value))
+                {
+                    return std::make_pair(nullptr, 0);
+                }
+                if (reg_value.GetAsUInt64() == value)
+                {
+                    return std::make_pair(&operand, 0);
+                }
+                else
+                {
+                    return std::make_pair(nullptr, 0);
+                }
+            }
+        }
+    }
+    
+    std::pair<const Instruction::Operand *, int64_t>
+    GetBaseExplainingDereference(const Instruction::Operand &operand,
+                                 RegisterContext &register_context,
+                                 lldb::addr_t addr)
+    {
+        if (operand.m_type == Instruction::Operand::Type::Dereference)
+        {
+            return GetBaseExplainingValue(operand.m_children[0],
+                                          register_context,
+                                          addr);
+        }
+        return std::make_pair(nullptr, 0);
+    }
+};
+
+lldb::ValueObjectSP
+StackFrame::GuessValueForAddress(lldb::addr_t addr)
+{
+    TargetSP target_sp = CalculateTarget();
+    
+    const ArchSpec &target_arch = target_sp->GetArchitecture();
+    
+    AddressRange pc_range;
+    pc_range.GetBaseAddress() = GetFrameCodeAddress();
+    pc_range.SetByteSize(target_arch.GetMaximumOpcodeByteSize());
+    
+    ExecutionContext exe_ctx (shared_from_this());
+    
+    const char *plugin_name = nullptr;
+    const char *flavor = nullptr;
+    const bool prefer_file_cache = false;
+    
+    DisassemblerSP disassembler_sp = Disassembler::DisassembleRange (target_arch,
+                                                                     plugin_name,
+                                                                     flavor,
+                                                                     exe_ctx,
+                                                                     pc_range,
+                                                                     prefer_file_cache);
+    
+    if (!disassembler_sp->GetInstructionList().GetSize())
+    {
+        return ValueObjectSP();
+    }
+    
+    InstructionSP instruction_sp = disassembler_sp->GetInstructionList().GetInstructionAtIndex(0);
+    
+    llvm::SmallVector<Instruction::Operand, 3> operands;
+    
+    if (!instruction_sp->ParseOperands(operands))
+    {
+        return ValueObjectSP();
+    }
+    
+    RegisterContextSP register_context_sp = GetRegisterContext();
+    
+    if (!register_context_sp)
+    {
+        return ValueObjectSP();
+    }
+    
+    for (const Instruction::Operand &operand : operands)
+    {
+        std::pair<const Instruction::Operand *, int64_t>
+            base_and_offset = GetBaseExplainingDereference(operand, *register_context_sp, addr);
+        
+        if (!base_and_offset.first)
+        {
+            continue;
+        }
+        
+        switch (base_and_offset.first->m_type)
+        {
+        case Instruction::Operand::Type::Immediate:
+            {
+                lldb_private::Address addr;
+                if (target_sp->ResolveLoadAddress(base_and_offset.first->m_immediate + base_and_offset.second, addr))
+                {
+                    TypeSystem *c_type_system = target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC);
+                    if (!c_type_system)
+                    {
+                        return ValueObjectSP();
+                    }
+                    else
+                    {
+                        CompilerType void_ptr_type = c_type_system->GetBasicTypeFromAST(lldb::BasicType::eBasicTypeChar).GetPointerType();
+                        return ValueObjectMemory::Create(this, "", addr, void_ptr_type);
+                    }
+                }
+                else
+                {
+                    return ValueObjectSP();
+                }
+                break;
+            }
+        case Instruction::Operand::Type::Register:
+            {
+                return GuessValueForRegisterAndOffset(base_and_offset.first->m_register, base_and_offset.second);
+            }
+        default:
+            return ValueObjectSP();
+        }
+        
+    }
+
+    return ValueObjectSP();
+}
+
+namespace
+{
+    ValueObjectSP
+    GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, int64_t offset)
+    {
+        if (offset < 0 || offset >= parent->GetByteSize())
+        {
+            return ValueObjectSP();
+        }
+        
+        if (parent->IsPointerOrReferenceType())
+        {
+            return parent;
+        }
+        
+        for (int ci = 0, ce = parent->GetNumChildren(); ci != ce; ++ci)
+        {
+            const bool can_create = true;
+            ValueObjectSP child_sp = parent->GetChildAtIndex(ci, can_create);
+            
+            if (!child_sp)
+            {
+                return ValueObjectSP();
+            }
+            
+            int64_t child_offset = child_sp->GetByteOffset();
+            int64_t child_size = child_sp->GetByteSize();
+            
+            if (offset >= child_offset &&
+                offset < (child_offset + child_size))
+            {
+                return GetValueForOffset(frame, child_sp, offset - child_offset);
+            }
+        }
+        
+        if (offset == 0)
+        {
+            return parent;
+        }
+        else
+        {
+            return ValueObjectSP();
+        }
+    }
+    
+    ValueObjectSP
+    GetValueForDereferincingOffset(StackFrame &frame, ValueObjectSP &base, int64_t offset)
+    {
+        // base is a pointer to something
+        // offset is the thing to add to the pointer
+        // We return the most sensible ValueObject for the result of *(base+offset)
+
+        if (!base->IsPointerOrReferenceType())
+        {
+            return ValueObjectSP();
+        }
+    
+        Error error;
+        ValueObjectSP pointee = base->Dereference(error);
+        
+        if (offset >= pointee->GetByteSize())
+        {
+            int64_t index = offset / pointee->GetByteSize();
+            offset = offset % pointee->GetByteSize();
+            const bool can_create = true;
+            pointee = base->GetSyntheticArrayMember(index, can_create);
+        }
+        
+        if (!pointee || error.Fail())
+        {
+            return ValueObjectSP();
+        }
+        
+        return GetValueForOffset(frame, pointee, offset);
+    }
+    
+    //------------------------------------------------------------------
+    /// Attempt to reconstruct the ValueObject for the address contained in a
+    /// given register plus an offset.
+    ///
+    /// @params [in] frame
+    ///   The current stack frame.
+    ///
+    /// @params [in] reg
+    ///   The register.
+    ///
+    /// @params [in] offset
+    ///   The offset from the register.
+    ///
+    /// @param [in] disassembler
+    ///   A disassembler containing instructions valid up to the current PC.
+    ///
+    /// @param [in] variables
+    ///   The variable list from the current frame,
+    ///
+    /// @param [in] pc
+    ///   The program counter for the instruction considered the 'user'.
+    ///
+    /// @return
+    ///   A string describing the base for the ExpressionPath.  This could be a
+    ///     variable, a register value, an argument, or a function return value.
+    ///   The ValueObject if found.  If valid, it has a valid ExpressionPath.
+    //------------------------------------------------------------------
+    lldb::ValueObjectSP
+    DoGuessValueAt(StackFrame &frame, ConstString reg, int64_t offset, Disassembler &disassembler, VariableList &variables, const Address &pc)
+    {
+        // Example of operation for Intel:
+        //
+        // +14: movq   -0x8(%rbp), %rdi
+        // +18: movq   0x8(%rdi), %rdi
+        // +22: addl   0x4(%rdi), %eax
+        //
+        // f, a pointer to a struct, is known to be at -0x8(%rbp).
+        //
+        // DoGuessValueAt(frame, rdi, 4, dis, vars, 0x22) finds the instruction at +18 that assigns to rdi, and calls itself recursively for that dereference
+        //   DoGuessValueAt(frame, rdi, 8, dis, vars, 0x18) finds the instruction at +14 that assigns to rdi, and calls itself recursively for that derefernece
+        //     DoGuessValueAt(frame, rbp, -8, dis, vars, 0x14) finds "f" in the variable list.
+        //     Returns a ValueObject for f.  (That's what was stored at rbp-8 at +14)
+        //   Returns a ValueObject for *(f+8) or f->b (That's what was stored at rdi+8 at +18)
+        // Returns a ValueObject for *(f->b+4) or f->b->a (That's what was stored at rdi+4 at +22)
+        
+        // First, check the variable list to see if anything is at the specified location.
+        for (size_t vi = 0, ve = variables.GetSize(); vi != ve; ++vi)
+        {
+            VariableSP var_sp = variables.GetVariableAtIndex(vi);
+            DWARFExpression &dwarf_expression = var_sp->LocationExpression();
+            
+            const RegisterInfo *expression_reg;
+            int64_t expression_offset;
+            ExecutionContext exe_ctx;
+            
+            if (dwarf_expression.IsDereferenceOfRegister(frame, expression_reg, expression_offset))
+            {
+                if ((reg == ConstString(expression_reg->name) ||
+                     reg == ConstString(expression_reg->alt_name)) &&
+                    expression_offset == offset)
+                {
+                    return frame.GetValueObjectForFrameVariable(var_sp, eNoDynamicValues);
+                }
+            }
+        }
+        
+        bool is_in_return_register = false;
+        ABISP abi_sp = frame.CalculateProcess()->GetABI();
+        RegisterInfo return_register_info;
+
+        if (abi_sp)
+        {
+            const char *return_register_name;
+            const RegisterInfo *reg_info = nullptr;
+            if (abi_sp->GetPointerReturnRegister(return_register_name) &&
+                reg == ConstString(return_register_name) &&
+                (reg_info = frame.GetRegisterContext()->GetRegisterInfoByName(return_register_name)))
+            {
+                is_in_return_register = true;
+                return_register_info = *reg_info;
+            }
+        }
+        
+        const uint32_t current_inst = disassembler.GetInstructionList().GetIndexOfInstructionAtAddress(pc);
+        if (current_inst == UINT32_MAX)
+        {
+            return ValueObjectSP();
+        }
+        
+        ValueObjectSP source_path;
+        
+        for (uint32_t ii = current_inst - 1; ii != (uint32_t)-1; --ii)
+        {
+            // This is not an exact algorithm, and it sacrifices accuracy for generality.
+            // Recognizing "mov" and "ld" instructions –– and which are their source and
+            // destination operands -- is something the disassembler should do for us.
+            InstructionSP instruction_sp = disassembler.GetInstructionList().GetInstructionAtIndex(ii);
+            
+            if (is_in_return_register && instruction_sp->IsCall())
+            {
+                llvm::SmallVector<Instruction::Operand, 1> operands;
+                if (!instruction_sp->ParseOperands(operands) || operands.size() != 1)
+                {
+                    continue;
+                }
+                
+                switch (operands[0].m_type)
+                {
+                default:
+                    break;
+                case Instruction::Operand::Type::Immediate:
+                    {
+                        SymbolContext sc;
+                        Address load_address;
+                        if (!frame.CalculateTarget()->ResolveLoadAddress(operands[0].m_immediate, load_address))
+                        {
+                            break;
+                        }
+                        frame.CalculateTarget()->GetImages().ResolveSymbolContextForAddress(load_address, eSymbolContextFunction, sc);
+                        if (!sc.function)
+                        {
+                            break;
+                        }
+                        CompilerType function_type = sc.function->GetCompilerType();
+                        if (!function_type.IsFunctionType())
+                        {
+                            break;
+                        }
+                        CompilerType return_type = function_type.GetFunctionReturnType();
+                        RegisterValue return_value;
+                        if (!frame.GetRegisterContext()->ReadRegister(&return_register_info, return_value))
+                        {
+                            break;
+                        }
+                        std::string name_str(sc.function->GetName().AsCString("<unknown function>"));
+                        name_str.append("()");
+                        Address return_value_address(return_value.GetAsUInt64());
+                        ValueObjectSP return_value_sp = ValueObjectMemory::Create(&frame, name_str.c_str(), return_value_address, return_type);
+                        return GetValueForDereferincingOffset(frame, return_value_sp, offset);
+                    }
+                }
+
+                continue;
+            }
+            
+            llvm::SmallVector<Instruction::Operand, 2> operands;
+            if (!instruction_sp->ParseOperands(operands) || operands.size() != 2)
+            {
+                continue;
+            }
+            
+            Instruction::Operand *register_operand = nullptr;
+            Instruction::Operand *origin_operand = nullptr;
+            if (operands[0].m_type == Instruction::Operand::Type::Register &&
+                operands[0].m_clobbered == true &&
+                operands[0].m_register == reg)
+            {
+                register_operand = &operands[0];
+                origin_operand = &operands[1];
+            }
+            else if (operands[1].m_type == Instruction::Operand::Type::Register &&
+                     operands[1].m_clobbered == true &&
+                     operands[1].m_register == reg)
+            {
+                register_operand = &operands[1];
+                origin_operand = &operands[0];
+            }
+            else
+            {
+                continue;
+            }
+            
+            // We have an origin operand.  Can we track its value down?
+            switch (origin_operand->m_type)
+            {
+            default:
+                break;
+            case Instruction::Operand::Type::Register:
+                source_path = DoGuessValueAt(frame, origin_operand->m_register, 0, disassembler, variables, instruction_sp->GetAddress());
+                break;
+            case Instruction::Operand::Type::Dereference:
+                {
+                    const Instruction::Operand &pointer = origin_operand->m_children[0];
+                    switch (pointer.m_type)
+                    {
+                    default:
+                        break;
+                    case Instruction::Operand::Type::Register:
+                        source_path = DoGuessValueAt(frame, pointer.m_register, 0, disassembler, variables, instruction_sp->GetAddress());
+                        if (source_path)
+                        {
+                            Error err;
+                            source_path = source_path->Dereference(err);
+                            if (!err.Success())
+                            {
+                                source_path.reset();
+                            }
+                        }
+                        break;
+                    case Instruction::Operand::Type::Sum:
+                        {
+                            const Instruction::Operand *origin_register = nullptr;
+                            const Instruction::Operand *origin_offset = nullptr;
+                            if (pointer.m_children.size() != 2)
+                            {
+                                break;
+                            }
+                            if (pointer.m_children[0].m_type == Instruction::Operand::Type::Register &&
+                                pointer.m_children[1].m_type == Instruction::Operand::Type::Immediate)
+                            {
+                                origin_register = &pointer.m_children[0];
+                                origin_offset = &pointer.m_children[1];
+                            }
+                            else if (pointer.m_children[1].m_type == Instruction::Operand::Type::Register &&
+                                     pointer.m_children[0].m_type == Instruction::Operand::Type::Immediate)
+                            {
+                                origin_register = &pointer.m_children[1];
+                                origin_offset = &pointer.m_children[0];
+                            }
+                            if (!origin_register)
+                            {
+                                break;
+                            }
+                            int64_t signed_origin_offset = origin_offset->m_negative ? -((int64_t)origin_offset->m_immediate) : origin_offset->m_immediate;
+                            source_path = DoGuessValueAt(frame, origin_register->m_register, signed_origin_offset, disassembler, variables, instruction_sp->GetAddress());
+                            if (!source_path)
+                            {
+                                break;
+                            }
+                            source_path = GetValueForDereferincingOffset(frame, source_path, offset);
+                            break;
+                        }
+                    }
+                }
+            }
+            
+            if (source_path)
+            {
+                return source_path;
+            }
+        }
+        
+        return ValueObjectSP();
+    }
+}
+
+lldb::ValueObjectSP
+StackFrame::GuessValueForRegisterAndOffset(ConstString reg, int64_t offset)
+{
+    TargetSP target_sp = CalculateTarget();
+    
+    const ArchSpec &target_arch = target_sp->GetArchitecture();
+
+    Block *frame_block = GetFrameBlock();
+    
+    if (!frame_block)
+    {
+        return ValueObjectSP();
+    }
+
+    Function *function = frame_block->CalculateSymbolContextFunction();
+    if (!function)
+    {
+        return ValueObjectSP();
+    }
+    
+    AddressRange pc_range = function->GetAddressRange();
+
+    if (GetFrameCodeAddress().GetFileAddress() < pc_range.GetBaseAddress().GetFileAddress() ||
+        GetFrameCodeAddress().GetFileAddress() - pc_range.GetBaseAddress().GetFileAddress() >= pc_range.GetByteSize())
+    {
+        return ValueObjectSP();
+    }
+    
+    ExecutionContext exe_ctx (shared_from_this());
+    
+    const char *plugin_name = nullptr;
+    const char *flavor = nullptr;
+    const bool prefer_file_cache = false;
+    DisassemblerSP disassembler_sp = Disassembler::DisassembleRange (target_arch,
+                                                                     plugin_name,
+                                                                     flavor,
+                                                                     exe_ctx,
+                                                                     pc_range,
+                                                                     prefer_file_cache);
+    
+    if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize())
+    {
+        return ValueObjectSP();
+    }
+    
+    const bool get_file_globals = false;
+    VariableList *variables = GetVariableList(get_file_globals);
+    
+    if (!variables)
+    {
+        return ValueObjectSP();
+    }
+    
+    return DoGuessValueAt(*this, reg, offset, *disassembler_sp, *variables, GetFrameCodeAddress());
+}
+
 TargetSP
 StackFrame::CalculateTarget ()
 {
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 7c244363ffd2..085c0f181c0e 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -1219,3 +1219,49 @@ StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp)
     else
         return ExpressionVariableSP();
 }
+
+lldb::ValueObjectSP
+StopInfo::GetCrashingDereference (StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address)
+{
+    if (!stop_info_sp)
+    {
+        return ValueObjectSP();
+    }
+    
+    const char *description = stop_info_sp->GetDescription();
+    if (!description)
+    {
+        return ValueObjectSP();
+    }
+    
+    ThreadSP thread_sp = stop_info_sp->GetThread();
+    if (!thread_sp)
+    {
+        return ValueObjectSP();
+    }
+    
+    StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+    
+    if (!frame_sp)
+    {
+        return ValueObjectSP();
+    }
+
+    const char address_string[] = "address=";
+    
+    const char *address_loc = strstr(description, address_string);
+    if (!address_loc)
+    {
+        return ValueObjectSP();
+    }
+    
+    address_loc += (sizeof(address_string) - 1);
+    
+    uint64_t address = std::stoull(address_loc, 0, 0);
+    if (crashing_address)
+    {
+        *crashing_address = address;
+    }
+    
+    return frame_sp->GuessValueForAddress(address);
+}