wallace updated this revision to Diff 423535.
wallace added a comment.
formatting
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D123982/new/
https://reviews.llvm.org/D123982
Files:
lldb/include/lldb/Target/TraceCursor.h
lldb/include/lldb/Target/TraceInstructionDumper.h
lldb/include/lldb/lldb-enumerations.h
lldb/source/Commands/CommandObjectThread.cpp
lldb/source/Commands/Options.td
lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
lldb/source/Target/TraceInstructionDumper.cpp
lldb/test/API/commands/trace/TestTraceDumpInfo.py
lldb/test/API/commands/trace/TestTraceEvents.py
lldb/test/API/commands/trace/TestTraceLoad.py
Index: lldb/test/API/commands/trace/TestTraceLoad.py
===================================================================
--- lldb/test/API/commands/trace/TestTraceLoad.py
+++ lldb/test/API/commands/trace/TestTraceLoad.py
@@ -40,12 +40,15 @@
Memory usage:
Raw trace size: 4 KiB
- Total approximate memory usage (excluding raw trace): 0.27 KiB
- Average memory usage per instruction (excluding raw trace): 13.00 bytes
+ Total approximate memory usage (excluding raw trace): 1.27 KiB
+ Average memory usage per instruction (excluding raw trace): 61.76 bytes
Timing:
Decoding instructions: ''', '''s
+ Events:
+ Total number of instructions with events: 1
+
Errors:
Number of TSC decoding errors: 0'''])
Index: lldb/test/API/commands/trace/TestTraceEvents.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/trace/TestTraceEvents.py
@@ -0,0 +1,82 @@
+import lldb
+from intelpt_testcase import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+from lldbsuite.test.decorators import *
+
+class TestTraceEvents(TraceIntelPTTestCaseBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @testSBAPIAndCommands
+ def testPauseEvents(self):
+ '''
+ Everytime the target stops running on the CPU, a 'disabled' event will
+ be emitted, which is represented by the TraceCursor API as a 'paused'
+ event.
+ '''
+ self.expect("target create " +
+ os.path.join(self.getSourceDir(), "intelpt-trace-multi-file", "a.out"))
+ self.expect("b 12")
+ self.expect("r")
+ self.traceStartThread()
+ self.expect("n")
+ self.expect("n")
+ self.expect("si")
+ self.expect("si")
+ self.expect("si")
+ # We ensure that the paused events are printed correctly forward
+ self.expect("thread trace dump instructions -e -f",
+ patterns=[f'''thread #1: tid = .*
+ a.out`main \+ 23 at main.cpp:12
+ 0: {ADDRESS_REGEX} movl .*
+ \[paused\]
+ 1: {ADDRESS_REGEX} addl .*
+ 2: {ADDRESS_REGEX} movl .*
+ \[paused\]
+ a.out`main \+ 34 \[inlined\] inline_function\(\) at main.cpp:4
+ 3: {ADDRESS_REGEX} movl .*
+ a.out`main \+ 41 \[inlined\] inline_function\(\) \+ 7 at main.cpp:5
+ 4: {ADDRESS_REGEX} movl .*
+ 5: {ADDRESS_REGEX} addl .*
+ 6: {ADDRESS_REGEX} movl .*
+ a.out`main \+ 52 \[inlined\] inline_function\(\) \+ 18 at main.cpp:6
+ 7: {ADDRESS_REGEX} movl .*
+ a.out`main \+ 55 at main.cpp:14
+ 8: {ADDRESS_REGEX} movl .*
+ 9: {ADDRESS_REGEX} addl .*
+ 10: {ADDRESS_REGEX} movl .*
+ \[paused\]
+ a.out`main \+ 63 at main.cpp:16
+ 11: {ADDRESS_REGEX} callq .* ; symbol stub for: foo\(\)
+ \[paused\]
+ a.out`symbol stub for: foo\(\)
+ 12: {ADDRESS_REGEX} jmpq'''])
+
+ # We ensure that the paused events are printed correctly backward
+ self.expect("thread trace dump instructions -e --id 12",
+ patterns=[f'''thread #1: tid = .*
+ a.out`symbol stub for: foo\(\)
+ 12: {ADDRESS_REGEX} jmpq .*
+ \[paused\]
+ a.out`main \+ 63 at main.cpp:16
+ 11: {ADDRESS_REGEX} callq .* ; symbol stub for: foo\(\)
+ \[paused\]
+ a.out`main \+ 60 at main.cpp:14
+ 10: {ADDRESS_REGEX} movl .*
+ 9: {ADDRESS_REGEX} addl .*
+ 8: {ADDRESS_REGEX} movl .*
+ a.out`main \+ 52 \[inlined\] inline_function\(\) \+ 18 at main.cpp:6
+ 7: {ADDRESS_REGEX} movl .*
+ a.out`main \+ 49 \[inlined\] inline_function\(\) \+ 15 at main.cpp:5
+ 6: {ADDRESS_REGEX} movl .*
+ 5: {ADDRESS_REGEX} addl .*
+ 4: {ADDRESS_REGEX} movl .*
+ a.out`main \+ 34 \[inlined\] inline_function\(\) at main.cpp:4
+ 3: {ADDRESS_REGEX} movl .*
+ \[paused\]
+ a.out`main \+ 31 at main.cpp:12
+ 2: {ADDRESS_REGEX} movl .*
+ 1: {ADDRESS_REGEX} addl .*
+ \[paused\]
+ 0: {ADDRESS_REGEX} movl .*'''])
Index: lldb/test/API/commands/trace/TestTraceDumpInfo.py
===================================================================
--- lldb/test/API/commands/trace/TestTraceDumpInfo.py
+++ lldb/test/API/commands/trace/TestTraceDumpInfo.py
@@ -42,12 +42,15 @@
Memory usage:
Raw trace size: 4 KiB
- Total approximate memory usage (excluding raw trace): 0.27 KiB
- Average memory usage per instruction (excluding raw trace): 13.00 bytes
+ Total approximate memory usage (excluding raw trace): 1.27 KiB
+ Average memory usage per instruction (excluding raw trace): 61.76 bytes
Timing:
Decoding instructions: ''', '''s
+ Events:
+ Total number of instructions with events: 1
+
Errors:
Number of TSC decoding errors: 0'''],
patterns=["Decoding instructions: \d.\d\ds"])
Index: lldb/source/Target/TraceInstructionDumper.cpp
===================================================================
--- lldb/source/Target/TraceInstructionDumper.cpp
+++ lldb/source/Target/TraceInstructionDumper.cpp
@@ -172,6 +172,16 @@
bool TraceInstructionDumper::HasMoreData() { return !m_no_more_data; }
+void TraceInstructionDumper::PrintEvents() {
+ if (!m_options.show_events)
+ return;
+
+ TraceEvents events = m_cursor_up->GetEvents();
+ if (events & lldb::eTraceEventPaused) {
+ m_s << " [paused]\n";
+ }
+}
+
Optional<lldb::tid_t> TraceInstructionDumper::DumpInstructions(size_t count) {
ThreadSP thread_sp = m_cursor_up->GetExecutionContextRef().GetThreadSP();
if (!thread_sp) {
@@ -259,6 +269,11 @@
break;
}
last_id = m_cursor_up->GetId();
+ if (m_options.forwards) {
+ // When moving forwards, we first print the event before printing
+ // the actual instruction.
+ PrintEvents();
+ }
if (const char *err = m_cursor_up->GetError()) {
if (!m_cursor_up->IsForwards() && !was_prev_instruction_an_error)
@@ -297,6 +312,13 @@
}
m_s.Printf("\n");
+
+ if (!m_options.forwards) {
+ // If we move backwards, we print the events after printing
+ // the actual instruction so that reading chronologically
+ // makes sense.
+ PrintEvents();
+ }
TryMoveOneStep();
}
return last_id;
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -142,6 +142,10 @@
s.Format(" {0}: {1:2}s\n", name, duration.count() / 1000.0);
});
+ s << "\n Events:\n";
+ s.Format(" Total number of instructions with events: {0}\n",
+ decoded_trace_sp->GetInstructionsWithEventsCount());
+
s << "\n Errors:\n";
const DecodedThread::LibiptErrors &tsc_errors =
decoded_trace_sp->GetTscErrors();
Index: lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
@@ -30,6 +30,8 @@
llvm::Optional<uint64_t> GetCounter(lldb::TraceCounter counter_type) override;
+ lldb::TraceEvents GetEvents() override;
+
lldb::TraceInstructionControlFlowType
GetInstructionControlFlowType() override;
Index: lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
@@ -108,6 +108,10 @@
}
}
+lldb::TraceEvents TraceCursorIntelPT::GetEvents() {
+ return m_decoded_thread_sp->GetEvents(m_pos);
+}
+
TraceInstructionControlFlowType
TraceCursorIntelPT::GetInstructionControlFlowType() {
return m_decoded_thread_sp->GetInstructionControlFlowType(m_pos);
Index: lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
+++ lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
@@ -43,7 +43,7 @@
});
if (err)
- decoded_thread_sp->AppendError(std::move(err));
+ decoded_thread_sp->SetAsFailed(std::move(err));
return decoded_thread_sp;
});
}
Index: lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
+++ lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
@@ -26,18 +26,6 @@
explicit operator bool() const { return has_tsc == eLazyBoolYes; }
};
-static inline bool IsLibiptError(int libipt_status) {
- return libipt_status < 0;
-}
-
-static inline bool IsEndOfStream(int libipt_status) {
- return libipt_status == -pte_eos;
-}
-
-static inline bool IsTscUnavailable(int libipt_status) {
- return libipt_status == -pte_no_time;
-}
-
/// Class that decodes a raw buffer for a single thread using the low level
/// libipt library.
///
@@ -75,20 +63,30 @@
}
private:
+ /// Invoke the low level function \a pt_insn_next and store the decoded
+ /// instruction in the given \a DecodedInstruction.
+ ///
+ /// \return
+ /// The status returned by pt_insn_next.
+ int DecodeNextInstruction(DecodedInstruction &insn) {
+ return pt_insn_next(&m_decoder, &insn.pt_insn, sizeof(insn.pt_insn));
+ }
+
/// Decode all the instructions and events until an error is found or the end
/// of the trace is reached.
///
/// \param[in] status
/// The status that was result of synchronizing to the most recent PSB.
void DecodeInstructionsAndEvents(int status) {
- pt_insn insn;
- while (ProcessPTEvents(status)) {
- status = pt_insn_next(&m_decoder, &insn, sizeof(insn));
- // The status returned by pt_insn_next will need to be processed by
- // ProcessPTEvents in the next loop.
- if (FoundErrors(status, insn.ip))
+ while (DecodedInstruction insn = ProcessPTEvents(status)) {
+ // The status returned by DecodeNextInstruction will need to be processed
+ // by ProcessPTEvents in the next loop if it is not an error.
+ if (IsLibiptError(status = DecodeNextInstruction(insn))) {
+ insn.libipt_error = status;
+ m_decoded_thread.Append(insn);
break;
- AppendInstruction(insn);
+ }
+ m_decoded_thread.Append(insn);
}
}
@@ -98,6 +96,8 @@
/// Once the decoder is at that synchronization point, it can start decoding
/// instructions.
///
+ /// If errors are found, they will be appended to the trace.
+ ///
/// \return
/// The libipt decoder status after moving to the next PSB. Negative if
/// no PSB was found.
@@ -135,7 +135,9 @@
}
// We make this call to record any synchronization errors.
- FoundErrors(status);
+ if (IsLibiptError(status))
+ m_decoded_thread.Append(DecodedInstruction(status));
+
return status;
}
@@ -143,21 +145,60 @@
/// instruction e.g. timing events like ptev_tick, or paging events like
/// ptev_paging.
///
+ /// If an error is found, it will be appended to the trace.
+ ///
+ /// \param[in] status
+ /// The status gotten from the previous instruction decoding or PSB
+ /// synchronization.
+ ///
/// \return
- /// \b true if we could process the events, \b false if errors were found.
- bool ProcessPTEvents(int status) {
+ /// A \a DecodedInstruction with event, tsc and error information.
+ DecodedInstruction ProcessPTEvents(int status) {
+ DecodedInstruction insn;
while (status & pts_event_pending) {
pt_event event;
status = pt_insn_event(&m_decoder, &event, sizeof(event));
- if (IsLibiptError(status))
+ if (IsLibiptError(status)) {
+ insn.libipt_error = status;
+ break;
+ }
+
+ switch (event.type) {
+ case ptev_enabled:
+ // The kernel started or resumed tracing the program.
+ break;
+ case ptev_disabled:
+ // The CPU paused tracing the program, e.g. due to ip filtering.
+ case ptev_async_disabled:
+ // The kernel or user code paused tracing the program, e.g.
+ // a breakpoint or a ioctl invocation pausing the trace, or a
+ // context switch happened.
+
+ if (m_decoded_thread.GetInstructionsCount() > 0) {
+ // A paused event before the first instruction can be safely
+ // discarded.
+ insn.events = (TraceEvents)(insn.events | eTraceEventPaused);
+ }
+ break;
+ case ptev_overflow:
+ // The CPU internal buffer had an overflow error and some instructions
+ // were lost.
+ insn.libipt_error = -pte_overflow;
+ break;
+ default:
break;
+ }
}
// We refresh the TSC that might have changed after processing the events.
// See
// https://github.com/intel/libipt/blob/master/doc/man/pt_evt_next.3.md
RefreshTscInfo();
- return !FoundErrors(status);
+ if (m_tsc_info)
+ insn.tsc = m_tsc_info.tsc;
+ if (!insn)
+ m_decoded_thread.Append(insn);
+ return insn;
}
/// Query the decoder for the most recent TSC timestamp and update
@@ -189,39 +230,6 @@
}
}
- /// Check if the given libipt status signals any errors. If errors were found,
- /// they will be recorded in the decoded trace.
- ///
- /// \param[in] ip
- /// An optional ip address can be passed if the error is associated with
- /// the decoding of a specific instruction.
- ///
- /// \return
- /// \b true if errors were found, \b false otherwise.
- bool FoundErrors(int status, lldb::addr_t ip = LLDB_INVALID_ADDRESS) {
- if (!IsLibiptError(status))
- return false;
-
- // We signal a gap only if it's not "end of stream", as that's not a proper
- // error.
- if (!IsEndOfStream(status)) {
- if (m_tsc_info) {
- m_decoded_thread.AppendError(make_error<IntelPTError>(status, ip),
- m_tsc_info.tsc);
- } else {
- m_decoded_thread.AppendError(make_error<IntelPTError>(status, ip));
- }
- }
- return true;
- }
-
- void AppendInstruction(const pt_insn &insn) {
- if (m_tsc_info)
- m_decoded_thread.AppendInstruction(insn, m_tsc_info.tsc);
- else
- m_decoded_thread.AppendInstruction(insn);
- }
-
private:
pt_insn_decoder &m_decoder;
DecodedThread &m_decoded_thread;
@@ -293,7 +301,7 @@
Expected<PtInsnDecoderUP> decoder_up =
CreateInstructionDecoder(decoded_thread, trace_intel_pt, buffer);
if (!decoder_up)
- return decoded_thread.AppendError(decoder_up.takeError());
+ return decoded_thread.SetAsFailed(decoder_up.takeError());
LibiptDecoder libipt_decoder(*decoder_up.get(), decoded_thread);
libipt_decoder.DecodeUntilEndOfTrace();
Index: lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
+++ lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -23,6 +23,15 @@
namespace lldb_private {
namespace trace_intel_pt {
+/// libipt status utils
+/// \{
+bool IsLibiptError(int libipt_status);
+
+bool IsEndOfStream(int libipt_status);
+
+bool IsTscUnavailable(int libipt_status);
+/// \}
+
/// Class for representing a libipt decoding error.
class IntelPTError : public llvm::ErrorInfo<IntelPTError> {
public:
@@ -51,6 +60,27 @@
lldb::addr_t m_address;
};
+/// Helper struct for building an instruction or error from the decoder.
+/// It holds associated events and timing information.
+struct DecodedInstruction {
+ DecodedInstruction() {
+ pt_insn.ip = LLDB_INVALID_ADDRESS;
+ libipt_error = pte_ok;
+ }
+
+ DecodedInstruction(int libipt_error_code) : DecodedInstruction() {
+ libipt_error = libipt_error_code;
+ }
+
+ /// \return \b true iff this struct holds a libipt error.
+ explicit operator bool() const;
+
+ int libipt_error;
+ lldb::TraceEvents events = (lldb::TraceEvents)0;
+ llvm::Optional<uint64_t> tsc = llvm::None;
+ pt_insn pt_insn;
+};
+
/// \class DecodedThread
/// Class holding the instructions and function call hierarchy obtained from
/// decoding a trace, as well as a position cursor used when reverse debugging
@@ -114,17 +144,16 @@
/// Utility constructor that initializes the trace with a provided error.
DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err);
- /// Append a successfully decoded instruction.
- void AppendInstruction(const pt_insn &instruction);
+ /// Append an instruction or a libipt error.
+ void Append(const DecodedInstruction &insn);
- /// Append a sucessfully decoded instruction with an associated TSC timestamp.
- void AppendInstruction(const pt_insn &instruction, uint64_t tsc);
-
- /// Append a decoding error (i.e. an instruction that failed to be decoded).
- void AppendError(llvm::Error &&error);
+ /// Append an error signaling that decoding completely failed.
+ void SetAsFailed(llvm::Error &&error);
- /// Append a decoding error with a corresponding TSC.
- void AppendError(llvm::Error &&error, uint64_t tsc);
+ /// Get a bitmask with the events that happened chronologically right before
+ /// the instruction pointed by the given instruction index, but after the
+ /// previous instruction.
+ lldb::TraceEvents GetEvents(int insn_index);
/// Get the total number of instruction pointers from the decoded trace.
/// This will include instructions that indicate errors (or gaps) in the
@@ -191,6 +220,10 @@
/// An error returned by the libipt library.
void RecordTscError(int libipt_error_code);
+ /// \return
+ /// The number of instructions with associated events.
+ size_t GetInstructionsWithEventsCount() const;
+
/// The approximate size in bytes used by this instance,
/// including all the already decoded instructions.
size_t CalculateApproximateMemoryUsage() const;
@@ -198,6 +231,9 @@
lldb::ThreadSP GetThread();
private:
+ /// Append a decoding error given an llvm::Error.
+ void AppendError(llvm::Error &&error);
+
/// Notify this class that the last added instruction or error has
/// an associated TSC.
void RecordTscForLastInstruction(uint64_t tsc);
@@ -225,9 +261,9 @@
// This variables stores the messages of all the error instructions in the
// trace. It maps `instruction index -> error message`.
llvm::DenseMap<uint64_t, std::string> m_errors;
- /// The size in bytes of the raw buffer before decoding. It might be None if
- /// the decoding failed.
- llvm::Optional<size_t> m_raw_trace_size;
+ /// This variable stores the bitmask of events that happened right before
+ /// the instruction given as a key. It maps `instruction index -> events`.
+ llvm::DenseMap<uint64_t, lldb::TraceEvents> m_events;
/// All occurrences of libipt errors when decoding TSCs.
LibiptErrors m_tsc_errors;
/// Total amount of time spent decoding.
Index: lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -19,6 +19,18 @@
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
+bool lldb_private::trace_intel_pt::IsLibiptError(int libipt_status) {
+ return libipt_status < 0;
+}
+
+bool lldb_private::trace_intel_pt::IsEndOfStream(int libipt_status) {
+ return libipt_status == -pte_eos;
+}
+
+bool lldb_private::trace_intel_pt::IsTscUnavailable(int libipt_status) {
+ return libipt_status == -pte_no_time;
+}
+
char IntelPTError::ID;
IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address)
@@ -35,6 +47,10 @@
OS << "error: " << libipt_error_message;
}
+DecodedInstruction::operator bool() const {
+ return !IsLibiptError(libipt_error);
+}
+
size_t DecodedThread::GetInstructionsCount() const {
return m_instruction_ips.size();
}
@@ -93,15 +109,22 @@
}
}
-void DecodedThread::AppendInstruction(const pt_insn &insn) {
- m_instruction_ips.emplace_back(insn.ip);
- m_instruction_sizes.emplace_back(insn.size);
- m_instruction_classes.emplace_back(insn.iclass);
-}
-
-void DecodedThread::AppendInstruction(const pt_insn &insn, uint64_t tsc) {
- AppendInstruction(insn);
- RecordTscForLastInstruction(tsc);
+void DecodedThread::Append(const DecodedInstruction &insn) {
+ if (!insn) {
+ // End of stream shouldn't be a public error
+ if (IsEndOfStream(insn.libipt_error))
+ return;
+
+ AppendError(make_error<IntelPTError>(insn.libipt_error, insn.pt_insn.ip));
+ } else {
+ m_instruction_ips.emplace_back(insn.pt_insn.ip);
+ m_instruction_sizes.emplace_back(insn.pt_insn.size);
+ m_instruction_classes.emplace_back(insn.pt_insn.iclass);
+ }
+ if (insn.tsc)
+ RecordTscForLastInstruction(*insn.tsc);
+ if (insn.events)
+ m_events.try_emplace(m_instruction_ips.size() - 1, insn.events);
}
void DecodedThread::AppendError(llvm::Error &&error) {
@@ -111,9 +134,15 @@
m_instruction_classes.emplace_back(pt_insn_class::ptic_error);
}
-void DecodedThread::AppendError(llvm::Error &&error, uint64_t tsc) {
+void DecodedThread::SetAsFailed(llvm::Error &&error) {
AppendError(std::move(error));
- RecordTscForLastInstruction(tsc);
+}
+
+lldb::TraceEvents DecodedThread::GetEvents(int insn_index) {
+ auto it = m_events.find(insn_index);
+ if (it != m_events.end())
+ return it->second;
+ return (TraceEvents)0;
}
void DecodedThread::LibiptErrors::RecordError(int libipt_error_code) {
@@ -182,12 +211,16 @@
return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
}
+size_t DecodedThread::GetInstructionsWithEventsCount() const {
+ return m_events.size();
+}
+
size_t DecodedThread::CalculateApproximateMemoryUsage() const {
return sizeof(pt_insn::ip) * m_instruction_ips.size() +
sizeof(pt_insn::size) * m_instruction_sizes.size() +
sizeof(pt_insn::iclass) * m_instruction_classes.size() +
(sizeof(size_t) + sizeof(uint64_t)) * m_instruction_timestamps.size() +
- m_errors.getMemorySize();
+ m_errors.getMemorySize() + m_events.getMemorySize();
}
DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it,
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -1121,12 +1121,15 @@
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_hide_events : Option<"events", "e">,
+ Group<1>,
+ Desc<"Dump the events that happened during the execution of the target.">;
def thread_trace_dump_instructions_continue: Option<"continue", "C">,
Group<1>,
- Desc<"Continue dumping instructions right where the previous invocation of this "
- "command was left, or from the beginning if this is the first invocation. The --skip "
- "argument is discarded and the other arguments are preserved from the previous "
- "invocation when possible.">;
+ Desc<"Continue dumping instructions right where the previous invocation of "
+ "this command was left, or from the beginning if this is the first "
+ "invocation. The --skip argument is discarded and the other arguments are "
+ "preserved from the previous invocation when possible.">;
}
let Command = "thread trace dump info" in {
Index: lldb/source/Commands/CommandObjectThread.cpp
===================================================================
--- lldb/source/Commands/CommandObjectThread.cpp
+++ lldb/source/Commands/CommandObjectThread.cpp
@@ -2156,6 +2156,10 @@
m_dumper_options.show_tsc = true;
break;
}
+ case 'e': {
+ m_dumper_options.show_events = true;
+ break;
+ }
case 'C': {
m_continue = true;
break;
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -1147,6 +1147,14 @@
eTraceCounterTSC,
};
+// Events that might happen during a trace session.
+FLAGS_ENUM(TraceEvents){
+ // Tracing was paused. If instructions were executed after pausing
+ // and before resuming, the TraceCursor used to traverse the trace
+ // should provide an error signalinig this data loss.
+ eTraceEventPaused = (1u << 0),
+};
+
} // namespace lldb
#endif // LLDB_LLDB_ENUMERATIONS_H
Index: lldb/include/lldb/Target/TraceInstructionDumper.h
===================================================================
--- lldb/include/lldb/Target/TraceInstructionDumper.h
+++ lldb/include/lldb/Target/TraceInstructionDumper.h
@@ -26,6 +26,8 @@
/// For each instruction, print the corresponding timestamp counter if
/// available.
bool show_tsc = false;
+ /// Dump the events that happened between instructions.
+ bool show_events = false;
/// Optional custom id to start traversing from.
llvm::Optional<uint64_t> id = llvm::None;
/// Optional number of instructions to skip from the starting position
@@ -79,6 +81,8 @@
/// \b true if the cursor moved.
bool TryMoveOneStep();
+ void PrintEvents();
+
lldb::TraceCursorUP m_cursor_up;
TraceInstructionDumperOptions m_options;
Stream &m_s;
Index: lldb/include/lldb/Target/TraceCursor.h
===================================================================
--- lldb/include/lldb/Target/TraceCursor.h
+++ lldb/include/lldb/Target/TraceCursor.h
@@ -234,9 +234,17 @@
/// \param[in] counter_type
/// The counter type.
/// \return
- /// The value of the counter or \b llvm::None if not available.
+ /// The value of the counter or \b llvm::None if not available.
virtual llvm::Optional<uint64_t> GetCounter(lldb::TraceCounter counter_type) = 0;
+ /// Get a bitmask with a list of events that happened chronologically right
+ /// before the current instruction or error, but after the previous
+ /// instruction.
+ ///
+ /// \return
+ /// The bitmask of events.
+ virtual lldb::TraceEvents GetEvents() = 0;
+
/// \return
/// The \a lldb::TraceInstructionControlFlowType categories the
/// instruction the cursor is pointing at falls into. If the cursor points
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits