A trace might contain events traced during the target's execution. For example, a thread might be paused for some period of time due to context switches or breakpoints, which actually force a context switch. Not only that, a trace might be paused because the CPU decides to trace only a specific part of the target, like the address filtering provided by intel pt, which will cause pause events. Besides this case, other kinds of events might exist. This patch adds the method `TraceCursor::GetEvents()`` that returns the list of events that happened right before the instruction being pointed at by the cursor. Some refactors were done to make this change simpler. Besides this new API, the instruction dumper now supports the -e flag which shows pause events, like in the following example, where pauses happened due to breakpoints. ``` thread #1: tid = 2717361 a.out`main + 20 at main.cpp:27:20 0: 0x00000000004023d9 leaq -0x1200(%rbp), %rax [paused] 1: 0x00000000004023e0 movq %rax, %rdi [paused] 2: 0x00000000004023e3 callq 0x403a62 ; std::vector<int, std::allocator<int> >::vector at stl_vector.h:391:7 a.out`std::vector<int, std::allocator<int> >::vector() at stl_vector.h:391:7 3: 0x0000000000403a62 pushq %rbp 4: 0x0000000000403a63 movq %rsp, %rbp ``` The `dump info` command has also been updated and now it shows the number of instructions that have associated events. Differential Revision: https://reviews.llvm.org/D123982
130 lines
3.7 KiB
C++
130 lines
3.7 KiB
C++
//===-- TraceCursorIntelPT.cpp --------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TraceCursorIntelPT.h"
|
|
#include "DecodedThread.h"
|
|
#include "TraceIntelPT.h"
|
|
|
|
#include <cstdlib>
|
|
|
|
using namespace lldb;
|
|
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) {
|
|
assert(m_decoded_thread_sp->GetInstructionsCount() > 0 &&
|
|
"a trace should have at least one instruction or error");
|
|
m_pos = m_decoded_thread_sp->GetInstructionsCount() - 1;
|
|
m_tsc_range =
|
|
m_decoded_thread_sp->CalculateTscRange(m_pos, /*hint_range*/ None);
|
|
}
|
|
|
|
size_t TraceCursorIntelPT::GetInternalInstructionSize() {
|
|
return m_decoded_thread_sp->GetInstructionsCount();
|
|
}
|
|
|
|
bool TraceCursorIntelPT::Next() {
|
|
auto canMoveOne = [&]() {
|
|
if (IsForwards())
|
|
return m_pos + 1 < GetInternalInstructionSize();
|
|
return m_pos > 0;
|
|
};
|
|
|
|
size_t initial_pos = m_pos;
|
|
|
|
while (canMoveOne()) {
|
|
m_pos += IsForwards() ? 1 : -1;
|
|
|
|
if (m_tsc_range && !m_tsc_range->InRange(m_pos))
|
|
m_tsc_range = IsForwards() ? m_tsc_range->Next() : m_tsc_range->Prev();
|
|
|
|
if (!m_ignore_errors && IsError())
|
|
return true;
|
|
if (GetInstructionControlFlowType() & m_granularity)
|
|
return true;
|
|
}
|
|
|
|
// Didn't find any matching instructions
|
|
m_pos = initial_pos;
|
|
return false;
|
|
}
|
|
|
|
uint64_t TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
|
|
int64_t last_index = GetInternalInstructionSize() - 1;
|
|
|
|
auto fitPosToBounds = [&](int64_t raw_pos) -> int64_t {
|
|
return std::min(std::max((int64_t)0, raw_pos), last_index);
|
|
};
|
|
|
|
auto FindDistanceAndSetPos = [&]() -> int64_t {
|
|
switch (origin) {
|
|
case TraceCursor::SeekType::Beginning:
|
|
m_pos = fitPosToBounds(offset);
|
|
return m_pos;
|
|
case TraceCursor::SeekType::End:
|
|
m_pos = fitPosToBounds(offset + last_index);
|
|
return last_index - m_pos;
|
|
case TraceCursor::SeekType::Current:
|
|
int64_t new_pos = fitPosToBounds(offset + m_pos);
|
|
int64_t dist = m_pos - new_pos;
|
|
m_pos = new_pos;
|
|
return std::abs(dist);
|
|
}
|
|
};
|
|
|
|
int64_t dist = FindDistanceAndSetPos();
|
|
m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range);
|
|
return dist;
|
|
}
|
|
|
|
bool TraceCursorIntelPT::IsError() {
|
|
return m_decoded_thread_sp->IsInstructionAnError(m_pos);
|
|
}
|
|
|
|
const char *TraceCursorIntelPT::GetError() {
|
|
return m_decoded_thread_sp->GetErrorByInstructionIndex(m_pos);
|
|
}
|
|
|
|
lldb::addr_t TraceCursorIntelPT::GetLoadAddress() {
|
|
return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
|
|
}
|
|
|
|
Optional<uint64_t>
|
|
TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) {
|
|
switch (counter_type) {
|
|
case lldb::eTraceCounterTSC:
|
|
if (m_tsc_range)
|
|
return m_tsc_range->GetTsc();
|
|
else
|
|
return llvm::None;
|
|
}
|
|
}
|
|
|
|
lldb::TraceEvents TraceCursorIntelPT::GetEvents() {
|
|
return m_decoded_thread_sp->GetEvents(m_pos);
|
|
}
|
|
|
|
TraceInstructionControlFlowType
|
|
TraceCursorIntelPT::GetInstructionControlFlowType() {
|
|
return m_decoded_thread_sp->GetInstructionControlFlowType(m_pos);
|
|
}
|
|
|
|
bool TraceCursorIntelPT::GoToId(user_id_t id) {
|
|
if (m_decoded_thread_sp->GetInstructionsCount() <= id)
|
|
return false;
|
|
m_pos = id;
|
|
m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range);
|
|
|
|
return true;
|
|
}
|
|
|
|
user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }
|