Skip to content

Commit 67203b8

Browse files
RamNalamothuJDevlieghere
authored andcommitted
[lldb][NFC] Use MCInstrAnalysis when available in the disassembler plugin
Since the info in MCInstrDesc is based on opcodes only, it is often quite inaccurate. The MCInstrAnalysis has been added so that targets can provide accurate info, which is based on registers used by the instruction, through the own versions of MCInstrDesc functions. The RISCVMCInstrAnalysis, which needs to refine several MCInstrDesc methods, is a good example for this. Given the llvm-objdump also uses MCInstrAnalysis, I think this change is in the right direction. The default implementation of MCInstrAnalysis methods forward the query to MCInstrDesc functions. Hence, no functional change is intended/expected. To avoid bloating up MCInstrAnalysis, only the methods provided by it and the ones used by disassembler plugin are changed to use MCInstrAnalysis when available. Though I am not sure if it will be useful, making MCInstrAnalysis available in the disassembler plugin would allow enabling symbolize operands (D84191) feature in lldb's disassembler as well. Reviewed By: jasonmolenda Differential Revision: https://reviews.llvm.org/D156086 (cherry picked from commit 254a312)
1 parent 5afd402 commit 67203b8

File tree

6 files changed

+162
-20
lines changed

6 files changed

+162
-20
lines changed

lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/MC/MCDisassembler/MCRelocationInfo.h"
1919
#include "llvm/MC/MCInst.h"
2020
#include "llvm/MC/MCInstPrinter.h"
21+
#include "llvm/MC/MCInstrAnalysis.h"
2122
#include "llvm/MC/MCInstrInfo.h"
2223
#include "llvm/MC/MCRegisterInfo.h"
2324
#include "llvm/MC/MCSubtargetInfo.h"
@@ -75,7 +76,8 @@ class DisassemblerLLVMC::MCDisasmInstance {
7576
std::unique_ptr<llvm::MCAsmInfo> &&asm_info_up,
7677
std::unique_ptr<llvm::MCContext> &&context_up,
7778
std::unique_ptr<llvm::MCDisassembler> &&disasm_up,
78-
std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up);
79+
std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up,
80+
std::unique_ptr<llvm::MCInstrAnalysis> &&instr_analysis_up);
7981

8082
std::unique_ptr<llvm::MCInstrInfo> m_instr_info_up;
8183
std::unique_ptr<llvm::MCRegisterInfo> m_reg_info_up;
@@ -84,6 +86,7 @@ class DisassemblerLLVMC::MCDisasmInstance {
8486
std::unique_ptr<llvm::MCContext> m_context_up;
8587
std::unique_ptr<llvm::MCDisassembler> m_disasm_up;
8688
std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_up;
89+
std::unique_ptr<llvm::MCInstrAnalysis> m_instr_analysis_up;
8790
};
8891

