ravitheja updated this revision to Diff 103355.
ravitheja added a comment.
Changes for last feedback.
https://reviews.llvm.org/D33674
Files:
include/lldb/Host/common/NativeProcessProtocol.h
include/lldb/Host/linux/Support.h
source/Host/linux/Support.cpp
source/Plugins/Process/Linux/CMakeLists.txt
source/Plugins/Process/Linux/NativeProcessLinux.cpp
source/Plugins/Process/Linux/NativeProcessLinux.h
source/Plugins/Process/Linux/ProcessorTrace.cpp
source/Plugins/Process/Linux/ProcessorTrace.h
source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
unittests/CMakeLists.txt
unittests/Process/CMakeLists.txt
unittests/Process/Linux/
unittests/Process/Linux/CMakeLists.txt
unittests/Process/Linux/ProcessorTraceTest.cpp
Index: unittests/Process/Linux/ProcessorTraceTest.cpp
===================================================================
--- /dev/null
+++ unittests/Process/Linux/ProcessorTraceTest.cpp
@@ -0,0 +1,149 @@
+//===-- ProcessorTraceMonitorTest.cpp -------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "ProcessorTrace.h"
+// C Includes
+
+// C++ Includes
+
+using namespace lldb_private;
+using namespace process_linux;
+
+size_t ReadCylicBufferWrapper(void *buf, size_t buf_size,
+ void *cyc_buf, size_t cyc_buf_size,
+ size_t cyc_start, size_t offset) {
+ llvm::MutableArrayRef<uint8_t> dst(reinterpret_cast<uint8_t *> (buf), buf_size);
+ llvm::MutableArrayRef<uint8_t> src(reinterpret_cast<uint8_t *> (cyc_buf), cyc_buf_size);
+ ProcessorTraceMonitor::ReadCyclicBuffer(dst, src, cyc_start, offset);
+ return dst.size();
+}
+
+TEST(CyclicBuffer, EdgeCases) {
+ size_t bytes_read = 0;
+ uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+ // We will always leave the last bytes untouched
+ // so that string comparisions work.
+ char bigger_buffer[10] = {};
+ char equal_size_buffer[7] = {};
+ char smaller_buffer[4] = {};
+
+ // empty buffer to read into
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, 0, cyclic_buffer, sizeof(cyclic_buffer), 3, 0);
+ ASSERT_EQ(0, bytes_read);
+
+ // empty cyclic buffer
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, sizeof(smaller_buffer), cyclic_buffer, 0, 3, 0);
+ ASSERT_EQ(0, bytes_read);
+
+ // bigger offset
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, sizeof(smaller_buffer), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 6);
+ ASSERT_EQ(0, bytes_read);
+
+ // wrong offset
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, sizeof(smaller_buffer), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 7);
+ ASSERT_EQ(0, bytes_read);
+
+ // wrong start
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, sizeof(smaller_buffer), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 7);
+ ASSERT_EQ(0, bytes_read);
+}
+
+TEST(CyclicBuffer, EqualSizeBuffer) {
+ size_t bytes_read = 0;
+ uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+ char cyclic[] = "cyclic";
+ for (int i = 0; i < sizeof(cyclic); i++) {
+ // We will always leave the last bytes untouched
+ // so that string comparisions work.
+ char equal_size_buffer[7] = {};
+ bytes_read = ReadCylicBufferWrapper(
+ equal_size_buffer, sizeof(cyclic_buffer), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, i);
+ ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
+ ASSERT_STREQ(equal_size_buffer, (cyclic + i));
+ }
+}
+
+TEST(CyclicBuffer, SmallerSizeBuffer) {
+ size_t bytes_read = 0;
+ uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+ // We will always leave the last bytes untouched
+ // so that string comparisions work.
+ char smaller_buffer[4] = {};
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 0);
+ ASSERT_EQ(3, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "cyc");
+
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 1);
+ ASSERT_EQ(3, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "ycl");
+
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 2);
+ ASSERT_EQ(3, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "cli");
+
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 3);
+ ASSERT_EQ(3, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "lic");
+ {
+ char smaller_buffer[4] = {};
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 4);
+ ASSERT_EQ(2, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "ic");
+ }
+ {
+ char smaller_buffer[4] = {};
+ bytes_read = ReadCylicBufferWrapper(
+ smaller_buffer, (sizeof(smaller_buffer) - 1), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, 5);
+ ASSERT_EQ(1, bytes_read);
+ ASSERT_STREQ(smaller_buffer, "c");
+ }
+}
+
+TEST(CyclicBuffer, BiggerSizeBuffer) {
+ size_t bytes_read = 0;
+ uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'};
+
+ char cyclic[] = "cyclic";
+ for (int i = 0; i < sizeof(cyclic); i++) {
+ // We will always leave the last bytes untouched
+ // so that string comparisions work.
+ char bigger_buffer[10] = {};
+ bytes_read = ReadCylicBufferWrapper(
+ bigger_buffer, (sizeof(bigger_buffer) - 1), cyclic_buffer,
+ sizeof(cyclic_buffer), 3, i);
+ ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read);
+ ASSERT_STREQ(bigger_buffer, (cyclic + i));
+ }
+}
Index: unittests/Process/Linux/CMakeLists.txt
===================================================================
--- /dev/null
+++ unittests/Process/Linux/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Process/Linux)
+
+add_lldb_unittest(ProcessorTraceTest
+ ProcessorTraceTest.cpp
+
+ LINK_LIBS
+ lldbPluginProcessLinux
+ )
\ No newline at end of file
Index: unittests/Process/CMakeLists.txt
===================================================================
--- unittests/Process/CMakeLists.txt
+++ unittests/Process/CMakeLists.txt
@@ -1,2 +1,3 @@
add_subdirectory(gdb-remote)
+add_subdirectory(Linux)
add_subdirectory(minidump)
Index: unittests/CMakeLists.txt
===================================================================
--- unittests/CMakeLists.txt
+++ unittests/CMakeLists.txt
@@ -73,4 +73,4 @@
if(LLDB_CAN_USE_DEBUGSERVER)
add_subdirectory(debugserver)
-endif()
\ No newline at end of file
+endif()
Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===================================================================
--- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -1280,9 +1280,9 @@
lldb::user_id_t uid = LLDB_INVALID_UID;
- size_t byte_count = std::numeric_limits<size_t>::max();
+ uint64_t byte_count = std::numeric_limits<uint64_t>::max();
lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
- size_t offset = std::numeric_limits<size_t>::max();
+ uint64_t offset = std::numeric_limits<uint64_t>::max();
auto json_object = StructuredData::ParseJSON(packet.Peek());
@@ -1316,8 +1316,8 @@
if (error.Fail())
return SendErrorResponse(error.GetError());
- for (size_t i = 0; i < buf.size(); ++i)
- response.PutHex8(buf[i]);
+ for (auto i : buf)
+ response.PutHex8(i);
StreamGDBRemote escaped_response;
escaped_response.PutEscapedBytes(response.GetData(), response.GetSize());
Index: source/Plugins/Process/Linux/ProcessorTrace.h
===================================================================
--- /dev/null
+++ source/Plugins/Process/Linux/ProcessorTrace.h
@@ -0,0 +1,143 @@
+//===-- ProcessorTrace.h -------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessorTrace_H_
+#define liblldb_ProcessorTrace_H_
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+
+#include "lldb/Core/TraceOptions.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-types.h"
+
+#include <linux/perf_event.h>
+
+namespace lldb_private {
+
+namespace process_linux {
+
+// ---------------------------------------------------------------------
+// This class keeps track of one tracing instance of
+// Intel(R) Processor Trace on Linux OS. There is a map keeping track
+// of different tracing instances on each thread, which enables trace
+// gathering on a per thread level.
+//
+// The tracing instance is linked with a trace id. The trace id acts like
+// a key to the tracing instance and trace manipulations could be
+// performed using the trace id.
+//
+// The traace id could map to trace instances for a group of threads
+// (spanning to all the threads in the process) or a single thread.
+// The kernel interface for us is the perf_event_open.
+// ---------------------------------------------------------------------
+
+class ProcessorTraceMonitor;
+typedef std::unique_ptr<ProcessorTraceMonitor> ProcessorTraceMonitorUP;
+
+class ProcessorTraceMonitor {
+ int m_fd;
+ perf_event_mmap_page *m_mmap_base;
+ lldb::user_id_t m_traceid;
+ lldb::tid_t m_thread_id;
+
+ llvm::MutableArrayRef<uint8_t> m_data;
+ llvm::MutableArrayRef<uint8_t> m_aux;
+
+ // Counter to track trace instances.
+ static lldb::user_id_t m_trace_num;
+
+ // Trace id of trace instance corresponding to the process.
+ static llvm::DenseMap<lldb::pid_t, lldb::user_id_t> m_pt_process_traceid;
+
+ // TraceOptions to be used for the complete process
+ // in case whole process is being traced.This config
+ // will also be applied to newly spawned threads.
+ static llvm::DenseMap<lldb::pid_t, TraceOptions> m_pt_process_config;
+
+ uint64_t GetAuxBufferSize() const;
+
+ uint64_t GetDataBufferSize() const;
+
+ void SetTraceID(lldb::user_id_t traceid) { m_traceid = traceid; }
+
+ static Status GetCPUType(StructuredData::DictionarySP params_dict);
+
+ Status StartTrace(lldb::pid_t pid, lldb::tid_t tid,
+ const TraceOptions &config);
+
+ ProcessorTraceMonitor()
+ : m_fd(-1),
+ m_mmap_base(nullptr), m_traceid(LLDB_INVALID_UID),
+ m_thread_id(LLDB_INVALID_THREAD_ID){};
+
+public:
+ static llvm::Expected<ProcessorTraceMonitorUP>
+ Create(lldb::pid_t pid, lldb::tid_t tid, const TraceOptions &config,
+ bool useProcessSettings);
+
+ Status ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0);
+
+ Status ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0);
+
+ Status Destroy();
+
+ ~ProcessorTraceMonitor() { (void)Destroy(); }
+
+ void SetThreadID(lldb::tid_t tid) { m_thread_id = tid; }
+
+ lldb::tid_t GetThreadID() const { return m_thread_id; }
+
+ lldb::user_id_t GetTraceID() const { return m_traceid; }
+
+ Status GetTraceConfig(TraceOptions &config) const;
+
+ static llvm::Expected<TraceOptions> GetProcessTraceConfig(lldb::pid_t pid) {
+ if (m_pt_process_config.count(pid) == 0)
+ return Status("tracing not active for this process").ToError();
+ return m_pt_process_config[pid];
+ }
+
+ static lldb::user_id_t GetProcessTraceID(lldb::pid_t pid) {
+ if (m_pt_process_traceid.count(pid) == 0)
+ return LLDB_INVALID_UID;
+ return m_pt_process_traceid[pid];
+ }
+
+ static Status SetProcessTraceConfig(lldb::pid_t pid, const TraceOptions &config);
+
+ static void SetProcessTraceID(lldb::pid_t pid, lldb::user_id_t traceid) {
+ m_pt_process_traceid[pid] = traceid;
+ }
+
+ // ---------------------------------------------------------------------
+ /// Read data from a cyclic buffer
+ ///
+ /// @param[in] [out] buf
+ /// Destination buffer, the buffer will be truncated to written size.
+ ///
+ /// @param[in] src
+ /// Source buffer which must be a cyclic buffer.
+ ///
+ /// @param[in] src_cyc_index
+ /// The index pointer (start of the valid data in the cyclic
+ /// buffer).
+ ///
+ /// @param[in] offset
+ /// The offset to begin reading the data in the cyclic buffer.
+ // ---------------------------------------------------------------------
+ static void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
+ llvm::MutableArrayRef<uint8_t> src,
+ size_t src_cyc_index, size_t offset);
+};
+} // namespace process_linux
+} // namespace lldb_private
+#endif
\ No newline at end of file
Index: source/Plugins/Process/Linux/ProcessorTrace.cpp
===================================================================
--- /dev/null
+++ source/Plugins/Process/Linux/ProcessorTrace.cpp
@@ -0,0 +1,508 @@
+//===-- ProcessorTrace.cpp ------------------------------------ -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+#include <fstream>
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "ProcessorTrace.h"
+#include "lldb/Host/linux/Support.h"
+
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace process_linux;
+using namespace llvm;
+
+lldb::user_id_t ProcessorTraceMonitor::m_trace_num = 0;
+llvm::DenseMap<lldb::pid_t, lldb::user_id_t> ProcessorTraceMonitor::m_pt_process_traceid;
+llvm::DenseMap<lldb::pid_t, TraceOptions> ProcessorTraceMonitor::m_pt_process_config;
+
+uint64_t ProcessorTraceMonitor::GetAuxBufferSize() const {
+ return m_aux.size();
+}
+
+uint64_t ProcessorTraceMonitor::GetDataBufferSize() const {
+ return m_data.size();
+}
+
+Status ProcessorTraceMonitor::GetTraceConfig(TraceOptions &config) const {
+ Status error;
+
+ config.setType(lldb::TraceType::eTraceTypeProcessorTrace);
+ uint64_t data_size = GetDataBufferSize();
+ config.setMetaDataBufferSize(data_size);
+
+ uint64_t aux_size = GetAuxBufferSize();
+ config.setTraceBufferSize(aux_size);
+
+ auto custom_params_sp = std::make_shared<StructuredData::Dictionary>();
+ error = GetCPUType(custom_params_sp);
+ if (error.Fail())
+ return error;
+
+ llvm::StringRef intel_custom_params_key("intel-pt");
+
+ auto intel_custom_params = std::make_shared<StructuredData::Dictionary>();
+ intel_custom_params->AddItem(
+ intel_custom_params_key,
+ StructuredData::ObjectSP(std::move(custom_params_sp)));
+
+ config.setTraceParams(intel_custom_params);
+
+ return error;
+}
+
+Status
+ProcessorTraceMonitor::SetProcessTraceConfig(lldb::pid_t pid, const TraceOptions &config) {
+ m_pt_process_config[pid] = config;
+
+ auto custom_params_sp = std::make_shared<StructuredData::Dictionary>();
+ Status error = ProcessorTraceMonitor::GetCPUType(custom_params_sp);
+ if (error.Fail())
+ return error;
+
+ llvm::StringRef intel_custom_params_key("intel-pt");
+ auto intel_custom_params = std::make_shared<StructuredData::Dictionary>();
+ intel_custom_params->AddItem(
+ intel_custom_params_key,
+ StructuredData::ObjectSP(std::move(custom_params_sp)));
+
+ m_pt_process_config[pid].setTraceParams(intel_custom_params);
+
+ return error;
+}
+
+Status ProcessorTraceMonitor::StartTrace(lldb::pid_t pid, lldb::tid_t tid,
+ const TraceOptions &config) {
+ Status error;
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ LLDB_LOG(log, "{0}", config.getThreadID());
+
+#ifndef PERF_ATTR_SIZE_VER5
+ llvm_unreachable("perf event not supported");
+#else
+
+ LLDB_LOG(log, "called thread id {0}", tid);
+ uint64_t page_size = getpagesize();
+ uint64_t bufsize = config.getTraceBufferSize();
+ uint64_t metabufsize = config.getMetaDataBufferSize();
+
+ uint64_t numpages = static_cast<uint64_t>(
+ llvm::PowerOf2Floor((bufsize + page_size - 1) / page_size));
+ numpages = std::max(1ul, numpages);
+ bufsize = page_size * numpages;
+
+ numpages = static_cast<uint64_t>(
+ llvm::PowerOf2Floor((metabufsize + page_size - 1) / page_size));
+ numpages = std::max(0ul, numpages);
+ metabufsize = page_size * numpages;
+
+ perf_event_attr attr;
+ memset(&attr, 0, sizeof(attr));
+ attr.size = sizeof(attr);
+ attr.exclude_kernel = 1;
+ attr.sample_type = PERF_SAMPLE_TIME;
+ attr.sample_id_all = 1;
+ attr.exclude_hv = 1;
+ attr.exclude_idle = 1;
+ attr.mmap = 1;
+
+ int intel_pt_type = 0;
+
+ auto ret = llvm::MemoryBuffer::getFileAsStream(
+ "/sys/bus/event_source/devices/intel_pt/type");
+ if (!ret) {
+ LLDB_LOG(log, "failed to open Config file");
+ error.SetErrorString("file not found");
+ return error;
+ }
+
+ StringRef rest = ret.get()->getBuffer();
+ if (rest.empty() || rest.trim().getAsInteger(10, intel_pt_type)) {
+ LLDB_LOG(log, "failed to read Config file");
+ error.SetErrorString("invalid file");
+ return error;
+ }
+
+ rest.trim().getAsInteger(10, intel_pt_type);
+ LLDB_LOG(log, "intel pt type {0}", intel_pt_type);
+ attr.type = intel_pt_type;
+
+ LLDB_LOG(log, "meta buffer size {0}", metabufsize);
+ LLDB_LOG(log, "buffer size {0} ", bufsize);
+
+ if (error.Fail()) {
+ LLDB_LOG(log, "Status in custom config {0}", error.AsCString());
+
+ return error;
+ }
+
+ errno = 0;
+ m_fd =
+ syscall(SYS_perf_event_open, &attr, static_cast<::tid_t>(tid), -1, -1, 0);
+ if (m_fd == -1) {
+ LLDB_LOG(log, "syscall error {0}", errno);
+ error.SetErrorString("perf event syscall Failed");
+ return error;
+ }
+
+ errno = 0;
+ auto base =
+ mmap(NULL, (metabufsize + page_size), PROT_WRITE, MAP_SHARED, m_fd, 0);
+ if (base == MAP_FAILED) {
+ base = nullptr;
+ LLDB_LOG(log, "mmap base error {0}", errno);
+ error.SetErrorString("Meta buffer allocation failed");
+ (void)Destroy();
+ return error;
+ }
+ m_mmap_base = reinterpret_cast<perf_event_mmap_page *> (base);
+ m_data = llvm::MutableArrayRef<uint8_t> ((reinterpret_cast<uint8_t *>(m_mmap_base) + m_mmap_base->data_offset), m_mmap_base->data_size);
+
+ m_mmap_base->aux_offset = m_mmap_base->data_offset + m_mmap_base->data_size;
+ m_mmap_base->aux_size = bufsize;
+
+ errno = 0;
+ void *mmap_aux = mmap(NULL, bufsize, PROT_READ, MAP_SHARED, m_fd,
+ static_cast<long int>(m_mmap_base->aux_offset));
+ if (mmap_aux == MAP_FAILED) {
+ LLDB_LOG(log, "second mmap done {0}", errno);
+ error.SetErrorString("Trace buffer allocation failed");
+ (void)Destroy();
+ return error;
+ }
+ m_aux = llvm::MutableArrayRef<uint8_t> (reinterpret_cast<uint8_t*> (mmap_aux),bufsize);
+#endif
+ return error;
+}
+
+Status
+ProcessorTraceMonitor::GetCPUType(StructuredData::DictionarySP params_dict) {
+
+ Status error;
+ uint64_t cpu_family = -1;
+ uint64_t model = -1;
+ uint64_t stepping = -1;
+ std::string vendor_id;
+
+ if (!params_dict) {
+ error.SetErrorString("null pointer");
+ return error;
+ }
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ auto BufferOrError = getProcFile("cpuinfo");
+ if (!BufferOrError)
+ return BufferOrError.getError();
+
+ LLDB_LOG(log, "GetCPUType Function");
+
+ StringRef Rest = BufferOrError.get()->getBuffer();
+ while (!Rest.empty()) {
+ StringRef Line;
+ std::tie(Line, Rest) = Rest.split('\n');
+
+ SmallVector<StringRef, 2> columns;
+ Line.split(columns, StringRef(":"), -1, false);
+
+ if (columns.size() < 2)
+ continue; // continue searching
+
+ columns[1] = columns[1].trim(" ");
+ if (columns[0].contains("cpu family") &&
+ columns[1].getAsInteger(10, cpu_family))
+ continue;
+
+ else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
+ continue;
+
+ else if (columns[0].contains("stepping") &&
+ columns[1].getAsInteger(10, stepping))
+ continue;
+
+ else if (columns[0].contains("vendor_id")) {
+ vendor_id = columns[1].str();
+ if (!vendor_id.empty())
+ continue;
+ }
+ LLDB_LOG(log, "{0}:{1}:{2}:{3}", cpu_family, model, stepping,
+ vendor_id.c_str());
+
+ if ((cpu_family != static_cast<uint64_t>(-1)) &&
+ (model != static_cast<uint64_t>(-1)) &&
+ (stepping != static_cast<uint64_t>(-1)) && (!vendor_id.empty())) {
+ params_dict->AddIntegerItem("cpu_family", cpu_family);
+ params_dict->AddIntegerItem("cpu_model", model);
+ params_dict->AddIntegerItem("cpu_stepping", stepping);
+ params_dict->AddStringItem("cpu_vendor", vendor_id);
+ return error; // we are done
+ }
+ }
+
+ error.SetErrorString("cpu info not found");
+ return error;
+}
+
+llvm::Expected<ProcessorTraceMonitorUP>
+ProcessorTraceMonitor::Create(lldb::pid_t pid, lldb::tid_t tid,
+ const TraceOptions &config,
+ bool useProcessSettings) {
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ Status error;
+ if (tid == LLDB_INVALID_THREAD_ID) {
+ error.SetErrorString("thread not specified");
+ return std::move(error.ToError());
+ }
+
+ if (useProcessSettings) {
+ if (GetProcessTraceID(pid) == LLDB_INVALID_UID)
+ SetProcessTraceID(pid, ++m_trace_num);
+ LLDB_LOG(log, "m_trace_num {0}", m_trace_num);
+ LLDB_LOG(log, "m_pt_process_traceid {0}",
+ m_pt_process_traceid[pid]);
+ }
+
+ ProcessorTraceMonitorUP pt_monitor_up(new ProcessorTraceMonitor);
+
+ error = pt_monitor_up->StartTrace(pid, tid, config);
+ if (error.Fail())
+ return std::move(error.ToError());
+
+ pt_monitor_up->SetThreadID(tid);
+
+ if (useProcessSettings) {
+ pt_monitor_up->SetTraceID(m_pt_process_traceid[pid]);
+
+ // The buffer sizes also need to be updated
+ // as the buffer sizes might have been rounded
+ // to page sizes.
+ uint64_t data_size = pt_monitor_up->GetDataBufferSize();
+ uint64_t aux_size = pt_monitor_up->GetAuxBufferSize();
+
+ m_pt_process_config[pid].setTraceBufferSize(aux_size);
+ m_pt_process_config[pid].setMetaDataBufferSize(data_size);
+ } else {
+ pt_monitor_up->SetTraceID(++m_trace_num);
+ LLDB_LOG(log, "Trace ID {0}", m_trace_num);
+ }
+ return std::move(pt_monitor_up);
+}
+
+Status ProcessorTraceMonitor::Destroy() {
+ Status error;
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ int ret;
+#ifndef PERF_ATTR_SIZE_VER5
+ llvm_unreachable("perf event not supported");
+#else
+ if (!m_aux.empty() && (m_mmap_base != nullptr)) {
+ ret = munmap(m_aux.data(), m_aux.size());
+ if (ret != 0) {
+ LLDB_LOG(log, "munmap aux error {0}", errno);
+ error.SetErrorString("Trace buffer deallocation failed");
+ } else
+ m_aux.drop_back(m_aux.size());
+ }
+ // Since we allocate one page extra during
+ // initialization for the perf_event_mmap_page header
+ if (m_mmap_base != nullptr) {
+ int page_size = getpagesize();
+ uint64_t data_size = m_data.size() + page_size;
+ ret = munmap(m_mmap_base, data_size);
+ if (ret != 0) {
+ LLDB_LOG(log, "munmap data error {0}", errno);
+ error.SetErrorString("Meta buffer deallocation failed");
+ } else {
+ m_mmap_base = nullptr;
+ m_data.drop_back(m_data.size());
+ }
+ }
+ if (m_fd != -1) {
+ ret = close(m_fd);
+ if (ret != 0) {
+ LLDB_LOG(log, "closing file descriptor error {0}", errno);
+ error.SetErrorString("perf event close failed");
+ } else
+ m_fd = -1;
+ }
+#endif
+ return error;
+}
+
+Status
+ProcessorTraceMonitor::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ Status error;
+
+#ifndef PERF_ATTR_SIZE_VER5
+ llvm_unreachable("perf event not supported");
+#else
+ if (buffer.empty()) {
+ LLDB_LOG(log, "Empty buffer ");
+ error.SetErrorString("empty Trace buffer");
+ return error;
+ }
+
+ uint64_t head = m_mmap_base->aux_head;
+
+ LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_aux.size(), head);
+
+ /**
+ * When configured as ring buffer, the aux buffer keeps wrapping around
+ * the buffer and its not possible to detect how many times the buffer
+ * wrapped. Initially the buffer is filled with zeros,as shown below
+ * so in order to get complete buffer we first copy firstpartsize, followed
+ * by any left over part from beginning to aux_head
+ *
+ * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size
+ * aux_head->||<- firstpartsize ->|
+ *
+ * */
+
+ ReadCyclicBuffer(
+ buffer,
+ m_aux,
+ static_cast<size_t>(head), offset);
+ LLDB_LOG(log, "ReadCyclic BUffer Done");
+ return error;
+#endif
+}
+
+Status
+ProcessorTraceMonitor::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ uint64_t bytes_remaining = buffer.size();
+ Status error;
+#ifndef PERF_ATTR_SIZE_VER5
+ llvm_unreachable("perf event not supported");
+#else
+ if (buffer.empty()) {
+ LLDB_LOG(log, "Empty buffer ");
+ error.SetErrorString("empty Meta buffer");
+ return error;
+ }
+
+ uint64_t head = m_mmap_base->data_head;
+
+ /*
+ * The data buffer and aux buffer have different implementations
+ * with respect to their definition of head pointer. In the case
+ * of Aux data buffer the head always wraps around the aux buffer
+ * and we don't need to care about it, whereas the data_head keeps
+ * increasing and needs to be wrapped by modulus operator
+ */
+
+ LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining);
+
+ if (head > m_data.size()) {
+ head = head % m_data.size();
+ LLDB_LOG(log, "Data size -{0} Head - {1}", m_data.size(), head);
+
+ ReadCyclicBuffer(
+ buffer,
+ m_data,
+ static_cast<size_t>(head), offset);
+ bytes_remaining -= buffer.size();
+ } else {
+ LLDB_LOG(log, "Head - {0}", head);
+ if (offset >= head) {
+ LLDB_LOG(log, "Invalid Offset ");
+ error.SetErrorString("invalid offset");
+ buffer = buffer.slice(buffer.size());
+ return error;
+ }
+
+ auto data = m_data.slice(offset, (head-offset));
+ auto remaining = std::copy(data.begin(), data.end(), buffer.begin());
+ bytes_remaining -= (remaining - buffer.begin());
+ }
+ buffer = llvm::MutableArrayRef<uint8_t>(buffer.data(),
+ (buffer.size() - bytes_remaining));
+ return error;
+#endif
+}
+
+void ProcessorTraceMonitor::ReadCyclicBuffer(
+ llvm::MutableArrayRef<uint8_t> &dst, llvm::MutableArrayRef<uint8_t> src,
+ size_t src_cyc_index, size_t offset) {
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ if (dst.empty() || src.empty()) {
+ dst = dst.drop_back(dst.size());
+ return;
+ }
+
+ if (dst.data() == nullptr || src.data() == nullptr) {
+ dst = dst.drop_back(dst.size());
+ return;
+ }
+
+ if (src_cyc_index > src.size()) {
+ dst = dst.drop_back(dst.size());
+ return;
+ }
+
+ if (offset >= src.size()) {
+ LLDB_LOG(log, "Too Big offset ");
+ dst = dst.drop_back(dst.size());
+ return;
+ }
+
+ auto firstpart = src.slice(src_cyc_index);
+ auto secondpart = src.drop_back(src_cyc_index);
+ size_t size_to_read = src.size() - offset;
+
+ if (dst.size() >= size_to_read) {
+ if (offset >= firstpart.size()) {
+ secondpart = secondpart.slice(offset - firstpart.size());
+ std::copy(secondpart.begin(), secondpart.end(), dst.begin());
+ dst = dst.drop_back(dst.size() - secondpart.size());
+ } else {
+ firstpart = firstpart.slice(offset);
+ auto read_end =
+ std::copy(firstpart.begin(), firstpart.end(), dst.begin());
+ size_to_read -= firstpart.size();
+ secondpart = secondpart.drop_back(secondpart.size() - size_to_read);
+ std::copy(secondpart.begin(), secondpart.end(), read_end);
+ dst = dst.drop_back(dst.size() - firstpart.size() - secondpart.size());
+ }
+ } else {
+ if (offset >= firstpart.size()) {
+ secondpart = secondpart.slice(offset - firstpart.size());
+ std::copy(secondpart.begin(), secondpart.begin() + dst.size(),
+ dst.begin());
+ } else {
+ firstpart = firstpart.slice(offset);
+ if (dst.size() <= firstpart.size()) {
+ std::copy(firstpart.begin(), firstpart.begin() + dst.size(),
+ dst.begin());
+ } else {
+ auto read_end =
+ std::copy(firstpart.begin(), firstpart.end(), dst.begin());
+ secondpart = secondpart.drop_back(secondpart.size() - dst.size() +
+ firstpart.size());
+ std::copy(secondpart.begin(), secondpart.end(), read_end);
+ }
+ }
+ }
+}
Index: source/Plugins/Process/Linux/NativeProcessLinux.h
===================================================================
--- source/Plugins/Process/Linux/NativeProcessLinux.h
+++ source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -13,6 +13,7 @@
// C++ Includes
#include <unordered_set>
+#include "llvm/Support/ErrorOr.h"
// Other libraries and framework includes
#include "lldb/Core/ArchSpec.h"
#include "lldb/Host/Debug.h"
@@ -23,6 +24,7 @@
#include "lldb/lldb-types.h"
#include "NativeThreadLinux.h"
+#include "ProcessorTrace.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
namespace lldb_private {
@@ -105,6 +107,22 @@
return getProcFile(GetID(), "auxv");
}
+ lldb::user_id_t StartTrace(const TraceOptions &config,
+ Status &error) override;
+
+ Status StopTrace(lldb::user_id_t traceid,
+ lldb::tid_t thread = LLDB_INVALID_THREAD_ID) override;
+
+ Status GetData(lldb::user_id_t traceid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) override;
+
+ Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset = 0) override;
+
+ Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) override;
+
// ---------------------------------------------------------------------
// Interface used by NativeRegisterContext-derived classes.
// ---------------------------------------------------------------------
@@ -228,6 +246,40 @@
void SigchldHandler();
Status PopulateMemoryRegionCache();
+
+ lldb::user_id_t StartTracingAllThreads(const TraceOptions &config,
+ Status &error);
+
+ // This function is intended to be used to stop tracing
+ // on a thread that exited.
+ Status StopTracingForThread(lldb::tid_t thread);
+
+ // The below function as the name suggests, looks up a ProcessorTrace
+ // instance from the m_processor_trace_monitor map. In the case of
+ // process tracing where the traceid passed would map to the complete
+ // process, it is mandatory to provide a threadid to obtain a trace
+ // instance (since ProcessorTrace is tied to a thread). In the other
+ // scenario that an individual thread is being traced, just the traceid
+ // is sufficient to obtain the actual ProcessorTrace instance.
+ llvm::Expected<ProcessorTraceMonitor &> LookupProcessorTraceInstance(lldb::user_id_t traceid,
+ lldb::tid_t thread);
+
+ // Stops tracing on individual threads being traced. Not intended
+ // to be used to stop tracing on complete process.
+ Status StopProcessorTracingOnThread(lldb::user_id_t traceid,
+ lldb::tid_t thread);
+
+ // Intended to stop tracing on complete process.
+ // Should not be used for stopping trace on
+ // individual threads.
+ void StopProcessorTracingOnProcess();
+
+ llvm::DenseMap<lldb::tid_t, ProcessorTraceMonitorUP>
+ m_processor_trace_monitor;
+
+ // Set for tracking threads being traced under
+ // same process user id.
+ llvm::DenseSet<lldb::tid_t> m_pt_traced_thread_group;
};
} // namespace process_linux
Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -607,6 +607,7 @@
info.si_pid);
auto thread_sp = AddThread(pid);
+
// Resume the newly created thread.
ResumeThread(*thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
ThreadWasCreated(*thread_sp);
@@ -719,6 +720,7 @@
LLDB_LOG(log, "pid = {0}: tracking new thread tid {1}", GetID(), tid);
new_thread_sp = AddThread(tid);
+
ResumeThread(*new_thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER);
ThreadWasCreated(*new_thread_sp);
}
@@ -1331,6 +1333,9 @@
e; // Save the error, but still attempt to detach from other threads.
}
+ m_processor_trace_monitor.clear();
+ ProcessorTraceMonitor::SetProcessTraceID(GetID(), LLDB_INVALID_UID);
+
return error;
}
@@ -2119,6 +2124,8 @@
}
}
+ if (found)
+ StopTracingForThread(thread_id);
SignalIfAllThreadsStopped();
return found;
}
@@ -2136,6 +2143,25 @@
auto thread_sp = std::make_shared<NativeThreadLinux>(this, thread_id);
m_threads.push_back(thread_sp);
+
+ if (ProcessorTraceMonitor::GetProcessTraceID(GetID()) != LLDB_INVALID_UID) {
+ auto process_config = ProcessorTraceMonitor::GetProcessTraceConfig(GetID());
+ if (!process_config) {
+ LLDB_LOG(log, "process_config not found");
+ return thread_sp;
+ }
+ auto traceMonitor = ProcessorTraceMonitor::Create(
+ GetID(), thread_id, *process_config, true);
+ if (traceMonitor) {
+ m_pt_traced_thread_group.insert(thread_id);
+ m_processor_trace_monitor.insert(std::make_pair(thread_id, std::move(*traceMonitor)));
+ } else {
+ LLDB_LOG(log, "failed to start trace on thread {0}", thread_id);
+ Status error(traceMonitor.takeError());
+ LLDB_LOG(log, "error {0}", error);
+ }
+ }
+
return thread_sp;
}
@@ -2451,3 +2477,261 @@
return error;
}
+
+llvm::Expected<ProcessorTraceMonitor &>
+NativeProcessLinux::LookupProcessorTraceInstance(
+ lldb::user_id_t traceid, lldb::tid_t thread) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ if (thread == LLDB_INVALID_THREAD_ID &&
+ traceid == ProcessorTraceMonitor::GetProcessTraceID(GetID())) {
+ LLDB_LOG(log, "thread not specified: {0}",
+ traceid);
+ return Status("tracing not active thread not specified").ToError();
+ }
+
+ for (auto& iter : m_processor_trace_monitor) {
+ if (traceid == iter.second->GetTraceID() &&
+ (thread == iter.first || thread == LLDB_INVALID_THREAD_ID))
+ return *(iter.second);
+ }
+
+ LLDB_LOG(log, "traceid not being traced: {0}",
+ traceid);
+ return Status("tracing not active for this thread").ToError();
+}
+
+Status NativeProcessLinux::GetMetaData(lldb::user_id_t traceid,
+ lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+ TraceOptions trace_options;
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ Status error;
+
+ LLDB_LOG(log, "traceid {0}", traceid);
+
+ auto perf_monitor = LookupProcessorTraceInstance(traceid, thread);
+ if (!perf_monitor) {
+ LLDB_LOG(log, "traceid not being traced: {0}",
+ traceid);
+ buffer = buffer.slice(buffer.size());
+ error = perf_monitor.takeError();
+ return error;
+ }
+ return (*perf_monitor).ReadPerfTraceData(buffer, offset);
+}
+
+Status NativeProcessLinux::GetData(lldb::user_id_t traceid, lldb::tid_t thread,
+ llvm::MutableArrayRef<uint8_t> &buffer,
+ size_t offset) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ Status error;
+
+ LLDB_LOG(log, "traceid {0}", traceid);
+
+ auto perf_monitor = LookupProcessorTraceInstance(traceid, thread);
+ if (!perf_monitor) {
+ LLDB_LOG(log, "traceid not being traced: {0}",
+ traceid);
+ buffer = buffer.slice(buffer.size());
+ error = perf_monitor.takeError();
+ return error;
+ }
+ return (*perf_monitor).ReadPerfTraceAux(buffer, offset);
+}
+
+Status NativeProcessLinux::GetTraceConfig(lldb::user_id_t traceid,
+ TraceOptions &config) {
+ Status error;
+
+ if (config.getThreadID() == LLDB_INVALID_THREAD_ID &&
+ traceid == ProcessorTraceMonitor::GetProcessTraceID(GetID())) {
+ auto process_config = ProcessorTraceMonitor::GetProcessTraceConfig(GetID());
+ if (!process_config) {
+ error = process_config.takeError();
+ return error;
+ }
+ config = *process_config;
+ } else {
+ auto perf_monitor =
+ LookupProcessorTraceInstance(traceid, config.getThreadID());
+ if (!perf_monitor) {
+ error = perf_monitor.takeError();
+ return error;
+ }
+ error = (*perf_monitor).GetTraceConfig(config);
+ }
+ return error;
+}
+
+lldb::user_id_t
+NativeProcessLinux::StartTracingAllThreads(const TraceOptions &config,
+ Status &error) {
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ if (config.getType() != TraceType::eTraceTypeProcessorTrace)
+ return LLDB_INVALID_UID;
+
+ if (ProcessorTraceMonitor::GetProcessTraceID(GetID()) != LLDB_INVALID_UID) {
+ error.SetErrorString("tracing already active on this process");
+ return ProcessorTraceMonitor::GetProcessTraceID(GetID());
+ }
+
+ ProcessorTraceMonitor::SetProcessTraceConfig(GetID(), config);
+
+ for (const auto &thread_sp : m_threads) {
+ if (auto traceInstance = ProcessorTraceMonitor::Create(
+ GetID(), thread_sp->GetID(), config, true)) {
+ m_pt_traced_thread_group.insert(thread_sp->GetID());
+ m_processor_trace_monitor.insert(std::make_pair(thread_sp->GetID(), std::move(*traceInstance)));
+ }
+ }
+
+ LLDB_LOG(log,"Process Trace ID {0}",
+ ProcessorTraceMonitor::GetProcessTraceID(GetID()));
+ return ProcessorTraceMonitor::GetProcessTraceID(GetID());
+}
+
+lldb::user_id_t NativeProcessLinux::StartTrace(const TraceOptions &config,
+ Status &error) {
+ if (config.getType() != TraceType::eTraceTypeProcessorTrace)
+ return NativeProcessProtocol::StartTrace(config, error);
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ lldb::tid_t threadid = config.getThreadID();
+
+ if (threadid == LLDB_INVALID_THREAD_ID)
+ return StartTracingAllThreads(config, error);
+
+ auto thread_sp = GetThreadByID(threadid);
+ if (!thread_sp) {
+ // Thread not tracked by lldb so don't trace.
+ error.SetErrorString("invalid thread id");
+ return LLDB_INVALID_UID;
+ }
+
+ const auto &iter = m_processor_trace_monitor.find(threadid);
+ if (iter != m_processor_trace_monitor.end()) {
+ LLDB_LOG(log, "Thread already being traced");
+ error.SetErrorString("tracing already active on this thread");
+ return LLDB_INVALID_UID;
+ }
+
+ auto traceMonitor =
+ ProcessorTraceMonitor::Create(GetID(), threadid, config, false);
+ if (!traceMonitor) {
+ error = traceMonitor.takeError();
+ LLDB_LOG(log, "error {0}", error);
+ return LLDB_INVALID_UID;
+ }
+ lldb::user_id_t ret_trace_id = (*traceMonitor)->GetTraceID();
+ m_processor_trace_monitor.insert(std::make_pair(threadid, std::move(*traceMonitor)));
+ return ret_trace_id;
+}
+
+Status NativeProcessLinux::StopTracingForThread(lldb::tid_t thread) {
+ Status error;
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ LLDB_LOG(log, "Thread {0}", thread);
+
+ const auto& iter = m_processor_trace_monitor.find(thread);
+ if (iter == m_processor_trace_monitor.end())
+ {
+ error.SetErrorString("tracing not active for this thread");
+ return error;
+ }
+
+ if (iter->second->GetTraceID() == ProcessorTraceMonitor::GetProcessTraceID(GetID())) {
+ // traceid maps to the whole process so we have to erase it from the
+ // thread group.
+ LLDB_LOG(log, "traceid maps to process");
+ m_pt_traced_thread_group.erase(thread);
+ }
+ m_processor_trace_monitor.erase(iter);
+
+ return error;
+}
+
+Status NativeProcessLinux::StopTrace(lldb::user_id_t traceid,
+ lldb::tid_t thread) {
+ Status error;
+
+ TraceOptions trace_options;
+ trace_options.setThreadID(thread);
+ error = NativeProcessLinux::GetTraceConfig(traceid, trace_options);
+
+ if (error.Fail())
+ return error;
+
+ switch (trace_options.getType()) {
+ case lldb::TraceType::eTraceTypeProcessorTrace:
+ if (traceid == ProcessorTraceMonitor::GetProcessTraceID(GetID()) &&
+ thread == LLDB_INVALID_THREAD_ID)
+ StopProcessorTracingOnProcess();
+ else
+ error = StopProcessorTracingOnThread(traceid, thread);
+ break;
+ default:
+ error.SetErrorString("trace not supported");
+ break;
+ }
+
+ return error;
+}
+
+void NativeProcessLinux::StopProcessorTracingOnProcess() {
+ for (auto thread_id_iter : m_pt_traced_thread_group)
+ m_processor_trace_monitor.erase(thread_id_iter);
+ m_pt_traced_thread_group.clear();
+ ProcessorTraceMonitor::SetProcessTraceID(GetID(), LLDB_INVALID_UID);
+}
+
+Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid,
+ lldb::tid_t thread) {
+ Status error;
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ if (thread == LLDB_INVALID_THREAD_ID) {
+ for (auto& iter : m_processor_trace_monitor) {
+ if (iter.second->GetTraceID() == traceid) {
+ // Stopping a trace instance for an individual thread
+ // hence there will only be one traceid that can match.
+ m_processor_trace_monitor.erase(iter.first);
+ return error;
+ }
+ LLDB_LOG(log, "Trace ID {0}", iter.second->GetTraceID());
+ }
+
+ LLDB_LOG(log, "Invalid TraceID");
+ error.SetErrorString("invalid trace id");
+ return error;
+ }
+
+ // thread is specified so we can use find function on the map.
+ const auto& iter = m_processor_trace_monitor.find(thread);
+ if (iter == m_processor_trace_monitor.end()) {
+ // thread not found in our map.
+ LLDB_LOG(log, "thread not being traced");
+ error.SetErrorString("tracing not active for this thread");
+ return error;
+ }
+ if (iter->second->GetTraceID() != traceid) {
+ // traceid did not match so it has to be invalid.
+ LLDB_LOG(log, "Invalid TraceID");
+ error.SetErrorString("invalid trace id");
+ return error;
+ }
+
+ LLDB_LOG(log, "UID - {0} , Thread -{1}", traceid, thread);
+
+ if (traceid == ProcessorTraceMonitor::GetProcessTraceID(GetID())) {
+ // traceid maps to the whole process so we have to erase it from the
+ // thread group.
+ LLDB_LOG(log, "traceid maps to process");
+ m_pt_traced_thread_group.erase(thread);
+ }
+ m_processor_trace_monitor.erase(iter);
+
+ return error;
+}
Index: source/Plugins/Process/Linux/CMakeLists.txt
===================================================================
--- source/Plugins/Process/Linux/CMakeLists.txt
+++ source/Plugins/Process/Linux/CMakeLists.txt
@@ -11,6 +11,7 @@
NativeRegisterContextLinux_mips64.cpp
NativeRegisterContextLinux_s390x.cpp
NativeThreadLinux.cpp
+ ProcessorTrace.cpp
SingleStepCheck.cpp
LINK_LIBS
Index: source/Host/linux/Support.cpp
===================================================================
--- source/Host/linux/Support.cpp
+++ source/Host/linux/Support.cpp
@@ -32,3 +32,13 @@
LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
return Ret;
}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+lldb_private::getProcFile(const llvm::Twine &file) {
+ Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ std::string File = ("/proc/" + file).str();
+ auto Ret = llvm::MemoryBuffer::getFileAsStream(File);
+ if (!Ret)
+ LLDB_LOG(log, "Failed to open {0}: {1}", File, Ret.getError().message());
+ return Ret;
+}
Index: include/lldb/Host/linux/Support.h
===================================================================
--- include/lldb/Host/linux/Support.h
+++ include/lldb/Host/linux/Support.h
@@ -22,6 +22,9 @@
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getProcFile(::pid_t pid, const llvm::Twine &file);
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+getProcFile(const llvm::Twine &file);
+
} // namespace lldb_private
#endif // #ifndef LLDB_HOST_LINUX_SUPPORT_H
Index: include/lldb/Host/common/NativeProcessProtocol.h
===================================================================
--- include/lldb/Host/common/NativeProcessProtocol.h
+++ include/lldb/Host/common/NativeProcessProtocol.h
@@ -335,7 +335,7 @@
//------------------------------------------------------------------
/// StopTracing API as the name suggests stops a tracing instance.
///
- /// @param[in] uid
+ /// @param[in] traceid
/// The user id of the trace intended to be stopped. Now a
/// user_id may map to multiple threads in which case this API
/// could be used to stop the tracing for a specific thread by
@@ -348,17 +348,17 @@
/// @return
/// Status indicating what went wrong.
//------------------------------------------------------------------
- virtual Status StopTrace(lldb::user_id_t uid,
+ virtual Status StopTrace(lldb::user_id_t traceid,
lldb::tid_t thread = LLDB_INVALID_THREAD_ID) {
return Status("Not implemented");
}
//------------------------------------------------------------------
/// This API provides the trace data collected in the form of raw
/// data.
///
- /// @param[in] uid thread
- /// The uid and thread provide the context for the trace
+ /// @param[in] traceid thread
+ /// The traceid and thread provide the context for the trace
/// instance.
///
/// @param[in] buffer
@@ -374,7 +374,7 @@
/// @return
/// The size of the data actually read.
//------------------------------------------------------------------
- virtual Status GetData(lldb::user_id_t uid, lldb::tid_t thread,
+ virtual Status GetData(lldb::user_id_t traceid, lldb::tid_t thread,
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) {
return Status("Not implemented");
@@ -384,16 +384,16 @@
/// Similar API as above except it aims to provide any extra data
/// useful for decoding the actual trace data.
//------------------------------------------------------------------
- virtual Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread,
+ virtual Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread,
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) {
return Status("Not implemented");
}
//------------------------------------------------------------------
/// API to query the TraceOptions for a given user id
///
- /// @param[in] uid
+ /// @param[in] traceid
/// The user id of the tracing instance.
///
/// @param[in] config
@@ -407,7 +407,7 @@
/// @param[out] config
/// The actual configuration being used for tracing.
//------------------------------------------------------------------
- virtual Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &config) {
+ virtual Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) {
return Status("Not implemented");
}
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits