Skip to content

Commit

Permalink
[trace] Add a flag to the decoder to output the instruction type
Browse files Browse the repository at this point in the history
To build complex binding upon instruction trace, additional metadata 'instruction type' is needed.

This diff has followings:
 - Add a flag -k  / --kind for instruction dump
 - Remove SetGranularity and SetIgnoreErros from Trace cursor

Sample output:

```
(lldb) thread trace dump instruction -k
thread #1: tid = 3198805
  libc.so.6`_IO_puts + 356
    2107: 0x00007ffff7163594 (    return)     retq
    2106: 0x00007ffff7163592 (     other)     popq   %r13
    2105: 0x00007ffff7163590 (     other)     popq   %r12
    2104: 0x00007ffff716358f (     other)     popq   %rbp
    2103: 0x00007ffff716358e (     other)     popq   %rbx
    2102: 0x00007ffff716358c (     other)     movl   %ebx, %eax
    2101: 0x00007ffff7163588 (     other)     addq   $0x8, %rsp
    2100: 0x00007ffff7163570 ( cond jump)     je     0x89588                   ; <+344>
    2099: 0x00007ffff716356e (     other)     decl   (%rdx)
    2098: 0x00007ffff7163565 ( cond jump)     je     0x8956e                   ; <+318>
    2097: 0x00007ffff716355e (     other)     cmpl   $0x0, 0x33c02b(%rip)      ; __libc_multiple_threads
    2096: 0x00007ffff7163556 (     other)     movq   $0x0, 0x8(%rdx)
    2095: 0x00007ffff7163554 ( cond jump)     jne    0x89588                   ; <+344>
    2094: 0x00007ffff7163550 (     other)     subl   $0x1, 0x4(%rdx)
    2093: 0x00007ffff7163549 (     other)     movq   0x88(%rbp), %rdx
    2092: 0x00007ffff7163547 ( cond jump)     jne    0x89588                   ; <+344>
    2091: 0x00007ffff7163540 (     other)     testl  $0x8000, (%rbp)           ; imm = 0x8000
    2090: 0x00007ffff716353c (     other)     cmovaq %rax, %rbx
    2089: 0x00007ffff7163535 (     other)     cmpq   $0x7fffffff, %rbx         ; imm = 0x7FFFFFFF
    2088: 0x00007ffff7163530 (     other)     movl   $0x7fffffff, %eax         ; imm = 0x7FFFFFFF
