<div dir="ltr">This is really exciting. I've been wanting something like this for a long time. Hopefully with more changes like these we can reduce the number of changes that have to be reverted because they fail on some architecture/os combination and the only way to diagnose is to get the hardware/software in question (fate of this first attempt).</div><div class="gmail_extra"><br><div class="gmail_quote">On 28 September 2016 at 03:52, Jason Molenda via lldb-commits <span dir="ltr"><<a href="mailto:lldb-commits@lists.llvm.org" target="_blank">lldb-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: jmolenda<br>
Date: Tue Sep 27 21:52:19 2016<br>
New Revision: 282565<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=282565&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=282565&view=rev</a><br>
Log:<br>
Refactor the x86 UnwindAssembly class into a separate class called<br>
x86AssemblyInspectionEngine and the current UnwindAssembly_x86 to<br>
allow for the core engine to be exercised by unit tests.<br>
<br>
The UnwindAssembly_x86 class will have access to Targets, Processes,<br>
Threads, RegisterContexts -- it will be working in the full lldb<br>
environment.<br>
<br>
x86AssemblyInspectionEngine is layered away from all of that, it is<br>
given some register definitions and a bag of bytes to profile.<br>
<br>
I wrote an initial unittest for a do-nothing simple x86_64/i386<br>
function to start with.  I'll be adding more.<br>
<br>
The x86 assembly unwinder was added to lldb early in its bringup;<br>
I made some modernization changes as I was refactoring the code<br>
to make it more consistent with how we write lldb today.<br>
<br>
I also added RegisterContextMinidump_x86_<wbr>64.cpp to the xcode project<br>
file so I can run the unittests from that.<br>
<br>
The testsuite passes with this change, but there was quite a bit of<br>
code change by the refactoring and it's possible there are some<br>
issues.  I'll be testing this more in the coming days, but it looks<br>
like it is behaving correctly as far as I can tell with automated<br>
testing.<br>
<br>
<rdar://problem/28509178><br>
<br>
Added:<br>
    lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.<wbr>cpp<br>
    lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.h<br>
    lldb/trunk/unittests/<wbr>UnwindAssembly/<br>
    lldb/trunk/unittests/<wbr>UnwindAssembly/CMakeLists.txt<br>
    lldb/trunk/unittests/<wbr>UnwindAssembly/x86/<br>
    lldb/trunk/unittests/<wbr>UnwindAssembly/x86/CMakeLists.<wbr>txt<br>
    lldb/trunk/unittests/<wbr>UnwindAssembly/x86/<wbr>Testx86AssemblyInspectionEngin<wbr>e.cpp<br>
Modified:<br>
    lldb/trunk/lldb.xcodeproj/<wbr>project.pbxproj<br>
    lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/CMakeLists.<wbr>txt<br>
    lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>UnwindAssembly-x86.cpp<br>
    lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>UnwindAssembly-x86.h<br>
    lldb/trunk/unittests/<wbr>CMakeLists.txt<br>
<br>
Modified: lldb/trunk/lldb.xcodeproj/<wbr>project.pbxproj<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=282565&r1=282564&r2=282565&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lldb/trunk/lldb.<wbr>xcodeproj/project.pbxproj?rev=<wbr>282565&r1=282564&r2=282565&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lldb/trunk/lldb.xcodeproj/<wbr>project.pbxproj (original)<br>
+++ lldb/trunk/lldb.xcodeproj/<wbr>project.pbxproj Tue Sep 27 21:52:19 2016<br>
@@ -928,6 +928,8 @@<br>
                AF33B4BE1C1FA441001B28D9 /* NetBSDSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF33B4BC1C1FA441001B28D9 /* NetBSDSignals.cpp */; };<br>
                AF33B4BF1C1FA441001B28D9 /* NetBSDSignals.h in Headers */ = {isa = PBXBuildFile; fileRef = AF33B4BD1C1FA441001B28D9 /* NetBSDSignals.h */; };<br>
                AF37E10A17C861F20061E18E /* ProcessRunLock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF37E10917C861F20061E18E /* ProcessRunLock.cpp */; };<br>
+               AF415AE71D949E4400FCE0D4 /* x86AssemblyInspectionEngine.<wbr>cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF415AE51D949E4400FCE0D4 /* x86AssemblyInspectionEngine.<wbr>cpp */; };<br>
+               AF415AE81D949E4400FCE0D4 /* x86AssemblyInspectionEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = AF415AE61D949E4400FCE0D4 /* x86AssemblyInspectionEngine.h */; };<br>
                AF45FDE518A1F3AC0007051C /* AppleGetThreadItemInfoHandler.<wbr>cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF45FDE318A1F3AC0007051C /* AppleGetThreadItemInfoHandler.<wbr>cpp */; };<br>
                AF6335E21C87B21E00F7D554 /* SymbolFilePDB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF6335E01C87B21E00F7D554 /* SymbolFilePDB.cpp */; };<br>
                AF6335E31C87B21E00F7D554 /* SymbolFilePDB.h in Headers */ = {isa = PBXBuildFile; fileRef = AF6335E11C87B21E00F7D554 /* SymbolFilePDB.h */; };<br>
@@ -953,9 +955,12 @@<br>
                AFC234091AF85CE100CDE8B6 /* CommandObjectLanguage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFC234061AF85CE000CDE8B6 /* CommandObjectLanguage.cpp */; };<br>
                AFCB2BBD1BF577F40018B553 /* PythonExceptionState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFCB2BBB1BF577F40018B553 /* PythonExceptionState.cpp */; };<br>
                AFCB2BBE1BF577F40018B553 /* PythonExceptionState.h in Headers */ = {isa = PBXBuildFile; fileRef = AFCB2BBC1BF577F40018B553 /* PythonExceptionState.h */; };<br>
+               AFD65C811D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.cpp */; };<br>
+               AFD65C821D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.h in Headers */ = {isa = PBXBuildFile; fileRef = AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.h */; };<br>
                AFDCDBCB19DD0F42005EA55E /* SBExecutionContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 940B02F419DC96CB00AD0F52 /* SBExecutionContext.h */; settings = {ATTRIBUTES = (Public, ); }; };<br>
                AFDFDFD119E34D3400EAE509 /* ConnectionFileDescriptorPosix.<wbr>cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.<wbr>cpp */; };<br>
                AFEC3362194A8ABA00FF05C6 /* StructuredData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3361194A8ABA00FF05C6 /* StructuredData.cpp */; };<br>
+               AFEC5FD81D94F9380076A480 /* Testx86AssemblyInspectionEngin<wbr>e.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC5FD51D94F9380076A480 /* Testx86AssemblyInspectionEngin<wbr>e.cpp */; };<br>
                AFF87C87150FF669000E1742 /* com.apple.debugserver.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = AFF87C86150FF669000E1742 /* com.apple.debugserver.plist */; };<br>
                AFF87C8F150FF688000E1742 /* com.apple.debugserver.applist.<wbr>plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = AFF87C8E150FF688000E1742 /* com.apple.debugserver.applist.<wbr>plist */; };<br>
                B207C4931429607D00F36E4E /* CommandObjectWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B207C4921429607D00F36E4E /* CommandObjectWatchpoint.cpp */; };<br>
@@ -2946,6 +2951,8 @@<br>
                AF3F54BF1B3BA5D500186E73 /* RegisterContextPOSIXProcessMon<wbr>itor_powerpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextPOSIXProcessMon<wbr>itor_powerpc.h; sourceTree = "<group>"; };<br>
                AF3F54C01B3BA5D500186E73 /* RegisterContextPOSIXProcessMon<wbr>itor_x86.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextPOSIXProcessMon<wbr>itor_x86.cpp; sourceTree = "<group>"; };<br>
                AF3F54C11B3BA5D500186E73 /* RegisterContextPOSIXProcessMon<wbr>itor_x86.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextPOSIXProcessMon<wbr>itor_x86.h; sourceTree = "<group>"; };<br>
+               AF415AE51D949E4400FCE0D4 /* x86AssemblyInspectionEngine.<wbr>cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x86AssemblyInspectionEngine.<wbr>cpp; sourceTree = "<group>"; };<br>
+               AF415AE61D949E4400FCE0D4 /* x86AssemblyInspectionEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x86AssemblyInspectionEngine.h; sourceTree = "<group>"; };<br>
                AF45E1FC1BF57C8D000563EB /* PythonTestSuite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PythonTestSuite.cpp; sourceTree = "<group>"; };<br>
                AF45E1FD1BF57C8D000563EB /* PythonTestSuite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PythonTestSuite.h; sourceTree = "<group>"; };<br>
                AF45FDE318A1F3AC0007051C /* AppleGetThreadItemInfoHandler.<wbr>cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleGetThreadItemInfoHandler.<wbr>cpp; sourceTree = "<group>"; };<br>
@@ -2992,8 +2999,11 @@<br>
                AFC234071AF85CE000CDE8B6 /* CommandObjectLanguage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectLanguage.h; path = source/Commands/<wbr>CommandObjectLanguage.h; sourceTree = "<group>"; };<br>
                AFCB2BBB1BF577F40018B553 /* PythonExceptionState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PythonExceptionState.cpp; path = ScriptInterpreter/Python/<wbr>PythonExceptionState.cpp; sourceTree = "<group>"; };<br>
                AFCB2BBC1BF577F40018B553 /* PythonExceptionState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PythonExceptionState.h; path = ScriptInterpreter/Python/<wbr>PythonExceptionState.h; sourceTree = "<group>"; };<br>
+               AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMinidump_x86_<wbr>64.cpp; sourceTree = "<group>"; };<br>
+               AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMinidump_x86_<wbr>64.h; sourceTree = "<group>"; };<br>
                AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.<wbr>cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConnectionFileDescriptorPosix.<wbr>cpp; sourceTree = "<group>"; };<br>
                AFEC3361194A8ABA00FF05C6 /* StructuredData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StructuredData.cpp; path = source/Core/StructuredData.<wbr>cpp; sourceTree = "<group>"; };<br>
+               AFEC5FD51D94F9380076A480 /* Testx86AssemblyInspectionEngin<wbr>e.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Testx86AssemblyInspectionEngin<wbr>e.cpp; path = UnwindAssembly/x86/<wbr>Testx86AssemblyInspectionEngin<wbr>e.cpp; sourceTree = "<group>"; };<br>
                AFF87C86150FF669000E1742 /* com.apple.debugserver.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.debugserver.plist; path = tools/debugserver/source/com.<wbr>apple.debugserver.plist; sourceTree = "<group>"; };<br>
                AFF87C8A150FF677000E1742 /* com.apple.debugserver.applist.<wbr>plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.debugserver.applist.<wbr>plist; path = tools/debugserver/source/com.<wbr>apple.debugserver.applist.<wbr>plist; sourceTree = "<group>"; };<br>
                AFF87C8C150FF680000E1742 /* com.apple.debugserver.applist.<wbr>plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.debugserver.applist.<wbr>plist; path = tools/debugserver/source/com.<wbr>apple.debugserver.applist.<wbr>plist; sourceTree = "<group>"; };<br>
@@ -3227,6 +3237,7 @@<br>
                                2321F93F1BDD33D800BA9A93 /* ScriptInterpreter */,<br>
                                23CB15091D66CF2B00EDDDE1 /* Symbol */,<br>
                                23CB150A1D66CF3200EDDDE1 /* SymbolFile */,<br>
+                               AFEC5FD31D94F9130076A480 /* UnwindAssembly */,<br>
                                2321F9421BDD343A00BA9A93 /* Utility */,<br>
                        );<br>
                        path = unittests;<br>
@@ -3527,6 +3538,8 @@<br>
                23E2E5351D9048E7006F38BB /* minidump */ = {<br>
                        isa = PBXGroup;<br>
                        children = (<br>
+                               AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.cpp */,<br>
+                               AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.h */,<br>
                                23E2E5361D9048FB006F38BB /* CMakeLists.txt */,<br>
                                23E2E5371D9048FB006F38BB /* MinidumpParser.cpp */,<br>
                                23E2E5381D9048FB006F38BB /* MinidumpParser.h */,<br>
@@ -4405,6 +4418,8 @@<br>
                2692BA17136611CD00F9E14D /* x86 */ = {<br>
                        isa = PBXGroup;<br>
                        children = (<br>
+                               AF415AE51D949E4400FCE0D4 /* x86AssemblyInspectionEngine.<wbr>cpp */,<br>
+                               AF415AE61D949E4400FCE0D4 /* x86AssemblyInspectionEngine.h */,<br>
                                263E949D13661AE400E7D1CE /* UnwindAssembly-x86.cpp */,<br>
                                263E949E13661AE400E7D1CE /* UnwindAssembly-x86.h */,<br>
                        );<br>
@@ -6283,6 +6298,22 @@<br>
                        name = "SysV-ppc64";<br>
                        sourceTree = "<group>";<br>
                };<br>
+               AFEC5FD31D94F9130076A480 /* UnwindAssembly */ = {<br>
+                       isa = PBXGroup;<br>
+                       children = (<br>
+                               AFEC5FD51D94F9380076A480 /* Testx86AssemblyInspectionEngin<wbr>e.cpp */,<br>
+                               AFEC5FD41D94F9270076A480 /* x86 */,<br>
+                       );<br>
+                       name = UnwindAssembly;<br>
+                       sourceTree = "<group>";<br>
+               };<br>
+               AFEC5FD41D94F9270076A480 /* x86 */ = {<br>
+                       isa = PBXGroup;<br>
+                       children = (<br>
+                       );<br>
+                       name = x86;<br>
+                       sourceTree = "<group>";<br>
+               };<br>
                E769331B1A94D10E00C73337 /* lldb-server */ = {<br>
                        isa = PBXGroup;<br>
                        children = (<br>
@@ -6400,7 +6431,9 @@<br>
                                4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */,<br>
                                26C7C4841BFFEA7E009BD01F /* WindowsMiniDump.h in Headers */,<br>
                                30B38A001CAAA6D7009524E3 /* ClangUtil.h in Headers */,<br>
+                               AFD65C821D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.h in Headers */,<br>
                                238F2BA11D2C835A001FF92A /* StructuredDataPlugin.h in Headers */,<br>
+                               AF415AE81D949E4400FCE0D4 /* x86AssemblyInspectionEngine.h in Headers */,<br>
                                AF8AD62F1BEC28A400150209 /* PlatformAppleTVSimulator.h in Headers */,<br>
                                238F2BA91D2C85FA001FF92A /* StructuredDataDarwinLog.h in Headers */,<br>
                                AF8AD63A1BEC28C400150209 /* PlatformRemoteAppleWatch.h in Headers */,<br>
@@ -6890,6 +6923,7 @@<br>
                                23CB153E1D66DA9300EDDDE1 /* PythonDataObjectsTests.cpp in Sources */,<br>
                                23CB153F1D66DA9300EDDDE1 /* SymbolsTest.cpp in Sources */,<br>
                                23E2E52B1D9037E6006F38BB /* ModuleCacheTest.cpp in Sources */,<br>
+                               AFEC5FD81D94F9380076A480 /* Testx86AssemblyInspectionEngin<wbr>e.cpp in Sources */,<br>
                                23CB15401D66DA9300EDDDE1 /* TestClangASTContext.cpp in Sources */,<br>
                                23CB15411D66DA9300EDDDE1 /* StringExtractorTest.cpp in Sources */,<br>
                                23CB15421D66DA9300EDDDE1 /* TaskPoolTest.cpp in Sources */,<br>
@@ -6989,6 +7023,7 @@<br>
                                26D1804216CEDF0700EDFB5B /* TimeSpecTimeout.cpp in Sources */,<br>
                                2689FFDA13353D9D00698AC0 /* lldb.cpp in Sources */,<br>
                                4C0083401B9F9BA900D5CF24 /* UtilityFunction.cpp in Sources */,<br>
+                               AF415AE71D949E4400FCE0D4 /* x86AssemblyInspectionEngine.<wbr>cpp in Sources */,<br>
                                26474CCD18D0CB5B0073DEBA /* RegisterContextPOSIX_x86.cpp in Sources */,<br>
                                AEB0E4591BD6E9F800B24093 /* LLVMUserExpression.cpp in Sources */,<br>
                                2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */,<br>
@@ -7547,6 +7582,7 @@<br>
                                23D0658F1D4A7BEE0008EDE6 /* RenderScriptExpressionOpts.cpp in Sources */,<br>
                                945215DF17F639EE00521C0B /* ValueObjectPrinter.cpp in Sources */,<br>
                                26EFB61B1BFE8D3E00544801 /* PlatformNetBSD.cpp in Sources */,<br>
+                               AFD65C811D9B5B2E00D93120 /* RegisterContextMinidump_x86_<wbr>64.cpp in Sources */,<br>
                                260CC64815D0440D002BF2E0 /* OptionValueArgs.cpp in Sources */,<br>
                                260CC64915D0440D002BF2E0 /* OptionValueArray.cpp in Sources */,<br>
                                260CC64A15D0440D002BF2E0 /* OptionValueBoolean.cpp in Sources */,<br>
<br>
Modified: lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/CMakeLists.<wbr>txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/CMakeLists.txt?rev=282565&r1=282564&r2=282565&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lldb/trunk/source/<wbr>Plugins/UnwindAssembly/x86/<wbr>CMakeLists.txt?rev=282565&r1=<wbr>282564&r2=282565&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/CMakeLists.<wbr>txt (original)<br>
+++ lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/CMakeLists.<wbr>txt Tue Sep 27 21:52:19 2016<br>
@@ -1,3 +1,4 @@<br>
 add_lldb_library(<wbr>lldbPluginUnwindAssemblyX86<br>
   UnwindAssembly-x86.cpp<br>
+  x86AssemblyInspectionEngine.<wbr>cpp<br>
   )<br>
<br>
Modified: lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>UnwindAssembly-x86.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp?rev=282565&r1=282564&r2=282565&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lldb/trunk/source/<wbr>Plugins/UnwindAssembly/x86/<wbr>UnwindAssembly-x86.cpp?rev=<wbr>282565&r1=282564&r2=282565&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>UnwindAssembly-x86.cpp (original)<br>
+++ lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>UnwindAssembly-x86.cpp Tue Sep 27 21:52:19 2016<br>
@@ -8,6 +8,7 @@<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
<br>
 #include "UnwindAssembly-x86.h"<br>
+#include "x86AssemblyInspectionEngine.<wbr>h"<br>
<br>
 #include "llvm-c/Disassembler.h"<br>
 #include "llvm/ADT/STLExtras.h"<br>
@@ -30,1200 +31,39 @@<br>
 using namespace lldb;<br>
 using namespace lldb_private;<br>
<br>
-enum CPU { k_i386, k_x86_64 };<br>
-<br>
-enum i386_register_numbers {<br>
-  k_machine_eax = 0,<br>
-  k_machine_ecx = 1,<br>
-  k_machine_edx = 2,<br>
-  k_machine_ebx = 3,<br>
-  k_machine_esp = 4,<br>
-  k_machine_ebp = 5,<br>
-  k_machine_esi = 6,<br>
-  k_machine_edi = 7,<br>
-  k_machine_eip = 8<br>
-};<br>
-<br>
-enum x86_64_register_numbers {<br>
-  k_machine_rax = 0,<br>
-  k_machine_rcx = 1,<br>
-  k_machine_rdx = 2,<br>
-  k_machine_rbx = 3,<br>
-  k_machine_rsp = 4,<br>
-  k_machine_rbp = 5,<br>
-  k_machine_rsi = 6,<br>
-  k_machine_rdi = 7,<br>
-  k_machine_r8 = 8,<br>
-  k_machine_r9 = 9,<br>
-  k_machine_r10 = 10,<br>
-  k_machine_r11 = 11,<br>
-  k_machine_r12 = 12,<br>
-  k_machine_r13 = 13,<br>
-  k_machine_r14 = 14,<br>
-  k_machine_r15 = 15,<br>
-  k_machine_rip = 16<br>
-};<br>
-<br>
-struct regmap_ent {<br>
-  const char *name;<br>
-  int machine_regno;<br>
-  int lldb_regno;<br>
-};<br>
-<br>
-static struct regmap_ent i386_register_map[] = {<br>
-    {"eax", k_machine_eax, -1}, {"ecx", k_machine_ecx, -1},<br>
-    {"edx", k_machine_edx, -1}, {"ebx", k_machine_ebx, -1},<br>
-    {"esp", k_machine_esp, -1}, {"ebp", k_machine_ebp, -1},<br>
-    {"esi", k_machine_esi, -1}, {"edi", k_machine_edi, -1},<br>
-    {"eip", k_machine_eip, -1}};<br>
-<br>
-const int size_of_i386_register_map = llvm::array_lengthof(i386_<wbr>register_map);<br>
-<br>
-static int i386_register_map_initialized = 0;<br>
-<br>
-static struct regmap_ent x86_64_register_map[] = {<br>
-    {"rax", k_machine_rax, -1}, {"rcx", k_machine_rcx, -1},<br>
-    {"rdx", k_machine_rdx, -1}, {"rbx", k_machine_rbx, -1},<br>
-    {"rsp", k_machine_rsp, -1}, {"rbp", k_machine_rbp, -1},<br>
-    {"rsi", k_machine_rsi, -1}, {"rdi", k_machine_rdi, -1},<br>
-    {"r8", k_machine_r8, -1},   {"r9", k_machine_r9, -1},<br>
-    {"r10", k_machine_r10, -1}, {"r11", k_machine_r11, -1},<br>
-    {"r12", k_machine_r12, -1}, {"r13", k_machine_r13, -1},<br>
-    {"r14", k_machine_r14, -1}, {"r15", k_machine_r15, -1},<br>
-    {"rip", k_machine_rip, -1}};<br>
-<br>
-const int size_of_x86_64_register_map =<br>
-    llvm::array_lengthof(x86_64_<wbr>register_map);<br>
-<br>
-static int x86_64_register_map_<wbr>initialized = 0;<br>
-<br>
 //----------------------------<wbr>------------------------------<wbr>------------------------------<wbr>-------<br>
-//  AssemblyParse_x86 local-file class definition & implementation functions<br>
+//  UnwindAssemblyParser_x86 method definitions<br>
 //----------------------------<wbr>------------------------------<wbr>------------------------------<wbr>-------<br>
<br>
-class AssemblyParse_x86 {<br>
-public:<br>
-  AssemblyParse_x86(const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch,<br>
-                    AddressRange func);<br>
-<br>
-  ~AssemblyParse_x86();<br>
-<br>
-  bool get_non_call_site_unwind_plan(<wbr>UnwindPlan &unwind_plan);<br>
-<br>
-  bool augment_unwind_plan_from_call_<wbr>site(AddressRange &func,<br>
-                                          UnwindPlan &unwind_plan);<br>
-<br>
-  bool get_fast_unwind_plan(<wbr>AddressRange &func, UnwindPlan &unwind_plan);<br>
-<br>
-  bool find_first_non_prologue_insn(<wbr>Address &address);<br>
-<br>
-private:<br>
-  enum { kMaxInstructionByteSize = 32 };<br>
-<br>
-  bool nonvolatile_reg_p(int machine_regno);<br>
-  bool push_rbp_pattern_p();<br>
-  bool push_0_pattern_p();<br>
-  bool mov_rsp_rbp_pattern_p();<br>
-  bool sub_rsp_pattern_p(int &amount);<br>
-  bool add_rsp_pattern_p(int &amount);<br>
-  bool lea_rsp_pattern_p(int &amount);<br>
-  bool push_reg_p(int &regno);<br>
-  bool pop_reg_p(int &regno);<br>
-  bool push_imm_pattern_p();<br>
-  bool mov_reg_to_local_stack_frame_<wbr>p(int &regno, int &fp_offset);<br>
-  bool ret_pattern_p();<br>
-  bool pop_rbp_pattern_p();<br>
-  bool leave_pattern_p();<br>
-  bool call_next_insn_pattern_p();<br>
-  uint32_t extract_4(uint8_t *b);<br>
-  bool machine_regno_to_lldb_regno(<wbr>int machine_regno, uint32_t &lldb_regno);<br>
-  bool instruction_length(Address addr, int &length);<br>
-<br>
-  const ExecutionContext m_exe_ctx;<br>
-<br>
-  AddressRange m_func_bounds;<br>
-<br>
-  Address m_cur_insn;<br>
-  uint8_t m_cur_insn_bytes[<wbr>kMaxInstructionByteSize];<br>
-<br>
-  uint32_t m_machine_ip_regnum;<br>
-  uint32_t m_machine_sp_regnum;<br>
-  uint32_t m_machine_fp_regnum;<br>
-<br>
-  uint32_t m_lldb_ip_regnum;<br>
-  uint32_t m_lldb_sp_regnum;<br>
-  uint32_t m_lldb_fp_regnum;<br>
-<br>
-  int m_wordsize;<br>
-  int m_cpu;<br>
-  ArchSpec m_arch;<br>
-  ::LLVMDisasmContextRef m_disasm_context;<br>
-<br>
-  DISALLOW_COPY_AND_ASSIGN(<wbr>AssemblyParse_x86);<br>
-};<br>
-<br>
-AssemblyParse_x86::<wbr>AssemblyParse_x86(const ExecutionContext &exe_ctx, int cpu,<br>
-                                     ArchSpec &arch, AddressRange func)<br>
-    : m_exe_ctx(exe_ctx), m_func_bounds(func), m_cur_insn(),<br>
-      m_machine_ip_regnum(LLDB_<wbr>INVALID_REGNUM),<br>
-      m_machine_sp_regnum(LLDB_<wbr>INVALID_REGNUM),<br>
-      m_machine_fp_regnum(LLDB_<wbr>INVALID_REGNUM),<br>
-      m_lldb_ip_regnum(LLDB_INVALID_<wbr>REGNUM),<br>
-      m_lldb_sp_regnum(LLDB_INVALID_<wbr>REGNUM),<br>
-      m_lldb_fp_regnum(LLDB_INVALID_<wbr>REGNUM), m_wordsize(-1), m_cpu(cpu),<br>
-      m_arch(arch) {<br>
-  int *initialized_flag = NULL;<br>
-  if (cpu == k_i386) {<br>
-    m_machine_ip_regnum = k_machine_eip;<br>
-    m_machine_sp_regnum = k_machine_esp;<br>
-    m_machine_fp_regnum = k_machine_ebp;<br>
-    m_wordsize = 4;<br>
-    initialized_flag = &i386_register_map_<wbr>initialized;<br>
-  } else {<br>
-    m_machine_ip_regnum = k_machine_rip;<br>
-    m_machine_sp_regnum = k_machine_rsp;<br>
-    m_machine_fp_regnum = k_machine_rbp;<br>
-    m_wordsize = 8;<br>
-    initialized_flag = &x86_64_register_map_<wbr>initialized;<br>
-  }<br>
-<br>
-  // we only look at prologue - it will be complete earlier than 512 bytes into<br>
-  // func<br>
-  if (m_func_bounds.GetByteSize() == 0)<br>
-    m_func_bounds.SetByteSize(512)<wbr>;<br>
-<br>
-  Thread *thread = m_exe_ctx.GetThreadPtr();<br>
-  if (thread && *initialized_flag == 0) {<br>
-    RegisterContext *reg_ctx = thread->GetRegisterContext().<wbr>get();<br>
-    if (reg_ctx) {<br>
-      struct regmap_ent *ent;<br>
-      int count, i;<br>
-      if (cpu == k_i386) {<br>
-        ent = i386_register_map;<br>
-        count = size_of_i386_register_map;<br>
-      } else {<br>
-        ent = x86_64_register_map;<br>
-        count = size_of_x86_64_register_map;<br>
-      }<br>
-      for (i = 0; i < count; i++, ent++) {<br>
-        const RegisterInfo *ri = reg_ctx-><wbr>GetRegisterInfoByName(ent-><wbr>name);<br>
-        if (ri)<br>
-          ent->lldb_regno = ri->kinds[eRegisterKindLLDB];<br>
-      }<br>
-      *initialized_flag = 1;<br>
-    }<br>
-  }<br>
-<br>
-  // on initial construction we may not have a Thread so these have to remain<br>
-  // uninitialized until we can get a RegisterContext to set up the register map<br>
-  // table<br>
-  if (*initialized_flag == 1) {<br>
-    uint32_t lldb_regno;<br>
-    if (machine_regno_to_lldb_regno(<wbr>m_machine_sp_regnum, lldb_regno))<br>
-      m_lldb_sp_regnum = lldb_regno;<br>
-    if (machine_regno_to_lldb_regno(<wbr>m_machine_fp_regnum, lldb_regno))<br>
-      m_lldb_fp_regnum = lldb_regno;<br>
-    if (machine_regno_to_lldb_regno(<wbr>m_machine_ip_regnum, lldb_regno))<br>
-      m_lldb_ip_regnum = lldb_regno;<br>
-  }<br>
-<br>
-  m_disasm_context =<br>
-      ::LLVMCreateDisasm(m_arch.<wbr>GetTriple().getTriple().c_str(<wbr>), (void *)this,<br>
-                         /*TagType=*/1, NULL, NULL);<br>
-}<br>
-<br>
-AssemblyParse_x86::~<wbr>AssemblyParse_x86() {<br>
-  ::LLVMDisasmDispose(m_disasm_<wbr>context);<br>
-}<br>
-<br>
-// This function expects an x86 native register number (i.e. the bits stripped<br>
-// out of the<br>
-// actual instruction), not an lldb register number.<br>
-<br>
-bool AssemblyParse_x86::<wbr>nonvolatile_reg_p(int machine_regno) {<br>
-  if (m_cpu == k_i386) {<br>
-    switch (machine_regno) {<br>
-    case k_machine_ebx:<br>
-    case k_machine_ebp: // not actually a nonvolatile but often treated as such<br>
-                        // by convention<br>
-    case k_machine_esi:<br>
-    case k_machine_edi:<br>
-    case k_machine_esp:<br>
-      return true;<br>
-    default:<br>
-      return false;<br>
-    }<br>
-  }<br>
-  if (m_cpu == k_x86_64) {<br>
-    switch (machine_regno) {<br>
-    case k_machine_rbx:<br>
-    case k_machine_rsp:<br>
-    case k_machine_rbp: // not actually a nonvolatile but often treated as such<br>
-                        // by convention<br>
-    case k_machine_r12:<br>
-    case k_machine_r13:<br>
-    case k_machine_r14:<br>
-    case k_machine_r15:<br>
-      return true;<br>
-    default:<br>
-      return false;<br>
-    }<br>
-  }<br>
-  return false;<br>
-}<br>
-<br>
-// Macro to detect if this is a REX mode prefix byte.<br>
-#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)<br>
-<br>
-// The high bit which should be added to the source register number (the "R"<br>
-// bit)<br>
-#define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2)<br>
-<br>
-// The high bit which should be added to the destination register number (the<br>
-// "B" bit)<br>
-#define REX_W_DSTREG(opcode) ((opcode)&0x1)<br>
-<br>
-// pushq %rbp [0x55]<br>
-bool AssemblyParse_x86::push_rbp_<wbr>pattern_p() {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  if (*p == 0x55)<br>
-    return true;<br>
-  return false;<br>
-}<br>
-<br>
-// pushq $0 ; the first instruction in start() [0x6a 0x00]<br>
-bool AssemblyParse_x86::push_0_<wbr>pattern_p() {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  if (*p == 0x6a && *(p + 1) == 0x0)<br>
-    return true;<br>
-  return false;<br>
-}<br>
-<br>
-// pushq $0<br>
-// pushl $0<br>
-bool AssemblyParse_x86::push_imm_<wbr>pattern_p() {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  if (*p == 0x68 || *p == 0x6a)<br>
-    return true;<br>
-  return false;<br>
-}<br>
-<br>
-// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]<br>
-// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]<br>
-bool AssemblyParse_x86::mov_rsp_<wbr>rbp_pattern_p() {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  if (m_wordsize == 8 && *p == 0x48)<br>
-    p++;<br>
-  if (*(p) == 0x8b && *(p + 1) == 0xec)<br>
-    return true;<br>
-  if (*(p) == 0x89 && *(p + 1) == 0xe5)<br>
-    return true;<br>
-  return false;<br>
-}<br>
+UnwindAssembly_x86::<wbr>UnwindAssembly_x86(const ArchSpec &arch)<br>
+    : lldb_private::UnwindAssembly(<wbr>arch),<br>
+      m_assembly_inspection_engine(<wbr>new x86AssemblyInspectionEngine(<wbr>arch)) {}<br>
<br>
-// subq $0x20, %rsp<br>
-bool AssemblyParse_x86::sub_rsp_<wbr>pattern_p(int &amount) {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  if (m_wordsize == 8 && *p == 0x48)<br>
-    p++;<br>
-  // 8-bit immediate operand<br>
-  if (*p == 0x83 && *(p + 1) == 0xec) {<br>
-    amount = (int8_t) * (p + 2);<br>
-    return true;<br>
-  }<br>
-  // 32-bit immediate operand<br>
-  if (*p == 0x81 && *(p + 1) == 0xec) {<br>
-    amount = (int32_t)extract_4(p + 2);<br>
-    return true;<br>
-  }<br>
-  return false;<br>
-}<br>
-<br>
-// addq $0x20, %rsp<br>
-bool AssemblyParse_x86::add_rsp_<wbr>pattern_p(int &amount) {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  if (m_wordsize == 8 && *p == 0x48)<br>
-    p++;<br>
-  // 8-bit immediate operand<br>
-  if (*p == 0x83 && *(p + 1) == 0xc4) {<br>
-    amount = (int8_t) * (p + 2);<br>
-    return true;<br>
-  }<br>
-  // 32-bit immediate operand<br>
-  if (*p == 0x81 && *(p + 1) == 0xc4) {<br>
-    amount = (int32_t)extract_4(p + 2);<br>
-    return true;<br>
-  }<br>
-  return false;<br>
-}<br>
-<br>
-// lea esp, [esp - 0x28]<br>
-// lea esp, [esp + 0x28]<br>
-bool AssemblyParse_x86::lea_rsp_<wbr>pattern_p(int &amount) {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  if (m_wordsize == 8 && *p == 0x48)<br>
-    p++;<br>
-<br>
-  // Check opcode<br>
-  if (*p != 0x8d)<br>
-    return false;<br>
-<br>
-  // 8 bit displacement<br>
-  if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24) {<br>
-    amount = (int8_t) * (p + 3);<br>
-    return true;<br>
-  }<br>
-<br>
-  // 32 bit displacement<br>
-  if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24) {<br>
-    amount = (int32_t)extract_4(p + 3);<br>
-    return true;<br>
-  }<br>
-<br>
-  return false;<br>
-}<br>
-<br>
-// pushq %rbx<br>
-// pushl %ebx<br>
-bool AssemblyParse_x86::push_reg_p(<wbr>int &regno) {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  int regno_prefix_bit = 0;<br>
-  // If we have a rex prefix byte, check to see if a B bit is set<br>
-  if (m_wordsize == 8 && *p == 0x41) {<br>
-    regno_prefix_bit = 1 << 3;<br>
-    p++;<br>
-  }<br>
-  if (*p >= 0x50 && *p <= 0x57) {<br>
-    regno = (*p - 0x50) | regno_prefix_bit;<br>
-    return true;<br>
-  }<br>
-  return false;<br>
+UnwindAssembly_x86::~<wbr>UnwindAssembly_x86() {<br>
+  delete m_assembly_inspection_engine;<br>
 }<br>
<br>
-// popq %rbx<br>
-// popl %ebx<br>
-bool AssemblyParse_x86::pop_reg_p(<wbr>int &regno) {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  int regno_prefix_bit = 0;<br>
-  // If we have a rex prefix byte, check to see if a B bit is set<br>
-  if (m_wordsize == 8 && *p == 0x41) {<br>
-    regno_prefix_bit = 1 << 3;<br>
-    p++;<br>
-  }<br>
-  if (*p >= 0x58 && *p <= 0x5f) {<br>
-    regno = (*p - 0x58) | regno_prefix_bit;<br>
-    return true;<br>
-  }<br>
-  return false;<br>
-}<br>
-<br>
-// popq %rbp [0x5d]<br>
-// popl %ebp [0x5d]<br>
-bool AssemblyParse_x86::pop_rbp_<wbr>pattern_p() {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  return (*p == 0x5d);<br>
-}<br>
-<br>
-// leave [0xc9]<br>
-bool AssemblyParse_x86::leave_<wbr>pattern_p() {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  return (*p == 0xc9);<br>
-}<br>
-<br>
-// call $0 [0xe8 0x0 0x0 0x0 0x0]<br>
-bool AssemblyParse_x86::call_next_<wbr>insn_pattern_p() {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  return (*p == 0xe8) && (*(p + 1) == 0x0) && (*(p + 2) == 0x0) &&<br>
-         (*(p + 3) == 0x0) && (*(p + 4) == 0x0);<br>
-}<br>
-<br>
-// Look for an instruction sequence storing a nonvolatile register<br>
-// on to the stack frame.<br>
-<br>
-//  movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]<br>
-//  movl %eax, -0xc(%ebp)  [0x89 0x45 0xf4]<br>
-<br>
-// The offset value returned in rbp_offset will be positive --<br>
-// but it must be subtraced from the frame base register to get<br>
-// the actual location.  The positive value returned for the offset<br>
-// is a convention used elsewhere for CFA offsets et al.<br>
-<br>
-bool AssemblyParse_x86::mov_reg_to_<wbr>local_stack_frame_p(int &regno,<br>
-                                                       int &rbp_offset) {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  int src_reg_prefix_bit = 0;<br>
-  int target_reg_prefix_bit = 0;<br>
-<br>
-  if (m_wordsize == 8 && REX_W_PREFIX_P(*p)) {<br>
-    src_reg_prefix_bit = REX_W_SRCREG(*p) << 3;<br>
-    target_reg_prefix_bit = REX_W_DSTREG(*p) << 3;<br>
-    if (target_reg_prefix_bit == 1) {<br>
-      // rbp/ebp don't need a prefix bit - we know this isn't the<br>
-      // reg we care about.<br>
-      return false;<br>
-    }<br>
-    p++;<br>
-  }<br>
-<br>
-  if (*p == 0x89) {<br>
-    /* Mask off the 3-5 bits which indicate the destination register<br>
-       if this is a ModR/M byte.  */<br>
-    int opcode_destreg_masked_out = *(p + 1) & (~0x38);<br>
-<br>
-    /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101<br>
-       and three bits between them, e.g. 01nnn101<br>
-       We're looking for a destination of ebp-disp8 or ebp-disp32.   */<br>
-    int immsize;<br>
-    if (opcode_destreg_masked_out == 0x45)<br>
-      immsize = 2;<br>
-    else if (opcode_destreg_masked_out == 0x85)<br>
-      immsize = 4;<br>
-    else<br>
-      return false;<br>
-<br>
-    int offset = 0;<br>
-    if (immsize == 2)<br>
-      offset = (int8_t) * (p + 2);<br>
-    if (immsize == 4)<br>
-      offset = (uint32_t)extract_4(p + 2);<br>
-    if (offset > 0)<br>
-      return false;<br>
-<br>
-    regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;<br>
-    rbp_offset = offset > 0 ? offset : -offset;<br>
-    return true;<br>
-  }<br>
-  return false;<br>
-}<br>
-<br>
-// ret [0xc9] or [0xc2 imm8] or [0xca imm8]<br>
-bool AssemblyParse_x86::ret_<wbr>pattern_p() {<br>
-  uint8_t *p = m_cur_insn_bytes;<br>
-  if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)<br>
-    return true;<br>
-  return false;<br>
-}<br>
-<br>
-uint32_t AssemblyParse_x86::extract_4(<wbr>uint8_t *b) {<br>
-  uint32_t v = 0;<br>
-  for (int i = 3; i >= 0; i--)<br>
-    v = (v << 8) | b[i];<br>
-  return v;<br>
-}<br>
-<br>
-bool AssemblyParse_x86::machine_<wbr>regno_to_lldb_regno(int machine_regno,<br>
-                                                    uint32_t &lldb_regno) {<br>
-  struct regmap_ent *ent;<br>
-  int count, i;<br>
-  if (m_cpu == k_i386) {<br>
-    ent = i386_register_map;<br>
-    count = size_of_i386_register_map;<br>
-  } else {<br>
-    ent = x86_64_register_map;<br>
-    count = size_of_x86_64_register_map;<br>
-  }<br>
-  for (i = 0; i < count; i++, ent++) {<br>
-    if (ent->machine_regno == machine_regno)<br>
-      if (ent->lldb_regno != -1) {<br>
-        lldb_regno = ent->lldb_regno;<br>
-        return true;<br>
-      }<br>
-  }<br>
-  return false;<br>
-}<br>
-<br>
-bool AssemblyParse_x86::<wbr>instruction_length(Address addr, int &length) {<br>
-  const uint32_t max_op_byte_size = m_arch.<wbr>GetMaximumOpcodeByteSize();<br>
-  llvm::SmallVector<uint8_t, 32> opcode_data;<br>
-  opcode_data.resize(max_op_<wbr>byte_size);<br>
-<br>
-  if (!addr.IsValid())<br>
+bool UnwindAssembly_x86::<wbr>GetNonCallSiteUnwindPlanFromAs<wbr>sembly(<br>
+    AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {<br>
+  if (!func.GetBaseAddress().<wbr>IsValid() || func.GetByteSize() == 0)<br>
     return false;<br>
-<br>
-  const bool prefer_file_cache = true;<br>
-  Error error;<br>
-  Target *target = m_exe_ctx.GetTargetPtr();<br>
-  if (target->ReadMemory(addr, prefer_file_cache, opcode_data.data(),<br>
-                         max_op_byte_size, error) == static_cast<size_t>(-1)) {<br>
+  if (m_assembly_inspection_engine == nullptr)<br>
     return false;<br>
-  }<br>
-<br>
-  char out_string[512];<br>
-  const addr_t pc = addr.GetFileAddress();<br>
-  const size_t inst_size = ::LLVMDisasmInstruction(<br>
-      m_disasm_context, opcode_data.data(), max_op_byte_size,<br>
-      pc, // PC value<br>
-      out_string, sizeof(out_string));<br>
-<br>
-  length = inst_size;<br>
-  return true;<br>
-}<br>
-<br>
-bool AssemblyParse_x86::get_non_<wbr>call_site_unwind_plan(<wbr>UnwindPlan &unwind_plan) {<br>
-  UnwindPlan::RowSP row(new UnwindPlan::Row);<br>
-  m_cur_insn = m_func_bounds.GetBaseAddress()<wbr>;<br>
-  addr_t current_func_text_offset = 0;<br>
-  int current_sp_bytes_offset_from_<wbr>cfa = 0;<br>
-  UnwindPlan::Row::<wbr>RegisterLocation initial_regloc;<br>
-  Error error;<br>
-<br>
-  if (!m_cur_insn.IsValid()) {<br>
+  ProcessSP process_sp(thread.GetProcess()<wbr>);<br>
+  if (process_sp.get() == nullptr)<br>
     return false;<br>
-  }<br>
-<br>
-  unwind_plan.<wbr>SetPlanValidAddressRange(m_<wbr>func_bounds);<br>
-  unwind_plan.SetRegisterKind(<wbr>eRegisterKindLLDB);<br>
-<br>
-  // At the start of the function, find the CFA by adding wordsize to the SP<br>
-  // register<br>
-  row->SetOffset(current_func_<wbr>text_offset);<br>
-  row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(m_<wbr>lldb_sp_regnum, m_wordsize);<br>
-<br>
-  // caller's stack pointer value before the call insn is the CFA address<br>
-  initial_regloc.<wbr>SetIsCFAPlusOffset(0);<br>
-  row->SetRegisterInfo(m_lldb_<wbr>sp_regnum, initial_regloc);<br>
-<br>
-  // saved instruction pointer can be found at CFA - wordsize.<br>
-  current_sp_bytes_offset_from_<wbr>cfa = m_wordsize;<br>
-  initial_regloc.<wbr>SetAtCFAPlusOffset(-current_<wbr>sp_bytes_offset_from_cfa);<br>
-  row->SetRegisterInfo(m_lldb_<wbr>ip_regnum, initial_regloc);<br>
-<br>
-  unwind_plan.AppendRow(row);<br>
-<br>
-  // Allocate a new Row, populate it with the existing Row contents.<br>
-  UnwindPlan::Row *newrow = new UnwindPlan::Row;<br>
-  *newrow = *row.get();<br>
-  row.reset(newrow);<br>
-<br>
-  // Track which registers have been saved so far in the prologue.<br>
-  // If we see another push of that register, it's not part of the prologue.<br>
-  // The register numbers used here are the machine register #'s<br>
-  // (i386_register_numbers, x86_64_register_numbers).<br>
-  std::vector<bool> saved_registers(32, false);<br>
-<br>
   const bool prefer_file_cache = true;<br>
-<br>
-  // Once the prologue has completed we'll save a copy of the unwind<br>
-  // instructions<br>
-  // If there is an epilogue in the middle of the function, after that epilogue<br>
-  // we'll reinstate<br>
-  // the unwind setup -- we assume that some code path jumps over the<br>
-  // mid-function epilogue<br>
-<br>
-  UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI<br>
-  int prologue_completed_sp_bytes_<wbr>offset_from_cfa; // The sp value before the<br>
-                                                   // epilogue started executed<br>
-  std::vector<bool> prologue_completed_saved_<wbr>registers;<br>
-<br>
-  Target *target = m_exe_ctx.GetTargetPtr();<br>
-  while (m_func_bounds.<wbr>ContainsFileAddress(m_cur_<wbr>insn)) {<br>
-    int stack_offset, insn_len;<br>
-    int machine_regno;   // register numbers masked directly out of instructions<br>
-    uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB<br>
-                         // numbering scheme<br>
-<br>
-    bool in_epilogue = false; // we're in the middle of an epilogue sequence<br>
-    bool row_updated = false; // The UnwindPlan::Row 'row' has been updated<br>
-<br>
-    if (!instruction_length(m_cur_<wbr>insn, insn_len) || insn_len == 0 ||<br>
-        insn_len > kMaxInstructionByteSize) {<br>
-      // An unrecognized/junk instruction<br>
-      break;<br>
-    }<br>
-<br>
-    if (target->ReadMemory(m_cur_<wbr>insn, prefer_file_cache, m_cur_insn_bytes,<br>
-                           insn_len, error) == static_cast<size_t>(-1)) {<br>
-      // Error reading the instruction out of the file, stop scanning<br>
-      break;<br>
-    }<br>
-<br>
-    if (push_rbp_pattern_p()) {<br>
-      current_sp_bytes_offset_from_<wbr>cfa += m_wordsize;<br>
-      row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-      UnwindPlan::Row::<wbr>RegisterLocation regloc;<br>
-      regloc.SetAtCFAPlusOffset(-<wbr>row->GetCFAValue().GetOffset()<wbr>);<br>
-      row->SetRegisterInfo(m_lldb_<wbr>fp_regnum, regloc);<br>
-      saved_registers[m_machine_fp_<wbr>regnum] = true;<br>
-      row_updated = true;<br>
-    }<br>
-<br>
-    else if (mov_rsp_rbp_pattern_p()) {<br>
-      row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
-          m_lldb_fp_regnum, row->GetCFAValue().GetOffset()<wbr>);<br>
-      row_updated = true;<br>
-    }<br>
-<br>
-    // This is the start() function (or a pthread equivalent), it starts with a<br>
-    // pushl $0x0 which puts the<br>
-    // saved pc value of 0 on the stack.  In this case we want to pretend we<br>
-    // didn't see a stack movement at all --<br>
-    // normally the saved pc value is already on the stack by the time the<br>
-    // function starts executing.<br>
-    else if (push_0_pattern_p()) {<br>
-    }<br>
-<br>
-    else if (push_reg_p(machine_regno)) {<br>
-      current_sp_bytes_offset_from_<wbr>cfa += m_wordsize;<br>
-      // the PUSH instruction has moved the stack pointer - if the CFA is set in<br>
-      // terms of the stack pointer,<br>
-      // we need to add a new row of instructions.<br>
-      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
-        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-        row_updated = true;<br>
-      }<br>
-      // record where non-volatile (callee-saved, spilled) registers are saved<br>
-      // on the stack<br>
-      if (nonvolatile_reg_p(machine_<wbr>regno) &&<br>
-          machine_regno_to_lldb_regno(<wbr>machine_regno, lldb_regno) &&<br>
-          saved_registers[machine_regno] == false) {<br>
-        UnwindPlan::Row::<wbr>RegisterLocation regloc;<br>
-        regloc.SetAtCFAPlusOffset(-<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-        row->SetRegisterInfo(lldb_<wbr>regno, regloc);<br>
-        saved_registers[machine_regno] = true;<br>
-        row_updated = true;<br>
-      }<br>
-    }<br>
-<br>
-    else if (pop_reg_p(machine_regno)) {<br>
-      current_sp_bytes_offset_from_<wbr>cfa -= m_wordsize;<br>
-<br>
-      if (nonvolatile_reg_p(machine_<wbr>regno) &&<br>
-          machine_regno_to_lldb_regno(<wbr>machine_regno, lldb_regno) &&<br>
-          saved_registers[machine_regno] == true) {<br>
-        saved_registers[machine_regno] = false;<br>
-        row->RemoveRegisterInfo(lldb_<wbr>regno);<br>
-<br>
-        if (machine_regno == (int)m_machine_fp_regnum) {<br>
-          row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
-              m_lldb_sp_regnum, row->GetCFAValue().GetOffset()<wbr>);<br>
-        }<br>
-<br>
-        in_epilogue = true;<br>
-        row_updated = true;<br>
-      }<br>
-<br>
-      // the POP instruction has moved the stack pointer - if the CFA is set in<br>
-      // terms of the stack pointer,<br>
-      // we need to add a new row of instructions.<br>
-      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
-        row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
-            m_lldb_sp_regnum, current_sp_bytes_offset_from_<wbr>cfa);<br>
-        row_updated = true;<br>
-      }<br>
-    }<br>
-<br>
-    // The LEAVE instruction moves the value from rbp into rsp and pops<br>
-    // a value off the stack into rbp (restoring the caller's rbp value).<br>
-    // It is the opposite of ENTER, or 'push rbp, mov rsp rbp'.<br>
-    else if (leave_pattern_p()) {<br>
-      // We're going to copy the value in rbp into rsp, so re-set the sp offset<br>
-      // based on the CFAValue.  Also, adjust it to recognize that we're popping<br>
-      // the saved rbp value off the stack.<br>
-      current_sp_bytes_offset_from_<wbr>cfa = row->GetCFAValue().GetOffset()<wbr>;<br>
-      current_sp_bytes_offset_from_<wbr>cfa -= m_wordsize;<br>
-      row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-<br>
-      // rbp is restored to the caller's value<br>
-      saved_registers[m_machine_fp_<wbr>regnum] = false;<br>
-      row->RemoveRegisterInfo(m_<wbr>lldb_fp_regnum);<br>
-<br>
-      // cfa is now in terms of rsp again.<br>
-      row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
-          m_lldb_sp_regnum, row->GetCFAValue().GetOffset()<wbr>);<br>
-      row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-<br>
-      in_epilogue = true;<br>
-      row_updated = true;<br>
-    }<br>
-<br>
-    else if (mov_reg_to_local_stack_frame_<wbr>p(machine_regno, stack_offset) &&<br>
-             nonvolatile_reg_p(machine_<wbr>regno) &&<br>
-             machine_regno_to_lldb_regno(<wbr>machine_regno, lldb_regno) &&<br>
-             saved_registers[machine_regno] == false) {<br>
-      saved_registers[machine_regno] = true;<br>
-<br>
-      UnwindPlan::Row::<wbr>RegisterLocation regloc;<br>
-<br>
-      // stack_offset for 'movq %r15, -80(%rbp)' will be 80.<br>
-      // In the Row, we want to express this as the offset from the CFA.  If the<br>
-      // frame base<br>
-      // is rbp (like the above instruction), the CFA offset for rbp is probably<br>
-      // 16.  So we<br>
-      // want to say that the value is stored at the CFA address - 96.<br>
-      regloc.SetAtCFAPlusOffset(<br>
-          -(stack_offset + row->GetCFAValue().GetOffset()<wbr>));<br>
-<br>
-      row->SetRegisterInfo(lldb_<wbr>regno, regloc);<br>
-<br>
-      row_updated = true;<br>
-    }<br>
-<br>
-    else if (sub_rsp_pattern_p(stack_<wbr>offset)) {<br>
-      current_sp_bytes_offset_from_<wbr>cfa += stack_offset;<br>
-      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
-        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-        row_updated = true;<br>
-      }<br>
-    }<br>
-<br>
-    else if (add_rsp_pattern_p(stack_<wbr>offset)) {<br>
-      current_sp_bytes_offset_from_<wbr>cfa -= stack_offset;<br>
-      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
-        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-        row_updated = true;<br>
-      }<br>
-      in_epilogue = true;<br>
-    }<br>
-<br>
-    else if (lea_rsp_pattern_p(stack_<wbr>offset)) {<br>
-      current_sp_bytes_offset_from_<wbr>cfa -= stack_offset;<br>
-      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
-        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-        row_updated = true;<br>
-      }<br>
-      if (stack_offset > 0)<br>
-        in_epilogue = true;<br>
-    }<br>
-<br>
-    else if (ret_pattern_p() && prologue_completed_row.get()) {<br>
-      // Reinstate the saved prologue setup for any instructions<br>
-      // that come after the ret instruction<br>
-<br>
-      UnwindPlan::Row *newrow = new UnwindPlan::Row;<br>
-      *newrow = *prologue_completed_row.get();<br>
-      row.reset(newrow);<br>
-      current_sp_bytes_offset_from_<wbr>cfa =<br>
-          prologue_completed_sp_bytes_<wbr>offset_from_cfa;<br>
-<br>
-      saved_registers.clear();<br>
-      saved_registers.resize(<wbr>prologue_completed_saved_<wbr>registers.size(), false);<br>
-      for (size_t i = 0; i < prologue_completed_saved_<wbr>registers.size(); ++i) {<br>
-        saved_registers[i] = prologue_completed_saved_<wbr>registers[i];<br>
-      }<br>
-<br>
-      in_epilogue = true;<br>
-      row_updated = true;<br>
-    }<br>
-<br>
-    // call next instruction<br>
-    //     call 0<br>
-    //  => pop  %ebx<br>
-    // This is used in i386 programs to get the PIC base address for finding<br>
-    // global data<br>
-    else if (call_next_insn_pattern_p()) {<br>
-      current_sp_bytes_offset_from_<wbr>cfa += m_wordsize;<br>
-      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
-        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
-        row_updated = true;<br>
-      }<br>
-    }<br>
-<br>
-    if (row_updated) {<br>
-      if (current_func_text_offset + insn_len < m_func_bounds.GetByteSize()) {<br>
-        row->SetOffset(current_func_<wbr>text_offset + insn_len);<br>
-        unwind_plan.AppendRow(row);<br>
-        // Allocate a new Row, populate it with the existing Row contents.<br>
-        newrow = new UnwindPlan::Row;<br>
-        *newrow = *row.get();<br>
-        row.reset(newrow);<br>
-      }<br>
-    }<br>
-<br>
-    if (in_epilogue == false && row_updated) {<br>
-      // If we're not in an epilogue sequence, save the updated Row<br>
-      UnwindPlan::Row *newrow = new UnwindPlan::Row;<br>
-      *newrow = *row.get();<br>
-      prologue_completed_row.reset(<wbr>newrow);<br>
-<br>
-      prologue_completed_saved_<wbr>registers.clear();<br>
-      prologue_completed_saved_<wbr>registers.resize(saved_<wbr>registers.size(), false);<br>
-      for (size_t i = 0; i < saved_registers.size(); ++i) {<br>
-        prologue_completed_saved_<wbr>registers[i] = saved_registers[i];<br>
-      }<br>
-    }<br>
-<br>
-    // We may change the sp value without adding a new Row necessarily -- keep<br>
-    // track of it either way.<br>
-    if (in_epilogue == false) {<br>
-      prologue_completed_sp_bytes_<wbr>offset_from_cfa =<br>
-          current_sp_bytes_offset_from_<wbr>cfa;<br>
-    }<br>
-<br>
-    m_cur_insn.SetOffset(m_cur_<wbr>insn.GetOffset() + insn_len);<br>
-    current_func_text_offset += insn_len;<br>
-  }<br>
-<br>
-  unwind_plan.SetSourceName("<wbr>assembly insn profiling");<br>
-  unwind_plan.<wbr>SetSourcedFromCompiler(<wbr>eLazyBoolNo);<br>
-  unwind_plan.<wbr>SetUnwindPlanValidAtAllInstruc<wbr>tions(eLazyBoolYes);<br>
-<br>
-  return true;<br>
-}<br>
-<br>
-bool AssemblyParse_x86::augment_<wbr>unwind_plan_from_call_site(<br>
-    AddressRange &func, UnwindPlan &unwind_plan) {<br>
-  // Is func address valid?<br>
-  Address addr_start = func.GetBaseAddress();<br>
-  if (!addr_start.IsValid())<br>
-    return false;<br>
-<br>
-  // Is original unwind_plan valid?<br>
-  // unwind_plan should have at least one row which is ABI-default (CFA register<br>
-  // is sp),<br>
-  // and another row in mid-function.<br>
-  if (unwind_plan.GetRowCount() < 2)<br>
-    return false;<br>
-  UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex(0);<br>
-  if (first_row->GetOffset() != 0)<br>
-    return false;<br>
-  uint32_t cfa_reg = m_exe_ctx.GetThreadPtr()<br>
-                         ->GetRegisterContext()<br>
-                         -><wbr>ConvertRegisterKindToRegisterN<wbr>umber(<br>
-                             unwind_plan.GetRegisterKind(),<br>
-                             first_row->GetCFAValue().<wbr>GetRegisterNumber());<br>
-  if (cfa_reg != m_lldb_sp_regnum ||<br>
-      first_row->GetCFAValue().<wbr>GetOffset() != m_wordsize)<br>
-    return false;<br>
-<br>
-  UnwindPlan::RowSP original_last_row = unwind_plan.<wbr>GetRowForFunctionOffset(-1);<br>
-<br>
-  Target *target = m_exe_ctx.GetTargetPtr();<br>
-  m_cur_insn = func.GetBaseAddress();<br>
-  uint64_t offset = 0;<br>
-  int row_id = 1;<br>
-  bool unwind_plan_updated = false;<br>
-  UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));<br>
-<br>
-  // After a mid-function epilogue we will need to re-insert the original unwind<br>
-  // rules<br>
-  // so unwinds work for the remainder of the function.  These aren't common<br>
-  // with clang/gcc<br>
-  // on x86 but it is possible.<br>
-  bool reinstate_unwind_state = false;<br>
-<br>
-  while (func.ContainsFileAddress(m_<wbr>cur_insn)) {<br>
-    int insn_len;<br>
-    if (!instruction_length(m_cur_<wbr>insn, insn_len) || insn_len == 0 ||<br>
-        insn_len > kMaxInstructionByteSize) {<br>
-      // An unrecognized/junk instruction.<br>
-      break;<br>
-    }<br>
-    const bool prefer_file_cache = true;<br>
-    Error error;<br>
-    if (target->ReadMemory(m_cur_<wbr>insn, prefer_file_cache, m_cur_insn_bytes,<br>
-                           insn_len, error) == static_cast<size_t>(-1)) {<br>
-      // Error reading the instruction out of the file, stop scanning.<br>
-      break;<br>
-    }<br>
-<br>
-    // Advance offsets.<br>
-    offset += insn_len;<br>
-    m_cur_insn.SetOffset(m_cur_<wbr>insn.GetOffset() + insn_len);<br>
-<br>
-    if (reinstate_unwind_state) {<br>
-      // that was the last instruction of this function<br>
-      if (func.ContainsFileAddress(m_<wbr>cur_insn) == false)<br>
-        continue;<br>
-<br>
-      UnwindPlan::RowSP new_row(new UnwindPlan::Row());<br>
-      *new_row = *original_last_row;<br>
-      new_row->SetOffset(offset);<br>
-      unwind_plan.AppendRow(new_row)<wbr>;<br>
-      row.reset(new UnwindPlan::Row());<br>
-      *row = *new_row;<br>
-      reinstate_unwind_state = false;<br>
-      unwind_plan_updated = true;<br>
-      continue;<br>
-    }<br>
-<br>
-    // If we already have one row for this instruction, we can continue.<br>
-    while (row_id < unwind_plan.GetRowCount() &&<br>
-           unwind_plan.GetRowAtIndex(row_<wbr>id)->GetOffset() <= offset) {<br>
-      row_id++;<br>
-    }<br>
-    UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex(row_<wbr>id - 1);<br>
-    if (original_row->GetOffset() == offset) {<br>
-      *row = *original_row;<br>
-      continue;<br>
-    }<br>
-<br>
-    if (row_id == 0) {<br>
-      // If we are here, compiler didn't generate CFI for prologue.<br>
-      // This won't happen to GCC or clang.<br>
-      // In this case, bail out directly.<br>
-      return false;<br>
-    }<br>
-<br>
-    // Inspect the instruction to check if we need a new row for it.<br>
-    cfa_reg = m_exe_ctx.GetThreadPtr()<br>
-                  ->GetRegisterContext()<br>
-                  -><wbr>ConvertRegisterKindToRegisterN<wbr>umber(<br>
-                      unwind_plan.GetRegisterKind(),<br>
-                      row->GetCFAValue().<wbr>GetRegisterNumber());<br>
-    if (cfa_reg == m_lldb_sp_regnum) {<br>
-      // CFA register is sp.<br>
-<br>
-      // call next instruction<br>
-      //     call 0<br>
-      //  => pop  %ebx<br>
-      if (call_next_insn_pattern_p()) {<br>
-        row->SetOffset(offset);<br>
-        row->GetCFAValue().IncOffset(<wbr>m_wordsize);<br>
-<br>
-        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
-        unwind_plan.InsertRow(new_row)<wbr>;<br>
-        unwind_plan_updated = true;<br>
-        continue;<br>
-      }<br>
-<br>
-      // push/pop register<br>
-      int regno;<br>
-      if (push_reg_p(regno)) {<br>
-        row->SetOffset(offset);<br>
-        row->GetCFAValue().IncOffset(<wbr>m_wordsize);<br>
-<br>
-        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
-        unwind_plan.InsertRow(new_row)<wbr>;<br>
-        unwind_plan_updated = true;<br>
-        continue;<br>
-      }<br>
-      if (pop_reg_p(regno)) {<br>
-        // Technically, this might be a nonvolatile register recover in<br>
-        // epilogue.<br>
-        // We should reset RegisterInfo for the register.<br>
-        // But in practice, previous rule for the register is still valid...<br>
-        // So we ignore this case.<br>
-<br>
-        row->SetOffset(offset);<br>
-        row->GetCFAValue().IncOffset(-<wbr>m_wordsize);<br>
-<br>
-        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
-        unwind_plan.InsertRow(new_row)<wbr>;<br>
-        unwind_plan_updated = true;<br>
-        continue;<br>
-      }<br>
-<br>
-      // push imm<br>
-      if (push_imm_pattern_p()) {<br>
-        row->SetOffset(offset);<br>
-        row->GetCFAValue().IncOffset(<wbr>m_wordsize);<br>
-        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
-        unwind_plan.InsertRow(new_row)<wbr>;<br>
-        unwind_plan_updated = true;<br>
-        continue;<br>
-      }<br>
-<br>
-      // add/sub %rsp/%esp<br>
-      int amount;<br>
-      if (add_rsp_pattern_p(amount)) {<br>
-        row->SetOffset(offset);<br>
-        row->GetCFAValue().IncOffset(-<wbr>amount);<br>
-<br>
-        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
-        unwind_plan.InsertRow(new_row)<wbr>;<br>
-        unwind_plan_updated = true;<br>
-        continue;<br>
-      }<br>
-      if (sub_rsp_pattern_p(amount)) {<br>
-        row->SetOffset(offset);<br>
-        row->GetCFAValue().IncOffset(<wbr>amount);<br>
-<br>
-        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
-        unwind_plan.InsertRow(new_row)<wbr>;<br>
-        unwind_plan_updated = true;<br>
-        continue;<br>
-      }<br>
-<br>
-      // lea %rsp, [%rsp + $offset]<br>
-      if (lea_rsp_pattern_p(amount)) {<br>
-        row->SetOffset(offset);<br>
-        row->GetCFAValue().IncOffset(-<wbr>amount);<br>
-<br>
-        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
-        unwind_plan.InsertRow(new_row)<wbr>;<br>
-        unwind_plan_updated = true;<br>
-        continue;<br>
-      }<br>
-<br>
-      if (ret_pattern_p()) {<br>
-        reinstate_unwind_state = true;<br>
-        continue;<br>
-      }<br>
-    } else if (cfa_reg == m_lldb_fp_regnum) {<br>
-      // CFA register is fp.<br>
-<br>
-      // The only case we care about is epilogue:<br>
-      //     [0x5d] pop %rbp/%ebp<br>
-      //  => [0xc3] ret<br>
-      if (pop_rbp_pattern_p() || leave_pattern_p()) {<br>
-        if (target->ReadMemory(m_cur_<wbr>insn, prefer_file_cache, m_cur_insn_bytes,<br>
-                               1, error) != static_cast<size_t>(-1) &&<br>
-            ret_pattern_p()) {<br>
-          row->SetOffset(offset);<br>
-          row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
-              first_row->GetCFAValue().<wbr>GetRegisterNumber(), m_wordsize);<br>
-<br>
-          UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
-          unwind_plan.InsertRow(new_row)<wbr>;<br>
-          unwind_plan_updated = true;<br>
-          reinstate_unwind_state = true;<br>
-          continue;<br>
-        }<br>
-      }<br>
-    } else {<br>
-      // CFA register is not sp or fp.<br>
-<br>
-      // This must be hand-written assembly.<br>
-      // Just trust eh_frame and assume we have finished.<br>
-      break;<br>
-    }<br>
-  }<br>
-<br>
-  unwind_plan.<wbr>SetPlanValidAddressRange(func)<wbr>;<br>
-  if (unwind_plan_updated) {<br>
-    std::string unwind_plan_source(unwind_<wbr>plan.GetSourceName().<wbr>AsCString());<br>
-    unwind_plan_source += " plus augmentation from assembly parsing";<br>
-    unwind_plan.SetSourceName(<wbr>unwind_plan_source.c_str());<br>
-    unwind_plan.<wbr>SetSourcedFromCompiler(<wbr>eLazyBoolNo);<br>
-    unwind_plan.<wbr>SetUnwindPlanValidAtAllInstruc<wbr>tions(eLazyBoolYes);<br>
-  }<br>
-  return true;<br>
-}<br>
-<br>
-/* The "fast unwind plan" is valid for functions that follow the usual<br>
-   convention of<br>
-   using the frame pointer register (ebp, rbp), i.e. the function prologue looks<br>
-   like<br>
-     push   %rbp      [0x55]<br>
-     mov    %rsp,%rbp [0x48 0x89 0xe5]   (this is a 2-byte insn seq on i386)<br>
-*/<br>
-<br>
-bool AssemblyParse_x86::get_fast_<wbr>unwind_plan(AddressRange &func,<br>
-                                             UnwindPlan &unwind_plan) {<br>
-  UnwindPlan::RowSP row(new UnwindPlan::Row);<br>
-  UnwindPlan::Row::<wbr>RegisterLocation pc_reginfo;<br>
-  UnwindPlan::Row::<wbr>RegisterLocation sp_reginfo;<br>
-  UnwindPlan::Row::<wbr>RegisterLocation fp_reginfo;<br>
-  unwind_plan.SetRegisterKind(<wbr>eRegisterKindLLDB);<br>
-<br>
-  if (!func.GetBaseAddress().<wbr>IsValid())<br>
-    return false;<br>
-<br>
-  Target *target = m_exe_ctx.GetTargetPtr();<br>
-<br>
-  uint8_t bytebuf[4];<br>
+  std::vector<uint8_t> function_text(func.<wbr>GetByteSize());<br>
   Error error;<br>
-  const bool prefer_file_cache = true;<br>
-  if (target->ReadMemory(func.<wbr>GetBaseAddress(), prefer_file_cache, bytebuf,<br>
-                         sizeof(bytebuf), error) == static_cast<size_t>(-1))<br>
-    return false;<br>
-<br>
-  uint8_t i386_prologue[] = {0x55, 0x89, 0xe5};<br>
-  uint8_t x86_64_prologue[] = {0x55, 0x48, 0x89, 0xe5};<br>
-  int prologue_size;<br>
-<br>
-  if (memcmp(bytebuf, i386_prologue, sizeof(i386_prologue)) == 0) {<br>
-    prologue_size = sizeof(i386_prologue);<br>
-  } else if (memcmp(bytebuf, x86_64_prologue, sizeof(x86_64_prologue)) == 0) {<br>
-    prologue_size = sizeof(x86_64_prologue);<br>
-  } else {<br>
-    return false;<br>
-  }<br>
-<br>
-  pc_reginfo.SetAtCFAPlusOffset(<wbr>-m_wordsize);<br>
-  row->SetRegisterInfo(m_lldb_<wbr>ip_regnum, pc_reginfo);<br>
-<br>
-  sp_reginfo.SetIsCFAPlusOffset(<wbr>0);<br>
-  row->SetRegisterInfo(m_lldb_<wbr>sp_regnum, sp_reginfo);<br>
-<br>
-  // Zero instructions into the function<br>
-  row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(m_<wbr>lldb_sp_regnum, m_wordsize);<br>
-  row->SetOffset(0);<br>
-  unwind_plan.AppendRow(row);<br>
-  UnwindPlan::Row *newrow = new UnwindPlan::Row;<br>
-  *newrow = *row.get();<br>
-  row.reset(newrow);<br>
-<br>
-  // push %rbp has executed - stack moved, rbp now saved<br>
-  row->GetCFAValue().IncOffset(<wbr>m_wordsize);<br>
-  fp_reginfo.SetAtCFAPlusOffset(<wbr>2 * -m_wordsize);<br>
-  row->SetRegisterInfo(m_lldb_<wbr>fp_regnum, fp_reginfo);<br>
-  row->SetOffset(1);<br>
-  unwind_plan.AppendRow(row);<br>
-<br>
-  newrow = new UnwindPlan::Row;<br>
-  *newrow = *row.get();<br>
-  row.reset(newrow);<br>
-<br>
-  // mov %rsp, %rbp has executed<br>
-  row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(m_<wbr>lldb_fp_regnum, 2 * m_wordsize);<br>
-  row->SetOffset(prologue_size); /// 3 or 4 bytes depending on arch<br>
-  unwind_plan.AppendRow(row);<br>
-<br>
-  newrow = new UnwindPlan::Row;<br>
-  *newrow = *row.get();<br>
-  row.reset(newrow);<br>
-<br>
-  unwind_plan.<wbr>SetPlanValidAddressRange(func)<wbr>;<br>
-  unwind_plan.SetSourceName("<wbr>fast unwind assembly profiling");<br>
-  unwind_plan.<wbr>SetSourcedFromCompiler(<wbr>eLazyBoolNo);<br>
-  unwind_plan.<wbr>SetUnwindPlanValidAtAllInstruc<wbr>tions(eLazyBoolNo);<br>
-  return true;<br>
-}<br>
-<br>
-bool AssemblyParse_x86::find_first_<wbr>non_prologue_insn(Address &address) {<br>
-  m_cur_insn = m_func_bounds.GetBaseAddress()<wbr>;<br>
-  if (!m_cur_insn.IsValid()) {<br>
-    return false;<br>
+  if (process_sp->GetTarget().<wbr>ReadMemory(<br>
+          func.GetBaseAddress(), prefer_file_cache, function_text.data(),<br>
+          func.GetByteSize(), error) == func.GetByteSize()) {<br>
+    RegisterContextSP reg_ctx(thread.<wbr>GetRegisterContext());<br>
+    m_assembly_inspection_engine-><wbr>Initialize(reg_ctx);<br>
+    return m_assembly_inspection_engine-><wbr>GetNonCallSiteUnwindPlanFromAs<wbr>sembly(<br>
+        function_text.data(), func.GetByteSize(), func, unwind_plan);<br>
   }<br>
-<br>
-  const bool prefer_file_cache = true;<br>
-  Target *target = m_exe_ctx.GetTargetPtr();<br>
-  while (m_func_bounds.<wbr>ContainsFileAddress(m_cur_<wbr>insn)) {<br>
-    Error error;<br>
-    int insn_len, offset, regno;<br>
-    if (!instruction_length(m_cur_<wbr>insn, insn_len) ||<br>
-        insn_len > kMaxInstructionByteSize || insn_len == 0) {<br>
-      // An error parsing the instruction, i.e. probably data/garbage - stop<br>
-      // scanning<br>
-      break;<br>
-    }<br>
-    if (target->ReadMemory(m_cur_<wbr>insn, prefer_file_cache, m_cur_insn_bytes,<br>
-                           insn_len, error) == static_cast<size_t>(-1)) {<br>
-      // Error reading the instruction out of the file, stop scanning<br>
-      break;<br>
-    }<br>
-<br>
-    if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() ||<br>
-        sub_rsp_pattern_p(offset) || push_reg_p(regno) ||<br>
-        mov_reg_to_local_stack_frame_<wbr>p(regno, offset) ||<br>
-        (lea_rsp_pattern_p(offset) && offset < 0)) {<br>
-      m_cur_insn.SetOffset(m_cur_<wbr>insn.GetOffset() + insn_len);<br>
-      continue;<br>
-    }<br>
-<br>
-    // Unknown non-prologue instruction - stop scanning<br>
-    break;<br>
-  }<br>
-<br>
-  address = m_cur_insn;<br>
-  return true;<br>
-}<br>
-<br>
-//---------------------------<wbr>------------------------------<wbr>------------------------------<wbr>--------<br>
-//  UnwindAssemblyParser_x86 method definitions<br>
-//---------------------------<wbr>------------------------------<wbr>------------------------------<wbr>--------<br>
-<br>
-UnwindAssembly_x86::<wbr>UnwindAssembly_x86(const ArchSpec &arch, int cpu)<br>
-    : lldb_private::UnwindAssembly(<wbr>arch), m_cpu(cpu), m_arch(arch) {}<br>
-<br>
-UnwindAssembly_x86::~<wbr>UnwindAssembly_x86() {}<br>
-<br>
-bool UnwindAssembly_x86::<wbr>GetNonCallSiteUnwindPlanFromAs<wbr>sembly(<br>
-    AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {<br>
-  ExecutionContext exe_ctx(thread.shared_from_<wbr>this());<br>
-  AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);<br>
-  return asm_parse.get_non_call_site_<wbr>unwind_plan(unwind_plan);<br>
+  return false;<br>
 }<br>
