Enable the fp-armv8 disassembler feature when disassembling Cortex-M
authorJason Molenda <jmolenda@apple.com>
Fri, 7 Sep 2018 01:28:48 +0000 (01:28 +0000)
committerJason Molenda <jmolenda@apple.com>
Fri, 7 Sep 2018 01:28:48 +0000 (01:28 +0000)
code.  This will enable disassembly of the optional subset of
neon that some Cortex cores support.  Add a unit test to check
that a few of these instructions disassemble as expected.

<rdar://problem/26674303>

llvm-svn: 341623

lldb/lldb.xcodeproj/project.pbxproj
lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
lldb/source/Utility/ArchSpec.cpp
lldb/unittests/Disassembler/CMakeLists.txt [new file with mode: 0644]
lldb/unittests/Disassembler/TestArmv7Disassembly.cpp [new file with mode: 0644]

index 1a0ea8f..4fe9485 100644 (file)
                23CB15421D66DA9300EDDDE1 /* TaskPoolTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2321F9451BDD346100BA9A93 /* TaskPoolTest.cpp */; };
                2689007413353E1A00698AC0 /* Terminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 268DA873130095ED00C9483A /* Terminal.cpp */; };
                4CEC86A4204738C5009B37B1 /* TestArm64InstEmulation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CEC86A3204738C5009B37B1 /* TestArm64InstEmulation.cpp */; };
+               AF7F97682141FA4500795BC0 /* TestArmv7Disassembly.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF7F97662141FA3800795BC0 /* TestArmv7Disassembly.cpp */; };
                23CB15401D66DA9300EDDDE1 /* TestClangASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23CB150C1D66CF5600EDDDE1 /* TestClangASTContext.cpp */; };
                9A20572D1F3B8E6600F6C293 /* TestCompletion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A20572B1F3B8E6200F6C293 /* TestCompletion.cpp */; };
                9A2057171F3B861400F6C293 /* TestDWARFCallFrameInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A2057131F3B860D00F6C293 /* TestDWARFCallFrameInfo.cpp */; };
                268DA873130095ED00C9483A /* Terminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Terminal.cpp; sourceTree = "<group>"; };
                268DA871130095D000C9483A /* Terminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Terminal.h; path = include/lldb/Host/Terminal.h; sourceTree = "<group>"; };
                4CEC86A3204738C5009B37B1 /* TestArm64InstEmulation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestArm64InstEmulation.cpp; path = UnwindAssembly/ARM64/TestArm64InstEmulation.cpp; sourceTree = "<group>"; };
+               AF7F97662141FA3800795BC0 /* TestArmv7Disassembly.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestArmv7Disassembly.cpp; path = unittests/Disassembler/TestArmv7Disassembly.cpp; sourceTree = SOURCE_ROOT; };
                23CB150C1D66CF5600EDDDE1 /* TestClangASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestClangASTContext.cpp; sourceTree = "<group>"; };
                9A20572B1F3B8E6200F6C293 /* TestCompletion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestCompletion.cpp; sourceTree = "<group>"; };
                9A2057131F3B860D00F6C293 /* TestDWARFCallFrameInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestDWARFCallFrameInfo.cpp; sourceTree = "<group>"; };
                                23E2E52C1D903806006F38BB /* Breakpoint */,
                                23CB14E51D66CBEB00EDDDE1 /* Core */,
                                9A2057421F3B904C00F6C293 /* debugserver */,
+                               AF7F97652141FA2100795BC0 /* Disassembler */,
                                2326CF501BDD68CA00A5CEAC /* Editline */,
                                AEC6FF9D1BE97035007882C1 /* Expression */,
                                239504C21BDD3FD600963CEA /* gtest_common.h */,
                        name = "SysV-ppc64";
                        sourceTree = "<group>";
                };
+               AF7F97652141FA2100795BC0 /* Disassembler */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF7F97662141FA3800795BC0 /* TestArmv7Disassembly.cpp */,
+                       );
+                       name = Disassembler;
+                       path = ../Disassembler;
+                       sourceTree = "<group>";
+               };
                AFAFD8081E57E19E0017A14F /* Target */ = {
                        isa = PBXGroup;
                        children = (
                                23CB15451D66DA9300EDDDE1 /* SocketAddressTest.cpp in Sources */,
                                9A3D43DD1F3151C400EB767C /* TimerTest.cpp in Sources */,
                                23CB15461D66DA9300EDDDE1 /* GDBRemoteTestUtils.cpp in Sources */,
+                               AF7F97682141FA4500795BC0 /* TestArmv7Disassembly.cpp in Sources */,
                                23E2E5271D903782006F38BB /* MinidumpParserTest.cpp in Sources */,
                                23CB15471D66DA9300EDDDE1 /* EditlineTest.cpp in Sources */,
                        );
index 6c40a0c..20209e9 100644 (file)
@@ -1126,11 +1126,13 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
       triple.getSubArch() == llvm::Triple::NoSubArch)
     triple.setArchName("armv8.2a");
 
+  std::string features_str = "";
   const char *triple_str = triple.getTriple().c_str();
 
   // ARM Cortex M0-M7 devices only execute thumb instructions
   if (arch.IsAlwaysThumbInstructions()) {
     triple_str = thumb_arch.GetTriple().getTriple().c_str();
+    features_str += "+fp-armv8,";
   }
 
   const char *cpu = "";
@@ -1181,7 +1183,6 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
     break;
   }
 
