[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
Mon Oct 3 09:38:45 PDT 2016


Thank you for fixing the regressions coming from this.

In terms of core files, I was able to get a linux core file down to about
40k, using some fancy compiler options (see
functionalities/postmortem/linux-core tests) -- it's still pretty big for a
unit test, but it's manageable.



On 28 September 2016 at 13:26, Jason Molenda <jmolenda at apple.com> wrote:

> Thanks, I'm real happy to have the time to work on unwinder testing, it's
> such a complicated subsystem that it's easy to break (and very tricky to
> test).  With this kind of restructuring, unit testing of x86/armv7/arm64
> unwind plan creation will be possible which will be great, we've had
> problems especially with the armv7 unwind plan creation code in the past.
> Testing UnwindLLDB and RegisterContextLLDB will be trickier - they assume a
> fully running inferior process with threads and stack frames and memory and
> live register contexts.  We may need to do something else there.  I'm
> toying with the idea of lldb creating very-very-stripped-down core files
> with just the stack/instruction memory + register context + symbol
> information needed to show a complicated unwind scenario.  Maybe we could
> get a core file down to hundreds of kilobytes?  I don't know if it'll
> really be possible, but it's worth pursuing.
>
> I had to revert this commit temporarily because I caused a regression on
> linux but I'll get that fixed today & check it in again.
>
> > On Sep 28, 2016, at 5:30 AM, Pavel Labath <labath at google.com> wrote:
> >
> > 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/
> Testx86AssemblyInspectionEngine.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/20161003/b01fcc85/attachment-0001.html>


More information about the lldb-commits mailing list