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