[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 ®no);
> > - bool pop_reg_p(int ®no);
> > - bool push_imm_pattern_p();
> > - bool mov_reg_to_local_stack_frame_p(int ®no, 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 ®no) {
> > - 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 ®no) {
> > - 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 ®no,
> > - 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
> ®_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> ®_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 ®no) {
> > + 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 ®no) {
> > + 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 ®no, 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 ®_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 ®_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> ®_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