8992
namespace x86 {
@@ -1287,11 +1290,15 @@ DisassemblerLLVMC::MCDisasmInstance::Create(const char *triple, const char *cpu,
12871290
if (!instr_printer_up)
12881291
return Instance();
12891292

1290-
return Instance(
1291-
new MCDisasmInstance(std::move(instr_info_up), std::move(reg_info_up),
1292-
std::move(subtarget_info_up), std::move(asm_info_up),
1293-
std::move(context_up), std::move(disasm_up),
1294-
std::move(instr_printer_up)));
1293+
// Not all targets may have registered createMCInstrAnalysis().
1294+
std::unique_ptr<llvm::MCInstrAnalysis> instr_analysis_up(
1295+
curr_target->createMCInstrAnalysis(instr_info_up.get()));
1296+
1297+
return Instance(new MCDisasmInstance(
1298+
std::move(instr_info_up), std::move(reg_info_up),
1299+
std::move(subtarget_info_up), std::move(asm_info_up),
1300+
std::move(context_up), std::move(disasm_up), std::move(instr_printer_up),
1301+
std::move(instr_analysis_up)));
12951302
}
12961303

12971304
DisassemblerLLVMC::MCDisasmInstance::MCDisasmInstance(
@@ -1301,13 +1308,15 @@ DisassemblerLLVMC::MCDisasmInstance::MCDisasmInstance(
13011308
std::unique_ptr<llvm::MCAsmInfo> &&asm_info_up,
13021309
std::unique_ptr<llvm::MCContext> &&context_up,
13031310
std::unique_ptr<llvm::MCDisassembler> &&disasm_up,
1304-
std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up)
1311+
std::unique_ptr<llvm::MCInstPrinter> &&instr_printer_up,
1312+
std::unique_ptr<llvm::MCInstrAnalysis> &&instr_analysis_up)
13051313
: m_instr_info_up(std::move(instr_info_up)),
13061314
m_reg_info_up(std::move(reg_info_up)),
13071315
m_subtarget_info_up(std::move(subtarget_info_up)),
13081316
m_asm_info_up(std::move(asm_info_up)),
13091317
m_context_up(std::move(context_up)), m_disasm_up(std::move(disasm_up)),
1310-
m_instr_printer_up(std::move(instr_printer_up)) {
1318+
m_instr_printer_up(std::move(instr_printer_up)),
1319+
m_instr_analysis_up(std::move(instr_analysis_up)) {
13111320
assert(m_instr_info_up && m_reg_info_up && m_subtarget_info_up &&
13121321
m_asm_info_up && m_context_up && m_disasm_up && m_instr_printer_up);
13131322
}
@@ -1365,6 +1374,8 @@ void DisassemblerLLVMC::MCDisasmInstance::SetStyle(
13651374

13661375
bool DisassemblerLLVMC::MCDisasmInstance::CanBranch(
13671376
llvm::MCInst &mc_inst) const {
1377+
if (m_instr_analysis_up)
1378+
return m_instr_analysis_up->mayAffectControlFlow(mc_inst, *m_reg_info_up);
13681379
return m_instr_info_up->get(mc_inst.getOpcode())
13691380
.mayAffectControlFlow(mc_inst, *m_reg_info_up);
13701381
}
@@ -1375,6 +1386,8 @@ bool DisassemblerLLVMC::MCDisasmInstance::HasDelaySlot(
13751386
}
13761387

13771388
bool DisassemblerLLVMC::MCDisasmInstance::IsCall(llvm::MCInst &mc_inst) const {
1389+
if (m_instr_analysis_up)
1390+
return m_instr_analysis_up->isCall(mc_inst);
13781391
return m_instr_info_up->get(mc_inst.getOpcode()).isCall();
13791392
}
13801393

lldb/unittests/Disassembler/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ endif()
55
if("X86" IN_LIST LLVM_TARGETS_TO_BUILD)
66
add_subdirectory(x86)
77
endif()
8+
9+
if("RISCV" IN_LIST LLVM_TARGETS_TO_BUILD)
10+
add_subdirectory(RISCV)
11+
endif()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
add_lldb_unittest(MCDisasmInstanceRISCVTests
2+
TestMCDisasmInstanceRISCV.cpp
3+
LINK_LIBS
4+
lldbCore
5+
lldbSymbol
6+
lldbTarget
7+
lldbPluginDisassemblerLLVMC
8+
lldbPluginProcessUtility
9+
LINK_COMPONENTS
10+
Support
11+
${LLVM_TARGETS_TO_BUILD}
12+
)
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===-- TestMCDisasmInstanceRISCV.cpp -------------------------------------===//
2+
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "llvm/Support/TargetSelect.h"
11+
#include "gtest/gtest.h"
12+
13+
#include "lldb/Core/Address.h"
14+
#include "lldb/Core/Disassembler.h"
15+
#include "lldb/Target/ExecutionContext.h"
16+
#include "lldb/Utility/ArchSpec.h"
17+
18+
#include "Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h"
19+
20+
using namespace lldb;
21+
using namespace lldb_private;
22+
23+
class TestMCDisasmInstanceRISCV : public testing::Test {
24+
public:
25+
static void SetUpTestCase();
26+
static void TearDownTestCase();
27+
28+
protected:
29+
};
30+
31+
void TestMCDisasmInstanceRISCV::SetUpTestCase() {
32+
llvm::InitializeAllTargets();
33+
llvm::InitializeAllAsmPrinters();
34+
llvm::InitializeAllTargetMCs();
35+
llvm::InitializeAllDisassemblers();
36+
DisassemblerLLVMC::Initialize();
37+
}
38+
39+
void TestMCDisasmInstanceRISCV::TearDownTestCase() {
40+
DisassemblerLLVMC::Terminate();
41+
}
42+
43+
TEST_F(TestMCDisasmInstanceRISCV, TestRISCV32Instruction) {
44+
ArchSpec arch("riscv32-*-linux");
45+
46+
const unsigned num_of_instructions = 5;
47+
uint8_t data[] = {
48+
0xef, 0x00, 0x00, 0x00, // call -- jal x1, 0
49+
0xe7, 0x00, 0x00, 0x00, // call -- jalr x1, x0, 0
50+
0x6f, 0x00, 0x00, 0x00, // jump -- jal x0, 0
51+
0x67, 0x00, 0x00, 0x00, // jump -- jalr x0, x0, 0
52+
0x67, 0x80, 0x00, 0x00 // ret -- jalr x0, x1, 0
53+
};
54+
55+
DisassemblerSP disass_sp;
56+
Address start_addr(0x100);
57+
disass_sp =
58+
Disassembler::DisassembleBytes(arch, nullptr, nullptr, start_addr, &data,
59+
sizeof (data), num_of_instructions, false);
60+
61+
// If we failed to get a disassembler, we can assume it is because
62+
// the llvm we linked against was not built with the riscv target,
63+
// and we should skip these tests without marking anything as failing.
64+
if (!disass_sp)
65+
return;
66+
67+
const InstructionList inst_list(disass_sp->GetInstructionList());
68+
EXPECT_EQ(num_of_instructions, inst_list.GetSize());
69+
70+
InstructionSP inst_sp;
71+
inst_sp = inst_list.GetInstructionAtIndex(0);
72+
EXPECT_TRUE(inst_sp->IsCall());
73+
EXPECT_TRUE(inst_sp->DoesBranch());
74+
75+
inst_sp = inst_list.GetInstructionAtIndex(1);
76+
EXPECT_TRUE(inst_sp->IsCall());
77+
EXPECT_TRUE(inst_sp->DoesBranch());
78+
79+
inst_sp = inst_list.GetInstructionAtIndex(2);
80+
EXPECT_FALSE(inst_sp->IsCall());
81+
EXPECT_TRUE(inst_sp->DoesBranch());
82+
83+
inst_sp = inst_list.GetInstructionAtIndex(3);
84+
EXPECT_FALSE(inst_sp->IsCall());
85+
EXPECT_TRUE(inst_sp->DoesBranch());
86+
87+
inst_sp = inst_list.GetInstructionAtIndex(4);
88+
EXPECT_FALSE(inst_sp->IsCall());
89+
EXPECT_TRUE(inst_sp->DoesBranch());
90+
}

lldb/unittests/Disassembler/x86/TestGetControlFlowKindx86.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,28 @@ TEST_F(TestGetControlFlowKindx86, TestX86_64Instruction) {
129129
// If we failed to get a disassembler, we can assume it is because
130130
// the llvm we linked against was not built with the i386 target,
131131
// and we should skip these tests without marking anything as failing.
132-
133-
if (disass_sp) {
134-
const InstructionList inst_list(disass_sp->GetInstructionList());
135-
EXPECT_EQ(num_of_instructions, inst_list.GetSize());
136-
137-
for (size_t i = 0; i < num_of_instructions; ++i) {
138-
InstructionSP inst_sp;
139-
inst_sp = inst_list.GetInstructionAtIndex(i);
140-
ExecutionContext exe_ctx (nullptr, nullptr, nullptr);
141-
InstructionControlFlowKind kind = inst_sp->GetControlFlowKind(&exe_ctx);
142-
EXPECT_EQ(kind, result[i]);
143-
}
132+
if (!disass_sp)
133+
return;
134+
135+
const InstructionList inst_list(disass_sp->GetInstructionList());
136+
EXPECT_EQ(num_of_instructions, inst_list.GetSize());
137+
138+
for (size_t i = 0; i < num_of_instructions; ++i) {
139+
InstructionSP inst_sp;
140+
inst_sp = inst_list.GetInstructionAtIndex(i);
141+
ExecutionContext exe_ctx(nullptr, nullptr, nullptr);
142+
InstructionControlFlowKind kind = inst_sp->GetControlFlowKind(&exe_ctx);
143+
EXPECT_EQ(kind, result[i]);
144+
145+
// Also, test the DisassemblerLLVMC::MCDisasmInstance methods.
146+
if (kind == eInstructionControlFlowKindReturn)
147+
EXPECT_FALSE(inst_sp->IsCall());
148+
if (kind == eInstructionControlFlowKindCall)
149+
EXPECT_TRUE(inst_sp->IsCall());
150+
if (kind == eInstructionControlFlowKindCall ||
151+
kind == eInstructionControlFlowKindJump ||
152+
kind == eInstructionControlFlowKindCondJump ||
153+
kind == eInstructionControlFlowKindReturn)
154+
EXPECT_TRUE(inst_sp->DoesBranch());
144155
}
145156
}

llvm/include/llvm/MC/MCInstrAnalysis.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/MC/MCInst.h"
1919
#include "llvm/MC/MCInstrDesc.h"
2020
#include "llvm/MC/MCInstrInfo.h"
21+
#include "llvm/MC/MCRegisterInfo.h"
2122
#include <cstdint>
2223
#include <vector>
2324

@@ -64,6 +65,17 @@ class MCInstrAnalysis {
6465
return Info->get(Inst.getOpcode()).isTerminator();
6566
}
6667

68+
virtual bool mayAffectControlFlow(const MCInst &Inst,
69+
const MCRegisterInfo &MCRI) const {
70+
if (isBranch(Inst) || isCall(Inst) || isReturn(Inst) ||
71+
isIndirectBranch(Inst))
72+
return true;
73+
unsigned PC = MCRI.getProgramCounter();
74+
if (PC == 0)
75+
return false;
76+
return Info->get(Inst.getOpcode()).hasDefOfPhysReg(Inst, PC, MCRI);
77+
}
78+
6779
/// Returns true if at least one of the register writes performed by
6880
/// \param Inst implicitly clears the upper portion of all super-registers.
6981
///

0 commit comments

Comments
 (0)