From 0dfb84ce9bc90fe996467f596b379c96525ed4cf Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Fri, 7 Sep 2018 01:28:48 +0000 Subject: [PATCH] Enable the fp-armv8 disassembler feature when disassembling Cortex-M 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. llvm-svn: 341623 --- lldb/lldb.xcodeproj/project.pbxproj | 13 ++++ .../Disassembler/llvm/DisassemblerLLVMC.cpp | 6 +- lldb/source/Utility/ArchSpec.cpp | 5 +- lldb/unittests/Disassembler/CMakeLists.txt | 11 +++ .../Disassembler/TestArmv7Disassembly.cpp | 90 ++++++++++++++++++++++ 5 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 lldb/unittests/Disassembler/CMakeLists.txt create mode 100644 lldb/unittests/Disassembler/TestArmv7Disassembly.cpp diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 1a0ea8f..4fe9485 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -934,6 +934,7 @@ 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 */; }; @@ -3032,6 +3033,7 @@ 268DA873130095ED00C9483A /* Terminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Terminal.cpp; sourceTree = ""; }; 268DA871130095D000C9483A /* Terminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Terminal.h; path = include/lldb/Host/Terminal.h; sourceTree = ""; }; 4CEC86A3204738C5009B37B1 /* TestArm64InstEmulation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestArm64InstEmulation.cpp; path = UnwindAssembly/ARM64/TestArm64InstEmulation.cpp; sourceTree = ""; }; + 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 = ""; }; 9A20572B1F3B8E6200F6C293 /* TestCompletion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestCompletion.cpp; sourceTree = ""; }; 9A2057131F3B860D00F6C293 /* TestDWARFCallFrameInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestDWARFCallFrameInfo.cpp; sourceTree = ""; }; @@ -3516,6 +3518,7 @@ 23E2E52C1D903806006F38BB /* Breakpoint */, 23CB14E51D66CBEB00EDDDE1 /* Core */, 9A2057421F3B904C00F6C293 /* debugserver */, + AF7F97652141FA2100795BC0 /* Disassembler */, 2326CF501BDD68CA00A5CEAC /* Editline */, AEC6FF9D1BE97035007882C1 /* Expression */, 239504C21BDD3FD600963CEA /* gtest_common.h */, @@ -6862,6 +6865,15 @@ name = "SysV-ppc64"; sourceTree = ""; }; + AF7F97652141FA2100795BC0 /* Disassembler */ = { + isa = PBXGroup; + children = ( + AF7F97662141FA3800795BC0 /* TestArmv7Disassembly.cpp */, + ); + name = Disassembler; + path = ../Disassembler; + sourceTree = ""; + }; AFAFD8081E57E19E0017A14F /* Target */ = { isa = PBXGroup; children = ( @@ -7608,6 +7620,7 @@ 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 */, ); diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index 6c40a0c..20209e9a 100644 --- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -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(); diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 1c50c31..7afa924 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -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 index 0000000..6f1b347 --- /dev/null +++ b/lldb/unittests/Disassembler/CMakeLists.txt @@ -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 index 0000000..8767a39 --- /dev/null +++ b/lldb/unittests/Disassembler/TestArmv7Disassembly.cpp @@ -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); + } +} -- 2.7.4