aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-27 20:11:54 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-08 19:04:48 +0000
commit972a253a57b6f144b0e4a3e2080a2a0076ec55a0 (patch)
treea8aeeb0997a0a52500f1fa0644244206cf71df94 /contrib/llvm-project/lldb
parentfcaf7f8644a9988098ac6be2165bce3ea4786e91 (diff)
parent08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff)
Diffstat (limited to 'contrib/llvm-project/lldb')
-rw-r--r--contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h8
-rw-r--r--contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h15
-rw-r--r--contrib/llvm-project/lldb/include/lldb/Target/Process.h4
-rw-r--r--contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h36
-rw-r--r--contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h7
-rw-r--r--contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h4
-rw-r--r--contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h8
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp3
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp2
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp2
-rw-r--r--contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp2
-rw-r--r--contrib/llvm-project/lldb/source/Commands/Options.td10
-rw-r--r--contrib/llvm-project/lldb/source/Core/Disassembler.cpp385
-rw-r--r--contrib/llvm-project/lldb/source/Host/common/Host.cpp2
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp331
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp10
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp5
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp4
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp85
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h7
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp4
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp65
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h6
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp2
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp3
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp72
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h14
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp18
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h2
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp68
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp3
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp2
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp198
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h180
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp57
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h10
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp19
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h6
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp89
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h46
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp50
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h9
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp26
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h6
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp2
-rw-r--r--contrib/llvm-project/lldb/source/Symbol/Type.cpp4
-rw-r--r--contrib/llvm-project/lldb/source/Target/Process.cpp15
-rw-r--r--contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp4
-rw-r--r--contrib/llvm-project/lldb/source/Target/StackFrame.cpp42
-rw-r--r--contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp10
-rw-r--r--contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp4
-rw-r--r--contrib/llvm-project/lldb/source/Target/TraceCursor.cpp2
-rw-r--r--contrib/llvm-project/lldb/source/Target/TraceDumper.cpp58
53 files changed, 1276 insertions, 750 deletions
diff --git a/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h b/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h
index 2cb983c40d19..b9ac0a5bca39 100644
--- a/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h
+++ b/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h
@@ -83,7 +83,10 @@ public:
/// The control flow kind of this instruction, or
/// eInstructionControlFlowKindUnknown if the instruction
/// can't be classified.
- lldb::InstructionControlFlowKind GetControlFlowKind(const ArchSpec &arch);
+ virtual lldb::InstructionControlFlowKind
+ GetControlFlowKind(const ExecutionContext *exe_ctx) {
+ return lldb::eInstructionControlFlowKindUnknown;
+ }
virtual void
CalculateMnemonicOperandsAndComment(const ExecutionContext *exe_ctx) = 0;
@@ -223,6 +226,9 @@ public:
virtual bool IsCall() { return false; }
+ static const char *GetNameForInstructionControlFlowKind(
+ lldb::InstructionControlFlowKind instruction_control_flow_kind);
+
protected:
Address m_address; // The section offset address of this instruction
// We include an address class in the Instruction class to
diff --git a/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h b/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h
index 28a8acc34632..b082224c38ed 100644
--- a/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h
+++ b/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h
@@ -113,6 +113,21 @@ public:
UnpackTagsData(const std::vector<uint8_t> &tags,
size_t granules = 0) const = 0;
+ // Unpack tags from a corefile segment containing compressed tags
+ // (compression that may be different from the one used for GDB transport).
+ //
+ // This method asumes that:
+ // * addr and len have been granule aligned by a tag manager
+ // * addr >= tag_segment_virtual_address
+ //
+ // 'reader' will always be a wrapper around a CoreFile in real use
+ // but allows testing without having to mock a CoreFile.
+ typedef std::function<size_t(lldb::offset_t, size_t, void *)> CoreReaderFn;
+ std::vector<lldb::addr_t> virtual UnpackTagsFromCoreFileSegment(
+ CoreReaderFn reader, lldb::addr_t tag_segment_virtual_address,
+ lldb::addr_t tag_segment_data_address, lldb::addr_t addr,
+ size_t len) const = 0;
+
// Pack uncompressed tags into their storage format (e.g. for gdb QMemTags).
// Checks that each tag is within the expected value range.
// We do not check the number of tags or range they apply to because
diff --git a/contrib/llvm-project/lldb/include/lldb/Target/Process.h b/contrib/llvm-project/lldb/include/lldb/Target/Process.h
index a55659225ef1..505e211e09b6 100644
--- a/contrib/llvm-project/lldb/include/lldb/Target/Process.h
+++ b/contrib/llvm-project/lldb/include/lldb/Target/Process.h
@@ -1715,8 +1715,8 @@ public:
/// an error saying so.
/// If it does, either the memory tags or an error describing a
/// failure to read or unpack them.
- llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr,
- size_t len);
+ virtual llvm::Expected<std::vector<lldb::addr_t>>
+ ReadMemoryTags(lldb::addr_t addr, size_t len);
/// Write memory tags for a range of memory.
/// (calls DoWriteMemoryTags to do the target specific work)
diff --git a/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h b/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h
index f6337e3d3d3f..95b022331634 100644
--- a/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h
+++ b/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h
@@ -215,7 +215,7 @@ public:
/// of this cursor.
ExecutionContextRef &GetExecutionContextRef();
- /// Instruction, event or error information
+ /// Trace item information (instructions, errors and events)
/// \{
/// \return
@@ -255,27 +255,35 @@ public:
/// The load address of the instruction the cursor is pointing at.
virtual lldb::addr_t GetLoadAddress() const = 0;
- /// Get the hardware counter of a given type associated with the current
- /// instruction. Each architecture might support different counters. It might
- /// happen that only some instructions of an entire trace have a given counter
- /// associated with them.
- ///
- /// \param[in] counter_type
- /// The counter type.
- /// \return
- /// The value of the counter or \b llvm::None if not available.
- virtual llvm::Optional<uint64_t>
- GetCounter(lldb::TraceCounter counter_type) const = 0;
-
/// Get the CPU associated with the current trace item.
///
/// This call might not be O(1), so it's suggested to invoke this method
- /// whenever a cpu change event is fired.
+ /// whenever an eTraceEventCPUChanged event is fired.
///
/// \return
/// The requested CPU id, or \a llvm::None if this information is
/// not available for the current item.
virtual llvm::Optional<lldb::cpu_id_t> GetCPU() const = 0;
+
+ /// Get the last hardware clock value that was emitted before the current
+ /// trace item.
+ ///
+ /// This call might not be O(1), so it's suggested to invoke this method
+ /// whenever an eTraceEventHWClockTick event is fired.
+ ///
+ /// \return
+ /// The requested HW clock value, or \a llvm::None if this information is
+ /// not available for the current item.
+ virtual llvm::Optional<uint64_t> GetHWClock() const = 0;
+
+ /// Get the approximate wall clock time in nanoseconds at which the current
+ /// trace item was executed. Each trace plug-in has a different definition for
+ /// what time 0 means.
+ ///
+ /// \return
+ /// The approximate wall clock time for the trace item, or \a llvm::None
+ /// if not available.
+ virtual llvm::Optional<double> GetWallClockTime() const = 0;
/// \}
protected:
diff --git a/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h b/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h
index bbc1a55873d7..ada779990e07 100644
--- a/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h
+++ b/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h
@@ -29,9 +29,9 @@ struct TraceDumperOptions {
bool json = false;
/// When dumping in JSON format, pretty print the output.
bool pretty_print_json = false;
- /// For each instruction, print the corresponding timestamp counter if
+ /// For each trace item, print the corresponding timestamp in nanoseconds if
/// available.
- bool show_tsc = false;
+ bool show_timestamps = false;
/// Dump the events that happened between instructions.
bool show_events = false;
/// For each instruction, print the instruction kind.
@@ -61,7 +61,8 @@ public:
struct TraceItem {
lldb::user_id_t id;
lldb::addr_t load_address;
- llvm::Optional<uint64_t> tsc;
+ llvm::Optional<double> timestamp;
+ llvm::Optional<uint64_t> hw_clock;
llvm::Optional<llvm::StringRef> error;
llvm::Optional<lldb::TraceEvent> event;
llvm::Optional<SymbolInfo> symbol_info;
diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
index bf9409743a6d..5930cd9970e7 100644
--- a/contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ b/contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -91,8 +91,8 @@ struct LinuxPerfZeroTscConversion {
/// nanoseconds) is defined by the kernel at boot time and has no particularly
/// useful meaning. On the other hand, this value is constant for an entire
/// trace session.
- // See 'time_zero' section of
- // https://man7.org/linux/man-pages/man2/perf_event_open.2.html
+ /// See 'time_zero' section of
+ /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html
///
/// \param[in] tsc
/// The TSC value to be converted.
diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h b/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h
index 83b98c37d122..80046e7e6bee 100644
--- a/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h
+++ b/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h
@@ -1159,12 +1159,6 @@ enum SaveCoreStyle {
eSaveCoreStackOnly = 3,
};
-// Type of counter values associated with instructions in a trace.
-enum TraceCounter {
- // Timestamp counter, like the one offered by Intel CPUs (TSC).
- eTraceCounterTSC = 0,
-};
-
/// Events that might happen during a trace session.
enum TraceEvent {
/// Tracing was disabled for some time due to a software trigger
@@ -1174,6 +1168,8 @@ enum TraceEvent {
/// Event due to CPU change for a thread. This event is also fired when
/// suddenly it's not possible to identify the cpu of a given thread.
eTraceEventCPUChanged,
+ /// Event due to a CPU HW clock tick
+ eTraceEventHWClockTick,
};
// Enum used to identify which kind of item a \a TraceCursor is pointing at
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp
index a11e2b719727..e65e12fe557a 100644
--- a/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -216,8 +216,7 @@ CommandObjectDisassemble::CommandObjectDisassemble(
"Disassemble specified instructions in the current target. "
"Defaults to the current function for the current thread and "
"stack frame.",
- "disassemble [<cmd-options>]", eCommandRequiresTarget),
- m_options() {}
+ "disassemble [<cmd-options>]", eCommandRequiresTarget) {}
CommandObjectDisassemble::~CommandObjectDisassemble() = default;
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp
index 0fb50420f70f..083309121b66 100644
--- a/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp
@@ -187,7 +187,7 @@ CommandObjectExpression::CommandObjectExpression(
m_format_options(eFormatDefault),
m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false,
true),
- m_command_options(), m_expr_line_count(0) {
+ m_expr_line_count(0) {
SetHelpLong(
R"(
Single and multi-line expressions:
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp
index ca0384cf9453..5051f9aeec85 100644
--- a/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp
@@ -1659,7 +1659,7 @@ class CommandObjectMemoryRegion : public CommandObjectParsed {
public:
class OptionGroupMemoryRegion : public OptionGroup {
public:
- OptionGroupMemoryRegion() : OptionGroup(), m_all(false, false) {}
+ OptionGroupMemoryRegion() : m_all(false, false) {}
~OptionGroupMemoryRegion() override = default;
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp
index 1371b9dbda1e..fe0cb0945cde 100644
--- a/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp
+++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp
@@ -2162,7 +2162,7 @@ public:
break;
}
case 't': {
- m_dumper_options.show_tsc = true;
+ m_dumper_options.show_timestamps = true;
break;
}
case 'e': {
diff --git a/contrib/llvm-project/lldb/source/Commands/Options.td b/contrib/llvm-project/lldb/source/Commands/Options.td
index 78221db18e65..cc47db575306 100644
--- a/contrib/llvm-project/lldb/source/Commands/Options.td
+++ b/contrib/llvm-project/lldb/source/Commands/Options.td
@@ -1146,15 +1146,17 @@ let Command = "thread trace dump instructions" in {
Desc<"Dump in simple JSON format.">;
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.">;
+ 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.">;
+ def thread_trace_dump_instructions_show_timestamps: Option<"time", "t">,
+ Group<1>,
+ Desc<"For each trace item, print the corresponding wall clock timestamp "
+ "if available.">;
def thread_trace_dump_instructions_show_events : Option<"events", "e">,
Group<1>,
Desc<"Dump the events that happened during the execution of the target.">;
diff --git a/contrib/llvm-project/lldb/source/Core/Disassembler.cpp b/contrib/llvm-project/lldb/source/Core/Disassembler.cpp
index 7a9e214748a7..4c57be44dc9c 100644
--- a/contrib/llvm-project/lldb/source/Core/Disassembler.cpp
+++ b/contrib/llvm-project/lldb/source/Core/Disassembler.cpp
@@ -571,340 +571,36 @@ Instruction::Instruction(const Address &address, AddressClass addr_class)
Instruction::~Instruction() = default;
-namespace x86 {
-
-/// These are the three values deciding instruction control flow kind.
-/// InstructionLengthDecode function decodes an instruction and get this struct.
-///
-/// primary_opcode
-/// Primary opcode of the instruction.
-/// For one-byte opcode instruction, it's the first byte after prefix.
-/// For two- and three-byte opcodes, it's the second byte.
-///
-/// opcode_len
-/// The length of opcode in bytes. Valid opcode lengths are 1, 2, or 3.
-///
-/// modrm
-/// ModR/M byte of the instruction.
-/// Bits[7:6] indicate MOD. Bits[5:3] specify a register and R/M bits[2:0]
-/// may contain a register or specify an addressing mode, depending on MOD.
-struct InstructionOpcodeAndModrm {
- uint8_t primary_opcode;
- uint8_t opcode_len;
- uint8_t modrm;
-};
-
-/// Determine the InstructionControlFlowKind based on opcode and modrm bytes.
-/// Refer to http://ref.x86asm.net/coder.html for the full list of opcode and
-/// instruction set.
-///
-/// \param[in] opcode_and_modrm
-/// Contains primary_opcode byte, its length, and ModR/M byte.
-/// Refer to the struct InstructionOpcodeAndModrm for details.
-///
-/// \return
-/// The control flow kind of the instruction or
-/// eInstructionControlFlowKindOther if the instruction doesn't affect
-/// the control flow of the program.
-lldb::InstructionControlFlowKind
-MapOpcodeIntoControlFlowKind(InstructionOpcodeAndModrm opcode_and_modrm) {
- uint8_t opcode = opcode_and_modrm.primary_opcode;
- uint8_t opcode_len = opcode_and_modrm.opcode_len;
- uint8_t modrm = opcode_and_modrm.modrm;
-
- if (opcode_len > 2)
- return lldb::eInstructionControlFlowKindOther;
-
- if (opcode >= 0x70 && opcode <= 0x7F) {
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindCondJump;
- else
- return lldb::eInstructionControlFlowKindOther;
- }
-
- if (opcode >= 0x80 && opcode <= 0x8F) {
- if (opcode_len == 2)
- return lldb::eInstructionControlFlowKindCondJump;
- else
- return lldb::eInstructionControlFlowKindOther;
- }
-
- switch (opcode) {
- case 0x9A:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarCall;
- break;
- case 0xFF:
- if (opcode_len == 1) {
- uint8_t modrm_reg = (modrm >> 3) & 7;
- if (modrm_reg == 2)
- return lldb::eInstructionControlFlowKindCall;
- else if (modrm_reg == 3)
- return lldb::eInstructionControlFlowKindFarCall;
- else if (modrm_reg == 4)
- return lldb::eInstructionControlFlowKindJump;
- else if (modrm_reg == 5)
- return lldb::eInstructionControlFlowKindFarJump;
- }
- break;
- case 0xE8:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindCall;
- break;
- case 0xCD:
- case 0xCC:
- case 0xCE:
- case 0xF1:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarCall;
- break;
- case 0xCF:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarReturn;
- break;
- case 0xE9:
- case 0xEB:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindJump;
- break;
- case 0xEA:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarJump;
- break;
- case 0xE3:
- case 0xE0:
- case 0xE1:
- case 0xE2:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindCondJump;
- break;
- case 0xC3:
- case 0xC2:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindReturn;
- break;
- case 0xCB:
- case 0xCA:
- if (opcode_len == 1)
- return lldb::eInstructionControlFlowKindFarReturn;
- break;
- case 0x05:
- case 0x34:
- if (opcode_len == 2)
- return lldb::eInstructionControlFlowKindFarCall;
- break;
- case 0x35:
- case 0x07:
- if (opcode_len == 2)
- return lldb::eInstructionControlFlowKindFarReturn;
- break;
- case 0x01:
- if (opcode_len == 2) {
- switch (modrm) {
- case 0xc1:
- return lldb::eInstructionControlFlowKindFarCall;
- case 0xc2:
- case 0xc3:
- return lldb::eInstructionControlFlowKindFarReturn;
- default:
- break;
- }
- }
- break;
- default:
- break;
- }
-
- return lldb::eInstructionControlFlowKindOther;
-}
-
-/// Decode an instruction into opcode, modrm and opcode_len.
-/// Refer to http://ref.x86asm.net/coder.html for the instruction bytes layout.
-/// Opcodes in x86 are generally the first byte of instruction, though two-byte
-/// instructions and prefixes exist. ModR/M is the byte following the opcode
-/// and adds additional information for how the instruction is executed.
-///
-/// \param[in] inst_bytes
-/// Raw bytes of the instruction
-///
-///
-/// \param[in] bytes_len
-/// The length of the inst_bytes array.
-///
-/// \param[in] is_exec_mode_64b
-/// If true, the execution mode is 64 bit.
-///
-/// \return
-/// Returns decoded instruction as struct InstructionOpcodeAndModrm, holding
-/// primary_opcode, opcode_len and modrm byte. Refer to the struct definition
-/// for more details.
-/// Otherwise if the given instruction is invalid, returns None.
-llvm::Optional<InstructionOpcodeAndModrm>
-InstructionLengthDecode(const uint8_t *inst_bytes, int bytes_len,
- bool is_exec_mode_64b) {
- int op_idx = 0;
- bool prefix_done = false;
- InstructionOpcodeAndModrm ret = {0, 0, 0};
-
- // In most cases, the primary_opcode is the first byte of the instruction
- // but some instructions have a prefix to be skipped for these calculations.
- // The following mapping is inspired from libipt's instruction decoding logic
- // in `src/pt_ild.c`
- while (!prefix_done) {
- if (op_idx >= bytes_len)
- return llvm::None;
-
- ret.primary_opcode = inst_bytes[op_idx];
- switch (ret.primary_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 (is_exec_mode_64b)
- op_idx++;
- else
- prefix_done = true;
- break;
-
- // prefix_vex_c4, c5
- case 0xc5:
- if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
- prefix_done = true;
- break;
- }
-
- ret.opcode_len = 2;
- ret.primary_opcode = inst_bytes[op_idx + 2];
- ret.modrm = inst_bytes[op_idx + 3];
- return ret;
-
- case 0xc4:
- if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
- prefix_done = true;
- break;
- }
- ret.opcode_len = inst_bytes[op_idx + 1] & 0x1f;
- ret.primary_opcode = inst_bytes[op_idx + 3];
- ret.modrm = inst_bytes[op_idx + 4];
- return ret;
-
- // prefix_evex
- case 0x62:
- if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
- prefix_done = true;
- break;
- }
- ret.opcode_len = inst_bytes[op_idx + 1] & 0x03;
- ret.primary_opcode = inst_bytes[op_idx + 4];
- ret.modrm = inst_bytes[op_idx + 5];
- return ret;
-
- default:
- prefix_done = true;
- break;
- }
- } // prefix done
-
- ret.primary_opcode = inst_bytes[op_idx];
- ret.modrm = inst_bytes[op_idx + 1];
- ret.opcode_len = 1;
-
- // If the first opcode is 0F, it's two- or three- byte opcodes.
- if (ret.primary_opcode == 0x0F) {
- ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
-
- if (ret.primary_opcode == 0x38) {
- ret.opcode_len = 3;
- ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
- ret.modrm = inst_bytes[op_idx + 1];
- } else if (ret.primary_opcode == 0x3A) {
- ret.opcode_len = 3;
- ret.primary_opcode = inst_bytes[++op_idx];
- ret.modrm = inst_bytes[op_idx + 1];
- } else if ((ret.primary_opcode & 0xf8) == 0x38) {
- ret.opcode_len = 0;
- ret.primary_opcode = inst_bytes[++op_idx];
- ret.modrm = inst_bytes[op_idx + 1];
- } else if (ret.primary_opcode == 0x0F) {
- ret.opcode_len = 3;
- // opcode is 0x0F, no needs to update
- ret.modrm = inst_bytes[op_idx + 1];
- } else {
- ret.opcode_len = 2;
- ret.modrm = inst_bytes[op_idx + 1];
- }
- }
-
- return ret;
-}
-
-lldb::InstructionControlFlowKind GetControlFlowKind(bool is_exec_mode_64b,
- Opcode m_opcode) {
- llvm::Optional<InstructionOpcodeAndModrm> ret = llvm::None;
-
- if (m_opcode.GetOpcodeBytes() == nullptr || m_opcode.GetByteSize() <= 0) {
- // x86_64 and i386 instructions are categorized as Opcode::Type::eTypeBytes
- return lldb::eInstructionControlFlowKindUnknown;
- }
-
- // Opcode bytes will be decoded into primary_opcode, modrm and opcode length.
- // These are the three values deciding instruction control flow kind.
- ret = InstructionLengthDecode((const uint8_t *)m_opcode.GetOpcodeBytes(),
- m_opcode.GetByteSize(), is_exec_mode_64b);
- if (!ret)
- return lldb::eInstructionControlFlowKindUnknown;
- else
- return MapOpcodeIntoControlFlowKind(ret.value());
-}
-
-} // namespace x86
-
-lldb::InstructionControlFlowKind
-Instruction::GetControlFlowKind(const ArchSpec &arch) {
- if (arch.GetTriple().getArch() == llvm::Triple::x86)
- return x86::GetControlFlowKind(/*is_exec_mode_64b=*/false, m_opcode);
- else if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
- return x86::GetControlFlowKind(/*is_exec_mode_64b=*/true, m_opcode);
- else
- return eInstructionControlFlowKindUnknown; // not implemented
-}
-
AddressClass Instruction::GetAddressClass() {
if (m_address_class == AddressClass::eInvalid)
m_address_class = m_address.GetAddressClass();
return m_address_class;
}
+const char *Instruction::GetNameForInstructionControlFlowKind(
+ lldb::InstructionControlFlowKind instruction_control_flow_kind) {
+ switch (instruction_control_flow_kind) {
+ case eInstructionControlFlowKindUnknown:
+ return "unknown";
+ case eInstructionControlFlowKindOther:
+ return "other";
+ case eInstructionControlFlowKindCall:
+ return "call";
+ case eInstructionControlFlowKindReturn:
+ return "return";
+ case eInstructionControlFlowKindJump:
+ return "jump";
+ case eInstructionControlFlowKindCondJump:
+ return "cond jump";
+ case eInstructionControlFlowKindFarCall:
+ return "far call";
+ case eInstructionControlFlowKindFarReturn:
+ return "far return";
+ case eInstructionControlFlowKindFarJump:
+ return "far jump";
+ }
+}
+
void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
bool show_address, bool show_bytes,
bool show_control_flow_kind,
@@ -946,35 +642,10 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
}
if (show_control_flow_kind) {
- switch (GetControlFlowKind(exe_ctx->GetTargetRef().GetArchitecture())) {
- case eInstructionControlFlowKindUnknown:
- ss.Printf("%-12s", "unknown");
- break;
- case eInstructionControlFlowKindOther:
- ss.Printf("%-12s", "other");
- break;
- case eInstructionControlFlowKindCall:
- ss.Printf("%-12s", "call");
- break;
- case eInstructionControlFlowKindReturn:
- ss.Printf("%-12s", "return");
- break;
- case eInstructionControlFlowKindJump:
- ss.Printf("%-12s", "jump");
- break;
- case eInstructionControlFlowKindCondJump:
- ss.Printf("%-12s", "cond jump");
- break;
- case eInstructionControlFlowKindFarCall:
- ss.Printf("%-12s", "far call");
- break;
- case eInstructionControlFlowKindFarReturn:
- ss.Printf("%-12s", "far return");
- break;
- case eInstructionControlFlowKindFarJump:
- ss.Printf("%-12s", "far jump");
- break;
- }
+ lldb::InstructionControlFlowKind instruction_control_flow_kind =
+ GetControlFlowKind(exe_ctx);
+ ss.Printf("%-12s", GetNameForInstructionControlFlowKind(
+ instruction_control_flow_kind));
}
const size_t opcode_pos = ss.GetSizeOfLastLine();
diff --git a/contrib/llvm-project/lldb/source/Host/common/Host.cpp b/contrib/llvm-project/lldb/source/Host/common/Host.cpp
index f35eb47ff683..4a0f0240bd19 100644
--- a/contrib/llvm-project/lldb/source/Host/common/Host.cpp
+++ b/contrib/llvm-project/lldb/source/Host/common/Host.cpp
@@ -172,7 +172,7 @@ MonitorChildProcessThreadFunction(::pid_t pid,
::sigaction(SIGUSR1, &sigUsr1Action, nullptr);
#endif // __linux__
- while(1) {
+ while (true) {
log = GetLog(LLDBLog::Process);
LLDB_LOG(log, "::waitpid({0}, &status, 0)...", pid);
diff --git a/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index fb404e985f80..973884283f46 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -85,6 +85,324 @@ private:
std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_up;
};
+namespace x86 {
+
+/// These are the three values deciding instruction control flow kind.
+/// InstructionLengthDecode function decodes an instruction and get this struct.
+///
+/// primary_opcode
+/// Primary opcode of the instruction.
+/// For one-byte opcode instruction, it's the first byte after prefix.
+/// For two- and three-byte opcodes, it's the second byte.
+///
+/// opcode_len
+/// The length of opcode in bytes. Valid opcode lengths are 1, 2, or 3.
+///
+/// modrm
+/// ModR/M byte of the instruction.
+/// Bits[7:6] indicate MOD. Bits[5:3] specify a register and R/M bits[2:0]
+/// may contain a register or specify an addressing mode, depending on MOD.
+struct InstructionOpcodeAndModrm {
+ uint8_t primary_opcode;
+ uint8_t opcode_len;
+ uint8_t modrm;
+};
+
+/// Determine the InstructionControlFlowKind based on opcode and modrm bytes.
+/// Refer to http://ref.x86asm.net/coder.html for the full list of opcode and
+/// instruction set.
+///
+/// \param[in] opcode_and_modrm
+/// Contains primary_opcode byte, its length, and ModR/M byte.
+/// Refer to the struct InstructionOpcodeAndModrm for details.
+///
+/// \return
+/// The control flow kind of the instruction or
+/// eInstructionControlFlowKindOther if the instruction doesn't affect
+/// the control flow of the program.
+lldb::InstructionControlFlowKind
+MapOpcodeIntoControlFlowKind(InstructionOpcodeAndModrm opcode_and_modrm) {
+ uint8_t opcode = opcode_and_modrm.primary_opcode;
+ uint8_t opcode_len = opcode_and_modrm.opcode_len;
+ uint8_t modrm = opcode_and_modrm.modrm;
+
+ if (opcode_len > 2)
+ return lldb::eInstructionControlFlowKindOther;
+
+ if (opcode >= 0x70 && opcode <= 0x7F) {
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindCondJump;
+ else
+ return lldb::eInstructionControlFlowKindOther;
+ }
+
+ if (opcode >= 0x80 && opcode <= 0x8F) {
+ if (opcode_len == 2)
+ return lldb::eInstructionControlFlowKindCondJump;
+ else
+ return lldb::eInstructionControlFlowKindOther;
+ }
+
+ switch (opcode) {
+ case 0x9A:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarCall;
+ break;
+ case 0xFF:
+ if (opcode_len == 1) {
+ uint8_t modrm_reg = (modrm >> 3) & 7;
+ if (modrm_reg == 2)
+ return lldb::eInstructionControlFlowKindCall;
+ else if (modrm_reg == 3)
+ return lldb::eInstructionControlFlowKindFarCall;
+ else if (modrm_reg == 4)
+ return lldb::eInstructionControlFlowKindJump;
+ else if (modrm_reg == 5)
+ return lldb::eInstructionControlFlowKindFarJump;
+ }
+ break;
+ case 0xE8:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindCall;
+ break;
+ case 0xCD:
+ case 0xCC:
+ case 0xCE:
+ case 0xF1:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarCall;
+ break;
+ case 0xCF:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarReturn;
+ break;
+ case 0xE9:
+ case 0xEB:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindJump;
+ break;
+ case 0xEA:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarJump;
+ break;
+ case 0xE3:
+ case 0xE0:
+ case 0xE1:
+ case 0xE2:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindCondJump;
+ break;
+ case 0xC3:
+ case 0xC2:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindReturn;
+ break;
+ case 0xCB:
+ case 0xCA:
+ if (opcode_len == 1)
+ return lldb::eInstructionControlFlowKindFarReturn;
+ break;
+ case 0x05:
+ case 0x34:
+ if (opcode_len == 2)
+ return lldb::eInstructionControlFlowKindFarCall;
+ break;
+ case 0x35:
+ case 0x07:
+ if (opcode_len == 2)
+ return lldb::eInstructionControlFlowKindFarReturn;
+ break;
+ case 0x01:
+ if (opcode_len == 2) {
+ switch (modrm) {
+ case 0xc1:
+ return lldb::eInstructionControlFlowKindFarCall;
+ case 0xc2:
+ case 0xc3:
+ return lldb::eInstructionControlFlowKindFarReturn;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return lldb::eInstructionControlFlowKindOther;
+}
+
+/// Decode an instruction into opcode, modrm and opcode_len.
+/// Refer to http://ref.x86asm.net/coder.html for the instruction bytes layout.
+/// Opcodes in x86 are generally the first byte of instruction, though two-byte
+/// instructions and prefixes exist. ModR/M is the byte following the opcode
+/// and adds additional information for how the instruction is executed.
+///
+/// \param[in] inst_bytes
+/// Raw bytes of the instruction
+///
+///
+/// \param[in] bytes_len
+/// The length of the inst_bytes array.
+///
+/// \param[in] is_exec_mode_64b
+/// If true, the execution mode is 64 bit.
+///
+/// \return
+/// Returns decoded instruction as struct InstructionOpcodeAndModrm, holding
+/// primary_opcode, opcode_len and modrm byte. Refer to the struct definition
+/// for more details.
+/// Otherwise if the given instruction is invalid, returns None.
+llvm::Optional<InstructionOpcodeAndModrm>
+InstructionLengthDecode(const uint8_t *inst_bytes, int bytes_len,
+ bool is_exec_mode_64b) {
+ int op_idx = 0;
+ bool prefix_done = false;
+ InstructionOpcodeAndModrm ret = {0, 0, 0};
+
+ // In most cases, the primary_opcode is the first byte of the instruction
+ // but some instructions have a prefix to be skipped for these calculations.
+ // The following mapping is inspired from libipt's instruction decoding logic
+ // in `src/pt_ild.c`
+ while (!prefix_done) {
+ if (op_idx >= bytes_len)
+ return llvm::None;
+
+ ret.primary_opcode = inst_bytes[op_idx];
+ switch (ret.primary_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 (is_exec_mode_64b)
+ op_idx++;
+ else
+ prefix_done = true;
+ break;
+
+ // prefix_vex_c4, c5
+ case 0xc5:
+ if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+
+ ret.opcode_len = 2;
+ ret.primary_opcode = inst_bytes[op_idx + 2];
+ ret.modrm = inst_bytes[op_idx + 3];
+ return ret;
+
+ case 0xc4:
+ if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+ ret.opcode_len = inst_bytes[op_idx + 1] & 0x1f;
+ ret.primary_opcode = inst_bytes[op_idx + 3];
+ ret.modrm = inst_bytes[op_idx + 4];
+ return ret;
+
+ // prefix_evex
+ case 0x62:
+ if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) {
+ prefix_done = true;
+ break;
+ }
+ ret.opcode_len = inst_bytes[op_idx + 1] & 0x03;
+ ret.primary_opcode = inst_bytes[op_idx + 4];
+ ret.modrm = inst_bytes[op_idx + 5];
+ return ret;
+
+ default:
+ prefix_done = true;
+ break;
+ }
+ } // prefix done
+
+ ret.primary_opcode = inst_bytes[op_idx];
+ ret.modrm = inst_bytes[op_idx + 1];
+ ret.opcode_len = 1;
+
+ // If the first opcode is 0F, it's two- or three- byte opcodes.
+ if (ret.primary_opcode == 0x0F) {
+ ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
+
+ if (ret.primary_opcode == 0x38) {
+ ret.opcode_len = 3;
+ ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte
+ ret.modrm = inst_bytes[op_idx + 1];
+ } else if (ret.primary_opcode == 0x3A) {
+ ret.opcode_len = 3;
+ ret.primary_opcode = inst_bytes[++op_idx];
+ ret.modrm = inst_bytes[op_idx + 1];
+ } else if ((ret.primary_opcode & 0xf8) == 0x38) {
+ ret.opcode_len = 0;
+ ret.primary_opcode = inst_bytes[++op_idx];
+ ret.modrm = inst_bytes[op_idx + 1];
+ } else if (ret.primary_opcode == 0x0F) {
+ ret.opcode_len = 3;
+ // opcode is 0x0F, no needs to update
+ ret.modrm = inst_bytes[op_idx + 1];
+ } else {
+ ret.opcode_len = 2;
+ ret.modrm = inst_bytes[op_idx + 1];
+ }
+ }
+
+ return ret;
+}
+
+lldb::InstructionControlFlowKind GetControlFlowKind(bool is_exec_mode_64b,
+ Opcode m_opcode) {
+ llvm::Optional<InstructionOpcodeAndModrm> ret = llvm::None;
+
+ if (m_opcode.GetOpcodeBytes() == nullptr || m_opcode.GetByteSize() <= 0) {
+ // x86_64 and i386 instructions are categorized as Opcode::Type::eTypeBytes
+ return lldb::eInstructionControlFlowKindUnknown;
+ }
+
+ // Opcode bytes will be decoded into primary_opcode, modrm and opcode length.
+ // These are the three values deciding instruction control flow kind.
+ ret = InstructionLengthDecode((const uint8_t *)m_opcode.GetOpcodeBytes(),
+ m_opcode.GetByteSize(), is_exec_mode_64b);
+ if (!ret)
+ return lldb::eInstructionControlFlowKindUnknown;
+ else
+ return MapOpcodeIntoControlFlowKind(ret.value());
+}
+
+} // namespace x86
+
class InstructionLLVMC : public lldb_private::Instruction {
public:
InstructionLLVMC(DisassemblerLLVMC &disasm,
@@ -223,6 +541,19 @@ public:
}
}
+ lldb::InstructionControlFlowKind
+ GetControlFlowKind(const lldb_private::ExecutionContext *exe_ctx) override {
+ DisassemblerScope disasm(*this, exe_ctx);
+ if (disasm){
+ if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86)
+ return x86::GetControlFlowKind(/*is_64b=*/false, m_opcode);
+ else if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
+ return x86::GetControlFlowKind(/*is_64b=*/true, m_opcode);
+ }
+
+ return eInstructionControlFlowKindUnknown;
+ }
+
void CalculateMnemonicOperandsAndComment(
const lldb_private::ExecutionContext *exe_ctx) override {
DataExtractor data;
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index f8443d608ac3..71242925862b 100644
--- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -191,12 +191,12 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
ClangASTImporter::NamespaceMapSP namespace_map =
m_ast_importer_sp->GetNamespaceMap(namespace_context);
- LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)",
- namespace_map.get(), namespace_map->size());
-
if (!namespace_map)
return nullptr;
+ LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)",
+ namespace_map.get(), namespace_map->size());
+
for (const ClangASTImporter::NamespaceMapItem &item : *namespace_map) {
LLDB_LOG(log, " CTD Searching namespace {0} in module {1}",
item.second.GetName(), item.first->GetFileSpec().GetFilename());
@@ -1430,9 +1430,7 @@ static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map,
std::vector<PairType> sorted_items;
sorted_items.reserve(source_map.size());
sorted_items.assign(source_map.begin(), source_map.end());
- llvm::sort(sorted_items, [](const PairType &lhs, const PairType &rhs) {
- return lhs.second < rhs.second;
- });
+ llvm::sort(sorted_items, llvm::less_second());
for (const auto &item : sorted_items) {
DeclFromUser<D> user_decl(const_cast<D *>(item.first));
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index fad0f724e4c8..ec3dc28a3a8c 100644
--- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -722,8 +722,9 @@ ClangExpressionParser::ClangExpressionParser(
m_llvm_context = std::make_unique<LLVMContext>();
m_code_generator.reset(CreateLLVMCodeGen(
m_compiler->getDiagnostics(), module_name,
- m_compiler->getHeaderSearchOpts(), m_compiler->getPreprocessorOpts(),
- m_compiler->getCodeGenOpts(), *m_llvm_context));
+ &m_compiler->getVirtualFileSystem(), m_compiler->getHeaderSearchOpts(),
+ m_compiler->getPreprocessorOpts(), m_compiler->getCodeGenOpts(),
+ *m_llvm_context));
}
ClangExpressionParser::~ClangExpressionParser() = default;
diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
index 5bc745cf3b8b..b00a17736679 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -14453,10 +14453,10 @@ bool EmulateInstructionARM::TestEmulation(Stream *out_stream, ArchSpec &arch,
return false;
}
- success = before_state.CompareState(after_state);
+ success = before_state.CompareState(after_state, out_stream);
if (!success)
out_stream->Printf(
- "TestEmulation: 'before' and 'after' states do not match.\n");
+ "TestEmulation: State after emulation does not match 'after' state.\n");
return success;
}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
index 569482c7b23b..da679a3e8547 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
@@ -97,7 +97,7 @@ uint64_t EmulationStateARM::ReadPseudoRegisterValue(uint32_t reg_num,
uint32_t idx = reg_num - dwarf_d0;
if (idx < 16)
value = (uint64_t)m_vfp_regs.s_regs[idx * 2] |
- ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] >> 32);
+ ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] << 32);
else
value = m_vfp_regs.d_regs[idx - 16];
} else
@@ -251,27 +251,67 @@ bool EmulationStateARM::WritePseudoRegister(
reg_value.GetAsUInt64());
}
-bool EmulationStateARM::CompareState(EmulationStateARM &other_state) {
+bool EmulationStateARM::CompareState(EmulationStateARM &other_state,
+ Stream *out_stream) {
bool match = true;
for (int i = 0; match && i < 17; ++i) {
- if (m_gpr[i] != other_state.m_gpr[i])
+ if (m_gpr[i] != other_state.m_gpr[i]) {
match = false;
+ out_stream->Printf("r%d: 0x%x != 0x%x\n", i, m_gpr[i],
+ other_state.m_gpr[i]);
+ }
}
for (int i = 0; match && i < 32; ++i) {
- if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i])
+ if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i]) {
match = false;
+ out_stream->Printf("s%d: 0x%x != 0x%x\n", i, m_vfp_regs.s_regs[i],
+ other_state.m_vfp_regs.s_regs[i]);
+ }
}
for (int i = 0; match && i < 16; ++i) {
- if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i])
+ if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i]) {
match = false;
+ out_stream->Printf("d%d: 0x%" PRIx64 " != 0x%" PRIx64 "\n", i + 16,
+ m_vfp_regs.d_regs[i],
+ other_state.m_vfp_regs.d_regs[i]);
+ }
+ }
+
+ // other_state is the expected state. If it has memory, check it.
+ if (!other_state.m_memory.empty() && m_memory != other_state.m_memory) {
+ match = false;
+ out_stream->Printf("memory does not match\n");
+ out_stream->Printf("got memory:\n");
+ for (auto p : m_memory)
+ out_stream->Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);
+ out_stream->Printf("expected memory:\n");
+ for (auto p : other_state.m_memory)
+ out_stream->Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second);
}
return match;
}
+bool EmulationStateARM::LoadRegistersStateFromDictionary(
+ OptionValueDictionary *reg_dict, char kind, int first_reg, int num) {
+ StreamString sstr;
+ for (int i = 0; i < num; ++i) {
+ sstr.Clear();
+ sstr.Printf("%c%d", kind, i);
+ OptionValueSP value_sp =
+ reg_dict->GetValueForKey(ConstString(sstr.GetString()));
+ if (value_sp.get() == nullptr)
+ return false;
+ uint64_t reg_value = value_sp->GetUInt64Value();
+ StorePseudoRegisterValue(first_reg + i, reg_value);
+ }
+
+ return true;
+}
+
bool EmulationStateARM::LoadStateFromDictionary(
OptionValueDictionary *test_data) {
static ConstString memory_key("memory");
@@ -321,18 +361,8 @@ bool EmulationStateARM::LoadStateFromDictionary(
// Load General Registers
OptionValueDictionary *reg_dict = value_sp->GetAsDictionary();
-
- StreamString sstr;
- for (int i = 0; i < 16; ++i) {
- sstr.Clear();
- sstr.Printf("r%d", i);
- ConstString reg_name(sstr.GetString());
- value_sp = reg_dict->GetValueForKey(reg_name);
- if (value_sp.get() == nullptr)
- return false;
- uint64_t reg_value = value_sp->GetUInt64Value();
- StorePseudoRegisterValue(dwarf_r0 + i, reg_value);
- }
+ if (!LoadRegistersStateFromDictionary(reg_dict, 'r', dwarf_r0, 16))
+ return false;
static ConstString cpsr_name("cpsr");
value_sp = reg_dict->GetValueForKey(cpsr_name);
@@ -341,16 +371,13 @@ bool EmulationStateARM::LoadStateFromDictionary(
StorePseudoRegisterValue(dwarf_cpsr, value_sp->GetUInt64Value());
// Load s/d Registers
- for (int i = 0; i < 32; ++i) {
- sstr.Clear();
- sstr.Printf("s%d", i);
- ConstString reg_name(sstr.GetString());
- value_sp = reg_dict->GetValueForKey(reg_name);
- if (value_sp.get() == nullptr)
- return false;
- uint64_t reg_value = value_sp->GetUInt64Value();
- StorePseudoRegisterValue(dwarf_s0 + i, reg_value);
- }
-
- return true;
+ // To prevent you giving both types in a state and overwriting
+ // one or the other, we'll expect to get either all S registers,
+ // or all D registers. Not a mix of the two.
+ bool found_s_registers =
+ LoadRegistersStateFromDictionary(reg_dict, 's', dwarf_s0, 32);
+ bool found_d_registers =
+ LoadRegistersStateFromDictionary(reg_dict, 'd', dwarf_d0, 32);
+
+ return found_s_registers != found_d_registers;
}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h
index 28bc5d98649d..bc885dab9ac7 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h
@@ -36,7 +36,8 @@ public:
bool LoadStateFromDictionary(lldb_private::OptionValueDictionary *test_data);
- bool CompareState(EmulationStateARM &other_state);
+ bool CompareState(EmulationStateARM &other_state,
+ lldb_private::Stream *out_stream);
static size_t
ReadPseudoMemory(lldb_private::EmulateInstruction *instruction, void *baton,
@@ -61,6 +62,10 @@ public:
const lldb_private::RegisterValue &reg_value);
private:
+ bool LoadRegistersStateFromDictionary(
+ lldb_private::OptionValueDictionary *reg_dict, char kind, int first_reg,
+ int num);
+
uint32_t m_gpr[17] = {0};
struct _sd_regs {
uint32_t s_regs[32]; // sregs 0 - 31 & dregs 0 - 15
diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
index acb131b8a775..c396cb061c01 100644
--- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
@@ -348,7 +348,7 @@ llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
lldb_private::minidump::MinidumpContext_x86_64
GetThreadContext_64(RegisterContext *reg_ctx) {
- lldb_private::minidump::MinidumpContext_x86_64 thread_context;
+ lldb_private::minidump::MinidumpContext_x86_64 thread_context = {};
thread_context.p1_home = {};
thread_context.context_flags = static_cast<uint32_t>(
lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |
@@ -534,7 +534,7 @@ Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) {
helper_data.AppendData(
&thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64));
- Exception exp_record;
+ Exception exp_record = {};
exp_record.ExceptionCode =
static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
index b71de4cadb18..7e25bc4ea2a2 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
@@ -247,6 +247,71 @@ MemoryTagManagerAArch64MTE::UnpackTagsData(const std::vector<uint8_t> &tags,
return unpacked;
}
+std::vector<lldb::addr_t>
+MemoryTagManagerAArch64MTE::UnpackTagsFromCoreFileSegment(
+ CoreReaderFn reader, lldb::addr_t tag_segment_virtual_address,
+ lldb::addr_t tag_segment_data_address, lldb::addr_t addr,
+ size_t len) const {
+ // We can assume by now that addr and len have been granule aligned by a tag
+ // manager. However because we have 2 tags per byte we need to round the range
+ // up again to align to 2 granule boundaries.
+ const size_t granule = GetGranuleSize();
+ const size_t two_granules = granule * 2;
+ lldb::addr_t aligned_addr = addr;
+ size_t aligned_len = len;
+
+ // First align the start address down.
+ if (aligned_addr % two_granules) {
+ assert(aligned_addr % two_granules == granule);
+ aligned_addr -= granule;
+ aligned_len += granule;
+ }
+
+ // Then align the length up.
+ bool aligned_length_up = false;
+ if (aligned_len % two_granules) {
+ assert(aligned_len % two_granules == granule);
+ aligned_len += granule;
+ aligned_length_up = true;
+ }
+
+ // ProcessElfCore should have validated this when it found the segment.
+ assert(aligned_addr >= tag_segment_virtual_address);
+
+ // By now we know that aligned_addr is aligned to a 2 granule boundary.
+ const size_t offset_granules =
+ (aligned_addr - tag_segment_virtual_address) / granule;
+ // 2 tags per byte.
+ const size_t file_offset_in_bytes = offset_granules / 2;
+
+ // By now we know that aligned_len is at least 2 granules.
+ const size_t tag_bytes_to_read = aligned_len / granule / 2;
+ std::vector<uint8_t> tag_data(tag_bytes_to_read);
+ const size_t bytes_copied =
+ reader(tag_segment_data_address + file_offset_in_bytes, tag_bytes_to_read,
+ tag_data.data());
+ UNUSED_IF_ASSERT_DISABLED(bytes_copied);
+ assert(bytes_copied == tag_bytes_to_read);
+
+ std::vector<lldb::addr_t> tags;
+ tags.reserve(2 * tag_data.size());
+ // No need to check the range of the tag value here as each occupies only 4
+ // bits.
+ for (auto tag_byte : tag_data) {
+ tags.push_back(tag_byte & 0xf);
+ tags.push_back(tag_byte >> 4);
+ }
+
+ // If we aligned the address down, don't return the extra first tag.
+ if (addr != aligned_addr)
+ tags.erase(tags.begin());
+ // If we aligned the length up, don't return the extra last tag.
+ if (aligned_length_up)
+ tags.pop_back();
+
+ return tags;
+}
+
llvm::Expected<std::vector<uint8_t>> MemoryTagManagerAArch64MTE::PackTags(
const std::vector<lldb::addr_t> &tags) const {
std::vector<uint8_t> packed;
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
index 7cda728b140f..365e176e5b1d 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
@@ -44,6 +44,12 @@ public:
UnpackTagsData(const std::vector<uint8_t> &tags,
size_t granules = 0) const override;
+ std::vector<lldb::addr_t>
+ UnpackTagsFromCoreFileSegment(CoreReaderFn reader,
+ lldb::addr_t tag_segment_virtual_address,
+ lldb::addr_t tag_segment_data_address,
+ lldb::addr_t addr, size_t len) const override;
+
llvm::Expected<std::vector<uint8_t>>
PackTags(const std::vector<lldb::addr_t> &tags) const override;
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
index 11b300bc44fb..691e7db3fc79 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
@@ -95,7 +95,7 @@ static size_t k_num_register_infos =
RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(
Thread &thread, uint32_t concrete_frame_idx)
- : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc() {
+ : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc(), dbg() {
uint32_t i;
for (i = 0; i < kNumErrors; i++) {
gpr_errs[i] = -1;
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
index 7469e7633e71..89ecc757a68f 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -23,7 +23,8 @@ using namespace lldb_private;
ThreadMemory::ThreadMemory(Process &process, tid_t tid,
const ValueObjectSP &thread_info_valobj_sp)
: Thread(process, tid), m_backing_thread_sp(),
- m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue() {}
+ m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(),
+ m_register_data_addr(LLDB_INVALID_ADDRESS) {}
ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid,
llvm::StringRef name, llvm::StringRef queue,
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 58b4fe3add1b..24d3c4bd0ba2 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -144,6 +144,18 @@ lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(
return addr;
}
+lldb::addr_t ProcessElfCore::AddAddressRangeFromMemoryTagSegment(
+ const elf::ELFProgramHeader &header) {
+ // If lldb understood multiple kinds of tag segments we would record the type
+ // of the segment here also. As long as there is only 1 type lldb looks for,
+ // there is no need.
+ FileRange file_range(header.p_offset, header.p_filesz);
+ m_core_tag_ranges.Append(
+ VMRangeToFileOffset::Entry(header.p_vaddr, header.p_memsz, file_range));
+
+ return header.p_vaddr;
+}
+
// Process Control
Status ProcessElfCore::DoLoadCore() {
Status error;
@@ -170,9 +182,12 @@ Status ProcessElfCore::DoLoadCore() {
bool ranges_are_sorted = true;
lldb::addr_t vm_addr = 0;
+ lldb::addr_t tag_addr = 0;
/// Walk through segments and Thread and Address Map information.
/// PT_NOTE - Contains Thread and Register information
/// PT_LOAD - Contains a contiguous range of Process Address Space
+ /// PT_AARCH64_MEMTAG_MTE - Contains AArch64 MTE memory tags for a range of
+ /// Process Address Space.
for (const elf::ELFProgramHeader &H : segments) {
DataExtractor data = core->GetSegmentData(H);
@@ -187,12 +202,18 @@ Status ProcessElfCore::DoLoadCore() {
if (vm_addr > last_addr)
ranges_are_sorted = false;
vm_addr = last_addr;
+ } else if (H.p_type == llvm::ELF::PT_AARCH64_MEMTAG_MTE) {
+ lldb::addr_t last_addr = AddAddressRangeFromMemoryTagSegment(H);
+ if (tag_addr > last_addr)
+ ranges_are_sorted = false;
+ tag_addr = last_addr;
}
}
if (!ranges_are_sorted) {
m_core_aranges.Sort();
m_core_range_infos.Sort();
+ m_core_tag_ranges.Sort();
}
// Even if the architecture is set in the target, we need to override it to
@@ -310,6 +331,15 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
? MemoryRegionInfo::eYes
: MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eYes);
+
+ // A region is memory tagged if there is a memory tag segment that covers
+ // the exact same range.
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+ const VMRangeToFileOffset::Entry *tag_entry =
+ m_core_tag_ranges.FindEntryStartsAt(permission_entry->GetRangeBase());
+ if (tag_entry &&
+ tag_entry->GetRangeEnd() == permission_entry->GetRangeEnd())
+ region_info.SetMemoryTagged(MemoryRegionInfo::eYes);
} else if (load_addr < permission_entry->GetRangeBase()) {
region_info.GetRange().SetRangeBase(load_addr);
region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
@@ -317,6 +347,7 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
region_info.SetWritable(MemoryRegionInfo::eNo);
region_info.SetExecutable(MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eNo);
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
}
return Status();
}
@@ -327,6 +358,7 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
region_info.SetWritable(MemoryRegionInfo::eNo);
region_info.SetExecutable(MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eNo);
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
return Status();
}
@@ -376,6 +408,38 @@ size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
return bytes_copied;
}
+llvm::Expected<std::vector<lldb::addr_t>>
+ProcessElfCore::ReadMemoryTags(lldb::addr_t addr, size_t len) {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile == nullptr)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No core object file.");
+
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ GetMemoryTagManager();
+ if (!tag_manager_or_err)
+ return tag_manager_or_err.takeError();
+
+ // LLDB only supports AArch64 MTE tag segments so we do not need to worry
+ // about the segment type here. If you got here then you must have a tag
+ // manager (meaning you are debugging AArch64) and all the segments in this
+ // list will have had type PT_AARCH64_MEMTAG_MTE.
+ const VMRangeToFileOffset::Entry *tag_entry =
+ m_core_tag_ranges.FindEntryThatContains(addr);
+ // If we don't have a tag segment or the range asked for extends outside the
+ // segment.
+ if (!tag_entry || (addr + len) >= tag_entry->GetRangeEnd())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No tag segment that covers this range.");
+
+ const MemoryTagManager *tag_manager = *tag_manager_or_err;
+ return tag_manager->UnpackTagsFromCoreFileSegment(
+ [core_objfile](lldb::offset_t offset, size_t length, void *dst) {
+ return core_objfile->CopyData(offset, length, dst);
+ },
+ tag_entry->GetRangeBase(), tag_entry->data.GetRangeBase(), addr, len);
+}
+
void ProcessElfCore::Clear() {
m_thread_list.Clear();
@@ -610,9 +674,9 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
// To be extracted from struct netbsd_elfcore_procinfo
// Used to sanity check of the LWPs of the process
uint32_t nlwps = 0;
- uint32_t signo; // killing signal
- uint32_t siglwp; // LWP target of killing signal
- uint32_t pr_pid;
+ uint32_t signo = 0; // killing signal
+ uint32_t siglwp = 0; // LWP target of killing signal
+ uint32_t pr_pid = 0;
for (const auto &note : notes) {
llvm::StringRef name = note.info.n_name;
@@ -764,7 +828,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
}
llvm::Error ProcessElfCore::parseOpenBSDNotes(llvm::ArrayRef<CoreNote> notes) {
- ThreadData thread_data;
+ ThreadData thread_data = {};
for (const auto &note : notes) {
// OpenBSD per-thread information is stored in notes named "OpenBSD@nnn" so
// match on the initial part of the string.
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index fd36e5027816..03c23378e3c1 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -86,6 +86,11 @@ public:
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
lldb_private::Status &error) override;
+ // We do not implement DoReadMemoryTags. Instead all the work is done in
+ // ReadMemoryTags which avoids having to unpack and repack tags.
+ llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr,
+ size_t len) override;
+
lldb::addr_t GetImageInfoAddress() override;
lldb_private::ArchSpec GetArchitecture();
@@ -105,6 +110,8 @@ protected:
DoGetMemoryRegionInfo(lldb::addr_t load_addr,
lldb_private::MemoryRegionInfo &region_info) override;
+ bool SupportsMemoryTagging() override { return !m_core_tag_ranges.IsEmpty(); }
+
private:
struct NT_FILE_Entry {
lldb::addr_t start;
@@ -139,6 +146,9 @@ private:
// Permissions for all ranges
VMRangeToPermissions m_core_range_infos;
+ // Memory tag ranges found in the core
+ VMRangeToFileOffset m_core_tag_ranges;
+
// NT_FILE entries found from the NOTE segment
std::vector<NT_FILE_Entry> m_nt_file_entries;
@@ -154,6 +164,10 @@ private:
lldb::addr_t
AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header);
+ // Parse a contiguous address range from a memory tag segment
+ lldb::addr_t
+ AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header);
+
llvm::Expected<std::vector<lldb_private::CoreNote>>
parseSegment(const lldb_private::DataExtractor &segment);
llvm::Error parseFreeBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index c44ace96dd55..580cdde57d80 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -4265,3 +4265,21 @@ bool GDBRemoteCommunicationClient::UsesNativeSignals() {
// check whether it is an old version of lldb-server.
return GetThreadSuffixSupported();
}
+
+llvm::Expected<int> GDBRemoteCommunicationClient::KillProcess(lldb::pid_t pid) {
+ StringExtractorGDBRemote response;
+ GDBRemoteCommunication::ScopedTimeout(*this, seconds(3));
+
+ if (SendPacketAndWaitForResponse("k", response, GetPacketTimeout()) !=
+ PacketResult::Success)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "failed to send k packet");
+
+ char packet_cmd = response.GetChar(0);
+ if (packet_cmd == 'W' || packet_cmd == 'X')
+ return response.GetHexU8();
+
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "unexpected response to k packet: %s",
+ response.GetStringRef().str().c_str());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index d367f75cee0e..3d838d6d8074 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -521,6 +521,8 @@ public:
bool GetSaveCoreSupported() const;
+ llvm::Expected<int> KillProcess(lldb::pid_t pid);
+
protected:
LazyBool m_supports_not_sending_acks = eLazyBoolCalculate;
LazyBool m_supports_thread_suffix = eLazyBoolCalculate;
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 5f18706f67e5..3e1a6fb6620a 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -2394,7 +2394,6 @@ Status ProcessGDBRemote::DoDetach(bool keep_stopped) {
}
Status ProcessGDBRemote::DoDestroy() {
- Status error;
Log *log = GetLog(GDBRLog::Process);
LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy()");
@@ -2404,54 +2403,35 @@ Status ProcessGDBRemote::DoDestroy() {
if (m_gdb_comm.IsConnected()) {
if (m_public_state.GetValue() != eStateAttaching) {
- StringExtractorGDBRemote response;
- GDBRemoteCommunication::ScopedTimeout(m_gdb_comm,
- std::chrono::seconds(3));
-
- if (m_gdb_comm.SendPacketAndWaitForResponse("k", response,
- GetInterruptTimeout()) ==
- GDBRemoteCommunication::PacketResult::Success) {
- char packet_cmd = response.GetChar(0);
+ llvm::Expected<int> kill_res = m_gdb_comm.KillProcess(GetID());
- if (packet_cmd == 'W' || packet_cmd == 'X') {
+ if (kill_res) {
+ exit_status = kill_res.get();
#if defined(__APPLE__)
- // For Native processes on Mac OS X, we launch through the Host
- // Platform, then hand the process off to debugserver, which becomes
- // the parent process through "PT_ATTACH". Then when we go to kill
- // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then
- // we call waitpid which returns with no error and the correct
- // status. But amusingly enough that doesn't seem to actually reap
- // the process, but instead it is left around as a Zombie. Probably
- // the kernel is in the process of switching ownership back to lldb
- // which was the original parent, and gets confused in the handoff.
- // Anyway, so call waitpid here to finally reap it.
- PlatformSP platform_sp(GetTarget().GetPlatform());
- if (platform_sp && platform_sp->IsHost()) {
- int status;
- ::pid_t reap_pid;
- reap_pid = waitpid(GetID(), &status, WNOHANG);
- LLDB_LOGF(log, "Reaped pid: %d, status: %d.\n", reap_pid, status);
- }
-#endif
- SetLastStopPacket(response);
- ClearThreadIDList();
- exit_status = response.GetHexU8();
- } else {
- LLDB_LOGF(log,
- "ProcessGDBRemote::DoDestroy - got unexpected response "
- "to k packet: %s",
- response.GetStringRef().data());
- exit_string.assign("got unexpected response to k packet: ");
- exit_string.append(std::string(response.GetStringRef()));
+ // For Native processes on Mac OS X, we launch through the Host
+ // Platform, then hand the process off to debugserver, which becomes
+ // the parent process through "PT_ATTACH". Then when we go to kill
+ // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then
+ // we call waitpid which returns with no error and the correct
+ // status. But amusingly enough that doesn't seem to actually reap
+ // the process, but instead it is left around as a Zombie. Probably
+ // the kernel is in the process of switching ownership back to lldb
+ // which was the original parent, and gets confused in the handoff.
+ // Anyway, so call waitpid here to finally reap it.
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (platform_sp && platform_sp->IsHost()) {
+ int status;
+ ::pid_t reap_pid;
+ reap_pid = waitpid(GetID(), &status, WNOHANG);
+ LLDB_LOGF(log, "Reaped pid: %d, status: %d.\n", reap_pid, status);
}
+#endif
+ ClearThreadIDList();
+ exit_string.assign("killed");
} else {
- LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy - failed to send k packet");
- exit_string.assign("failed to send the k packet");
+ exit_string.assign(llvm::toString(kill_res.takeError()));
}
} else {
- LLDB_LOGF(log,
- "ProcessGDBRemote::DoDestroy - killed or interrupted while "
- "attaching");
exit_string.assign("killed or interrupted while attaching.");
}
} else {
@@ -2465,7 +2445,7 @@ Status ProcessGDBRemote::DoDestroy() {
StopAsyncThread();
KillDebugserverProcess();
- return error;
+ return Status();
}
void ProcessGDBRemote::SetLastStopPacket(
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index c91c111d8df3..64219e1a960b 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -233,7 +233,8 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
const FileSpec &core_file,
DataBufferSP core_data)
: PostMortemProcess(target_sp, listener_sp), m_core_file(core_file),
- m_core_data(std::move(core_data)), m_is_wow64(false) {}
+ m_core_data(std::move(core_data)), m_active_exception(nullptr),
+ m_is_wow64(false) {}
ProcessMinidump::~ProcessMinidump() {
Clear();
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
index 6317b140f7e8..7d730ecdd1f3 100644
--- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -475,7 +475,7 @@ llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
}
VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) {
- VariableInfo result;
+ VariableInfo result = {};
if (sym.kind() == S_REGREL32) {
RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
index 0859c5a20b7e..02f1d2f24d8c 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -44,11 +44,65 @@ void IntelPTError::log(llvm::raw_ostream &OS) const {
OS << formatv(": {0:x+16}", m_address);
}
-int64_t DecodedThread::GetItemsCount() const {
- return static_cast<int64_t>(m_item_kinds.size());
+bool DecodedThread::TSCRange::InRange(uint64_t item_index) const {
+ return item_index >= first_item_index &&
+ item_index < first_item_index + items_count;
+}
+
+bool DecodedThread::NanosecondsRange::InRange(uint64_t item_index) const {
+ return item_index >= first_item_index &&
+ item_index < first_item_index + items_count;
+}
+
+double DecodedThread::NanosecondsRange::GetInterpolatedTime(
+ uint64_t item_index, uint64_t begin_of_time_nanos,
+ const LinuxPerfZeroTscConversion &tsc_conversion) const {
+ uint64_t items_since_last_tsc = item_index - first_item_index;
+
+ auto interpolate = [&](uint64_t next_range_start_ns) {
+ if (next_range_start_ns == nanos) {
+ // If the resolution of the conversion formula is bad enough to consider
+ // these two timestamps as equal, then we just increase the next one by 1
+ // for correction
+ next_range_start_ns++;
+ }
+ long double item_duration =
+ static_cast<long double>(items_count) / (next_range_start_ns - nanos);
+ return (nanos - begin_of_time_nanos) + items_since_last_tsc * item_duration;
+ };
+
+ if (!next_range) {
+ // If this is the last TSC range, so we have to extrapolate. In this case,
+ // we assume that each instruction took one TSC, which is what an
+ // instruction would take if no parallelism is achieved and the frequency
+ // multiplier is 1.
+ return interpolate(tsc_conversion.ToNanos(tsc + items_count));
+ }
+ if (items_count < (next_range->tsc - tsc)) {
+ // If the numbers of items in this range is less than the total TSC duration
+ // of this range, i.e. each instruction taking longer than 1 TSC, then we
+ // can assume that something else happened between these TSCs (e.g. a
+ // context switch, change to kernel, decoding errors, etc). In this case, we
+ // also assume that each instruction took 1 TSC. A proper way to improve
+ // this would be to analize the next events in the trace looking for context
+ // switches or trace disablement events, but for now, as we only want an
+ // approximation, we keep it simple. We are also guaranteed that the time in
+ // nanos of the next range is different to the current one, just because of
+ // the definition of a NanosecondsRange.
+ return interpolate(
+ std::min(tsc_conversion.ToNanos(tsc + items_count), next_range->nanos));
+ }
+
+ // In this case, each item took less than 1 TSC, so some parallelism was
+ // achieved, which is an indication that we didn't suffered of any kind of
+ // interruption.
+ return interpolate(next_range->nanos);
}
-lldb::addr_t DecodedThread::GetInstructionLoadAddress(size_t item_index) const {
+uint64_t DecodedThread::GetItemsCount() const { return m_item_kinds.size(); }
+
+lldb::addr_t
+DecodedThread::GetInstructionLoadAddress(uint64_t item_index) const {
return m_item_data[item_index].load_address;
}
@@ -58,33 +112,69 @@ DecodedThread::TraceItemStorage &
DecodedThread::CreateNewTraceItem(lldb::TraceItemKind kind) {
m_item_kinds.push_back(kind);
m_item_data.emplace_back();
+ if (m_last_tsc)
+ (*m_last_tsc)->second.items_count++;
+ if (m_last_nanoseconds)
+ (*m_last_nanoseconds)->second.items_count++;
return m_item_data.back();
}
-void DecodedThread::NotifyTsc(uint64_t tsc) {
- if (!m_last_tsc || *m_last_tsc != tsc) {
- m_timestamps.emplace(m_item_kinds.size(), tsc);
- m_last_tsc = tsc;
+void DecodedThread::NotifyTsc(TSC tsc) {
+ if (m_last_tsc && (*m_last_tsc)->second.tsc == tsc)
+ return;
+
+ m_last_tsc =
+ m_tscs.emplace(GetItemsCount(), TSCRange{tsc, 0, GetItemsCount()}).first;
+
+ if (m_tsc_conversion) {
+ uint64_t nanos = m_tsc_conversion->ToNanos(tsc);
+ if (!m_last_nanoseconds || (*m_last_nanoseconds)->second.nanos != nanos) {
+ m_last_nanoseconds =
+ m_nanoseconds
+ .emplace(GetItemsCount(), NanosecondsRange{nanos, tsc, nullptr, 0,
+ GetItemsCount()})
+ .first;
+ if (*m_last_nanoseconds != m_nanoseconds.begin()) {
+ auto prev_range = prev(*m_last_nanoseconds);
+ prev_range->second.next_range = &(*m_last_nanoseconds)->second;
+ }
+ }
}
+ AppendEvent(lldb::eTraceEventHWClockTick);
}
void DecodedThread::NotifyCPU(lldb::cpu_id_t cpu_id) {
if (!m_last_cpu || *m_last_cpu != cpu_id) {
- m_cpus.emplace(m_item_kinds.size(), cpu_id);
+ m_cpus.emplace(GetItemsCount(), cpu_id);
m_last_cpu = cpu_id;
AppendEvent(lldb::eTraceEventCPUChanged);
}
}
Optional<lldb::cpu_id_t>
-DecodedThread::GetCPUByIndex(uint64_t insn_index) const {
- // Could possibly optimize the search
- auto it = m_cpus.upper_bound(insn_index);
+DecodedThread::GetCPUByIndex(uint64_t item_index) const {
+ auto it = m_cpus.upper_bound(item_index);
if (it == m_cpus.begin())
return None;
return prev(it)->second;
}
+Optional<DecodedThread::TSCRange>
+DecodedThread::GetTSCRangeByIndex(uint64_t item_index) const {
+ auto next_it = m_tscs.upper_bound(item_index);
+ if (next_it == m_tscs.begin())
+ return None;
+ return prev(next_it)->second;
+}
+
+Optional<DecodedThread::NanosecondsRange>
+DecodedThread::GetNanosecondsRangeByIndex(uint64_t item_index) {
+ auto next_it = m_nanoseconds.upper_bound(item_index);
+ if (next_it == m_nanoseconds.begin())
+ return None;
+ return prev(next_it)->second;
+}
+
void DecodedThread::AppendEvent(lldb::TraceEvent event) {
CreateNewTraceItem(lldb::eTraceItemKindEvent).event = event;
m_events_stats.RecordEvent(event);
@@ -134,90 +224,24 @@ void DecodedThread::EventsStats::RecordEvent(lldb::TraceEvent event) {
total_count++;
}
-Optional<DecodedThread::TscRange> DecodedThread::CalculateTscRange(
- size_t insn_index,
- const Optional<DecodedThread::TscRange> &hint_range) const {
- // We first try to check the given hint range in case we are traversing the
- // trace in short jumps. If that fails, then we do the more expensive
- // arbitrary lookup.
- if (hint_range) {
- Optional<TscRange> candidate_range;
- if (insn_index < hint_range->GetStartInstructionIndex())
- candidate_range = hint_range->Prev();
- else if (insn_index > hint_range->GetEndInstructionIndex())
- candidate_range = hint_range->Next();
- else
- candidate_range = hint_range;
-
- if (candidate_range && candidate_range->InRange(insn_index))
- return candidate_range;
- }
- // Now we do a more expensive lookup
- auto it = m_timestamps.upper_bound(insn_index);
- if (it == m_timestamps.begin())
- return None;
-
- return TscRange(--it, *this);
-}
-
-lldb::TraceItemKind DecodedThread::GetItemKindByIndex(size_t item_index) const {
+lldb::TraceItemKind
+DecodedThread::GetItemKindByIndex(uint64_t item_index) const {
return static_cast<lldb::TraceItemKind>(m_item_kinds[item_index]);
}
-const char *DecodedThread::GetErrorByIndex(size_t item_index) const {
+const char *DecodedThread::GetErrorByIndex(uint64_t item_index) const {
return m_item_data[item_index].error;
}
-DecodedThread::DecodedThread(ThreadSP thread_sp) : m_thread_sp(thread_sp) {}
-
-lldb::TraceCursorUP DecodedThread::CreateNewCursor() {
- return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
-}
+DecodedThread::DecodedThread(
+ ThreadSP thread_sp,
+ const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion)
+ : m_thread_sp(thread_sp), m_tsc_conversion(tsc_conversion) {}
size_t DecodedThread::CalculateApproximateMemoryUsage() const {
return sizeof(TraceItemStorage) * m_item_data.size() +
sizeof(uint8_t) * m_item_kinds.size() +
- (sizeof(size_t) + sizeof(uint64_t)) * m_timestamps.size() +
- (sizeof(size_t) + sizeof(lldb::cpu_id_t)) * m_cpus.size();
-}
-
-DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it,
- const DecodedThread &decoded_thread)
- : m_it(it), m_decoded_thread(&decoded_thread) {
- auto next_it = m_it;
- ++next_it;
- m_end_index = (next_it == m_decoded_thread->m_timestamps.end())
- ? std::numeric_limits<uint64_t>::max()
- : next_it->first - 1;
-}
-
-size_t DecodedThread::TscRange::GetTsc() const { return m_it->second; }
-
-size_t DecodedThread::TscRange::GetStartInstructionIndex() const {
- return m_it->first;
-}
-
-size_t DecodedThread::TscRange::GetEndInstructionIndex() const {
- return m_end_index;
-}
-
-bool DecodedThread::TscRange::InRange(size_t insn_index) const {
- return GetStartInstructionIndex() <= insn_index &&
- insn_index <= GetEndInstructionIndex();
-}
-
-Optional<DecodedThread::TscRange> DecodedThread::TscRange::Next() const {
- auto next_it = m_it;
- ++next_it;
- if (next_it == m_decoded_thread->m_timestamps.end())
- return None;
- return TscRange(next_it, *m_decoded_thread);
-}
-
-Optional<DecodedThread::TscRange> DecodedThread::TscRange::Prev() const {
- if (m_it == m_decoded_thread->m_timestamps.begin())
- return None;
- auto prev_it = m_it;
- --prev_it;
- return TscRange(prev_it, *m_decoded_thread);
+ (sizeof(uint64_t) + sizeof(TSC)) * m_tscs.size() +
+ (sizeof(uint64_t) + sizeof(uint64_t)) * m_nanoseconds.size() +
+ (sizeof(uint64_t) + sizeof(lldb::cpu_id_t)) * m_cpus.size();
}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
index bd1a90aaf250..9376a0af169d 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -71,45 +71,7 @@ private:
/// stopped at. See \a Trace::GetCursorPosition for more information.
class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
public:
- /// \class TscRange
- /// Class that represents the trace range associated with a given TSC.
- /// It provides efficient iteration to the previous or next TSC range in the
- /// decoded trace.
- ///
- /// TSC timestamps are emitted by the decoder infrequently, which means
- /// that each TSC covers a range of instruction indices, which can be used to
- /// speed up TSC lookups.
- class TscRange {
- public:
- /// Check if this TSC range includes the given instruction index.
- bool InRange(size_t insn_index) const;
-
- /// Get the next range chronologically.
- llvm::Optional<TscRange> Next() const;
-
- /// Get the previous range chronologically.
- llvm::Optional<TscRange> Prev() const;
-
- /// Get the TSC value.
- size_t GetTsc() const;
- /// Get the smallest instruction index that has this TSC.
- size_t GetStartInstructionIndex() const;
- /// Get the largest instruction index that has this TSC.
- size_t GetEndInstructionIndex() const;
-
- private:
- friend class DecodedThread;
-
- TscRange(std::map<size_t, uint64_t>::const_iterator it,
- const DecodedThread &decoded_thread);
-
- /// The iterator pointing to the beginning of the range.
- std::map<size_t, uint64_t>::const_iterator m_it;
- /// The largest instruction index that has this TSC.
- size_t m_end_index;
-
- const DecodedThread *m_decoded_thread;
- };
+ using TSC = uint64_t;
// Struct holding counts for libipts errors;
struct LibiptErrorsStats {
@@ -120,6 +82,61 @@ public:
void RecordError(int libipt_error_code);
};
+ /// A structure that represents a maximal range of trace items associated to
+ /// the same TSC value.
+ struct TSCRange {
+ TSC tsc;
+ /// Number of trace items in this range.
+ uint64_t items_count;
+ /// Index of the first trace item in this range.
+ uint64_t first_item_index;
+
+ /// \return
+ /// \b true if and only if the given \p item_index is covered by this
+ /// range.
+ bool InRange(uint64_t item_index) const;
+ };
+
+ /// A structure that represents a maximal range of trace items associated to
+ /// the same non-interpolated timestamps in nanoseconds.
+ struct NanosecondsRange {
+ /// The nanoseconds value for this range.
+ uint64_t nanos;
+ /// The corresponding TSC value for this range.
+ TSC tsc;
+ /// A nullable pointer to the next range.
+ NanosecondsRange *next_range;
+ /// Number of trace items in this range.
+ uint64_t items_count;
+ /// Index of the first trace item in this range.
+ uint64_t first_item_index;
+
+ /// Calculate an interpolated timestamp in nanoseconds for the given item
+ /// index. It's guaranteed that two different item indices will produce
+ /// different interpolated values.
+ ///
+ /// \param[in] item_index
+ /// The index of the item whose timestamp will be estimated. It has to be
+ /// part of this range.
+ ///
+ /// \param[in] beginning_of_time_nanos
+ /// The timestamp at which tracing started.
+ ///
+ /// \param[in] tsc_conversion
+ /// The tsc -> nanos conversion utility
+ ///
+ /// \return
+ /// An interpolated timestamp value for the given trace item.
+ double
+ GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos,
+ const LinuxPerfZeroTscConversion &tsc_conversion) const;
+
+ /// \return
+ /// \b true if and only if the given \p item_index is covered by this
+ /// range.
+ bool InRange(uint64_t item_index) const;
+ };
+
// Struct holding counts for events;
struct EventsStats {
/// A count for each individual event kind. We use an unordered map instead
@@ -130,39 +147,21 @@ public:
void RecordEvent(lldb::TraceEvent event);
};
- DecodedThread(lldb::ThreadSP thread_sp);
-
- /// Utility constructor that initializes the trace with a provided error.
- DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err);
+ DecodedThread(
+ lldb::ThreadSP thread_sp,
+ const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion);
/// Get the total number of instruction, errors and events from the decoded
/// trace.
- int64_t GetItemsCount() const;
-
- /// Construct the TSC range that covers the given instruction index.
- /// This operation is O(logn) and should be used sparingly.
- /// If the trace was collected with TSC support, all the instructions of
- /// the trace will have associated TSCs. This means that this method will
- /// only return \b llvm::None if there are no TSCs whatsoever in the trace.
- ///
- /// \param[in] insn_index
- /// The instruction index in question.
- ///
- /// \param[in] hint_range
- /// An optional range that might include the given index or might be a
- /// neighbor of it. It might help speed it traversals of the trace with
- /// short jumps.
- llvm::Optional<TscRange> CalculateTscRange(
- size_t insn_index,
- const llvm::Optional<DecodedThread::TscRange> &hint_range) const;
+ uint64_t GetItemsCount() const;
/// \return
/// The error associated with a given trace item.
- const char *GetErrorByIndex(size_t item_index) const;
+ const char *GetErrorByIndex(uint64_t item_index) const;
/// \return
/// The trace item kind given an item index.
- lldb::TraceItemKind GetItemKindByIndex(size_t item_index) const;
+ lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const;
/// \return
/// The underlying event type for the given trace item index.
@@ -177,12 +176,31 @@ public:
/// The requested cpu id, or \a llvm::None if not available.
llvm::Optional<lldb::cpu_id_t> GetCPUByIndex(uint64_t item_index) const;
+ /// Get a maximal range of trace items that include the given \p item_index
+ /// that have the same TSC value.
+ ///
+ /// \param[in] item_index
+ /// The trace item index to compare with.
+ ///
+ /// \return
+ /// The requested TSC range, or \a llvm::None if not available.
+ llvm::Optional<DecodedThread::TSCRange>
+ GetTSCRangeByIndex(uint64_t item_index) const;
+
+ /// Get a maximal range of trace items that include the given \p item_index
+ /// that have the same nanoseconds timestamp without interpolation.
+ ///
+ /// \param[in] item_index
+ /// The trace item index to compare with.
+ ///
+ /// \return
+ /// The requested nanoseconds range, or \a llvm::None if not available.
+ llvm::Optional<DecodedThread::NanosecondsRange>
+ GetNanosecondsRangeByIndex(uint64_t item_index);
+
/// \return
/// The load address of the instruction at the given index.
- lldb::addr_t GetInstructionLoadAddress(size_t item_index) const;
-
- /// Get a new cursor for the decoded thread.
- lldb::TraceCursorUP CreateNewCursor();
+ lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const;
/// Return an object with statistics of the TSC decoding errors that happened.
/// A TSC error is not a fatal error and doesn't create gaps in the trace.
@@ -214,7 +232,7 @@ public:
/// Notify this object that a new tsc has been seen.
/// If this a new TSC, an event will be created.
- void NotifyTsc(uint64_t tsc);
+ void NotifyTsc(TSC tsc);
/// Notify this object that a CPU has been seen.
/// If this a new CPU, an event will be created.
@@ -262,15 +280,22 @@ private:
/// it in TraceItemStorage to avoid padding.
std::vector<uint8_t> m_item_kinds;
- /// This map contains the TSCs of the decoded instructions. It maps
- /// `instruction index -> TSC`, where `instruction index` is the first index
- /// at which the mapped TSC appears. We use this representation because TSCs
- /// are sporadic and we can think of them as ranges. If TSCs are present in
- /// the trace, all instructions will have an associated TSC, including the
- /// first one. Otherwise, this map will be empty.
- std::map<uint64_t, uint64_t> m_timestamps;
+ /// This map contains the TSCs of the decoded trace items. It maps
+ /// `item index -> TSC`, where `item index` is the first index
+ /// at which the mapped TSC first appears. We use this representation because
+ /// TSCs are sporadic and we can think of them as ranges.
+ std::map<uint64_t, TSCRange> m_tscs;
/// This is the chronologically last TSC that has been added.
- llvm::Optional<uint64_t> m_last_tsc = llvm::None;
+ llvm::Optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc =
+ llvm::None;
+ /// This map contains the non-interpolated nanoseconds timestamps of the
+ /// decoded trace items. It maps `item index -> nanoseconds`, where `item
+ /// index` is the first index at which the mapped nanoseconds first appears.
+ /// We use this representation because timestamps are sporadic and we think of
+ /// them as ranges.
+ std::map<uint64_t, NanosecondsRange> m_nanoseconds;
+ llvm::Optional<std::map<uint64_t, NanosecondsRange>::iterator>
+ m_last_nanoseconds = llvm::None;
// The cpu information is stored as a map. It maps `instruction index -> CPU`
// A CPU is associated with the next instructions that follow until the next
@@ -279,6 +304,9 @@ private:
/// This is the chronologically last CPU ID.
llvm::Optional<uint64_t> m_last_cpu = llvm::None;
+ /// TSC -> nanos conversion utility.
+ llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
+
/// Statistics of all tracing events.
EventsStats m_events_stats;
/// Statistics of libipt errors when decoding TSCs.
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
index a98337a4e058..234b9f917d32 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
@@ -285,9 +285,23 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
for (size_t i = 0; i < executions.size(); i++) {
const IntelPTThreadContinousExecution &execution = executions[i];
- decoded_thread.NotifyCPU(execution.thread_execution.cpu_id);
auto variant = execution.thread_execution.variant;
+ // We report the TSCs we are sure of
+ switch (variant) {
+ case ThreadContinuousExecution::Variant::Complete:
+ decoded_thread.NotifyTsc(execution.thread_execution.tscs.complete.start);
+ break;
+ case ThreadContinuousExecution::Variant::OnlyStart:
+ decoded_thread.NotifyTsc(
+ execution.thread_execution.tscs.only_start.start);
+ break;
+ default:
+ break;
+ }
+
+ decoded_thread.NotifyCPU(execution.thread_execution.cpu_id);
+
// If we haven't seen a PSB yet, then it's fine not to show errors
if (has_seen_psbs) {
if (execution.intelpt_subtraces.empty()) {
@@ -299,12 +313,12 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
}
// If the first execution is incomplete because it doesn't have a previous
- // context switch in its cpu, all good.
+ // context switch in its cpu, all good, otherwise we report the error.
if (variant == ThreadContinuousExecution::Variant::OnlyEnd ||
variant == ThreadContinuousExecution::Variant::HintedStart) {
decoded_thread.AppendCustomError(
- formatv("Thread execution starting on cpu id = {0} doesn't "
- "have a matching context switch in.",
+ formatv("Unable to find the context switch in for the thread "
+ "execution starting on cpu id = {0}",
execution.thread_execution.cpu_id)
.str());
}
@@ -318,6 +332,18 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
decoder.DecodePSB(intel_pt_execution.psb_offset);
}
+ // We report the TSCs we are sure of
+ switch (variant) {
+ case ThreadContinuousExecution::Variant::Complete:
+ decoded_thread.NotifyTsc(execution.thread_execution.tscs.complete.end);
+ break;
+ case ThreadContinuousExecution::Variant::OnlyEnd:
+ decoded_thread.NotifyTsc(execution.thread_execution.tscs.only_end.end);
+ break;
+ default:
+ break;
+ }
+
// If we haven't seen a PSB yet, then it's fine not to show errors
if (has_seen_psbs) {
// If the last execution is incomplete because it doesn't have a following
@@ -326,8 +352,8 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread(
i + 1 != executions.size()) ||
variant == ThreadContinuousExecution::Variant::HintedEnd) {
decoded_thread.AppendCustomError(
- formatv("Thread execution on cpu id = {0} doesn't have a "
- "matching context switch out",
+ formatv("Unable to find the context switch out for the thread "
+ "execution on cpu id = {0}",
execution.thread_execution.cpu_id)
.str());
}
@@ -380,3 +406,22 @@ lldb_private::trace_intel_pt::SplitTraceInContinuousExecutions(
}
return executions;
}
+
+Expected<Optional<uint64_t>>
+lldb_private::trace_intel_pt::FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt,
+ ArrayRef<uint8_t> buffer) {
+ Expected<PtInsnDecoderUP> decoder_up =
+ CreateInstructionDecoder(trace_intel_pt, buffer);
+ if (!decoder_up)
+ return decoder_up.takeError();
+
+ pt_insn_decoder *decoder = decoder_up.get().get();
+ int status = pte_ok;
+ if (IsLibiptError(status = pt_insn_sync_forward(decoder)))
+ return None;
+
+ uint64_t tsc;
+ if (IsLibiptError(pt_insn_time(decoder, &tsc, nullptr, nullptr)))
+ return None;
+ return tsc;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
index cad4d39fcf24..66f3798cd600 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h
@@ -94,6 +94,16 @@ llvm::Expected<std::vector<IntelPTThreadSubtrace>>
SplitTraceInContinuousExecutions(TraceIntelPT &trace_intel_pt,
llvm::ArrayRef<uint8_t> buffer);
+/// Find the lowest TSC in the given trace.
+///
+/// \return
+/// The lowest TSC value in this trace if available, \a llvm::None if the
+/// trace is empty or the trace contains no timing information, or an \a
+/// llvm::Error if it was not possible to set up the decoder.
+llvm::Expected<llvm::Optional<uint64_t>>
+FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt,
+ llvm::ArrayRef<uint8_t> buffer);
+
} // namespace trace_intel_pt
} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
index d3ac61f7e658..920992d9d636 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
@@ -23,6 +23,21 @@ using namespace llvm;
ThreadDecoder::ThreadDecoder(const ThreadSP &thread_sp, TraceIntelPT &trace)
: m_thread_sp(thread_sp), m_trace(trace) {}
+Expected<Optional<uint64_t>> ThreadDecoder::FindLowestTSC() {
+ Optional<uint64_t> lowest_tsc;
+ Error err = m_trace.OnThreadBufferRead(
+ m_thread_sp->GetID(), [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
+ Expected<Optional<uint64_t>> tsc = FindLowestTSCInTrace(m_trace, data);
+ if (!tsc)
+ return tsc.takeError();
+ lowest_tsc = *tsc;
+ return Error::success();
+ });
+ if (err)
+ return std::move(err);
+ return lowest_tsc;
+}
+
Expected<DecodedThreadSP> ThreadDecoder::Decode() {
if (!m_decoded_thread.hasValue()) {
if (Expected<DecodedThreadSP> decoded_thread = DoDecode()) {
@@ -38,8 +53,8 @@ llvm::Expected<DecodedThreadSP> ThreadDecoder::DoDecode() {
return m_trace.GetThreadTimer(m_thread_sp->GetID())
.TimeTask(
"Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
- DecodedThreadSP decoded_thread_sp =
- std::make_shared<DecodedThread>(m_thread_sp);
+ DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
+ m_thread_sp, m_trace.GetPerfZeroTscConversion());
Error err = m_trace.OnThreadBufferRead(
m_thread_sp->GetID(), [&](llvm::ArrayRef<uint8_t> data) {
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
index 5c77ad93d27a..d580bc4dd335 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h
@@ -36,6 +36,12 @@ public:
/// A \a DecodedThread instance.
llvm::Expected<DecodedThreadSP> Decode();
+ /// \return
+ /// The lowest TSC value in this trace if available, \a llvm::None if the
+ /// trace is empty or the trace contains no timing information, or an \a
+ /// llvm::Error if it was not possible to set up the decoder.
+ llvm::Expected<llvm::Optional<uint64_t>> FindLowestTSC();
+
ThreadDecoder(const ThreadDecoder &other) = delete;
ThreadDecoder &operator=(const ThreadDecoder &other) = delete;
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
index 185c02b6bcd9..a4d86fb48ebe 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
@@ -17,28 +17,55 @@ using namespace lldb_private;
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
-TraceCursorIntelPT::TraceCursorIntelPT(ThreadSP thread_sp,
- DecodedThreadSP decoded_thread_sp)
- : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp) {
+TraceCursorIntelPT::TraceCursorIntelPT(
+ ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp,
+ const Optional<LinuxPerfZeroTscConversion> &tsc_conversion,
+ Optional<uint64_t> beginning_of_time_nanos)
+ : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp),
+ m_tsc_conversion(tsc_conversion),
+ m_beginning_of_time_nanos(beginning_of_time_nanos) {
Seek(0, SeekType::End);
}
-void TraceCursorIntelPT::CalculateTscRange() {
- // If we failed, then we look for the exact range
- if (!m_tsc_range || !m_tsc_range->InRange(m_pos))
- m_tsc_range = m_decoded_thread_sp->CalculateTscRange(
- m_pos, /*hit_range=*/m_tsc_range);
-}
-
void TraceCursorIntelPT::Next() {
m_pos += IsForwards() ? 1 : -1;
+ ClearTimingRangesIfInvalid();
+}
+
+void TraceCursorIntelPT::ClearTimingRangesIfInvalid() {
+ if (m_tsc_range_calculated) {
+ if (!m_tsc_range || m_pos < 0 || !m_tsc_range->InRange(m_pos)) {
+ m_tsc_range = None;
+ m_tsc_range_calculated = false;
+ }
+ }
+
+ if (m_nanoseconds_range_calculated) {
+ if (!m_nanoseconds_range || m_pos < 0 ||
+ !m_nanoseconds_range->InRange(m_pos)) {
+ m_nanoseconds_range = None;
+ m_nanoseconds_range_calculated = false;
+ }
+ }
+}
- // We try to go to a neighbor tsc range that might contain the current pos
- if (m_tsc_range && !m_tsc_range->InRange(m_pos))
- m_tsc_range = IsForwards() ? m_tsc_range->Next() : m_tsc_range->Prev();
+const Optional<DecodedThread::TSCRange> &
+TraceCursorIntelPT::GetTSCRange() const {
+ if (!m_tsc_range_calculated) {
+ m_tsc_range_calculated = true;
+ m_tsc_range = m_decoded_thread_sp->GetTSCRangeByIndex(m_pos);
+ }
+ return m_tsc_range;
+}
- // If we failed, this call will fix it
- CalculateTscRange();
+const Optional<DecodedThread::NanosecondsRange> &
+TraceCursorIntelPT::GetNanosecondsRange() const {
+ if (!m_nanoseconds_range_calculated) {
+ m_nanoseconds_range_calculated = true;
+ m_nanoseconds_range =
+ m_decoded_thread_sp->GetNanosecondsRangeByIndex(m_pos);
+ }
+ return m_nanoseconds_range;
}
bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
@@ -52,13 +79,15 @@ bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
case TraceCursor::SeekType::Current:
m_pos += offset;
}
- CalculateTscRange();
+
+ ClearTimingRangesIfInvalid();
return HasValue();
}
bool TraceCursorIntelPT::HasValue() const {
- return m_pos >= 0 && m_pos < m_decoded_thread_sp->GetItemsCount();
+ return m_pos >= 0 &&
+ static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount();
}
lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const {
@@ -73,15 +102,18 @@ lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const {
return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
}
-Optional<uint64_t>
-TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) const {
- switch (counter_type) {
- case lldb::eTraceCounterTSC:
- if (m_tsc_range)
- return m_tsc_range->GetTsc();
- else
- return llvm::None;
- }
+Optional<uint64_t> TraceCursorIntelPT::GetHWClock() const {
+ if (const Optional<DecodedThread::TSCRange> &range = GetTSCRange())
+ return range->tsc;
+ return None;
+}
+
+Optional<double> TraceCursorIntelPT::GetWallClockTime() const {
+ if (const Optional<DecodedThread::NanosecondsRange> &range =
+ GetNanosecondsRange())
+ return range->GetInterpolatedTime(m_pos, *m_beginning_of_time_nanos,
+ *m_tsc_conversion);
+ return None;
}
Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const {
@@ -96,13 +128,12 @@ bool TraceCursorIntelPT::GoToId(user_id_t id) {
if (!HasId(id))
return false;
m_pos = id;
- m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range);
-
+ ClearTimingRangesIfInvalid();
return true;
}
bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
- return static_cast<int64_t>(id) < m_decoded_thread_sp->GetItemsCount();
+ return id < m_decoded_thread_sp->GetItemsCount();
}
user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
index 2e0f67e67dfc..3cd9ab831f5e 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
@@ -16,8 +16,10 @@ namespace trace_intel_pt {
class TraceCursorIntelPT : public TraceCursor {
public:
- TraceCursorIntelPT(lldb::ThreadSP thread_sp,
- DecodedThreadSP decoded_thread_sp);
+ TraceCursorIntelPT(
+ lldb::ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp,
+ const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion,
+ llvm::Optional<uint64_t> beginning_of_time_nanos);
bool Seek(int64_t offset, SeekType origin) override;
@@ -29,13 +31,12 @@ public:
lldb::addr_t GetLoadAddress() const override;
- llvm::Optional<uint64_t>
- GetCounter(lldb::TraceCounter counter_type) const override;
-
lldb::TraceEvent GetEventType() const override;
llvm::Optional<lldb::cpu_id_t> GetCPU() const override;
+ llvm::Optional<uint64_t> GetHWClock() const override;
+
lldb::TraceItemKind GetItemKind() const override;
bool GoToId(lldb::user_id_t id) override;
@@ -44,16 +45,43 @@ public:
bool HasId(lldb::user_id_t id) const override;
+ llvm::Optional<double> GetWallClockTime() const override;
+
private:
- /// Calculate the tsc range for the current position if needed.
- void CalculateTscRange();
+ /// Clear the current TSC and nanoseconds ranges if after moving they are not
+ /// valid anymore.
+ void ClearTimingRangesIfInvalid();
+
+ /// Get or calculate the TSC range that includes the current trace item.
+ const llvm::Optional<DecodedThread::TSCRange> &GetTSCRange() const;
+
+ /// Get or calculate the TSC range that includes the current trace item.
+ const llvm::Optional<DecodedThread::NanosecondsRange> &
+ GetNanosecondsRange() const;
/// Storage of the actual instructions
DecodedThreadSP m_decoded_thread_sp;
/// Internal instruction index currently pointing at.
int64_t m_pos;
- /// Tsc range covering the current instruction.
- llvm::Optional<DecodedThread::TscRange> m_tsc_range;
+
+ /// Timing information and cached values.
+ /// \{
+
+ /// TSC -> nanos conversion utility. \a None if not available at all.
+ llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
+ /// Lowest nanoseconds timestamp seen in any thread trace, \a None if not
+ /// available at all.
+ llvm::Optional<uint64_t> m_beginning_of_time_nanos;
+ /// Range of trace items with the same TSC that includes the current trace
+ /// item, \a None if not calculated or not available.
+ llvm::Optional<DecodedThread::TSCRange> mutable m_tsc_range;
+ bool mutable m_tsc_range_calculated = false;
+ /// Range of trace items with the same non-interpolated timestamps in
+ /// nanoseconds that includes the current trace item, \a None if not
+ /// calculated or not available.
+ llvm::Optional<DecodedThread::NanosecondsRange> mutable m_nanoseconds_range;
+ bool mutable m_nanoseconds_range_calculated = false;
+ /// \}
};
} // namespace trace_intel_pt
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index 57433ffb14cb..f3f0a513e3fa 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -8,6 +8,8 @@
#include "TraceIntelPT.h"
+#include "TraceCursorIntelPT.h"
+
#include "../common/ThreadPostMortemTrace.h"
#include "CommandObjectTraceStartIntelPT.h"
#include "DecodedThread.h"
@@ -138,11 +140,53 @@ Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {
return it->second->Decode();
}
+Expected<Optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {
+ Storage &storage = GetUpdatedStorage();
+ if (storage.beginning_of_time_nanos_calculated)
+ return storage.beginning_of_time_nanos;
+ storage.beginning_of_time_nanos_calculated = true;
+
+ if (!storage.tsc_conversion)
+ return None;
+
+ Optional<uint64_t> lowest_tsc;
+
+ if (storage.multicpu_decoder) {
+ if (Expected<Optional<uint64_t>> tsc =
+ storage.multicpu_decoder->FindLowestTSC()) {
+ lowest_tsc = *tsc;
+ } else {
+ return tsc.takeError();
+ }
+ }
+
+ for (auto &decoder : storage.thread_decoders) {
+ Expected<Optional<uint64_t>> tsc = decoder.second->FindLowestTSC();
+ if (!tsc)
+ return tsc.takeError();
+
+ if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
+ lowest_tsc = **tsc;
+ }
+
+ if (lowest_tsc) {
+ storage.beginning_of_time_nanos =
+ storage.tsc_conversion->ToNanos(*lowest_tsc);
+ }
+ return storage.beginning_of_time_nanos;
+}
+
llvm::Expected<lldb::TraceCursorUP>
TraceIntelPT::CreateNewCursor(Thread &thread) {
- if (Expected<DecodedThreadSP> decoded_thread = Decode(thread))
- return decoded_thread.get()->CreateNewCursor();
- else
+ if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) {
+ if (Expected<Optional<uint64_t>> beginning_of_time =
+ FindBeginningOfTimeNanos())
+ return std::make_unique<TraceCursorIntelPT>(
+ thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion,
+ *beginning_of_time);
+ else
+ return beginning_of_time.takeError();
+ } else
return decoded_thread.takeError();
}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
index d3e58374867d..7f2c3f8dda5d 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -220,6 +220,13 @@ private:
/// returned if the decoder couldn't be properly set up.
llvm::Expected<DecodedThreadSP> Decode(Thread &thread);
+ /// \return
+ /// The lowest timestamp in nanoseconds in all traces if available, \a
+ /// llvm::None if all the traces were empty or no trace contained no
+ /// timing information, or an \a llvm::Error if it was not possible to set
+ /// up the decoder for some trace.
+ llvm::Expected<llvm::Optional<uint64_t>> FindBeginningOfTimeNanos();
+
// Dump out trace info in JSON format
void DumpTraceInfoAsJson(Thread &thread, Stream &s, bool verbose);
@@ -236,6 +243,8 @@ private:
/// It is provided by either a trace bundle or a live process to convert TSC
/// counters to and from nanos. It might not be available on all hosts.
llvm::Optional<LinuxPerfZeroTscConversion> tsc_conversion;
+ llvm::Optional<uint64_t> beginning_of_time_nanos;
+ bool beginning_of_time_nanos_calculated = false;
} m_storage;
/// It is provided by either a trace bundle or a live process' "cpuInfo"
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
index e547032f739d..08f54b582e3f 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
@@ -35,6 +35,28 @@ bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {
return m_tids.count(tid);
}
+Expected<Optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {
+ Optional<uint64_t> lowest_tsc;
+ TraceIntelPTSP trace_sp = GetTrace();
+
+ Error err = GetTrace()->OnAllCpusBinaryDataRead(
+ IntelPTDataKinds::kIptTrace,
+ [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
+ for (auto &cpu_id_to_buffer : buffers) {
+ Expected<Optional<uint64_t>> tsc =
+ FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);
+ if (!tsc)
+ return tsc.takeError();
+ if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
+ lowest_tsc = **tsc;
+ }
+ return Error::success();
+ });
+ if (err)
+ return std::move(err);
+ return lowest_tsc;
+}
+
Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
return std::move(err);
@@ -48,8 +70,8 @@ Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
if (it != m_decoded_threads.end())
return it->second;
- DecodedThreadSP decoded_thread_sp =
- std::make_shared<DecodedThread>(thread.shared_from_this());
+ DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
+ thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());
Error err = trace_sp->OnAllCpusBinaryDataRead(
IntelPTDataKinds::kIptTrace,
diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
index 3b7926760f3c..87c370e88ae6 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
+++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
@@ -66,6 +66,12 @@ public:
/// The total number of PSB blocks in all cores.
size_t GetTotalPSBBlocksCount() const;
+ /// \return
+ /// The lowest TSC value in this trace if available, \a llvm::None if the
+ /// trace is empty or the trace contains no timing information, or an \a
+ /// llvm::Error if it was not possible to set up the decoder.
+ llvm::Expected<llvm::Optional<uint64_t>> FindLowestTSC();
+
private:
/// Traverse the context switch traces and the basic intel pt continuous
/// subtraces and produce a list of continuous executions for each process and
diff --git a/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
index 92eec139e07c..c796cbc75c1b 100644
--- a/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -968,7 +968,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the
// epilogue started executed
- bool prologue_completed_is_aligned;
+ bool prologue_completed_is_aligned = false;
std::vector<bool> prologue_completed_saved_registers;
while (current_func_text_offset < size) {
diff --git a/contrib/llvm-project/lldb/source/Symbol/Type.cpp b/contrib/llvm-project/lldb/source/Symbol/Type.cpp
index 4ee5a3e76ae4..f83bdcdc1c74 100644
--- a/contrib/llvm-project/lldb/source/Symbol/Type.cpp
+++ b/contrib/llvm-project/lldb/source/Symbol/Type.cpp
@@ -162,8 +162,8 @@ Type::Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name,
}
Type::Type()
- : std::enable_shared_from_this<Type>(), UserID(0),
- m_name("<INVALID TYPE>") {
+ : std::enable_shared_from_this<Type>(), UserID(0), m_name("<INVALID TYPE>"),
+ m_payload(0) {
m_byte_size = 0;
m_byte_size_has_value = false;
}
diff --git a/contrib/llvm-project/lldb/source/Target/Process.cpp b/contrib/llvm-project/lldb/source/Target/Process.cpp
index 046706637691..b2f1318ca91d 100644
--- a/contrib/llvm-project/lldb/source/Target/Process.cpp
+++ b/contrib/llvm-project/lldb/source/Target/Process.cpp
@@ -433,7 +433,8 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0),
m_memory_cache(*this), m_allocated_memory_cache(*this),
m_should_detach(false), m_next_event_action_up(), m_public_run_lock(),
- m_private_run_lock(), m_finalizing(false),
+ m_private_run_lock(), m_currently_handling_do_on_removals(false),
+ m_resume_requested(false), m_finalizing(false),
m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false),
m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false),
m_can_interpret_function_calls(false), m_run_thread_plan_lock(),
@@ -2566,8 +2567,8 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state,
if (state == eStateStopped || state == eStateCrashed) {
DidLaunch();
-
- // Now that we know the process type, update its signal responses from the
+
+ // Now that we know the process type, update its signal responses from the
// ones stored in the Target:
if (m_unix_signals_sp) {
StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream();
@@ -2935,7 +2936,7 @@ void Process::CompleteAttach() {
}
}
}
- // Now that we know the process type, update its signal responses from the
+ // Now that we know the process type, update its signal responses from the
// ones stored in the Target:
if (m_unix_signals_sp) {
StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream();
@@ -4550,9 +4551,9 @@ public:
private:
lldb::ThreadPlanSP m_thread_plan_sp;
bool m_already_reset = false;
- bool m_private;
- bool m_is_controlling;
- bool m_okay_to_discard;
+ bool m_private = false;
+ bool m_is_controlling = false;
+ bool m_okay_to_discard = false;
};
} // anonymous namespace
diff --git a/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp b/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp
index a0f97d7e7cff..2da40ba2bf61 100644
--- a/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1525,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister(
// unwindplan_regloc has valid contents about where to retrieve the register
if (unwindplan_regloc.IsUnspecified()) {
- lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc = {};
new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
UnwindLogMsg("save location for %s (%d) is unspecified, continue searching",
@@ -1731,7 +1731,7 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() {
addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS;
addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS;
- UnwindLLDB::RegisterLocation regloc;
+ UnwindLLDB::RegisterLocation regloc = {};
if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB),
regloc) ==
UnwindLLDB::RegisterSearchResult::eRegisterFound) {
diff --git a/contrib/llvm-project/lldb/source/Target/StackFrame.cpp b/contrib/llvm-project/lldb/source/Target/StackFrame.cpp
index e87cf5af3e39..4fb5ba0b735e 100644
--- a/contrib/llvm-project/lldb/source/Target/StackFrame.cpp
+++ b/contrib/llvm-project/lldb/source/Target/StackFrame.cpp
@@ -1145,26 +1145,34 @@ bool StackFrame::HasDebugInformation() {
ValueObjectSP
StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp,
DynamicValueType use_dynamic) {
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
ValueObjectSP valobj_sp;
- if (IsHistorical()) {
- return valobj_sp;
- }
- VariableList *var_list = GetVariableList(true);
- if (var_list) {
- // Make sure the variable is a frame variable
- const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get());
- const uint32_t num_variables = var_list->GetSize();
- if (var_idx < num_variables) {
- valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
- if (!valobj_sp) {
- if (m_variable_list_value_objects.GetSize() < num_variables)
- m_variable_list_value_objects.Resize(num_variables);
- valobj_sp = ValueObjectVariable::Create(this, variable_sp);
- m_variable_list_value_objects.SetValueObjectAtIndex(var_idx, valobj_sp);
+ { // Scope for stack frame mutex. We need to drop this mutex before we figure
+ // out the dynamic value. That will require converting the StackID in the
+ // VO back to a StackFrame, which will in turn require locking the
+ // StackFrameList. If we still hold the StackFrame mutex, we could suffer
+ // lock inversion against the pattern of getting the StackFrameList and
+ // then the stack frame, which is fairly common.
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (IsHistorical()) {
+ return valobj_sp;
+ }
+ VariableList *var_list = GetVariableList(true);
+ if (var_list) {
+ // Make sure the variable is a frame variable
+ const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get());
+ const uint32_t num_variables = var_list->GetSize();
+ if (var_idx < num_variables) {
+ valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
+ if (!valobj_sp) {
+ if (m_variable_list_value_objects.GetSize() < num_variables)
+ m_variable_list_value_objects.Resize(num_variables);
+ valobj_sp = ValueObjectVariable::Create(this, variable_sp);
+ m_variable_list_value_objects.SetValueObjectAtIndex(var_idx,
+ valobj_sp);
+ }
}
}
- }
+ } // End of StackFrame mutex scope.
if (use_dynamic != eNoDynamicValues && valobj_sp) {
ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue(use_dynamic);
if (dynamic_sp)
diff --git a/contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp b/contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp
index a9f774aa6109..7e9bb963bb5d 100644
--- a/contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -104,7 +104,10 @@ ThreadPlanCallFunction::ThreadPlanCallFunction(
m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
m_debug_execution(options.GetDebug()),
m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function),
- m_function_sp(0), m_takedown_done(false),
+ m_start_addr(), m_function_sp(0), m_subplan_sp(),
+ m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr),
+ m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(),
+ m_return_valobj_sp(), m_takedown_done(false),
m_should_clear_objc_exception_bp(false),
m_should_clear_cxx_exception_bp(false),
m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) {
@@ -134,7 +137,10 @@ ThreadPlanCallFunction::ThreadPlanCallFunction(
m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
m_debug_execution(options.GetDebug()),
m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function),
- m_function_sp(0), m_takedown_done(false),
+ m_start_addr(), m_function_sp(0), m_subplan_sp(),
+ m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr),
+ m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(),
+ m_return_valobj_sp(), m_takedown_done(false),
m_should_clear_objc_exception_bp(false),
m_should_clear_cxx_exception_bp(false),
m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(CompilerType()) {}
diff --git a/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp b/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp
index f5331428038b..7e0925307644 100644
--- a/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp
+++ b/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp
@@ -36,11 +36,11 @@ using namespace lldb_private;
ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp)
: m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
- m_enabled(false), m_stream_sp(stream_sp) {}
+ m_enabled(false), m_stream_sp(stream_sp), m_thread(nullptr) {}
ThreadPlanTracer::ThreadPlanTracer(Thread &thread)
: m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
- m_enabled(false), m_stream_sp() {}
+ m_enabled(false), m_stream_sp(), m_thread(nullptr) {}
Stream *ThreadPlanTracer::GetLogStream() {
if (m_stream_sp)
diff --git a/contrib/llvm-project/lldb/source/Target/TraceCursor.cpp b/contrib/llvm-project/lldb/source/Target/TraceCursor.cpp
index f99b0d28c154..de3f9bf1b33d 100644
--- a/contrib/llvm-project/lldb/source/Target/TraceCursor.cpp
+++ b/contrib/llvm-project/lldb/source/Target/TraceCursor.cpp
@@ -50,6 +50,8 @@ const char *TraceCursor::EventKindToString(lldb::TraceEvent event_kind) {
return "software disabled tracing";
case lldb::eTraceEventCPUChanged:
return "CPU core changed";
+ case lldb::eTraceEventHWClockTick:
+ return "HW clock tick";
}
llvm_unreachable("Fully covered switch above");
}
diff --git a/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp b/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp
index 739105e9e9fb..5b71e9e4e97a 100644
--- a/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp
+++ b/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp
@@ -128,16 +128,26 @@ public:
m_s.Format(" {0}: ", item.id);
- if (m_options.show_tsc) {
- m_s.Format("[tsc={0}] ",
- item.tsc ? std::to_string(*item.tsc) : "unavailable");
+ if (m_options.show_timestamps) {
+ m_s.Format("[{0}] ", item.timestamp
+ ? formatv("{0:3} ns", *item.timestamp).str()
+ : "unavailable");
}
if (item.event) {
m_s << "(event) " << TraceCursor::EventKindToString(*item.event);
- if (*item.event == eTraceEventCPUChanged) {
+ switch (*item.event) {
+ case eTraceEventCPUChanged:
m_s.Format(" [new CPU={0}]",
item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable");
+ break;
+ case eTraceEventHWClockTick:
+ m_s.Format(" [{0}]", item.hw_clock ? std::to_string(*item.hw_clock)
+ : "unavailable");
+ break;
+ case eTraceEventDisabledHW:
+ case eTraceEventDisabledSW:
+ break;
}
} else if (item.error) {
m_s << "(error) " << *item.error;
@@ -181,7 +191,8 @@ class OutputWriterJSON : public TraceDumper::OutputWriter {
| {
"loadAddress": string decimal,
"id": decimal,
- "tsc"?: string decimal,
+ "hwClock"?: string decimal,
+ "timestamp_ns"?: string decimal,
"module"?: string,
"symbol"?: string,
"line"?: decimal,
@@ -202,8 +213,17 @@ public:
void DumpEvent(const TraceDumper::TraceItem &item) {
m_j.attribute("event", TraceCursor::EventKindToString(*item.event));
- if (item.event == eTraceEventCPUChanged)
+ switch (*item.event) {
+ case eTraceEventCPUChanged:
m_j.attribute("cpuId", item.cpu_id);
+ break;
+ case eTraceEventHWClockTick:
+ m_j.attribute("hwClock", item.hw_clock);
+ break;
+ case eTraceEventDisabledHW:
+ case eTraceEventDisabledSW:
+ break;
+ }
}
void DumpInstruction(const TraceDumper::TraceItem &item) {
@@ -234,10 +254,11 @@ public:
void TraceItem(const TraceDumper::TraceItem &item) override {
m_j.object([&] {
m_j.attribute("id", item.id);
- if (m_options.show_tsc)
- m_j.attribute(
- "tsc",
- item.tsc ? Optional<std::string>(std::to_string(*item.tsc)) : None);
+ if (m_options.show_timestamps)
+ m_j.attribute("timestamp_ns", item.timestamp
+ ? Optional<std::string>(
+ std::to_string(*item.timestamp))
+ : None);
if (item.event) {
DumpEvent(item);
@@ -286,11 +307,11 @@ TraceDumper::TraceDumper(lldb::TraceCursorUP &&cursor_up, Stream &s,
}
TraceDumper::TraceItem TraceDumper::CreatRawTraceItem() {
- TraceItem item;
+ TraceItem item = {};
item.id = m_cursor_up->GetId();
- if (m_options.show_tsc)
- item.tsc = m_cursor_up->GetCounter(lldb::eTraceCounterTSC);
+ if (m_options.show_timestamps)
+ item.timestamp = m_cursor_up->GetWallClockTime();
return item;
}
@@ -366,8 +387,17 @@ Optional<lldb::user_id_t> TraceDumper::DumpInstructions(size_t count) {
if (!m_options.show_events)
continue;
item.event = m_cursor_up->GetEventType();
- if (*item.event == eTraceEventCPUChanged)
+ switch (*item.event) {
+ case eTraceEventCPUChanged:
item.cpu_id = m_cursor_up->GetCPU();
+ break;
+ case eTraceEventHWClockTick:
+ item.hw_clock = m_cursor_up->GetHWClock();
+ break;
+ case eTraceEventDisabledHW:
+ case eTraceEventDisabledSW:
+ break;
+ }
} else if (m_cursor_up->IsError()) {
item.error = m_cursor_up->GetError();
} else {