<br>
 bool UnwindAssembly_x86::<wbr>AugmentUnwindPlanFromCallSite(<br>
@@ -1235,9 +75,10 @@ bool UnwindAssembly_x86::<wbr>AugmentUnwindPl<br>
<br>
   int wordsize = 8;<br>
   ProcessSP process_sp(thread.GetProcess()<wbr>);<br>
-  if (process_sp) {<br>
-    wordsize = process_sp->GetTarget().<wbr>GetArchitecture().<wbr>GetAddressByteSize();<br>
-  }<br>
+  if (process_sp.get() == nullptr)<br>
+    return false;<br>
+<br>
+  wordsize = process_sp->GetTarget().<wbr>GetArchitecture().<wbr>GetAddressByteSize();<br>
<br>
   RegisterNumber sp_regnum(thread, eRegisterKindGeneric,<br>
                            LLDB_REGNUM_GENERIC_SP);<br>
@@ -1314,9 +155,21 @@ bool UnwindAssembly_x86::<wbr>AugmentUnwindPl<br>
   }<br>
<br>
   if (do_augment_unwindplan) {<br>
-    ExecutionContext exe_ctx(thread.shared_from_<wbr>this());<br>
-    AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);<br>
-    return asm_parse.augment_unwind_plan_<wbr>from_call_site(func, unwind_plan);<br>
+    if (!func.GetBaseAddress().<wbr>IsValid() || func.GetByteSize() == 0)<br>
+      return false;<br>
+    if (m_assembly_inspection_engine == nullptr)<br>
+      return false;<br>
+    const bool prefer_file_cache = true;<br>
+    std::vector<uint8_t> function_text(func.<wbr>GetByteSize());<br>
+    Error error;<br>
+    if (process_sp->GetTarget().<wbr>ReadMemory(<br>
+            func.GetBaseAddress(), prefer_file_cache, function_text.data(),<br>
+            func.GetByteSize(), error) == func.GetByteSize()) {<br>
+      RegisterContextSP reg_ctx(thread.<wbr>GetRegisterContext());<br>
+      m_assembly_inspection_engine-><wbr>Initialize(reg_ctx);<br>
+      return m_assembly_inspection_engine-><wbr>AugmentUnwindPlanFromCallSite(<br>
+          function_text.data(), func.GetByteSize(), func, unwind_plan, reg_ctx);<br>
+    }<br>
   }<br>
