persona0220 updated this revision to Diff 441226.
persona0220 marked 26 inline comments as done.
persona0220 added a comment.
- Modify function name `instruction_decode` into `DecodeInstructionOpcode`
- explicit naming for flag `show_kind` -> `show_control_flow_kind`
- Convert `InstructionControlFlowType` FLAG_ENUM into simple enum
- Create x86 namespace in `Disassembler.cpp` to decode instruction.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D128477/new/
https://reviews.llvm.org/D128477
Files:
lldb/include/lldb/Core/Disassembler.h
lldb/include/lldb/Target/TraceDumper.h
lldb/include/lldb/lldb-enumerations.h
lldb/source/API/SBInstruction.cpp
lldb/source/API/SBInstructionList.cpp
lldb/source/Commands/CommandObjectDisassemble.cpp
lldb/source/Commands/CommandObjectDisassemble.h
lldb/source/Commands/CommandObjectThread.cpp
lldb/source/Commands/Options.td
lldb/source/Core/Disassembler.cpp
lldb/source/Core/DumpDataExtractor.cpp
lldb/source/Expression/IRExecutionUnit.cpp
lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
lldb/source/Symbol/Function.cpp
lldb/source/Symbol/Symbol.cpp
lldb/source/Target/ThreadPlanTracer.cpp
lldb/source/Target/TraceDumper.cpp
Index: lldb/source/Target/TraceDumper.cpp
===================================================================
--- lldb/source/Target/TraceDumper.cpp
+++ lldb/source/Target/TraceDumper.cpp
@@ -147,14 +147,14 @@
m_s.Format("{0:x+16}", item.load_address);
if (item.symbol_info) {
m_s << " ";
- item.symbol_info->instruction->Dump(&m_s, /*max_opcode_byte_size=*/0,
- /*show_address=*/false,
- /*show_bytes=*/false,
- &item.symbol_info->exe_ctx,
- &item.symbol_info->sc,
- /*prev_sym_ctx=*/nullptr,
- /*disassembly_addr_format=*/nullptr,
- /*max_address_text_size=*/0);
+ item.symbol_info->instruction->Dump(
+ &m_s, /*max_opcode_byte_size=*/0,
+ /*show_address=*/false,
+ /*show_bytes=*/false, m_options.show_control_flow_kind,
+ &item.symbol_info->exe_ctx, &item.symbol_info->sc,
+ /*prev_sym_ctx=*/nullptr,
+ /*disassembly_addr_format=*/nullptr,
+ /*max_address_text_size=*/0);
}
}
Index: lldb/source/Target/ThreadPlanTracer.cpp
===================================================================
--- lldb/source/Target/ThreadPlanTracer.cpp
+++ lldb/source/Target/ThreadPlanTracer.cpp
@@ -170,13 +170,14 @@
if (instruction_list.GetSize()) {
const bool show_bytes = true;
const bool show_address = true;
+ const bool show_control_flow_kind = true;
Instruction *instruction =
instruction_list.GetInstructionAtIndex(0).get();
const FormatEntity::Entry *disassemble_format =
m_process.GetTarget().GetDebugger().GetDisassemblyFormat();
instruction->Dump(stream, max_opcode_byte_size, show_address,
- show_bytes, nullptr, nullptr, nullptr,
- disassemble_format, 0);
+ show_bytes, show_control_flow_kind, nullptr, nullptr,
+ nullptr, disassemble_format, 0);
}
}
}
Index: lldb/source/Symbol/Symbol.cpp
===================================================================
--- lldb/source/Symbol/Symbol.cpp
+++ lldb/source/Symbol/Symbol.cpp
@@ -558,8 +558,9 @@
if (disassembler_sp) {
const bool show_address = true;
const bool show_bytes = false;
- disassembler_sp->GetInstructionList().Dump(&strm, show_address, show_bytes,
- &exe_ctx);
+ const bool show_control_flow_kind = false;
+ disassembler_sp->GetInstructionList().Dump(
+ &strm, show_address, show_bytes, show_control_flow_kind, &exe_ctx);
return true;
}
return false;
Index: lldb/source/Symbol/Function.cpp
===================================================================
--- lldb/source/Symbol/Function.cpp
+++ lldb/source/Symbol/Function.cpp
@@ -440,8 +440,9 @@
if (disassembler_sp) {
const bool show_address = true;
const bool show_bytes = false;
- disassembler_sp->GetInstructionList().Dump(&strm, show_address, show_bytes,
- &exe_ctx);
+ const bool show_control_flow_kind = false;
+ disassembler_sp->GetInstructionList().Dump(
+ &strm, show_address, show_bytes, show_control_flow_kind, &exe_ctx);
return true;
}
return false;
Index: lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
===================================================================
--- lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -83,6 +83,7 @@
const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
const bool show_address = true;
const bool show_bytes = true;
+ const bool show_control_flow_kind = true;
m_inst_emulator_up->GetRegisterInfo(unwind_plan.GetRegisterKind(),
unwind_plan.GetInitialCFARegister(),
m_cfa_reg_info);
@@ -244,7 +245,8 @@
lldb_private::FormatEntity::Entry format;
FormatEntity::Parse("${frame.pc}: ", format);
inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
- show_bytes, nullptr, nullptr, nullptr, &format, 0);
+ show_bytes, show_control_flow_kind, nullptr, nullptr,
+ nullptr, &format, 0);
log->PutString(strm.GetString());
}
Index: lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
===================================================================
--- lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
+++ lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
@@ -158,7 +158,7 @@
cursor.Next();
} else {
lldb::addr_t current_instruction_load_address = cursor.GetLoadAddress();
- lldb::TraceInstructionControlFlowType current_instruction_type =
+ lldb::InstructionControlFlowType current_instruction_type =
cursor.GetInstructionControlFlowType();
m_instruction_layer_up->AppendInstruction(
@@ -166,7 +166,7 @@
cursor.Next();
bool more_data_in_trace = cursor.HasValue();
if (current_instruction_type &
- lldb::eTraceInstructionControlFlowTypeCall) {
+ lldb::eInstructionControlFlowTypeCall) {
if (more_data_in_trace && !cursor.IsError()) {
m_instruction_layer_up->AddCallInstructionMetadata(
current_instruction_load_address,
Index: lldb/source/Expression/IRExecutionUnit.cpp
===================================================================
--- lldb/source/Expression/IRExecutionUnit.cpp
+++ lldb/source/Expression/IRExecutionUnit.cpp
@@ -200,7 +200,9 @@
UINT32_MAX, false, false);
InstructionList &instruction_list = disassembler_sp->GetInstructionList();
- instruction_list.Dump(&stream, true, true, &exe_ctx);
+ instruction_list.Dump(&stream, true, true, /*show_control_flow_type*/ true,
+ &exe_ctx);
+
return ret;
}
Index: lldb/source/Core/DumpDataExtractor.cpp
===================================================================
--- lldb/source/Core/DumpDataExtractor.cpp
+++ lldb/source/Core/DumpDataExtractor.cpp
@@ -170,10 +170,11 @@
offset += bytes_consumed;
const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
const bool show_bytes = true;
+ const bool show_kind = true;
ExecutionContext exe_ctx;
exe_scope->CalculateExecutionContext(exe_ctx);
disassembler_sp->GetInstructionList().Dump(s, show_address, show_bytes,
- &exe_ctx);
+ show_kind, &exe_ctx);
}
}
} else
Index: lldb/source/Core/Disassembler.cpp
===================================================================
--- lldb/source/Core/Disassembler.cpp
+++ lldb/source/Core/Disassembler.cpp
@@ -527,8 +527,11 @@
}
const bool show_bytes = (options & eOptionShowBytes) != 0;
- inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc,
- &prev_sc, nullptr, address_text_size);
+ const bool show_control_flow_kind =
+ (options & eOptionShowControlFlowKind) != 0;
+ inst->Dump(&strm, max_opcode_byte_size, true, show_bytes,
+ show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
+ address_text_size);
strm.EOL();
} else {
break;
@@ -568,6 +571,283 @@
Instruction::~Instruction() = default;
+namespace x86 {
+enum PTI_MAP {
+ PTI_MAP_0, /* 1-byte opcodes. may have modrm */
+ PTI_MAP_1, /* 2-byte opcodes (0x0f). may have modrm */
+ PTI_MAP_2, /* 3-byte opcodes (0x0f38). has modrm */
+ PTI_MAP_3, /* 3-byte opcodes (0x0f3a). has modrm */
+ PTI_MAP_AMD3DNOW, /* 3d-now opcodes (0x0f0f). has modrm */
+ PTI_MAP_INVALID
+};
+
+/// Decide InstructionControlFlowType based on bytes of instruction.
+/// The insruction bytes are parsed beforehand into opcode, modrm and map byte
+/// to be passed as parameters.
+lldb::InstructionControlFlowType
+DecodeInstructionOpcode(uint8_t opcode, uint8_t modrm, uint8_t map) {
+ lldb::InstructionControlFlowType itype;
+ if (map > PTI_MAP_1)
+ return lldb::eInstructionControlFlowTypeUnknown;
+
+ if (opcode >= 0x70 && opcode <= 0x7F) {
+ if (map == PTI_MAP_0)
+ return lldb::eInstructionControlFlowTypeCondJump;
+ } else if (opcode >= 0x80 && opcode <= 0x8F) {
+ if (map == PTI_MAP_1)
+ return lldb::eInstructionControlFlowTypeCondJump;
+ }
+
+ itype = lldb::eInstructionControlFlowTypeOther;
+ switch (opcode) {
+ case 0x9A:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeFarCall;
+ break;
+ case 0xFF:
+ if (map == PTI_MAP_0) {
+ uint8_t modrm_reg = (modrm >> 3) & 7;
+ if (modrm_reg == 2)
+ itype = lldb::eInstructionControlFlowTypeCall;
+ else if (modrm_reg == 3)
+ itype = lldb::eInstructionControlFlowTypeFarCall;
+ else if (modrm_reg == 4)
+ itype = lldb::eInstructionControlFlowTypeJump;
+ else if (modrm_reg == 5)
+ itype = lldb::eInstructionControlFlowTypeFarJump;
+ }
+ break;
+ case 0xE8:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeCall;
+ break;
+ case 0xCD:
+ case 0xCC:
+ case 0xCE:
+ case 0xF1:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeFarCall;
+ break;
+ case 0xCF:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeFarReturn;
+ break;
+ case 0xE9:
+ case 0xEB:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeJump;
+ break;
+ case 0xEA:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeFarJump;
+ break;
+ case 0xE3:
+ case 0xE0:
+ case 0xE1:
+ case 0xE2:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeCondJump;
+ break;
+ case 0xC3:
+ case 0xC2:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeReturn;
+ break;
+ case 0xCB:
+ case 0xCA:
+ if (map == PTI_MAP_0)
+ itype = lldb::eInstructionControlFlowTypeFarReturn;
+ break;
+ case 0x05:
+ case 0x34:
+ if (map == PTI_MAP_1)
+ itype = lldb::eInstructionControlFlowTypeFarCall;
+ break;
+ case 0x35:
+ case 0x07:
+ if (map == PTI_MAP_1)
+ itype = lldb::eInstructionControlFlowTypeFarReturn;
+ break;
+ case 0x01:
+ if (map == PTI_MAP_1) {
+ switch (modrm) {
+ case 0xc1:
+ itype = lldb::eInstructionControlFlowTypeFarCall;
+ break;
+ case 0xc2:
+ case 0xc3:
+ itype = lldb::eInstructionControlFlowTypeFarReturn;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return itype;
+}
+
+lldb::InstructionControlFlowType
+GetControlFlowInstructionKind(const ExecutionContext *exe_ctx,
+ Opcode m_opcode) {
+ // inst_bytes will be parsed into opcode, modrm and map bytes.
+ // These are the three values deciding instruction control flow type.
+ uint8_t inst_bytes[16];
+ uint8_t opcode, modrm, map;
+ int op_idx = 0;
+ bool prefix_done = false;
+
+ if (m_opcode.GetOpcodeBytes() == nullptr || m_opcode.GetByteSize() <= 0) {
+ // x86_64 and i386 are the only ones that use bytes right now
+ // Else, we have ARM or MIPS, not yet implemented
+ return lldb::eInstructionControlFlowTypeUnknown;
+ }
+
+ memcpy(inst_bytes, m_opcode.GetOpcodeBytes(), m_opcode.GetByteSize());
+
+ // In most cases, opcode is the first byte of instruction (and modrm is the
+ // second byte), but some instructions has prefix to be skipped.
+ // The mapping is inspired from libipt's instruction decode logic
+ // in `src/pt_ild.c`
+ map = PTI_MAP_INVALID;
+ while (!prefix_done) {
+ opcode = inst_bytes[op_idx];
+ switch (opcode) {
+ // prefix_ignore
+ case 0x26:
+ case 0x2e:
+ case 0x36:
+ case 0x3e:
+ case 0x64:
+ case 0x65:
+ // prefix_osz, prefix_asz
+ case 0x66:
+ case 0x67:
+ // prefix_lock, prefix_f2, prefix_f3
+ case 0xf0:
+ case 0xf2:
+ case 0xf3:
+ op_idx++;
+ break;
+
+ // prefix_rex
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ if (exe_ctx->GetTargetRef().GetArchitecture().GetMachine() ==
+ llvm::Triple::ArchType::x86_64)
+ op_idx++;
+ else
+ prefix_done = true;
+ break;
+
+ // prefix_vex_c4, c5
+ case 0xc5:
+ if (exe_ctx->GetTargetRef().GetArchitecture().GetMachine() !=
+ llvm::Triple::ArchType::x86_64 &&
+ (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+
+ map = PTI_MAP_1;
+ opcode = inst_bytes[op_idx + 2];
+ modrm = inst_bytes[op_idx + 3];
+ return DecodeInstructionOpcode(opcode, modrm, map);
+ break;
+
+ case 0xc4:
+ if (exe_ctx->GetTargetRef().GetArchitecture().GetMachine() !=
+ llvm::Triple::ArchType::x86_64 &&
+ (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+ map = inst_bytes[op_idx + 1] & 0x1f;
+ opcode = inst_bytes[op_idx + 3];
+ modrm = inst_bytes[op_idx + 4];
+ return DecodeInstructionOpcode(opcode, modrm, map);
+ break;
+
+ // prefix_evex
+ case 0x62:
+ if (exe_ctx->GetTargetRef().GetArchitecture().GetMachine() !=
+ llvm::Triple::ArchType::x86_64 &&
+ (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+ map = inst_bytes[op_idx + 1] & 0x03;
+ opcode = inst_bytes[op_idx + 4];
+ modrm = inst_bytes[op_idx + 5];
+ return DecodeInstructionOpcode(opcode, modrm, map);
+ break;
+
+ default:
+ prefix_done = true;
+ break;
+ }
+ } // prefix done
+
+ opcode = inst_bytes[op_idx];
+ modrm = inst_bytes[op_idx + 1];
+ map = PTI_MAP_0;
+
+ if (opcode == 0x0F) {
+ if (inst_bytes[op_idx + 1] == 0x38) {
+ map = PTI_MAP_2;
+ opcode = inst_bytes[op_idx + 2];
+ modrm = inst_bytes[op_idx + 3];
+ } else if (inst_bytes[op_idx + 1] == 0x3A) {
+ map = PTI_MAP_3;
+ opcode = inst_bytes[op_idx + 2];
+ modrm = inst_bytes[op_idx + 3];
+ } else if ((inst_bytes[op_idx + 1] & 0xf8) == 0x38) {
+ map = PTI_MAP_INVALID;
+ opcode = inst_bytes[op_idx + 2];
+ modrm = inst_bytes[op_idx + 3];
+ } else if (inst_bytes[op_idx + 1] == 0x0F) {
+ map = PTI_MAP_AMD3DNOW;
+ opcode = inst_bytes[op_idx + 1];
+ modrm = inst_bytes[op_idx + 2];
+ } else {
+ map = PTI_MAP_1;
+ opcode = inst_bytes[op_idx + 1];
+ modrm = inst_bytes[op_idx + 2];
+ }
+ }
+
+ return DecodeInstructionOpcode(opcode, modrm, map);
+}
+
+} // namespace x86
+
+lldb::InstructionControlFlowType
+Instruction::GetControlFlowInstructionKind(const ExecutionContext *exe_ctx) {
+ if (exe_ctx->GetTargetRef().GetArchitecture().GetMachine() ==
+ llvm::Triple::ArchType::x86 ||
+ exe_ctx->GetTargetRef().GetArchitecture().GetMachine() ==
+ llvm::Triple::ArchType::x86_64) {
+ return x86::GetControlFlowInstructionKind(exe_ctx, m_opcode);
+ } else
+ return eInstructionControlFlowTypeUnknown; // not implemented
+}
+
AddressClass Instruction::GetAddressClass() {
if (m_address_class == AddressClass::eInvalid)
m_address_class = m_address.GetAddressClass();
@@ -576,6 +856,7 @@
void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
bool show_address, bool show_bytes,
+ bool show_control_flow_kind,
const ExecutionContext *exe_ctx,
const SymbolContext *sym_ctx,
const SymbolContext *prev_sym_ctx,
@@ -613,6 +894,38 @@
}
}
+ if (show_control_flow_kind) {
+ switch (GetControlFlowInstructionKind(exe_ctx)) {
+ case eInstructionControlFlowTypeUnknown:
+ ss.Printf("%-12s", "unknown");
+ break;
+ case eInstructionControlFlowTypeOther:
+ ss.Printf("%-12s", "other");
+ break;
+ case eInstructionControlFlowTypeCall:
+ ss.Printf("%-12s", "call");
+ break;
+ case eInstructionControlFlowTypeReturn:
+ ss.Printf("%-12s", "return");
+ break;
+ case eInstructionControlFlowTypeJump:
+ ss.Printf("%-12s", "jump");
+ break;
+ case eInstructionControlFlowTypeCondJump:
+ ss.Printf("%-12s", "cond jump");
+ break;
+ case eInstructionControlFlowTypeFarCall:
+ ss.Printf("%-12s", "far call");
+ break;
+ case eInstructionControlFlowTypeFarReturn:
+ ss.Printf("%-12s", "far return");
+ break;
+ case eInstructionControlFlowTypeFarJump:
+ ss.Printf("%-12s", "far jump");
+ break;
+ }
+ }
+
const size_t opcode_pos = ss.GetSizeOfLastLine();
// The default opcode size of 7 characters is plenty for most architectures
@@ -957,6 +1270,7 @@
}
void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,
+ bool show_control_flow_kind,
const ExecutionContext *exe_ctx) {
const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
collection::const_iterator pos, begin, end;
@@ -975,8 +1289,9 @@
pos != end; ++pos) {
if (pos != begin)
s->EOL();
- (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx,
- nullptr, nullptr, disassembly_format, 0);
+ (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes,
+ show_control_flow_kind, exe_ctx, nullptr, nullptr,
+ disassembly_format, 0);
}
}
@@ -994,7 +1309,7 @@
size_t num_instructions = m_instructions.size();
uint32_t next_branch = UINT32_MAX;
-
+
if (found_calls)
*found_calls = false;
for (size_t i = start; i < num_instructions; i++) {
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -300,6 +300,10 @@
let Command = "disassemble" in {
def disassemble_options_bytes : Option<"bytes", "b">,
Desc<"Show opcode bytes when disassembling.">;
+ def disassemble_options_kind : Option<"kind", "k">,
+ Desc<"Show instruction control flow kind. Refer enum "
+ "`InstructionControlFlowType` for a list of control flow kind. "
+ "far jump and far return often indicate syscall and return.">;
def disassemble_options_context : Option<"context", "C">, Arg<"NumLines">,
Desc<"Number of context lines of source to show.">;
def disassemble_options_mixed : Option<"mixed", "m">,
@@ -1150,6 +1154,10 @@
def thread_trace_dump_instructions_pretty_print: Option<"pretty-json", "J">,
Group<1>,
Desc<"Dump in JSON format but pretty printing the output for easier readability.">;
+ def thread_trace_dump_instructions_show_kind : Option<"kind", "k">, Group<1>,
+ Desc<"For each instruction, print the instruction control flow kind. "
+ "`InstructionControlFlowType` enum has a list of control flow kind. "
+ "far jump and far return often indicate syscall and return.">;
def thread_trace_dump_instructions_show_tsc : Option<"tsc", "t">, Group<1>,
Desc<"For each instruction, print the corresponding timestamp counter if "
"available.">;
Index: lldb/source/Commands/CommandObjectThread.cpp
===================================================================
--- lldb/source/Commands/CommandObjectThread.cpp
+++ lldb/source/Commands/CommandObjectThread.cpp
@@ -2164,6 +2164,10 @@
m_dumper_options.forwards = true;
break;
}
+ case 'k': {
+ m_dumper_options.show_control_flow_kind = true;
+ break;
+ }
case 't': {
m_dumper_options.show_tsc = true;
break;
Index: lldb/source/Commands/CommandObjectDisassemble.h
===================================================================
--- lldb/source/Commands/CommandObjectDisassemble.h
+++ lldb/source/Commands/CommandObjectDisassemble.h
@@ -46,6 +46,7 @@
bool show_mixed; // Show mixed source/assembly
bool show_bytes;
+ bool show_control_flow_kind;
uint32_t num_lines_context = 0;
uint32_t num_instructions = 0;
bool raw;
Index: lldb/source/Commands/CommandObjectDisassemble.cpp
===================================================================
--- lldb/source/Commands/CommandObjectDisassemble.cpp
+++ lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -65,6 +65,10 @@
show_bytes = true;
break;
+ case 'k':
+ show_control_flow_kind = true;
+ break;
+
case 's': {
start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
LLDB_INVALID_ADDRESS, &error);
@@ -154,6 +158,7 @@
ExecutionContext *execution_context) {
show_mixed = false;
show_bytes = false;
+ show_control_flow_kind = false;
num_lines_context = 0;
num_instructions = 0;
func_name.clear();
@@ -493,6 +498,9 @@
if (m_options.show_bytes)
options |= Disassembler::eOptionShowBytes;
+ if (m_options.show_control_flow_kind)
+ options |= Disassembler::eOptionShowControlFlowKind;
+
if (m_options.raw)
options |= Disassembler::eOptionRawOuput;
Index: lldb/source/API/SBInstructionList.cpp
===================================================================
--- lldb/source/API/SBInstructionList.cpp
+++ lldb/source/API/SBInstructionList.cpp
@@ -165,8 +165,9 @@
addr, eSymbolContextEverything, sc);
}
- inst->Dump(&sref, max_opcode_byte_size, true, false, nullptr, &sc,
- &prev_sc, &format, 0);
+ inst->Dump(&sref, max_opcode_byte_size, true, false,
+ /*show_control_flow_type*/ false, nullptr, &sc, &prev_sc,
+ &format, 0);
sref.EOL();
}
return true;
Index: lldb/source/API/SBInstruction.cpp
===================================================================
--- lldb/source/API/SBInstruction.cpp
+++ lldb/source/API/SBInstruction.cpp
@@ -241,7 +241,8 @@
// didn't have a stream already created, one will get created...
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
- inst_sp->Dump(&s.ref(), 0, true, false, nullptr, &sc, nullptr, &format, 0);
+ inst_sp->Dump(&s.ref(), 0, true, false, /*show_control_flow_type*/ false,
+ nullptr, &sc, nullptr, &format, 0);
return true;
}
return false;
@@ -275,8 +276,8 @@
StreamFile out_stream(out_sp);
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
- inst_sp->Dump(&out_stream, 0, true, false, nullptr, &sc, nullptr, &format,
- 0);
+ inst_sp->Dump(&out_stream, 0, true, false, /*show_control_flow_type*/ false,
+ nullptr, &sc, nullptr, &format, 0);
}
}
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -970,20 +970,29 @@
/// control flow of a trace.
///
/// A single instruction can match one or more of these categories.
-FLAGS_ENUM(TraceInstructionControlFlowType){
- /// Any instruction.
- eTraceInstructionControlFlowTypeInstruction = (1u << 1),
- /// A conditional or unconditional branch/jump.
- eTraceInstructionControlFlowTypeBranch = (1u << 2),
- /// A conditional or unconditional branch/jump that changed
- /// the control flow of the program.
- eTraceInstructionControlFlowTypeTakenBranch = (1u << 3),
- /// A call to a function.
- eTraceInstructionControlFlowTypeCall = (1u << 4),
- /// A return from a function.
- eTraceInstructionControlFlowTypeReturn = (1u << 5)};
-
-LLDB_MARK_AS_BITMASK_ENUM(TraceInstructionControlFlowType)
+enum InstructionControlFlowType {
+ /// The instruction could not be classified.
+ eInstructionControlFlowTypeUnknown = 0,
+ /// The instruction is something not listed below.
+ eInstructionControlFlowTypeOther,
+ /// The instruction is a near (function) call.
+ eInstructionControlFlowTypeCall,
+ /// The instruction is a near (function) return.
+ eInstructionControlFlowTypeReturn,
+ /// The instruction is a near unconditional jump.
+ eInstructionControlFlowTypeJump,
+ /// The instruction is a near conditional jump.
+ eInstructionControlFlowTypeCondJump,
+ /// The instruction is a call-like far transfer.
+ /// E.g. SYSCALL, SYSENTER, or FAR CALL.
+ eInstructionControlFlowTypeFarCall,
+ /// The instruction is a return-like far transfer.
+ /// E.g. SYSRET, SYSEXIT, IRET, or FAR RET.
+ eInstructionControlFlowTypeFarReturn,
+ /// The instruction is a jump-like far transfer.
+ /// E.g. FAR JMP.
+ eInstructionControlFlowTypeFarJump
+};
/// Watchpoint Kind.
///
Index: lldb/include/lldb/Target/TraceDumper.h
===================================================================
--- lldb/include/lldb/Target/TraceDumper.h
+++ lldb/include/lldb/Target/TraceDumper.h
@@ -34,6 +34,8 @@
bool show_tsc = false;
/// Dump the events that happened between instructions.
bool show_events = false;
+ /// For each instruction, print the instruction type.
+ bool show_control_flow_kind = false;
/// Optional custom id to start traversing from.
llvm::Optional<uint64_t> id = llvm::None;
/// Optional number of instructions to skip from the starting position
Index: lldb/include/lldb/Core/Disassembler.h
===================================================================
--- lldb/include/lldb/Core/Disassembler.h
+++ lldb/include/lldb/Core/Disassembler.h
@@ -79,6 +79,9 @@
return m_comment.c_str();
}
+ lldb::InstructionControlFlowType
+ GetControlFlowInstructionKind(const ExecutionContext *exe_ctx);
+
virtual void
CalculateMnemonicOperandsAndComment(const ExecutionContext *exe_ctx) = 0;
@@ -105,6 +108,9 @@
/// \param[in] show_bytes
/// Whether the bytes of the assembly instruction should be printed.
///
+ /// \param[in] show_control_flow_kind
+ /// Whether the control flow type of the instruction should be printed.
+ ///
/// \param[in] max_opcode_byte_size
/// The size (in bytes) of the largest instruction in the list that
/// we are printing (for text justification/alignment purposes)
@@ -140,7 +146,8 @@
/// so this method can properly align the instruction opcodes.
/// May be 0 to indicate no indentation/alignment of the opcodes.
virtual void Dump(Stream *s, uint32_t max_opcode_byte_size, bool show_address,
- bool show_bytes, const ExecutionContext *exe_ctx,
+ bool show_bytes, bool show_control_flow_kind,
+ const ExecutionContext *exe_ctx,
const SymbolContext *sym_ctx,
const SymbolContext *prev_sym_ctx,
const FormatEntity::Entry *disassembly_addr_format,
@@ -320,7 +327,7 @@
void Append(lldb::InstructionSP &inst_sp);
void Dump(Stream *s, bool show_address, bool show_bytes,
- const ExecutionContext *exe_ctx);
+ bool show_control_flow_kind, const ExecutionContext *exe_ctx);
private:
typedef std::vector<lldb::InstructionSP> collection;
@@ -375,7 +382,8 @@
eOptionMarkPCSourceLine = (1u << 2), // Mark the source line that contains
// the current PC (mixed mode only)
eOptionMarkPCAddress =
- (1u << 3) // Mark the disassembly line the contains the PC
+ (1u << 3), // Mark the disassembly line the contains the PC
+ eOptionShowControlFlowKind = (1u << 4),
};
enum HexImmediateStyle {
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits