[Lldb-commits] [lldb] r282565 - Refactor the x86 UnwindAssembly class into a separate class called

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Wed Sep 28 05:30:10 PDT 2016


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).

On 28 September 2016 at 03:52, Jason Molenda via lldb-commits <
lldb-commits at lists.llvm.org> wrote:

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


More information about the lldb-commits mailing list