<br>
   return false;<br>
@@ -1362,16 +215,38 @@ bool UnwindAssembly_x86::<wbr>GetFastUnwindPl<br>
 bool UnwindAssembly_x86::<wbr>FirstNonPrologueInsn(<br>
     AddressRange &func, const ExecutionContext &exe_ctx,<br>
     Address &first_non_prologue_insn) {<br>
-  AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);<br>
-  return asm_parse.find_first_non_<wbr>prologue_insn(first_non_<wbr>prologue_insn);<br>
+<br>
+  if (!func.GetBaseAddress().<wbr>IsValid())<br>
+    return false;<br>
+<br>
+  Target *target = exe_ctx.GetTargetPtr();<br>
+  if (target == nullptr)<br>
+    return false;<br>
+<br>
+  if (m_assembly_inspection_engine == nullptr)<br>
+    return false;<br>
+<br>
+  const bool prefer_file_cache = true;<br>
+  std::vector<uint8_t> function_text(func.<wbr>GetByteSize());<br>
+  Error error;<br>
+  if (target->ReadMemory(func.<wbr>GetBaseAddress(), prefer_file_cache,<br>
+                         function_text.data(), func.GetByteSize(),<br>
+                         error) == func.GetByteSize()) {<br>
+    size_t offset;<br>
+    if (m_assembly_inspection_engine-<wbr>><wbr>FindFirstNonPrologueInstructio<wbr>n(<br>
+            function_text.data(), func.GetByteSize(), offset)) {<br>
+      first_non_prologue_insn = func.GetBaseAddress();<br>
+      first_non_prologue_insn.Slide(<wbr>offset);<br>
+    }<br>
+    return true;<br>
+  }<br>
+  return false;<br>
 }<br>