-  std::string features_str = "";
   if (triple.getArch() == llvm::Triple::mips ||
       triple.getArch() == llvm::Triple::mipsel ||
       triple.getArch() == llvm::Triple::mips64 ||
@@ -1213,7 +1214,8 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
   if (llvm_arch == llvm::Triple::arm) {
     std::string thumb_triple(thumb_arch.GetTriple().getTriple());
     m_alternate_disasm_up =
-        MCDisasmInstance::Create(thumb_triple.c_str(), "", "", flavor, *this);
+        MCDisasmInstance::Create(thumb_triple.c_str(), "", features_str.c_str(), 
+                                 flavor, *this);
     if (!m_alternate_disasm_up)
       m_disasm_up.reset();
 
index 1c50c31..7afa924 100644 (file)
@@ -1477,7 +1477,10 @@ bool ArchSpec::IsAlwaysThumbInstructions() const {
 
     if (GetCore() == ArchSpec::Core::eCore_arm_armv7m ||
         GetCore() == ArchSpec::Core::eCore_arm_armv7em ||
-        GetCore() == ArchSpec::Core::eCore_arm_armv6m) {
+        GetCore() == ArchSpec::Core::eCore_arm_armv6m ||
+        GetCore() == ArchSpec::Core::eCore_thumbv7m ||
+        GetCore() == ArchSpec::Core::eCore_thumbv7em ||
+        GetCore() == ArchSpec::Core::eCore_thumbv6m) {
       return true;
     }
   }
diff --git a/lldb/unittests/Disassembler/CMakeLists.txt b/lldb/unittests/Disassembler/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6f1b347
--- /dev/null
@@ -0,0 +1,11 @@
+add_lldb_unittest(DisassemblerTests
+  TestArmv7Disassembly.cpp
+  LINK_LIBS
+    lldbCore
+    lldbSymbol
+    lldbTarget
+    lldbPluginDisassemblerLLVM
+    lldbPluginProcessUtility
+  LINK_COMPONENTS
+    Support
+    ${LLVM_TARGETS_TO_BUILD})
diff --git a/lldb/unittests/Disassembler/TestArmv7Disassembly.cpp b/lldb/unittests/Disassembler/TestArmv7Disassembly.cpp
new file mode 100644 (file)
index 0000000..8767a39
--- /dev/null
@@ -0,0 +1,90 @@
+//===-- TestArmv7Disassembly.cpp ------------------------------------*- C++
+//-*-===//
+
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Target/ExecutionContext.h"
+
+#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
+#include "llvm/Support/TargetSelect.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class TestArmv7Disassembly : public testing::Test {
+public:
+  static void SetUpTestCase();
+  static void TearDownTestCase();
+
+  //  virtual void SetUp() override { }
+  //  virtual void TearDown() override { }
+
+protected:
+};
+
+void TestArmv7Disassembly::SetUpTestCase() {
+  llvm::InitializeAllTargets();
+  llvm::InitializeAllAsmPrinters();
+  llvm::InitializeAllTargetMCs();
+  llvm::InitializeAllDisassemblers();
+  DisassemblerLLVMC::Initialize();
+}
+
+void TestArmv7Disassembly::TearDownTestCase() {
+  DisassemblerLLVMC::Terminate();
+}
+
+TEST_F(TestArmv7Disassembly, TestCortexFPDisass) {
+  ArchSpec arch("armv7em--");
+
+  const int num_of_instructions = 3;
+  uint8_t data[] = {
+      0x00, 0xee, 0x10, 0x2a, // 0xee002a10 :  vmov   s0, r2
+      0xb8, 0xee, 0xc0, 0x0b, // 0xeeb80bc0 :  vcvt.f64.s32 d0, s0
+      0xb6, 0xee, 0x00, 0x0a, // 0xeeb60a00 :  vmov.f32 s0, #5.000000e-01
+  };
+
+  // these can be disassembled by hand with llvm-mc, e.g.
+  //
+  // 0x00, 0xee, 0x10, 0x2a, // 0xee002a10 :  vmov   s0, r2
+  //
+  // echo 0x00 0xee 0x10  0x2a | llvm-mc -arch thumb -disassemble -mattr=+fp-armv8
+       //       vmov s0, r2
+
+  DisassemblerSP disass_sp;
+  Address start_addr(0x100);
+  disass_sp = Disassembler::DisassembleBytes(arch, nullptr, nullptr, start_addr,
+                                 &data, sizeof (data), num_of_instructions, false);
+
+  ASSERT_NE (nullptr, disass_sp.get());
+  if (disass_sp) {
+    const InstructionList inst_list (disass_sp->GetInstructionList());
+    EXPECT_EQ (num_of_instructions, inst_list.GetSize());
+
+    InstructionSP inst_sp;
+    const char *mnemonic;
+    ExecutionContext exe_ctx (nullptr, nullptr, nullptr);
+    inst_sp = inst_list.GetInstructionAtIndex (0);
+    mnemonic = inst_sp->GetMnemonic(&exe_ctx);
+    ASSERT_STREQ ("vmov", mnemonic);
+
+    inst_sp = inst_list.GetInstructionAtIndex (1);
+    mnemonic = inst_sp->GetMnemonic(&exe_ctx);
+    ASSERT_STREQ ("vcvt.f64.s32", mnemonic);
+
+    inst_sp = inst_list.GetInstructionAtIndex (2);
+    mnemonic = inst_sp->GetMnemonic(&exe_ctx);
+    ASSERT_STREQ ("vmov.f32", mnemonic);
+  }
+}