Skip to content

Commit 0029013

Browse files
committed
[lldb] Add syntax color highlighting for disassembly
Add support for syntax color highlighting disassembly in LLDB. This patch relies on 77d1032, which introduces support for syntax highlighting in MC. Currently only AArch64 and X86 have color support, but other interested backends can adopt WithColor in their respective MCInstPrinter. Differential revision: https://reviews.llvm.org/D159164 (cherry picked from commit a69f78b)
1 parent 999a491 commit 0029013

File tree

5 files changed

+91
-7
lines changed

5 files changed

+91
-7
lines changed

lldb/include/lldb/Core/Disassembler.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,16 @@ class Instruction {
6464

6565
const Address &GetAddress() const { return m_address; }
6666

67-
const char *GetMnemonic(const ExecutionContext *exe_ctx) {
67+
const char *GetMnemonic(const ExecutionContext *exe_ctx,
68+
bool markup = false) {
6869
CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx);
69-
return m_opcode_name.c_str();
70+
return markup ? m_markup_opcode_name.c_str() : m_opcode_name.c_str();
7071
}
7172

72-
const char *GetOperands(const ExecutionContext *exe_ctx) {
73+
const char *GetOperands(const ExecutionContext *exe_ctx,
74+
bool markup = false) {
7375
CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx);
74-
return m_mnemonics.c_str();
76+
return markup ? m_markup_mnemonics.c_str() : m_mnemonics.c_str();
7577
}
7678

7779
const char *GetComment(const ExecutionContext *exe_ctx) {
@@ -244,7 +246,9 @@ class Instruction {
244246
protected:
245247
Opcode m_opcode; // The opcode for this instruction
246248
std::string m_opcode_name;
249+
std::string m_markup_opcode_name;
247250
std::string m_mnemonics;
251+
std::string m_markup_mnemonics;
248252
std::string m_comment;
249253
bool m_calculated_strings;
250254

lldb/source/Core/Disassembler.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -645,18 +645,29 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
645645
instruction_control_flow_kind));
646646
}
647647

648+
bool show_color = false;
649+
if (exe_ctx) {
650+
if (TargetSP target_sp = exe_ctx->GetTargetSP()) {
651+
show_color = target_sp->GetDebugger().GetUseColor();
652+
}
653+
}
648654
const size_t opcode_pos = ss.GetSizeOfLastLine();
655+
const std::string &opcode_name =
656+
show_color ? m_markup_opcode_name : m_opcode_name;
657+
const std::string &mnemonics = show_color ? m_markup_mnemonics : m_mnemonics;
649658

650659
// The default opcode size of 7 characters is plenty for most architectures
651660
// but some like arm can pull out the occasional vqrshrun.s16. We won't get
652-
// consistent column spacing in these cases, unfortunately.
661+
// consistent column spacing in these cases, unfortunately. Also note that we
662+
// need to directly use m_opcode_name here (instead of opcode_name) so we
663+
// don't include color codes as characters.
653664
if (m_opcode_name.length() >= opcode_column_width) {
654665
opcode_column_width = m_opcode_name.length() + 1;
655666
}
656667

657-
ss.PutCString(m_opcode_name);
668+
ss.PutCString(opcode_name);
658669
ss.FillLastLineToColumn(opcode_pos + opcode_column_width, ' ');
659-
ss.PutCString(m_mnemonics);
670+
ss.PutCString(mnemonics);
660671