<br>
 UnwindAssembly *UnwindAssembly_x86::<wbr>CreateInstance(const ArchSpec &arch) {<br>
   const llvm::Triple::ArchType cpu = arch.GetMachine();<br>
-  if (cpu == llvm::Triple::x86)<br>
-    return new UnwindAssembly_x86(arch, k_i386);<br>
-  else if (cpu == llvm::Triple::x86_64)<br>
-    return new UnwindAssembly_x86(arch, k_x86_64);<br>
+  if (cpu == llvm::Triple::x86 || cpu == llvm::Triple::x86_64)<br>
+    return new UnwindAssembly_x86(arch);<br>
   return NULL;<br>
 }<br>
<br>
<br>
Modified: lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>UnwindAssembly-x86.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h?rev=282565&r1=282564&r2=282565&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lldb/trunk/source/<wbr>Plugins/UnwindAssembly/x86/<wbr>UnwindAssembly-x86.h?rev=<wbr>282565&r1=282564&r2=282565&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>UnwindAssembly-x86.h (original)<br>
+++ lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>UnwindAssembly-x86.h Tue Sep 27 21:52:19 2016<br>
@@ -13,7 +13,7 @@<br>
 // C Includes<br>
 // C++ Includes<br>
 // Other libraries and framework includes<br>
-#include "llvm-c/Disassembler.h"<br>
+#include "x86AssemblyInspectionEngine.<wbr>h"<br>
<br>
 // Project includes<br>
 #include "lldb/Target/UnwindAssembly.h"<br>
@@ -62,10 +62,11 @@ public:<br>
   uint32_t GetPluginVersion() override;<br>
<br>
 private:<br>
-  UnwindAssembly_x86(const lldb_private::ArchSpec &arch, int cpu);<br>
+  UnwindAssembly_x86(const lldb_private::ArchSpec &arch);<br>
<br>
-  int m_cpu;<br>
   lldb_private::ArchSpec m_arch;<br>
+<br>
+  lldb_private::<wbr>x86AssemblyInspectionEngine *m_assembly_inspection_engine;<br>
 };<br>
<br>
 #endif // liblldb_UnwindAssembly_x86_h_<br>
