Skip to content

Commit 48d8af9

Browse files
[intel-pt] Disable/Enable tracing to guarantee the trace is correct
As mentioned in the comment inside the code, the Intel documentation states that the internal CPU buffer is flushed out to RAM only when tracing is disabled. Otherwise, the buffer on RAM might be stale. This diff disables tracing when the trace buffer is going to be read. This is a quite safe operation, as the reading is done when the inferior is paused at a breakpoint, so we are not losing any packets because there's no code being executed. After the reading is finished, tracing is enabled back. It's a bit hard to write a test for this now, but Greg Clayton and I will refactor the PT support and writing tests for it will be easier. However I tested it manually by doing a script that automates the following flow ``` (lldb) b main Breakpoint 1: where = a.out`main + 15 at main.cpp:4:7, address = 0x000000000040050f (lldb) r Process 3078226 stopped * thread #1, name = 'a.out', stop reason = breakpoint 1.1 frame #0: 0x000000000040050f a.out`main at main.cpp:4:7 (lldb) processor-trace start (lldb) b 5 Breakpoint 2: where = a.out`main + 22 at main.cpp:5:12, address = 0x0000000000400516 (lldb) c Process 3078226 resuming Process 3078226 stopped * thread #1, name = 'a.out', stop reason = breakpoint 2.1 frame #0: 0x0000000000400516 a.out`main at main.cpp:5:12 (lldb) processor-trace show-instr-log thread #1: tid=3078226 0x40050f <+15>: movl $0x0, -0x8(%rbp) >>> Before, some runs of the script up to this point lead to empty traces (lldb) b 6 Breakpoint 3: where = a.out`main + 42 at main.cpp:6:14, address = 0x000000000040052a (lldb) c Process 3092991 resuming Process 3092991 stopped * thread #1, name = 'a.out', stop reason = breakpoint 3.1 frame #0: 0x000000000040052a a.out`main at main.cpp:6:14 (lldb) processor-trace show-instr-log thread #1: tid=3092991 0x40050f <+15>: movl $0x0, -0x8(%rbp) 0x400516 <+22>: movl $0x0, -0xc(%rbp) 0x40051d <+29>: cmpl $0x2710, -0xc(%rbp) ; imm = 0x2710 0x400524 <+36>: jge 0x400546 ; <+70> at main.cpp 0x400524 <+36>: jge 0x400546 ; <+70> at main.cpp >>> The trace was re-enabled correctly and includes the instruction of the first reading. ``` Those instructions correspond to these lines ``` 3 int main() { 4 int z = 0; 5 for (int i = 0; i < 10000; i++) { 6 z += fun(z) ... ``` Differential Revision: https://reviews.llvm.org/D85241
1 parent ccca93b commit 48d8af9

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

lldb/source/Plugins/Process/Linux/ProcessorTrace.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "ProcessorTrace.h"
1818
#include "lldb/Host/linux/Support.h"
1919

20+
#include <sys/ioctl.h>
2021
#include <sys/syscall.h>
2122

2223
using namespace lldb;
@@ -273,6 +274,23 @@ ProcessorTraceMonitor::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
273274
#ifndef PERF_ATTR_SIZE_VER5
274275
llvm_unreachable("perf event not supported");
275276
#else
277+
// Disable the perf event to force a flush out of the CPU's internal buffer.
278+
// Besides, we can guarantee that the CPU won't override any data as we are
279+
// reading the buffer.
280+
//
281+
// The Intel documentation says:
282+
//
283+
// Packets are first buffered internally and then written out asynchronously.
284+
// To collect packet output for postprocessing, a collector needs first to
285+
// ensure that all packet data has been flushed from internal buffers.
286+
// Software can ensure this by stopping packet generation by clearing
287+
// IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in
288+
// Section 35.2.7.2).
289+
//
290+
// This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned
291+
// in the man page of perf_event_open.
292+
ioctl(*m_fd, PERF_EVENT_IOC_DISABLE);
293+
276294
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
277295
Status error;
278296
uint64_t head = m_mmap_meta->aux_head;
@@ -293,6 +311,9 @@ ProcessorTraceMonitor::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
293311

294312
ReadCyclicBuffer(buffer, GetAuxBuffer(), static_cast<size_t>(head), offset);
295313
LLDB_LOG(log, "ReadCyclic BUffer Done");
314+
315+
// Reenable tracing now we have read the buffer
316+
ioctl(*m_fd, PERF_EVENT_IOC_ENABLE);
296317
return error;
297318
#endif
298319
}

0 commit comments

Comments
 (0)