```

Reviewed By: wallace

Differential Revision: https://reviews.llvm.org/D128477
  • Loading branch information
walter-erquinigo committed Jul 12, 2022
1 parent 5f8cefe commit ad7bcda
Show file tree
Hide file tree
Showing 24 changed files with 643 additions and 60 deletions.
17 changes: 14 additions & 3 deletions lldb/include/lldb/Core/Disassembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ class Instruction {
return m_comment.c_str();
}

/// \return
/// The control flow kind of this instruction, or
/// eInstructionControlFlowKindUnknown if the instruction
/// can't be classified.
lldb::InstructionControlFlowKind GetControlFlowKind(const ArchSpec &arch);

virtual void
CalculateMnemonicOperandsAndComment(const ExecutionContext *exe_ctx) = 0;

Expand All @@ -105,6 +111,9 @@ class Instruction {
/// \param[in] show_bytes
/// Whether the bytes of the assembly instruction should be printed.
///
/// \param[in] show_control_flow_kind
/// Whether the control flow kind 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)
Expand Down Expand Up @@ -140,7 +149,8 @@ class Instruction {
/// 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,
Expand Down Expand Up @@ -320,7 +330,7 @@ class InstructionList {
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;
Expand Down Expand Up @@ -375,7 +385,8 @@ class Disassembler : public std::enable_shared_from_this<Disassembler>,
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 {
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Target/TraceDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ struct TraceDumperOptions {
bool show_tsc = false;
/// Dump the events that happened between instructions.
bool show_events = false;
/// For each instruction, print the instruction kind.
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
Expand Down
38 changes: 24 additions & 14 deletions lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -970,20 +970,30 @@ enum ExpressionEvaluationPhase {
/// 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 InstructionControlFlowKind {
/// The instruction could not be classified.
eInstructionControlFlowKindUnknown = 0,
/// The instruction is something not listed below, i.e. it's a sequential
/// instruction that doesn't affect the control flow of the program.
eInstructionControlFlowKindOther,
/// The instruction is a near (function) call.
eInstructionControlFlowKindCall,
/// The instruction is a near (function) return.
eInstructionControlFlowKindReturn,
/// The instruction is a near unconditional jump.
eInstructionControlFlowKindJump,
/// The instruction is a near conditional jump.
eInstructionControlFlowKindCondJump,
/// The instruction is a call-like far transfer.
/// E.g. SYSCALL, SYSENTER, or FAR CALL.
eInstructionControlFlowKindFarCall,
/// The instruction is a return-like far transfer.
/// E.g. SYSRET, SYSEXIT, IRET, or FAR RET.
eInstructionControlFlowKindFarReturn,
/// The instruction is a jump-like far transfer.
/// E.g. FAR JMP.
eInstructionControlFlowKindFarJump
};

/// Watchpoint Kind.
///
Expand Down
7 changes: 4 additions & 3 deletions lldb/source/API/SBInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ bool SBInstruction::GetDescription(lldb::SBStream &s) {
// 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_kind=*/false,
nullptr, &sc, nullptr, &format, 0);
return true;
}
return false;
Expand Down Expand Up @@ -275,8 +276,8 @@ void SBInstruction::Print(FileSP out_sp) {
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_kind=*/false,
nullptr, &sc, nullptr, &format, 0);
}
}

Expand Down
5 changes: 3 additions & 2 deletions lldb/source/API/SBInstructionList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,9 @@ bool SBInstructionList::GetDescription(Stream &sref) {
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_kind=*/false, nullptr, &sc, &prev_sc,
&format, 0);
sref.EOL();
}
return true;
Expand Down
8 changes: 8 additions & 0 deletions lldb/source/Commands/CommandObjectDisassemble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
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);
Expand Down Expand Up @@ -154,6 +158,7 @@ void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
ExecutionContext *execution_context) {
show_mixed = false;
show_bytes = false;
show_control_flow_kind = false;
num_lines_context = 0;
num_instructions = 0;
func_name.clear();
Expand Down Expand Up @@ -493,6 +498,9 @@ bool CommandObjectDisassemble::DoExecute(Args &command,
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;

Expand Down
1 change: 1 addition & 0 deletions lldb/source/Commands/CommandObjectDisassemble.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class CommandObjectDisassemble : public CommandObjectParsed {

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;
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Commands/CommandObjectThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2174,6 +2174,10 @@ class CommandObjectTraceDumpInstructions : public CommandObjectParsed {
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;
Expand Down
10 changes: 10 additions & 0 deletions lldb/source/Commands/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ let Command = "breakpoint command delete" in {
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 to the enum "
"`InstructionControlFlowKind` for a list of control flow kind. "
"As an important note, far jumps, far calls and far returns often indicate "
"calls to and from kernel.">;
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">,
Expand Down Expand Up @@ -1150,6 +1155,11 @@ let Command = "thread trace dump instructions" in {
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<"Show instruction control flow kind. Refer to the enum "
"`InstructionControlFlowKind` for a list of control flow kind. "
"As an important note, far jumps, far calls and far returns often indicate "
"calls to and from kernel.">;
def thread_trace_dump_instructions_show_tsc : Option<"tsc", "t">, Group<1>,
Desc<"For each instruction, print the corresponding timestamp counter if "
"available.">;
Expand Down
Loading

0 comments on commit ad7bcda

Please sign in to comment.