661672
if (!m_comment.empty()) {
662673
ss.FillLastLineToColumn(

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class DisassemblerLLVMC::MCDisasmInstance {
6363
void PrintMCInst(llvm::MCInst &mc_inst, lldb::addr_t pc,
6464
std::string &inst_string, std::string &comments_string);
6565
void SetStyle(bool use_hex_immed, HexImmediateStyle hex_style);
66+
void SetUseColor(bool use_color);
67+
bool GetUseColor() const;
6668
bool CanBranch(llvm::MCInst &mc_inst) const;
6769
bool HasDelaySlot(llvm::MCInst &mc_inst) const;
6870
bool IsCall(llvm::MCInst &mc_inst) const;
@@ -565,7 +567,9 @@ class InstructionLLVMC : public lldb_private::Instruction {
565567

566568
if (m_opcode.GetData(data)) {
567569
std::string out_string;
570+
std::string markup_out_string;
568571
std::string comment_string;
572+
std::string markup_comment_string;
569573

570574
DisassemblerScope disasm(*this, exe_ctx);
571575
if (disasm) {
@@ -607,7 +611,14 @@ class InstructionLLVMC : public lldb_private::Instruction {
607611

608612
if (inst_size > 0) {
609613
mc_disasm_ptr->SetStyle(use_hex_immediates, hex_style);
614+
615+
const bool saved_use_color = mc_disasm_ptr->GetUseColor();
616+
mc_disasm_ptr->SetUseColor(false);
610617
mc_disasm_ptr->PrintMCInst(inst, pc, out_string, comment_string);
618+
mc_disasm_ptr->SetUseColor(true);
619+
mc_disasm_ptr->PrintMCInst(inst, pc, markup_out_string,
620+
markup_comment_string);
621+
mc_disasm_ptr->SetUseColor(saved_use_color);
611622

612623
if (!comment_string.empty()) {
613624
AppendComment(comment_string);
@@ -672,6 +683,11 @@ class InstructionLLVMC : public lldb_private::Instruction {
672683
m_opcode_name = matches[1].str();
673684
m_mnemonics = matches[2].str();
674685
}
686+
matches.clear();
687+
if (s_regex.Execute(markup_out_string, &matches)) {
688+
m_markup_opcode_name = matches[1].str();
689+
m_markup_mnemonics = matches[2].str();
690+
}
675691
}
676692
}
677693
}
@@ -1344,10 +1360,12 @@ void DisassemblerLLVMC::MCDisasmInstance::PrintMCInst(
13441360
llvm::raw_string_ostream inst_stream(inst_string);
13451361
llvm::raw_string_ostream comments_stream(comments_string);
13461362

1363+
inst_stream.enable_colors(m_instr_printer_up->getUseColor());
13471364
m_instr_printer_up->setCommentStream(comments_stream);
13481365
m_instr_printer_up->printInst(&mc_inst, pc, llvm::StringRef(),
13491366
*m_subtarget_info_up, inst_stream);
13501367
m_instr_printer_up->setCommentStream(llvm::nulls());
1368+
13511369
comments_stream.flush();
13521370

13531371
static std::string g_newlines("\r\n");
@@ -1374,6 +1392,14 @@ void DisassemblerLLVMC::MCDisasmInstance::SetStyle(
13741392
}
13751393
}
13761394

1395+
void DisassemblerLLVMC::MCDisasmInstance::SetUseColor(bool use_color) {
1396+
m_instr_printer_up->setUseColor(use_color);
1397+
}
1398+
1399+
bool DisassemblerLLVMC::MCDisasmInstance::GetUseColor() const {
1400+
return m_instr_printer_up->getUseColor();
1401+
}
1402+
13771403
bool DisassemblerLLVMC::MCDisasmInstance::CanBranch(
13781404
llvm::MCInst &mc_inst) const {
13791405
if (m_instr_analysis_up)

lldb/test/API/python_api/disassemble-raw-data/TestDisassembleRawData.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,19 @@ def test_disassemble_raw_data(self):
5959
elif arch in ("aarch64", "arm64"):
6060
self.assertEqual(inst.GetMnemonic(target), "mov")
6161
self.assertEqual(inst.GetOperands(target), "w0, #0x63")
62+
self.assertEqual(inst.GetComment(target), "=99 ")
6263
self.assertEqual(
6364
inst.GetControlFlowKind(target), lldb.eInstructionControlFlowKindUnknown
6465
)
66+
# Make sure that using colors doesn't affect the output here.
67+
res = lldb.SBCommandReturnObject()
68+
ci = self.dbg.GetCommandInterpreter()
69+
ci.HandleCommand("settings set use-color true", res)
70+
self.assertEqual(inst.GetOperands(target), "w0, #0x63")
71+
self.assertEqual(inst.GetMnemonic(target), "mov")
72+
self.assertEqual(inst.GetComment(target), "=99 ")
73+
ci.HandleCommand("settings set use-color false", res)
74+
6575
elif arch == "arm":
6676
self.assertEqual(inst.GetMnemonic(target), "mov")
6777
self.assertEqual(inst.GetOperands(target), "r3, #99")
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# UNSUPPORTED: system-windows
2+
# REQUIRES: aarch64
3+
4+
# This checks that lldb's disassembler colors AArch64 disassembly.
5+
6+
# RUN: llvm-mc -filetype=obj -triple aarch64-linux-gnueabihf %s -o %t --mattr=+all
7+
# RUN: %lldb %t -o "settings set use-color true" -o "disassemble -n fn" -o exit 2>&1 | FileCheck %s
8+
9+
.globl fn
10+
.type fn, @function
11+
fn:
12+
// These are in alphabetical order by extension name
13+
aesd v0.16b, v0.16b // AEK_AES
14+
bfadd z23.h, p3/m, z23.h, z13.h // AEK_B16B16
15+
bfdot v2.2s, v3.4h, v4.4h // AEK_BF16
16+
brb iall // AEK_BRBE
17+
crc32b w0, w0, w0 // AEK_CRC
18+
// AEK_CRYPTO enables a combination of other features
19+
smin x0, x0, #0 // AEK_CSSC
20+
sysp #0, c2, c0, #0, x0, x1 // AEK_D128
21+
sdot v0.2s, v1.8b, v2.8b // AEK_DOTPROD
22+
fmmla z0.s, z1.s, z2.s // AEK_F32MM
23+
24+
# CHECK: `fn:
25+
# CHECK-NEXT: [0x0] <+0>: aesd v0.16b, v0.16b
26+
# CHECK-NEXT: [0x4] <+4>: bfadd z23.h, p3/m, z23.h, z13.h
27+
# CHECK-NEXT: [0x8] <+8>: bfdot v2.2s, v3.4h, v4.4h
28+
# CHECK-NEXT: [0xc] <+12>: brb iall
29+
# CHECK-NEXT: [0x10] <+16>: crc32b w0, w0, w0
30+
# CHECK-NEXT: [0x14] <+20>: smin x0, x0, #0x0
31+
# CHECK-NEXT: [0x18] <+24>: sysp #0x0, c2, c0, #0x0, x0, x1
32+
# CHECK-NEXT: [0x1c] <+28>: sdot v0.2s, v1.8b, v2.8b
33+
# CHECK-NEXT: [0x20] <+32>: fmmla z0.s, z1.s, z2.s

0 commit comments

Comments
 (0)