<br>
Added: lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp?rev=282565&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lldb/trunk/source/<wbr>Plugins/UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.<wbr>cpp?rev=282565&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.<wbr>cpp (added)<br>
+++ lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.<wbr>cpp Tue Sep 27 21:52:19 2016<br>
@@ -0,0 +1,1117 @@<br>
+//===-- x86AssemblyInspectionEngine.<wbr>cpp -------------------------*- C++ -*-===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#include "x86AssemblyInspectionEngine.<wbr>h"<br>
+<br>
+#include "llvm-c/Disassembler.h"<br>
+<br>
+#include "lldb/Core/Address.h"<br>
+#include "lldb/Symbol/UnwindPlan.h"<br>
+#include "lldb/Target/RegisterContext.<wbr>h"<br>
+#include "lldb/Target/UnwindAssembly.h"<br>
+<br>
+using namespace lldb_private;<br>
+using namespace lldb;<br>
+<br>
+x86AssemblyInspectionEngine::<wbr>x86AssemblyInspectionEngine(<wbr>const ArchSpec &arch)<br>
+    : m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_<wbr>INVALID_REGNUM),<br>
+      m_machine_sp_regnum(LLDB_<wbr>INVALID_REGNUM),<br>
+      m_machine_fp_regnum(LLDB_<wbr>INVALID_REGNUM),<br>
+      m_lldb_ip_regnum(LLDB_INVALID_<wbr>REGNUM),<br>
+      m_lldb_sp_regnum(LLDB_INVALID_<wbr>REGNUM),<br>
+      m_lldb_fp_regnum(LLDB_INVALID_<wbr>REGNUM),<br>
+<br>
+      m_reg_map(), m_arch(arch), m_cpu(k_cpu_unspecified), m_wordsize(-1),<br>
+      m_register_map_initialized(<wbr>false), m_disasm_context() {<br>
+  m_disasm_context = ::LLVMCreateDisasm("x86_64-<wbr>apple-macosx", nullptr,<br>
+                                        /*TagType=*/1, nullptr, nullptr);<br>
+  //      ::LLVMCreateDisasm(arch.<wbr>GetTriple().getTriple().c_str(<wbr>), nullptr,<br>
+  //                         /*TagType=*/1, nullptr, nullptr);<br>
+}<br>
+<br>
+x86AssemblyInspectionEngine::<wbr>~x86AssemblyInspectionEngine() {<br>
+  ::LLVMDisasmDispose(m_disasm_<wbr>context);<br>
+}<br>
+<br>
+void x86AssemblyInspectionEngine::<wbr>Initialize(RegisterContextSP &reg_ctx) {<br>
+  m_cpu = k_cpu_unspecified;<br>
+  m_wordsize = -1;<br>
+  m_register_map_initialized = false;<br>
+<br>
+  const llvm::Triple::ArchType cpu = m_arch.GetMachine();<br>
+  if (cpu == llvm::Triple::x86)<br>
+    m_cpu = k_i386;<br>
+  else if (cpu == llvm::Triple::x86_64)<br>
+    m_cpu = k_x86_64;<br>
+<br>
+  if (m_cpu == k_cpu_unspecified)<br>
+    return;<br>
+<br>
+  if (reg_ctx.get() == nullptr)<br>
+    return;<br>
+<br>
+  if (m_cpu == k_i386) {<br>
+    m_machine_ip_regnum = k_machine_eip;<br>
+    m_machine_sp_regnum = k_machine_esp;<br>
+    m_machine_fp_regnum = k_machine_ebp;<br>
+    m_wordsize = 4;<br>
+<br>
+    struct lldb_reg_info reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "eax";<br>
+    m_reg_map[k_machine_eax] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "edx";<br>
+    m_reg_map[k_machine_edx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "esp";<br>
+    m_reg_map[k_machine_esp] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "esi";<br>
+    m_reg_map[k_machine_esi] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "eip";<br>
+    m_reg_map[k_machine_eip] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "ecx";<br>
+    m_reg_map[k_machine_ecx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "ebx";<br>
+    m_reg_map[k_machine_ebx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "ebp";<br>
+    m_reg_map[k_machine_ebp] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "edi";<br>
+    m_reg_map[k_machine_edi] = reginfo;<br>
+  } else {<br>
+    m_machine_ip_regnum = k_machine_rip;<br>
+    m_machine_sp_regnum = k_machine_rsp;<br>
+    m_machine_fp_regnum = k_machine_rbp;<br>
+    m_wordsize = 8;<br>
+<br>
+    struct lldb_reg_info reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rax";<br>
+    m_reg_map[k_machine_rax] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rdx";<br>
+    m_reg_map[k_machine_rdx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rsp";<br>
+    m_reg_map[k_machine_rsp] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rsi";<br>
+    m_reg_map[k_machine_rsi] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r8";<br>
+    m_reg_map[k_machine_r8] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r10";<br>
+    m_reg_map[k_machine_r10] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r12";<br>
+    m_reg_map[k_machine_r12] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r14";<br>
+    m_reg_map[k_machine_r14] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rip";<br>
+    m_reg_map[k_machine_rip] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rcx";<br>
+    m_reg_map[k_machine_rcx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rbx";<br>
+    m_reg_map[k_machine_rbx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rbp";<br>
+    m_reg_map[k_machine_rbp] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rdi";<br>
+    m_reg_map[k_machine_rdi] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r9";<br>
+    m_reg_map[k_machine_r9] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r11";<br>
+    m_reg_map[k_machine_r11] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r13";<br>
+    m_reg_map[k_machine_r13] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r15";<br>
+    m_reg_map[k_machine_r15] = reginfo;<br>
+  }<br>
+<br>
+  for (<wbr>MachineRegnumToNameAndLLDBRegn<wbr>um::iterator it = m_reg_map.begin();<br>
+       it != m_reg_map.end(); ++it) {<br>
+    const RegisterInfo *ri = reg_ctx-><wbr>GetRegisterInfoByName(it-><a href="http://second.name" rel="noreferrer" target="_blank">seco<wbr>nd.name</a>);<br>
+    if (ri)<br>
+      it->second.lldb_regnum = ri->kinds[eRegisterKindLLDB];<br>
+  }<br>
+<br>
+  uint32_t lldb_regno;<br>
+  if (machine_regno_to_lldb_regno(<wbr>m_machine_sp_regnum, lldb_regno))<br>
+    m_lldb_sp_regnum = lldb_regno;<br>
+  if (machine_regno_to_lldb_regno(<wbr>m_machine_fp_regnum, lldb_regno))<br>
+    m_lldb_fp_regnum = lldb_regno;<br>
+  if (machine_regno_to_lldb_regno(<wbr>m_machine_ip_regnum, lldb_regno))<br>
+    m_lldb_ip_regnum = lldb_regno;<br>
+<br>
+  m_register_map_initialized = true;<br>
+}<br>
+<br>
+void x86AssemblyInspectionEngine::<wbr>Initialize(<br>
+    std::vector<lldb_reg_info> &reg_info) {<br>
+  m_cpu = k_cpu_unspecified;<br>
+  m_wordsize = -1;<br>
+  m_register_map_initialized = false;<br>
+<br>
+  const llvm::Triple::ArchType cpu = m_arch.GetMachine();<br>
+  if (cpu == llvm::Triple::x86)<br>
+    m_cpu = k_i386;<br>
+  else if (cpu == llvm::Triple::x86_64)<br>
+    m_cpu = k_x86_64;<br>
+<br>
+  if (m_cpu == k_cpu_unspecified)<br>
+    return;<br>
+<br>
+  if (m_cpu == k_i386) {<br>
+    m_machine_ip_regnum = k_machine_eip;<br>
+    m_machine_sp_regnum = k_machine_esp;<br>
+    m_machine_fp_regnum = k_machine_ebp;<br>
+    m_wordsize = 4;<br>
+<br>
+    struct lldb_reg_info reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "eax";<br>
+    m_reg_map[k_machine_eax] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "edx";<br>
+    m_reg_map[k_machine_edx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "esp";<br>
+    m_reg_map[k_machine_esp] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "esi";<br>
+    m_reg_map[k_machine_esi] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "eip";<br>
+    m_reg_map[k_machine_eip] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "ecx";<br>
+    m_reg_map[k_machine_ecx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "ebx";<br>
+    m_reg_map[k_machine_ebx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "ebp";<br>
+    m_reg_map[k_machine_ebp] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "edi";<br>
+    m_reg_map[k_machine_edi] = reginfo;<br>
+  } else {<br>
+    m_machine_ip_regnum = k_machine_rip;<br>
+    m_machine_sp_regnum = k_machine_rsp;<br>
+    m_machine_fp_regnum = k_machine_rbp;<br>
+    m_wordsize = 8;<br>
+<br>
+    struct lldb_reg_info reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rax";<br>
+    m_reg_map[k_machine_rax] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rdx";<br>
+    m_reg_map[k_machine_rdx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rsp";<br>
+    m_reg_map[k_machine_rsp] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rsi";<br>
+    m_reg_map[k_machine_rsi] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r8";<br>
+    m_reg_map[k_machine_r8] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r10";<br>
+    m_reg_map[k_machine_r10] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r12";<br>
+    m_reg_map[k_machine_r12] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r14";<br>
+    m_reg_map[k_machine_r14] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rip";<br>
+    m_reg_map[k_machine_rip] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rcx";<br>
+    m_reg_map[k_machine_rcx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rbx";<br>
+    m_reg_map[k_machine_rbx] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rbp";<br>
+    m_reg_map[k_machine_rbp] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "rdi";<br>
+    m_reg_map[k_machine_rdi] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r9";<br>
+    m_reg_map[k_machine_r9] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r11";<br>
+    m_reg_map[k_machine_r11] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r13";<br>
+    m_reg_map[k_machine_r13] = reginfo;<br>
+    <a href="http://reginfo.name" rel="noreferrer" target="_blank">reginfo.name</a> = "r15";<br>
+    m_reg_map[k_machine_r15] = reginfo;<br>
+  }<br>
+<br>
+  for (<wbr>MachineRegnumToNameAndLLDBRegn<wbr>um::iterator it = m_reg_map.begin();<br>
+       it != m_reg_map.end(); ++it) {<br>
+    for (size_t i = 0; i < reg_info.size(); ++i) {<br>
+      if (::strcmp(reg_info[i].name, it-><a href="http://second.name" rel="noreferrer" target="_blank">second.name</a>) == 0) {<br>
+        it->second.lldb_regnum = reg_info[i].lldb_regnum;<br>
+        break;<br>
+      }<br>
+    }<br>
+  }<br>
+<br>
+  uint32_t lldb_regno;<br>
+  if (machine_regno_to_lldb_regno(<wbr>m_machine_sp_regnum, lldb_regno))<br>
+    m_lldb_sp_regnum = lldb_regno;<br>
+  if (machine_regno_to_lldb_regno(<wbr>m_machine_fp_regnum, lldb_regno))<br>
+    m_lldb_fp_regnum = lldb_regno;<br>
+  if (machine_regno_to_lldb_regno(<wbr>m_machine_ip_regnum, lldb_regno))<br>
+    m_lldb_ip_regnum = lldb_regno;<br>
+<br>
+  m_register_map_initialized = true;<br>
+}<br>
+<br>
+// This function expects an x86 native register number (i.e. the bits stripped<br>
+// out of the<br>
+// actual instruction), not an lldb register number.<br>
+//<br>
+// FIXME: This is ABI dependent, it shouldn't be hardcoded here.<br>
+<br>
+bool x86AssemblyInspectionEngine::<wbr>nonvolatile_reg_p(int machine_regno) {<br>
+  if (m_cpu == k_i386) {<br>
+    switch (machine_regno) {<br>
+    case k_machine_ebx:<br>
+    case k_machine_ebp: // not actually a nonvolatile but often treated as such<br>
+                        // by convention<br>
+    case k_machine_esi:<br>
+    case k_machine_edi:<br>
+    case k_machine_esp:<br>
+      return true;<br>
+    default:<br>
+      return false;<br>
+    }<br>
+  }<br>
+  if (m_cpu == k_x86_64) {<br>
+    switch (machine_regno) {<br>
+    case k_machine_rbx:<br>
+    case k_machine_rsp:<br>
+    case k_machine_rbp: // not actually a nonvolatile but often treated as such<br>
+                        // by convention<br>
+    case k_machine_r12:<br>
+    case k_machine_r13:<br>
+    case k_machine_r14:<br>
+    case k_machine_r15:<br>
+      return true;<br>
+    default:<br>
+      return false;<br>
+    }<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+// Macro to detect if this is a REX mode prefix byte.<br>
+#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)<br>
+<br>
+// The high bit which should be added to the source register number (the "R"<br>
+// bit)<br>
+#define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2)<br>
+<br>
+// The high bit which should be added to the destination register number (the<br>
+// "B" bit)<br>
+#define REX_W_DSTREG(opcode) ((opcode)&0x1)<br>
+<br>
+// pushq %rbp [0x55]<br>
+bool x86AssemblyInspectionEngine::<wbr>push_rbp_pattern_p() {<br>
+  uint8_t *p = m_cur_insn;<br>
+  if (*p == 0x55)<br>
+    return true;<br>
+  return false;<br>
+}<br>
+<br>
+// pushq $0 ; the first instruction in start() [0x6a 0x00]<br>
+bool x86AssemblyInspectionEngine::<wbr>push_0_pattern_p() {<br>
+  uint8_t *p = m_cur_insn;<br>
+  if (*p == 0x6a && *(p + 1) == 0x0)<br>
+    return true;<br>
+  return false;<br>
+}<br>
+<br>
+// pushq $0<br>
+// pushl $0<br>
+bool x86AssemblyInspectionEngine::<wbr>push_imm_pattern_p() {<br>
+  uint8_t *p = m_cur_insn;<br>
+  if (*p == 0x68 || *p == 0x6a)<br>
+    return true;<br>
+  return false;<br>
+}<br>
+<br>
+// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]<br>
+// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]<br>
+bool x86AssemblyInspectionEngine::<wbr>mov_rsp_rbp_pattern_p() {<br>
+  uint8_t *p = m_cur_insn;<br>
+  if (m_wordsize == 8 && *p == 0x48)<br>
+    p++;<br>
+  if (*(p) == 0x8b && *(p + 1) == 0xec)<br>
+    return true;<br>
+  if (*(p) == 0x89 && *(p + 1) == 0xe5)<br>
+    return true;<br>
+  return false;<br>
+}<br>
+<br>
+// subq $0x20, %rsp<br>
+bool x86AssemblyInspectionEngine::<wbr>sub_rsp_pattern_p(int &amount) {<br>
+  uint8_t *p = m_cur_insn;<br>
+  if (m_wordsize == 8 && *p == 0x48)<br>
+    p++;<br>
+  // 8-bit immediate operand<br>
+  if (*p == 0x83 && *(p + 1) == 0xec) {<br>
+    amount = (int8_t) * (p + 2);<br>
+    return true;<br>
+  }<br>
+  // 32-bit immediate operand<br>
+  if (*p == 0x81 && *(p + 1) == 0xec) {<br>
+    amount = (int32_t)extract_4(p + 2);<br>
+    return true;<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+// addq $0x20, %rsp<br>
+bool x86AssemblyInspectionEngine::<wbr>add_rsp_pattern_p(int &amount) {<br>
+  uint8_t *p = m_cur_insn;<br>
+  if (m_wordsize == 8 && *p == 0x48)<br>
+    p++;<br>
+  // 8-bit immediate operand<br>
+  if (*p == 0x83 && *(p + 1) == 0xc4) {<br>
+    amount = (int8_t) * (p + 2);<br>
+    return true;<br>
+  }<br>
+  // 32-bit immediate operand<br>
+  if (*p == 0x81 && *(p + 1) == 0xc4) {<br>
+    amount = (int32_t)extract_4(p + 2);<br>
+    return true;<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+// lea esp, [esp - 0x28]<br>
+// lea esp, [esp + 0x28]<br>
+bool x86AssemblyInspectionEngine::<wbr>lea_rsp_pattern_p(int &amount) {<br>
+  uint8_t *p = m_cur_insn;<br>
+  if (m_wordsize == 8 && *p == 0x48)<br>
+    p++;<br>
+<br>
+  // Check opcode<br>
+  if (*p != 0x8d)<br>
+    return false;<br>
+<br>
+  // 8 bit displacement<br>
+  if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24) {<br>
+    amount = (int8_t) * (p + 3);<br>
+    return true;<br>
+  }<br>
+<br>
+  // 32 bit displacement<br>
+  if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24) {<br>
+    amount = (int32_t)extract_4(p + 3);<br>
+    return true;<br>
+  }<br>
+<br>
+  return false;<br>
+}<br>
+<br>
+// pushq %rbx<br>
+// pushl %ebx<br>
+bool x86AssemblyInspectionEngine::<wbr>push_reg_p(int &regno) {<br>
+  uint8_t *p = m_cur_insn;<br>
+  int regno_prefix_bit = 0;<br>
+  // If we have a rex prefix byte, check to see if a B bit is set<br>
+  if (m_wordsize == 8 && *p == 0x41) {<br>
+    regno_prefix_bit = 1 << 3;<br>
+    p++;<br>
+  }<br>
+  if (*p >= 0x50 && *p <= 0x57) {<br>
+    regno = (*p - 0x50) | regno_prefix_bit;<br>
+    return true;<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+// popq %rbx<br>
+// popl %ebx<br>
+bool x86AssemblyInspectionEngine::<wbr>pop_reg_p(int &regno) {<br>
+  uint8_t *p = m_cur_insn;<br>
+  int regno_prefix_bit = 0;<br>
+  // If we have a rex prefix byte, check to see if a B bit is set<br>
+  if (m_wordsize == 8 && *p == 0x41) {<br>
+    regno_prefix_bit = 1 << 3;<br>
+    p++;<br>
+  }<br>
+  if (*p >= 0x58 && *p <= 0x5f) {<br>
+    regno = (*p - 0x58) | regno_prefix_bit;<br>
+    return true;<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+// popq %rbp [0x5d]<br>
+// popl %ebp [0x5d]<br>
+bool x86AssemblyInspectionEngine::<wbr>pop_rbp_pattern_p() {<br>
+  uint8_t *p = m_cur_insn;<br>
+  return (*p == 0x5d);<br>
+}<br>
+<br>
+// leave [0xc9]<br>
+bool x86AssemblyInspectionEngine::<wbr>leave_pattern_p() {<br>
+  uint8_t *p = m_cur_insn;<br>
+  return (*p == 0xc9);<br>
+}<br>
+<br>
+// call $0 [0xe8 0x0 0x0 0x0 0x0]<br>
+bool x86AssemblyInspectionEngine::<wbr>call_next_insn_pattern_p() {<br>
+  uint8_t *p = m_cur_insn;<br>
+  return (*p == 0xe8) && (*(p + 1) == 0x0) && (*(p + 2) == 0x0) &&<br>
+         (*(p + 3) == 0x0) && (*(p + 4) == 0x0);<br>
+}<br>
+<br>
+// Look for an instruction sequence storing a nonvolatile register<br>
+// on to the stack frame.<br>
+<br>
+//  movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]<br>
+//  movl %eax, -0xc(%ebp)  [0x89 0x45 0xf4]<br>
+<br>
+// The offset value returned in rbp_offset will be positive --<br>
+// but it must be subtraced from the frame base register to get<br>
+// the actual location.  The positive value returned for the offset<br>
+// is a convention used elsewhere for CFA offsets et al.<br>
+<br>
+bool x86AssemblyInspectionEngine::<wbr>mov_reg_to_local_stack_frame_<wbr>p(<br>
+    int &regno, int &rbp_offset) {<br>
+  uint8_t *p = m_cur_insn;<br>
+  int src_reg_prefix_bit = 0;<br>
+  int target_reg_prefix_bit = 0;<br>
+<br>
+  if (m_wordsize == 8 && REX_W_PREFIX_P(*p)) {<br>
+    src_reg_prefix_bit = REX_W_SRCREG(*p) << 3;<br>
+    target_reg_prefix_bit = REX_W_DSTREG(*p) << 3;<br>
+    if (target_reg_prefix_bit == 1) {<br>
+      // rbp/ebp don't need a prefix bit - we know this isn't the<br>
+      // reg we care about.<br>
+      return false;<br>
+    }<br>
+    p++;<br>
+  }<br>
+<br>
+  if (*p == 0x89) {<br>
+    /* Mask off the 3-5 bits which indicate the destination register<br>
+       if this is a ModR/M byte.  */<br>
+    int opcode_destreg_masked_out = *(p + 1) & (~0x38);<br>
+<br>
+    /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101<br>
+       and three bits between them, e.g. 01nnn101<br>
+       We're looking for a destination of ebp-disp8 or ebp-disp32.   */<br>
+    int immsize;<br>
+    if (opcode_destreg_masked_out == 0x45)<br>
+      immsize = 2;<br>
+    else if (opcode_destreg_masked_out == 0x85)<br>
+      immsize = 4;<br>
+    else<br>
+      return false;<br>
+<br>
+    int offset = 0;<br>
+    if (immsize == 2)<br>
+      offset = (int8_t) * (p + 2);<br>
+    if (immsize == 4)<br>
+      offset = (uint32_t)extract_4(p + 2);<br>
+    if (offset > 0)<br>
+      return false;<br>
+<br>
+    regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;<br>
+    rbp_offset = offset > 0 ? offset : -offset;<br>
+    return true;<br>
+  }<br>
+  return false;<br>
+}<br>
+<br>
+// ret [0xc9] or [0xc2 imm8] or [0xca imm8]<br>
+bool x86AssemblyInspectionEngine::<wbr>ret_pattern_p() {<br>
+  uint8_t *p = m_cur_insn;<br>
+  if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)<br>
+    return true;<br>
+  return false;<br>
+}<br>
+<br>
+uint32_t x86AssemblyInspectionEngine::<wbr>extract_4(uint8_t *b) {<br>
+  uint32_t v = 0;<br>
+  for (int i = 3; i >= 0; i--)<br>
+    v = (v << 8) | b[i];<br>
+  return v;<br>
+}<br>
+<br>
+bool x86AssemblyInspectionEngine::<wbr>instruction_length(uint8_t *insn_p,<br>
+                                                     int &length) {<br>
+<br>
+  const uint32_t max_op_byte_size = m_arch.<wbr>GetMaximumOpcodeByteSize();<br>
+  llvm::SmallVector<uint8_t, 32> opcode_data;<br>
+  opcode_data.resize(max_op_<wbr>byte_size);<br>
+<br>
+  char out_string[512];<br>
+  const size_t inst_size =<br>
+      ::LLVMDisasmInstruction(m_<wbr>disasm_context, insn_p, max_op_byte_size, 0,<br>
+                              out_string, sizeof(out_string));<br>
+<br>
+  length = inst_size;<br>
+  return true;<br>
+}<br>
+<br>
+bool x86AssemblyInspectionEngine::<wbr>machine_regno_to_lldb_regno(<br>
+    int machine_regno, uint32_t &lldb_regno) {<br>
+  MachineRegnumToNameAndLLDBRegn<wbr>um::iterator it = m_reg_map.find(machine_regno);<br>
+  if (it != m_reg_map.end()) {<br>
+    lldb_regno = it->second.lldb_regnum;<br>
+    return true;<br>
+  }<br>
+  return false;<br>
+  return false;<br>
+}<br>
+<br>
+bool x86AssemblyInspectionEngine::<wbr>GetNonCallSiteUnwindPlanFromAs<wbr>sembly(<br>
+    uint8_t *data, size_t size, AddressRange &func_range,<br>
+    UnwindPlan &unwind_plan) {<br>
+  unwind_plan.Clear();<br>
+<br>
+  if (data == nullptr || size == 0)<br>
+    return false;<br>
+<br>
+  if (m_register_map_initialized == false)<br>
+    return false;<br>
+<br>
+  addr_t current_func_text_offset = 0;<br>
+  int current_sp_bytes_offset_from_<wbr>cfa = 0;<br>
+  UnwindPlan::Row::<wbr>RegisterLocation initial_regloc;<br>
+  UnwindPlan::RowSP row(new UnwindPlan::Row);<br>
+<br>
+  unwind_plan.<wbr>SetPlanValidAddressRange(func_<wbr>range);<br>
+  unwind_plan.SetRegisterKind(<wbr>eRegisterKindLLDB);<br>
+<br>
+  // At the start of the function, find the CFA by adding wordsize to the SP<br>
+  // register<br>
+  row->SetOffset(current_func_<wbr>text_offset);<br>
+  row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(m_<wbr>lldb_sp_regnum, m_wordsize);<br>
+<br>
+  // caller's stack pointer value before the call insn is the CFA address<br>
+  initial_regloc.<wbr>SetIsCFAPlusOffset(0);<br>
+  row->SetRegisterInfo(m_lldb_<wbr>sp_regnum, initial_regloc);<br>
+<br>
+  // saved instruction pointer can be found at CFA - wordsize.<br>
+  current_sp_bytes_offset_from_<wbr>cfa = m_wordsize;<br>
+  initial_regloc.<wbr>SetAtCFAPlusOffset(-current_<wbr>sp_bytes_offset_from_cfa);<br>
+  row->SetRegisterInfo(m_lldb_<wbr>ip_regnum, initial_regloc);<br>
+<br>
+  unwind_plan.AppendRow(row);<br>
+<br>
+  // Allocate a new Row, populate it with the existing Row contents.<br>
+  UnwindPlan::Row *newrow = new UnwindPlan::Row;<br>
+  *newrow = *row.get();<br>
+  row.reset(newrow);<br>
+<br>
+  // Track which registers have been saved so far in the prologue.<br>
+  // If we see another push of that register, it's not part of the prologue.<br>
+  // The register numbers used here are the machine register #'s<br>
+  // (i386_register_numbers, x86_64_register_numbers).<br>
+  std::vector<bool> saved_registers(32, false);<br>
+<br>
+  // Once the prologue has completed we'll save a copy of the unwind<br>
+  // instructions<br>
+  // If there is an epilogue in the middle of the function, after that epilogue<br>
+  // we'll reinstate<br>
+  // the unwind setup -- we assume that some code path jumps over the<br>
+  // mid-function epilogue<br>
+<br>
+  UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI<br>
+  int prologue_completed_sp_bytes_<wbr>offset_from_cfa; // The sp value before the<br>
+                                                   // epilogue started executed<br>
+  std::vector<bool> prologue_completed_saved_<wbr>registers;<br>
+<br>
+  while (current_func_text_offset < size) {<br>
+    int stack_offset, insn_len;<br>
+    int machine_regno;   // register numbers masked directly out of instructions<br>
+    uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB<br>
+                         // numbering scheme<br>
+<br>
+    bool in_epilogue = false; // we're in the middle of an epilogue sequence<br>
+    bool row_updated = false; // The UnwindPlan::Row 'row' has been updated<br>
+<br>
+    m_cur_insn = data + current_func_text_offset;<br>
+    if (!instruction_length(m_cur_<wbr>insn, insn_len) || insn_len == 0 ||<br>
+        insn_len > kMaxInstructionByteSize) {<br>
+      // An unrecognized/junk instruction<br>
+      break;<br>
+    }<br>
+<br>
+    if (push_rbp_pattern_p()) {<br>
+      current_sp_bytes_offset_from_<wbr>cfa += m_wordsize;<br>
+      row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+      UnwindPlan::Row::<wbr>RegisterLocation regloc;<br>
+      regloc.SetAtCFAPlusOffset(-<wbr>row->GetCFAValue().GetOffset()<wbr>);<br>
+      row->SetRegisterInfo(m_lldb_<wbr>fp_regnum, regloc);<br>
+      saved_registers[m_machine_fp_<wbr>regnum] = true;<br>
+      row_updated = true;<br>
+    }<br>
+<br>
+    else if (mov_rsp_rbp_pattern_p()) {<br>
+      row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
+          m_lldb_fp_regnum, row->GetCFAValue().GetOffset()<wbr>);<br>
+      row_updated = true;<br>
+    }<br>
+<br>
+    // This is the start() function (or a pthread equivalent), it starts with a<br>
+    // pushl $0x0 which puts the<br>
+    // saved pc value of 0 on the stack.  In this case we want to pretend we<br>
+    // didn't see a stack movement at all --<br>
+    // normally the saved pc value is already on the stack by the time the<br>
+    // function starts executing.<br>
+    else if (push_0_pattern_p()) {<br>
+    }<br>
+<br>
+    else if (push_reg_p(machine_regno)) {<br>
+      current_sp_bytes_offset_from_<wbr>cfa += m_wordsize;<br>
+      // the PUSH instruction has moved the stack pointer - if the CFA is set in<br>
+      // terms of the stack pointer,<br>
+      // we need to add a new row of instructions.<br>
+      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
+        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+        row_updated = true;<br>
+      }<br>
+      // record where non-volatile (callee-saved, spilled) registers are saved<br>
+      // on the stack<br>
+      if (nonvolatile_reg_p(machine_<wbr>regno) &&<br>
+          machine_regno_to_lldb_regno(<wbr>machine_regno, lldb_regno) &&<br>
+          saved_registers[machine_regno] == false) {<br>
+        UnwindPlan::Row::<wbr>RegisterLocation regloc;<br>
+        regloc.SetAtCFAPlusOffset(-<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+        row->SetRegisterInfo(lldb_<wbr>regno, regloc);<br>
+        saved_registers[machine_regno] = true;<br>
+        row_updated = true;<br>
+      }<br>
+    }<br>
+<br>
+    else if (pop_reg_p(machine_regno)) {<br>
+      current_sp_bytes_offset_from_<wbr>cfa -= m_wordsize;<br>
+<br>
+      if (nonvolatile_reg_p(machine_<wbr>regno) &&<br>
+          machine_regno_to_lldb_regno(<wbr>machine_regno, lldb_regno) &&<br>
+          saved_registers[machine_regno] == true) {<br>
+        saved_registers[machine_regno] = false;<br>
+        row->RemoveRegisterInfo(lldb_<wbr>regno);<br>
+<br>
+        if (machine_regno == (int)m_machine_fp_regnum) {<br>
+          row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
+              m_lldb_sp_regnum, row->GetCFAValue().GetOffset()<wbr>);<br>
+        }<br>
+<br>
+        in_epilogue = true;<br>
+        row_updated = true;<br>
+      }<br>
+<br>
+      // the POP instruction has moved the stack pointer - if the CFA is set in<br>
+      // terms of the stack pointer,<br>
+      // we need to add a new row of instructions.<br>
+      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
+        row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
+            m_lldb_sp_regnum, current_sp_bytes_offset_from_<wbr>cfa);<br>
+        row_updated = true;<br>
+      }<br>
+    }<br>
+<br>
+    // The LEAVE instruction moves the value from rbp into rsp and pops<br>
+    // a value off the stack into rbp (restoring the caller's rbp value).<br>
+    // It is the opposite of ENTER, or 'push rbp, mov rsp rbp'.<br>
+    else if (leave_pattern_p()) {<br>
+      // We're going to copy the value in rbp into rsp, so re-set the sp offset<br>
+      // based on the CFAValue.  Also, adjust it to recognize that we're popping<br>
+      // the saved rbp value off the stack.<br>
+      current_sp_bytes_offset_from_<wbr>cfa = row->GetCFAValue().GetOffset()<wbr>;<br>
+      current_sp_bytes_offset_from_<wbr>cfa -= m_wordsize;<br>
+      row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+<br>
+      // rbp is restored to the caller's value<br>
+      saved_registers[m_machine_fp_<wbr>regnum] = false;<br>
+      row->RemoveRegisterInfo(m_<wbr>lldb_fp_regnum);<br>
+<br>
+      // cfa is now in terms of rsp again.<br>
+      row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
+          m_lldb_sp_regnum, row->GetCFAValue().GetOffset()<wbr>);<br>
+      row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+<br>
+      in_epilogue = true;<br>
+      row_updated = true;<br>
+    }<br>
+<br>
+    else if (mov_reg_to_local_stack_frame_<wbr>p(machine_regno, stack_offset) &&<br>
+             nonvolatile_reg_p(machine_<wbr>regno) &&<br>
+             machine_regno_to_lldb_regno(<wbr>machine_regno, lldb_regno) &&<br>
+             saved_registers[machine_regno] == false) {<br>
+      saved_registers[machine_regno] = true;<br>
+<br>
+      UnwindPlan::Row::<wbr>RegisterLocation regloc;<br>
+<br>
+      // stack_offset for 'movq %r15, -80(%rbp)' will be 80.<br>
+      // In the Row, we want to express this as the offset from the CFA.  If the<br>
+      // frame base<br>
+      // is rbp (like the above instruction), the CFA offset for rbp is probably<br>
+      // 16.  So we<br>
+      // want to say that the value is stored at the CFA address - 96.<br>
+      regloc.SetAtCFAPlusOffset(<br>
+          -(stack_offset + row->GetCFAValue().GetOffset()<wbr>));<br>
+<br>
+      row->SetRegisterInfo(lldb_<wbr>regno, regloc);<br>
+<br>
+      row_updated = true;<br>
+    }<br>
+<br>
+    else if (sub_rsp_pattern_p(stack_<wbr>offset)) {<br>
+      current_sp_bytes_offset_from_<wbr>cfa += stack_offset;<br>
+      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
+        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+        row_updated = true;<br>
+      }<br>
+    }<br>
+<br>
+    else if (add_rsp_pattern_p(stack_<wbr>offset)) {<br>
+      current_sp_bytes_offset_from_<wbr>cfa -= stack_offset;<br>
+      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
+        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+        row_updated = true;<br>
+      }<br>
+      in_epilogue = true;<br>
+    }<br>
+<br>
+    else if (lea_rsp_pattern_p(stack_<wbr>offset)) {<br>
+      current_sp_bytes_offset_from_<wbr>cfa -= stack_offset;<br>
+      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
+        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+        row_updated = true;<br>
+      }<br>
+      if (stack_offset > 0)<br>
+        in_epilogue = true;<br>
+    }<br>
+<br>
+    else if (ret_pattern_p() && prologue_completed_row.get()) {<br>
+      // Reinstate the saved prologue setup for any instructions<br>
+      // that come after the ret instruction<br>
+<br>
+      UnwindPlan::Row *newrow = new UnwindPlan::Row;<br>
+      *newrow = *prologue_completed_row.get();<br>
+      row.reset(newrow);<br>
+      current_sp_bytes_offset_from_<wbr>cfa =<br>
+          prologue_completed_sp_bytes_<wbr>offset_from_cfa;<br>
+<br>
+      saved_registers.clear();<br>
+      saved_registers.resize(<wbr>prologue_completed_saved_<wbr>registers.size(), false);<br>
+      for (size_t i = 0; i < prologue_completed_saved_<wbr>registers.size(); ++i) {<br>
+        saved_registers[i] = prologue_completed_saved_<wbr>registers[i];<br>
+      }<br>
+<br>
+      in_epilogue = true;<br>
+      row_updated = true;<br>
+    }<br>
+<br>
+    // call next instruction<br>
+    //     call 0<br>
+    //  => pop  %ebx<br>
+    // This is used in i386 programs to get the PIC base address for finding<br>
+    // global data<br>
+    else if (call_next_insn_pattern_p()) {<br>
+      current_sp_bytes_offset_from_<wbr>cfa += m_wordsize;<br>
+      if (row->GetCFAValue().<wbr>GetRegisterNumber() == m_lldb_sp_regnum) {<br>
+        row->GetCFAValue().SetOffset(<wbr>current_sp_bytes_offset_from_<wbr>cfa);<br>
+        row_updated = true;<br>
+      }<br>
+    }<br>
+<br>
+    if (row_updated) {<br>
+      if (current_func_text_offset + insn_len < size) {<br>
+        row->SetOffset(current_func_<wbr>text_offset + insn_len);<br>
+        unwind_plan.AppendRow(row);<br>
+        // Allocate a new Row, populate it with the existing Row contents.<br>
+        newrow = new UnwindPlan::Row;<br>
+        *newrow = *row.get();<br>
+        row.reset(newrow);<br>
+      }<br>
+    }<br>
+<br>
+    if (in_epilogue == false && row_updated) {<br>
+      // If we're not in an epilogue sequence, save the updated Row<br>
+      UnwindPlan::Row *newrow = new UnwindPlan::Row;<br>
+      *newrow = *row.get();<br>
+      prologue_completed_row.reset(<wbr>newrow);<br>
+<br>
+      prologue_completed_saved_<wbr>registers.clear();<br>
+      prologue_completed_saved_<wbr>registers.resize(saved_<wbr>registers.size(), false);<br>
+      for (size_t i = 0; i < saved_registers.size(); ++i) {<br>
+        prologue_completed_saved_<wbr>registers[i] = saved_registers[i];<br>
+      }<br>
+    }<br>
+<br>
+    // We may change the sp value without adding a new Row necessarily -- keep<br>
+    // track of it either way.<br>
+    if (in_epilogue == false) {<br>
+      prologue_completed_sp_bytes_<wbr>offset_from_cfa =<br>
+          current_sp_bytes_offset_from_<wbr>cfa;<br>
+    }<br>
+<br>
+    m_cur_insn = m_cur_insn + insn_len;<br>
+    current_func_text_offset += insn_len;<br>
+  }<br>
+<br>
+  unwind_plan.SetSourceName("<wbr>assembly insn profiling");<br>
+  unwind_plan.<wbr>SetSourcedFromCompiler(<wbr>eLazyBoolNo);<br>
+  unwind_plan.<wbr>SetUnwindPlanValidAtAllInstruc<wbr>tions(eLazyBoolYes);<br>
+<br>
+  return true;<br>
+}<br>
+<br>
+bool x86AssemblyInspectionEngine::<wbr>AugmentUnwindPlanFromCallSite(<br>
+    uint8_t *data, size_t size, AddressRange &func_range,<br>
+    UnwindPlan &unwind_plan, RegisterContextSP &reg_ctx) {<br>
+  Address addr_start = func_range.GetBaseAddress();<br>
+  if (!addr_start.IsValid())<br>
+    return false;<br>
+<br>
+  // We either need a live RegisterContext, or we need the UnwindPlan to already<br>
+  // be in the lldb register numbering scheme.<br>
+  if (reg_ctx.get() == nullptr &&<br>
+      unwind_plan.GetRegisterKind() != eRegisterKindLLDB)<br>
+    return false;<br>
+<br>
+  // Is original unwind_plan valid?<br>
+  // unwind_plan should have at least one row which is ABI-default (CFA register<br>
+  // is sp),<br>
+  // and another row in mid-function.<br>
+  if (unwind_plan.GetRowCount() < 2)<br>
+    return false;<br>
+<br>
+  UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex(0);<br>
+  if (first_row->GetOffset() != 0)<br>
+    return false;<br>
+  uint32_t cfa_reg = first_row->GetCFAValue().<wbr>GetRegisterNumber();<br>
+  if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {<br>
+    cfa_reg = reg_ctx-><wbr>ConvertRegisterKindToRegisterN<wbr>umber(<br>
+        unwind_plan.GetRegisterKind(),<br>
+        first_row->GetCFAValue().<wbr>GetRegisterNumber());<br>
+  }<br>
+  if (cfa_reg != m_lldb_sp_regnum ||<br>
+      first_row->GetCFAValue().<wbr>GetOffset() != m_wordsize)<br>
+    return false;<br>
+<br>
+  UnwindPlan::RowSP original_last_row = unwind_plan.<wbr>GetRowForFunctionOffset(-1);<br>
+<br>
+  size_t offset = 0;<br>
+  int row_id = 1;<br>
+  bool unwind_plan_updated = false;<br>
+  UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));<br>
+  m_cur_insn = data + offset;<br>
+<br>
+  // After a mid-function epilogue we will need to re-insert the original unwind<br>
+  // rules<br>
+  // so unwinds work for the remainder of the function.  These aren't common<br>
+  // with clang/gcc<br>
+  // on x86 but it is possible.<br>
+  bool reinstate_unwind_state = false;<br>
+<br>
+  while (offset < size) {<br>
+    m_cur_insn = data + offset;<br>
+    int insn_len;<br>
+    if (!instruction_length(m_cur_<wbr>insn, insn_len) || insn_len == 0 ||<br>
+        insn_len > kMaxInstructionByteSize) {<br>
+      // An unrecognized/junk instruction.<br>
+      break;<br>
+    }<br>
+<br>
+    // Advance offsets.<br>
+    offset += insn_len;<br>
+    m_cur_insn = data + offset;<br>
+<br>
+    if (reinstate_unwind_state) {<br>
+      // that was the last instruction of this function<br>
+      if (offset >= size)<br>
+        continue;<br>
+<br>
+      UnwindPlan::RowSP new_row(new UnwindPlan::Row());<br>
+      *new_row = *original_last_row;<br>
+      new_row->SetOffset(offset);<br>
+      unwind_plan.AppendRow(new_row)<wbr>;<br>
+      row.reset(new UnwindPlan::Row());<br>
+      *row = *new_row;<br>
+      reinstate_unwind_state = false;<br>
+      unwind_plan_updated = true;<br>
+      continue;<br>
+    }<br>
+<br>
+    // If we already have one row for this instruction, we can continue.<br>
+    while (row_id < unwind_plan.GetRowCount() &&<br>
+           unwind_plan.GetRowAtIndex(row_<wbr>id)->GetOffset() <= offset) {<br>
+      row_id++;<br>
+    }<br>
+    UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex(row_<wbr>id - 1);<br>
+    if (original_row->GetOffset() == offset) {<br>
+      *row = *original_row;<br>
+      continue;<br>
+    }<br>
+<br>
+    if (row_id == 0) {<br>
+      // If we are here, compiler didn't generate CFI for prologue.<br>
+      // This won't happen to GCC or clang.<br>
+      // In this case, bail out directly.<br>
+      return false;<br>
+    }<br>
+<br>
+    // Inspect the instruction to check if we need a new row for it.<br>
+    cfa_reg = row->GetCFAValue().<wbr>GetRegisterNumber();<br>
+    if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {<br>
+      cfa_reg = reg_ctx-><wbr>ConvertRegisterKindToRegisterN<wbr>umber(<br>
+          unwind_plan.GetRegisterKind(),<br>
+          row->GetCFAValue().<wbr>GetRegisterNumber());<br>
+    }<br>
+    if (cfa_reg == m_lldb_sp_regnum) {<br>
+      // CFA register is sp.<br>
+<br>
+      // call next instruction<br>
+      //     call 0<br>
+      //  => pop  %ebx<br>
+      if (call_next_insn_pattern_p()) {<br>
+        row->SetOffset(offset);<br>
+        row->GetCFAValue().IncOffset(<wbr>m_wordsize);<br>
+<br>
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
+        unwind_plan.InsertRow(new_row)<wbr>;<br>
+        unwind_plan_updated = true;<br>
+        continue;<br>
+      }<br>
+<br>
+      // push/pop register<br>
+      int regno;<br>
+      if (push_reg_p(regno)) {<br>
+        row->SetOffset(offset);<br>
+        row->GetCFAValue().IncOffset(<wbr>m_wordsize);<br>
+<br>
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
+        unwind_plan.InsertRow(new_row)<wbr>;<br>
+        unwind_plan_updated = true;<br>
+        continue;<br>
+      }<br>
+      if (pop_reg_p(regno)) {<br>
+        // Technically, this might be a nonvolatile register recover in<br>
+        // epilogue.<br>
+        // We should reset RegisterInfo for the register.<br>
+        // But in practice, previous rule for the register is still valid...<br>
+        // So we ignore this case.<br>
+<br>
+        row->SetOffset(offset);<br>
+        row->GetCFAValue().IncOffset(-<wbr>m_wordsize);<br>
+<br>
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
+        unwind_plan.InsertRow(new_row)<wbr>;<br>
+        unwind_plan_updated = true;<br>
+        continue;<br>
+      }<br>
+<br>
+      // push imm<br>
+      if (push_imm_pattern_p()) {<br>
+        row->SetOffset(offset);<br>
+        row->GetCFAValue().IncOffset(<wbr>m_wordsize);<br>
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
+        unwind_plan.InsertRow(new_row)<wbr>;<br>
+        unwind_plan_updated = true;<br>
+        continue;<br>
+      }<br>
+<br>
+      // add/sub %rsp/%esp<br>
+      int amount;<br>
+      if (add_rsp_pattern_p(amount)) {<br>
+        row->SetOffset(offset);<br>
+        row->GetCFAValue().IncOffset(-<wbr>amount);<br>
+<br>
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
+        unwind_plan.InsertRow(new_row)<wbr>;<br>
+        unwind_plan_updated = true;<br>
+        continue;<br>
+      }<br>
+      if (sub_rsp_pattern_p(amount)) {<br>
+        row->SetOffset(offset);<br>
+        row->GetCFAValue().IncOffset(<wbr>amount);<br>
+<br>
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
+        unwind_plan.InsertRow(new_row)<wbr>;<br>
+        unwind_plan_updated = true;<br>
+        continue;<br>
+      }<br>
+<br>
+      // lea %rsp, [%rsp + $offset]<br>
+      if (lea_rsp_pattern_p(amount)) {<br>
+        row->SetOffset(offset);<br>
+        row->GetCFAValue().IncOffset(-<wbr>amount);<br>
+<br>
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
+        unwind_plan.InsertRow(new_row)<wbr>;<br>
+        unwind_plan_updated = true;<br>
+        continue;<br>
+      }<br>
+<br>
+      if (ret_pattern_p()) {<br>
+        reinstate_unwind_state = true;<br>
+        continue;<br>
+      }<br>
+    } else if (cfa_reg == m_lldb_fp_regnum) {<br>
+      // CFA register is fp.<br>
+<br>
+      // The only case we care about is epilogue:<br>
+      //     [0x5d] pop %rbp/%ebp<br>
+      //  => [0xc3] ret<br>
+      if (pop_rbp_pattern_p() || leave_pattern_p()) {<br>
+        // FIXME m_cur_insn should probably be updated -- I<br>
+        // think it's not advanced here because this should be<br>
+        // the last instruction in a function, assuming no<br>
+        // mid-function epilogues...<br>
+        if (ret_pattern_p()) {<br>
+          row->SetOffset(offset);<br>
+          row->GetCFAValue().<wbr>SetIsRegisterPlusOffset(<br>
+              first_row->GetCFAValue().<wbr>GetRegisterNumber(), m_wordsize);<br>
+<br>
+          UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));<br>
+          unwind_plan.InsertRow(new_row)<wbr>;<br>
+          unwind_plan_updated = true;<br>
+          reinstate_unwind_state = true;<br>
+          continue;<br>
+        }<br>
+      }<br>
+    } else {<br>
+      // CFA register is not sp or fp.<br>
+<br>
+      // This must be hand-written assembly.<br>
+      // Just trust eh_frame and assume we have finished.<br>
+      break;<br>
+    }<br>
+  }<br>
+<br>
+  unwind_plan.<wbr>SetPlanValidAddressRange(func_<wbr>range);<br>
+  if (unwind_plan_updated) {<br>
+    std::string unwind_plan_source(unwind_<wbr>plan.GetSourceName().<wbr>AsCString());<br>
+    unwind_plan_source += " plus augmentation from assembly parsing";<br>
+    unwind_plan.SetSourceName(<wbr>unwind_plan_source.c_str());<br>
+    unwind_plan.<wbr>SetSourcedFromCompiler(<wbr>eLazyBoolNo);<br>
+    unwind_plan.<wbr>SetUnwindPlanValidAtAllInstruc<wbr>tions(eLazyBoolYes);<br>
+  }<br>
+  return true;<br>
+}<br>
+<br>
+bool x86AssemblyInspectionEngine::<wbr>FindFirstNonPrologueInstructio<wbr>n(<br>
+    uint8_t *data, size_t size, size_t &offset) {<br>
+  offset = 0;<br>
+<br>
+  if (m_register_map_initialized == false)<br>
+    return false;<br>
+<br>
+  while (offset < size) {<br>
+    int regno;<br>
+    int insn_len;<br>
+    int scratch;<br>
+<br>
+    m_cur_insn = data + offset;<br>
+    if (!instruction_length(m_cur_<wbr>insn, insn_len) ||<br>
+        insn_len > kMaxInstructionByteSize || insn_len == 0) {<br>
+      // An error parsing the instruction, i.e. probably data/garbage - stop<br>
+      // scanning<br>
+      break;<br>
+    }<br>
+<br>
+    if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() ||<br>
+        sub_rsp_pattern_p(scratch) || push_reg_p(regno) ||<br>
+        mov_reg_to_local_stack_frame_<wbr>p(regno, scratch) ||<br>
+        (lea_rsp_pattern_p(scratch) && offset == 0)) {<br>
+      offset += insn_len;<br>
+      continue;<br>
+    }<br>
+    //<br>
+    // Unknown non-prologue instruction - stop scanning<br>
+    break;<br>
+  }<br>
+<br>
+  return true;<br>
+}<br>
<br>
Added: lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h?rev=282565&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/lldb/trunk/source/<wbr>Plugins/UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.h?<wbr>rev=282565&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.h (added)<br>
+++ lldb/trunk/source/Plugins/<wbr>UnwindAssembly/x86/<wbr>x86AssemblyInspectionEngine.h Tue Sep 27 21:52:19 2016<br>
@@ -0,0 +1,178 @@<br>
+//===-- x86AssemblyInspectionEngine.h ---------------------------*- C++ -*-===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+#ifndef liblldb_<wbr>x86AssemblyInspectionEngine_h_<br>
+#define liblldb_<wbr>x86AssemblyInspectionEngine_h_<br>
+<br>
+#include "llvm-c/Disassembler.h"<br>
+<br>
+#include "lldb/lldb-enumerations.h"<br>
+#include "lldb/lldb-forward.h"<br>
+#include "lldb/lldb-private.h"<br>
+<br>
+#include "lldb/Core/ArchSpec.h"<br>
+#include "lldb/Core/ConstString.h"<br>
+<br>
+#include <map><br>
+#include <vector><br>
+<br>
+namespace lldb_private {<br>
+<br>
+// x86AssemblyInspectionEngine - a class which will take a buffer of bytes<br>
+// of i386/x86_64 instructions and create an UnwindPlan based on those<br>
+// assembly instructions.<br>
+class x86AssemblyInspectionEngine {<br>
+<br>
+public:<br>
+  /// default ctor<br>
+  x86AssemblyInspectionEngine(<wbr>const lldb_private::ArchSpec &arch);<br>
+<br>
+  /// default dtor<br>
+  ~x86AssemblyInspectionEngine()<wbr>;<br>
+<br>
+  /// One of the two initialize methods that can be called on this object;<br>
+  /// they must be called before any of the assembly inspection methods<br>
+  /// are called.  This one should be used if the caller has access to a<br>
+  /// valid RegisterContext.<br>
+  void Initialize(lldb::<wbr>RegisterContextSP &reg_ctx);<br>
+<br>
+  /// One of the two initialize methods that can be called on this object;<br>
+  /// they must be called before any of the assembly inspection methods<br>
+  /// are called.  This one takes a vector of register name and lldb<br>
+  /// register numbers.<br>
+  struct lldb_reg_info {<br>
+    const char *name;<br>
+    uint32_t lldb_regnum;<br>
+    lldb_reg_info() : name(nullptr), lldb_regnum(LLDB_INVALID_<wbr>REGNUM) {}<br>
+  };<br>
+  void Initialize(std::vector<lldb_<wbr>reg_info> &reg_info);<br>
+<br>
+  /// Create an UnwindPlan for a "non-call site" stack frame situation.<br>
+  /// This is usually when this function/method is currently executing, and may<br>
+  /// be at<br>
+  /// a location where exception-handling style unwind information (eh_frame,<br>
+  /// compact unwind info, arm unwind info)<br>
+  /// are not valid.<br>
+  /// \p data is a pointer to the instructions for the function<br>
+  /// \p size is the size of the instruction buffer above<br>
+  /// \p func_range is the start Address and size of the function, to be<br>
+  /// included in the UnwindPlan<br>
+  /// \p unwind_plan is the unwind plan that this method creates<br>
+  /// \returns true if it was able to create an UnwindPlan; false if not.<br>
+  bool<br>
+  GetNonCallSiteUnwindPlanFromAs<wbr>sembly(uint8_t *data, size_t size,<br>
+                                       lldb_private::AddressRange &func_range,<br>
+                                       lldb_private::UnwindPlan &unwind_plan);<br>
+<br>
+  /// Take an existing UnwindPlan, probably from eh_frame which may be missing<br>
+  /// descriptio...<br><br>[Message clipped]  </blockquote></div><br></div>