1 //===-- IntelPTCollector.cpp ------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <algorithm> 10 #include <fstream> 11 #include <sstream> 12 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/Support/Error.h" 15 #include "llvm/Support/MathExtras.h" 16 17 #include "IntelPTCollector.h" 18 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 19 #include "lldb/Host/linux/Support.h" 20 #include "lldb/Utility/StreamString.h" 21 22 #include <sys/ioctl.h> 23 #include <sys/syscall.h> 24 25 using namespace lldb; 26 using namespace lldb_private; 27 using namespace process_linux; 28 using namespace llvm; 29 30 const char *kOSEventIntelPTTypeFile = 31 "/sys/bus/event_source/devices/intel_pt/type"; 32 33 const char *kPSBPeriodCapFile = 34 "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc"; 35 36 const char *kPSBPeriodValidValuesFile = 37 "/sys/bus/event_source/devices/intel_pt/caps/psb_periods"; 38 39 const char *kTSCBitOffsetFile = 40 "/sys/bus/event_source/devices/intel_pt/format/tsc"; 41 42 const char *kPSBPeriodBitOffsetFile = 43 "/sys/bus/event_source/devices/intel_pt/format/psb_period"; 44 45 enum IntelPTConfigFileType { 46 Hex = 0, 47 // 0 or 1 48 ZeroOne, 49 Decimal, 50 // a bit index file always starts with the prefix config: following by an int, 51 // which represents the offset of the perf_event_attr.config value where to 52 // store a given configuration. 53 BitOffset 54 }; 55 56 static Expected<uint32_t> ReadIntelPTConfigFile(const char *file, 57 IntelPTConfigFileType type) { 58 ErrorOr<std::unique_ptr<MemoryBuffer>> stream = 59 MemoryBuffer::getFileAsStream(file); 60 61 if (!stream) 62 return createStringError(inconvertibleErrorCode(), 63 "Can't open the file '%s'", file); 64 65 uint32_t value = 0; 66 StringRef text_buffer = stream.get()->getBuffer(); 67 68 if (type == BitOffset) { 69 const char *prefix = "config:"; 70 if (!text_buffer.startswith(prefix)) 71 return createStringError(inconvertibleErrorCode(), 72 "The file '%s' contents doesn't start with '%s'", 73 file, prefix); 74 text_buffer = text_buffer.substr(strlen(prefix)); 75 } 76 77 auto getRadix = [&]() { 78 switch (type) { 79 case Hex: 80 return 16; 81 case ZeroOne: 82 case Decimal: 83 case BitOffset: 84 return 10; 85 } 86 }; 87 88 auto createError = [&](const char *expected_value_message) { 89 return createStringError( 90 inconvertibleErrorCode(), 91 "The file '%s' has an invalid value. It should be %s.", file, 92 expected_value_message); 93 }; 94 95 if (text_buffer.trim().consumeInteger(getRadix(), value) || 96 (type == ZeroOne && value != 0 && value != 1)) { 97 switch (type) { 98 case Hex: 99 return createError("an unsigned hexadecimal int"); 100 case ZeroOne: 101 return createError("0 or 1"); 102 case Decimal: 103 case BitOffset: 104 return createError("an unsigned decimal int"); 105 } 106 } 107 return value; 108 } 109 /// Return the Linux perf event type for Intel PT. 110 static Expected<uint32_t> GetOSEventType() { 111 return ReadIntelPTConfigFile(kOSEventIntelPTTypeFile, 112 IntelPTConfigFileType::Decimal); 113 } 114 115 static Error CheckPsbPeriod(size_t psb_period) { 116 Expected<uint32_t> cap = 117 ReadIntelPTConfigFile(kPSBPeriodCapFile, IntelPTConfigFileType::ZeroOne); 118 if (!cap) 119 return cap.takeError(); 120 if (*cap == 0) 121 return createStringError(inconvertibleErrorCode(), 122 "psb_period is unsupported in the system."); 123 124 Expected<uint32_t> valid_values = ReadIntelPTConfigFile( 125 kPSBPeriodValidValuesFile, IntelPTConfigFileType::Hex); 126 if (!valid_values) 127 return valid_values.takeError(); 128 129 if (valid_values.get() & (1 << psb_period)) 130 return Error::success(); 131 132 std::ostringstream error; 133 // 0 is always a valid value 134 error << "Invalid psb_period. Valid values are: 0"; 135 uint32_t mask = valid_values.get(); 136 while (mask) { 137 int index = __builtin_ctz(mask); 138 if (index > 0) 139 error << ", " << index; 140 // clear the lowest bit 141 mask &= mask - 1; 142 } 143 error << "."; 144 return createStringError(inconvertibleErrorCode(), error.str().c_str()); 145 } 146 147 size_t IntelPTThreadTrace::GetTraceBufferSize() const { 148 #ifndef PERF_ATTR_SIZE_VER5 149 llvm_unreachable("Intel PT Linux perf event not supported"); 150 #else 151 return m_mmap_meta->aux_size; 152 #endif 153 } 154 155 static Expected<uint64_t> 156 GeneratePerfEventConfigValue(bool enable_tsc, Optional<size_t> psb_period) { 157 uint64_t config = 0; 158 // tsc is always supported 159 if (enable_tsc) { 160 if (Expected<uint32_t> offset = ReadIntelPTConfigFile( 161 kTSCBitOffsetFile, IntelPTConfigFileType::BitOffset)) 162 config |= 1 << *offset; 163 else 164 return offset.takeError(); 165 } 166 if (psb_period) { 167 if (Error error = CheckPsbPeriod(*psb_period)) 168 return std::move(error); 169 170 if (Expected<uint32_t> offset = ReadIntelPTConfigFile( 171 kPSBPeriodBitOffsetFile, IntelPTConfigFileType::BitOffset)) 172 config |= *psb_period << *offset; 173 else 174 return offset.takeError(); 175 } 176 return config; 177 } 178 179 Error IntelPTThreadTrace::StartTrace(lldb::pid_t pid, lldb::tid_t tid, 180 uint64_t buffer_size, bool enable_tsc, 181 Optional<size_t> psb_period) { 182 #ifndef PERF_ATTR_SIZE_VER5 183 llvm_unreachable("Intel PT Linux perf event not supported"); 184 #else 185 Log *log = GetLog(POSIXLog::Ptrace); 186 187 m_tid = tid; 188 LLDB_LOG(log, "called thread id {0}", tid); 189 uint64_t page_size = getpagesize(); 190 191 if (__builtin_popcount(buffer_size) != 1 || buffer_size < 4096) { 192 return createStringError( 193 inconvertibleErrorCode(), 194 "The trace buffer size must be a power of 2 greater than or equal to " 195 "4096 (2^12) bytes. It was %" PRIu64 ".", 196 buffer_size); 197 } 198 uint64_t numpages = static_cast<uint64_t>( 199 llvm::PowerOf2Floor((buffer_size + page_size - 1) / page_size)); 200 numpages = std::max<uint64_t>(1, numpages); 201 buffer_size = page_size * numpages; 202 203 perf_event_attr attr; 204 memset(&attr, 0, sizeof(attr)); 205 attr.size = sizeof(attr); 206 attr.exclude_kernel = 1; 207 attr.sample_type = PERF_SAMPLE_TIME; 208 attr.sample_id_all = 1; 209 attr.exclude_hv = 1; 210 attr.exclude_idle = 1; 211 attr.mmap = 1; 212 213 if (Expected<uint64_t> config_value = 214 GeneratePerfEventConfigValue(enable_tsc, psb_period)) { 215 attr.config = *config_value; 216 LLDB_LOG(log, "intel pt config {0}", attr.config); 217 } else { 218 return config_value.takeError(); 219 } 220 221 if (Expected<uint32_t> intel_pt_type = GetOSEventType()) { 222 attr.type = *intel_pt_type; 223 LLDB_LOG(log, "intel pt type {0}", attr.type); 224 } else { 225 return intel_pt_type.takeError(); 226 } 227 228 LLDB_LOG(log, "buffer size {0} ", buffer_size); 229 230 errno = 0; 231 auto fd = 232 syscall(SYS_perf_event_open, &attr, static_cast<::tid_t>(tid), -1, -1, 0); 233 if (fd == -1) { 234 LLDB_LOG(log, "syscall error {0}", errno); 235 return createStringError(inconvertibleErrorCode(), 236 "perf event syscall failed"); 237 } 238 239 m_fd = std::unique_ptr<int, file_close>(new int(fd), file_close()); 240 241 errno = 0; 242 auto base = 243 mmap(nullptr, (buffer_size + page_size), PROT_WRITE, MAP_SHARED, fd, 0); 244 245 if (base == MAP_FAILED) { 246 LLDB_LOG(log, "mmap base error {0}", errno); 247 return createStringError(inconvertibleErrorCode(), 248 "Meta buffer allocation failed"); 249 } 250 251 m_mmap_meta = std::unique_ptr<perf_event_mmap_page, munmap_delete>( 252 reinterpret_cast<perf_event_mmap_page *>(base), 253 munmap_delete(buffer_size + page_size)); 254 255 m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size; 256 m_mmap_meta->aux_size = buffer_size; 257 258 errno = 0; 259 auto mmap_aux = mmap(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd, 260 static_cast<long int>(m_mmap_meta->aux_offset)); 261 262 if (mmap_aux == MAP_FAILED) { 263 LLDB_LOG(log, "second mmap done {0}", errno); 264 return createStringError(inconvertibleErrorCode(), 265 "Trace buffer allocation failed"); 266 } 267 m_mmap_aux = std::unique_ptr<uint8_t, munmap_delete>( 268 reinterpret_cast<uint8_t *>(mmap_aux), munmap_delete(buffer_size)); 269 return Error::success(); 270 #endif 271 } 272 273 llvm::MutableArrayRef<uint8_t> IntelPTThreadTrace::GetDataBuffer() const { 274 #ifndef PERF_ATTR_SIZE_VER5 275 llvm_unreachable("Intel PT Linux perf event not supported"); 276 #else 277 return MutableArrayRef<uint8_t>( 278 (reinterpret_cast<uint8_t *>(m_mmap_meta.get()) + 279 m_mmap_meta->data_offset), 280 m_mmap_meta->data_size); 281 #endif 282 } 283 284 llvm::MutableArrayRef<uint8_t> IntelPTThreadTrace::GetAuxBuffer() const { 285 #ifndef PERF_ATTR_SIZE_VER5 286 llvm_unreachable("Intel PT Linux perf event not supported"); 287 #else 288 return MutableArrayRef<uint8_t>(m_mmap_aux.get(), m_mmap_meta->aux_size); 289 #endif 290 } 291 292 Expected<ArrayRef<uint8_t>> IntelPTThreadTrace::GetCPUInfo() { 293 static llvm::Optional<std::vector<uint8_t>> cpu_info; 294 if (!cpu_info) { 295 auto buffer_or_error = getProcFile("cpuinfo"); 296 if (!buffer_or_error) 297 return Status(buffer_or_error.getError()).ToError(); 298 MemoryBuffer &buffer = **buffer_or_error; 299 cpu_info = std::vector<uint8_t>( 300 reinterpret_cast<const uint8_t *>(buffer.getBufferStart()), 301 reinterpret_cast<const uint8_t *>(buffer.getBufferEnd())); 302 } 303 return *cpu_info; 304 } 305 306 llvm::Expected<IntelPTThreadTraceUP> 307 IntelPTThreadTrace::Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size, 308 bool enable_tsc, Optional<size_t> psb_period) { 309 IntelPTThreadTraceUP thread_trace_up(new IntelPTThreadTrace()); 310 311 if (llvm::Error err = thread_trace_up->StartTrace(pid, tid, buffer_size, 312 enable_tsc, psb_period)) 313 return std::move(err); 314 315 return std::move(thread_trace_up); 316 } 317 318 Expected<std::vector<uint8_t>> 319 IntelPTThreadTrace::GetIntelPTBuffer(size_t offset, size_t size) const { 320 std::vector<uint8_t> data(size, 0); 321 MutableArrayRef<uint8_t> buffer_ref(data); 322 Status error = ReadPerfTraceAux(buffer_ref, 0); 323 if (error.Fail()) 324 return error.ToError(); 325 return data; 326 } 327 328 Status 329 IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer, 330 size_t offset) const { 331 #ifndef PERF_ATTR_SIZE_VER5 332 llvm_unreachable("perf event not supported"); 333 #else 334 // Disable the perf event to force a flush out of the CPU's internal buffer. 335 // Besides, we can guarantee that the CPU won't override any data as we are 336 // reading the buffer. 337 // 338 // The Intel documentation says: 339 // 340 // Packets are first buffered internally and then written out asynchronously. 341 // To collect packet output for postprocessing, a collector needs first to 342 // ensure that all packet data has been flushed from internal buffers. 343 // Software can ensure this by stopping packet generation by clearing 344 // IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in 345 // Section 35.2.7.2). 346 // 347 // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned 348 // in the man page of perf_event_open. 349 ioctl(*m_fd, PERF_EVENT_IOC_DISABLE); 350 351 Log *log = GetLog(POSIXLog::Ptrace); 352 Status error; 353 uint64_t head = m_mmap_meta->aux_head; 354 355 LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_mmap_meta->aux_size, head); 356 357 /** 358 * When configured as ring buffer, the aux buffer keeps wrapping around 359 * the buffer and its not possible to detect how many times the buffer 360 * wrapped. Initially the buffer is filled with zeros,as shown below 361 * so in order to get complete buffer we first copy firstpartsize, followed 362 * by any left over part from beginning to aux_head 363 * 364 * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size 365 * aux_head->||<- firstpartsize ->| 366 * 367 * */ 368 369 ReadCyclicBuffer(buffer, GetAuxBuffer(), static_cast<size_t>(head), offset); 370 LLDB_LOG(log, "ReadCyclic BUffer Done"); 371 372 // Reenable tracing now we have read the buffer 373 ioctl(*m_fd, PERF_EVENT_IOC_ENABLE); 374 return error; 375 #endif 376 } 377 378 Status 379 IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer, 380 size_t offset) const { 381 #ifndef PERF_ATTR_SIZE_VER5 382 llvm_unreachable("perf event not supported"); 383 #else 384 Log *log = GetLog(POSIXLog::Ptrace); 385 uint64_t bytes_remaining = buffer.size(); 386 Status error; 387 388 uint64_t head = m_mmap_meta->data_head; 389 390 /* 391 * The data buffer and aux buffer have different implementations 392 * with respect to their definition of head pointer. In the case 393 * of Aux data buffer the head always wraps around the aux buffer 394 * and we don't need to care about it, whereas the data_head keeps 395 * increasing and needs to be wrapped by modulus operator 396 */ 397 398 LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining); 399 400 auto data_buffer = GetDataBuffer(); 401 402 if (head > data_buffer.size()) { 403 head = head % data_buffer.size(); 404 LLDB_LOG(log, "Data size -{0} Head - {1}", m_mmap_meta->data_size, head); 405 406 ReadCyclicBuffer(buffer, data_buffer, static_cast<size_t>(head), offset); 407 bytes_remaining -= buffer.size(); 408 } else { 409 LLDB_LOG(log, "Head - {0}", head); 410 if (offset >= head) { 411 LLDB_LOG(log, "Invalid Offset "); 412 error.SetErrorString("invalid offset"); 413 buffer = buffer.slice(buffer.size()); 414 return error; 415 } 416 417 auto data = data_buffer.slice(offset, (head - offset)); 418 auto remaining = std::copy(data.begin(), data.end(), buffer.begin()); 419 bytes_remaining -= (remaining - buffer.begin()); 420 } 421 buffer = buffer.drop_back(bytes_remaining); 422 return error; 423 #endif 424 } 425 426 void IntelPTThreadTrace::ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst, 427 llvm::MutableArrayRef<uint8_t> src, 428 size_t src_cyc_index, size_t offset) { 429 430 Log *log = GetLog(POSIXLog::Ptrace); 431 432 if (dst.empty() || src.empty()) { 433 dst = dst.drop_back(dst.size()); 434 return; 435 } 436 437 if (dst.data() == nullptr || src.data() == nullptr) { 438 dst = dst.drop_back(dst.size()); 439 return; 440 } 441 442 if (src_cyc_index > src.size()) { 443 dst = dst.drop_back(dst.size()); 444 return; 445 } 446 447 if (offset >= src.size()) { 448 LLDB_LOG(log, "Too Big offset "); 449 dst = dst.drop_back(dst.size()); 450 return; 451 } 452 453 llvm::SmallVector<MutableArrayRef<uint8_t>, 2> parts = { 454 src.slice(src_cyc_index), src.take_front(src_cyc_index)}; 455 456 if (offset > parts[0].size()) { 457 parts[1] = parts[1].slice(offset - parts[0].size()); 458 parts[0] = parts[0].drop_back(parts[0].size()); 459 } else if (offset == parts[0].size()) { 460 parts[0] = parts[0].drop_back(parts[0].size()); 461 } else { 462 parts[0] = parts[0].slice(offset); 463 } 464 auto next = dst.begin(); 465 auto bytes_left = dst.size(); 466 for (auto part : parts) { 467 size_t chunk_size = std::min(part.size(), bytes_left); 468 next = std::copy_n(part.begin(), chunk_size, next); 469 bytes_left -= chunk_size; 470 } 471 dst = dst.drop_back(bytes_left); 472 } 473 474 TraceThreadState IntelPTThreadTrace::GetState() const { 475 return {static_cast<int64_t>(m_tid), 476 {TraceBinaryData{"threadTraceBuffer", 477 static_cast<int64_t>(GetTraceBufferSize())}}}; 478 } 479 480 /// IntelPTThreadTraceCollection 481 482 bool IntelPTThreadTraceCollection::TracesThread(lldb::tid_t tid) const { 483 return m_thread_traces.count(tid); 484 } 485 486 Error IntelPTThreadTraceCollection::TraceStop(lldb::tid_t tid) { 487 auto it = m_thread_traces.find(tid); 488 if (it == m_thread_traces.end()) 489 return createStringError(inconvertibleErrorCode(), 490 "Thread %" PRIu64 " not currently traced", tid); 491 m_total_buffer_size -= it->second->GetTraceBufferSize(); 492 m_thread_traces.erase(tid); 493 return Error::success(); 494 } 495 496 Error IntelPTThreadTraceCollection::TraceStart( 497 lldb::tid_t tid, const TraceIntelPTStartRequest &request) { 498 if (TracesThread(tid)) 499 return createStringError(inconvertibleErrorCode(), 500 "Thread %" PRIu64 " already traced", tid); 501 502 Expected<IntelPTThreadTraceUP> trace_up = IntelPTThreadTrace::Create( 503 m_pid, tid, request.threadBufferSize, request.enableTsc, 504 request.psbPeriod.map([](int64_t period) { return (size_t)period; })); 505 if (!trace_up) 506 return trace_up.takeError(); 507 508 m_total_buffer_size += (*trace_up)->GetTraceBufferSize(); 509 m_thread_traces.try_emplace(tid, std::move(*trace_up)); 510 return Error::success(); 511 } 512 513 size_t IntelPTThreadTraceCollection::GetTotalBufferSize() const { 514 return m_total_buffer_size; 515 } 516 517 std::vector<TraceThreadState> 518 IntelPTThreadTraceCollection::GetThreadStates() const { 519 std::vector<TraceThreadState> states; 520 for (const auto &it : m_thread_traces) 521 states.push_back(it.second->GetState()); 522 return states; 523 } 524 525 Expected<const IntelPTThreadTrace &> 526 IntelPTThreadTraceCollection::GetTracedThread(lldb::tid_t tid) const { 527 auto it = m_thread_traces.find(tid); 528 if (it == m_thread_traces.end()) 529 return createStringError(inconvertibleErrorCode(), 530 "Thread %" PRIu64 " not currently traced", tid); 531 return *it->second.get(); 532 } 533 534 void IntelPTThreadTraceCollection::Clear() { 535 m_thread_traces.clear(); 536 m_total_buffer_size = 0; 537 } 538 539 /// IntelPTProcessTrace 540 541 bool IntelPTProcessTrace::TracesThread(lldb::tid_t tid) const { 542 return m_thread_traces.TracesThread(tid); 543 } 544 545 Error IntelPTProcessTrace::TraceStop(lldb::tid_t tid) { 546 return m_thread_traces.TraceStop(tid); 547 } 548 549 Error IntelPTProcessTrace::TraceStart(lldb::tid_t tid) { 550 if (m_thread_traces.GetTotalBufferSize() + m_tracing_params.threadBufferSize > 551 static_cast<size_t>(*m_tracing_params.processBufferSizeLimit)) 552 return createStringError( 553 inconvertibleErrorCode(), 554 "Thread %" PRIu64 " can't be traced as the process trace size limit " 555 "has been reached. Consider retracing with a higher " 556 "limit.", 557 tid); 558 559 return m_thread_traces.TraceStart(tid, m_tracing_params); 560 } 561 562 const IntelPTThreadTraceCollection & 563 IntelPTProcessTrace::GetThreadTraces() const { 564 return m_thread_traces; 565 } 566 567 /// IntelPTCollector 568 569 Error IntelPTCollector::TraceStop(lldb::tid_t tid) { 570 if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid)) 571 return m_process_trace->TraceStop(tid); 572 return m_thread_traces.TraceStop(tid); 573 } 574 575 Error IntelPTCollector::TraceStop(const TraceStopRequest &request) { 576 if (request.IsProcessTracing()) { 577 Clear(); 578 return Error::success(); 579 } else { 580 Error error = Error::success(); 581 for (int64_t tid : *request.tids) 582 error = joinErrors(std::move(error), 583 TraceStop(static_cast<lldb::tid_t>(tid))); 584 return error; 585 } 586 } 587 588 Error IntelPTCollector::TraceStart( 589 const TraceIntelPTStartRequest &request, 590 const std::vector<lldb::tid_t> &process_threads) { 591 if (request.IsProcessTracing()) { 592 if (IsProcessTracingEnabled()) { 593 return createStringError( 594 inconvertibleErrorCode(), 595 "Process currently traced. Stop process tracing first"); 596 } 597 m_process_trace = IntelPTProcessTrace(m_pid, request); 598 599 Error error = Error::success(); 600 for (lldb::tid_t tid : process_threads) 601 error = joinErrors(std::move(error), m_process_trace->TraceStart(tid)); 602 return error; 603 } else { 604 Error error = Error::success(); 605 for (int64_t tid : *request.tids) 606 error = joinErrors(std::move(error), 607 m_thread_traces.TraceStart(tid, request)); 608 return error; 609 } 610 } 611 612 Error IntelPTCollector::OnThreadCreated(lldb::tid_t tid) { 613 if (!IsProcessTracingEnabled()) 614 return Error::success(); 615 return m_process_trace->TraceStart(tid); 616 } 617 618 Error IntelPTCollector::OnThreadDestroyed(lldb::tid_t tid) { 619 if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid)) 620 return m_process_trace->TraceStop(tid); 621 else if (m_thread_traces.TracesThread(tid)) 622 return m_thread_traces.TraceStop(tid); 623 return Error::success(); 624 } 625 626 Expected<json::Value> IntelPTCollector::GetState() const { 627 Expected<ArrayRef<uint8_t>> cpu_info = IntelPTThreadTrace::GetCPUInfo(); 628 if (!cpu_info) 629 return cpu_info.takeError(); 630 631 TraceGetStateResponse state; 632 state.processBinaryData.push_back( 633 {"cpuInfo", static_cast<int64_t>(cpu_info->size())}); 634 635 std::vector<TraceThreadState> thread_states = 636 m_thread_traces.GetThreadStates(); 637 state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(), 638 thread_states.end()); 639 640 if (IsProcessTracingEnabled()) { 641 thread_states = m_process_trace->GetThreadTraces().GetThreadStates(); 642 state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(), 643 thread_states.end()); 644 } 645 return toJSON(state); 646 } 647 648 Expected<const IntelPTThreadTrace &> 649 IntelPTCollector::GetTracedThread(lldb::tid_t tid) const { 650 if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid)) 651 return m_process_trace->GetThreadTraces().GetTracedThread(tid); 652 return m_thread_traces.GetTracedThread(tid); 653 } 654 655 Expected<std::vector<uint8_t>> 656 IntelPTCollector::GetBinaryData(const TraceGetBinaryDataRequest &request) const { 657 if (request.kind == "threadTraceBuffer") { 658 if (Expected<const IntelPTThreadTrace &> trace = 659 GetTracedThread(*request.tid)) 660 return trace->GetIntelPTBuffer(request.offset, request.size); 661 else 662 return trace.takeError(); 663 } else if (request.kind == "cpuInfo") { 664 return IntelPTThreadTrace::GetCPUInfo(); 665 } 666 return createStringError(inconvertibleErrorCode(), 667 "Unsuported trace binary data kind: %s", 668 request.kind.c_str()); 669 } 670 671 void IntelPTCollector::ClearProcessTracing() { m_process_trace = None; } 672 673 bool IntelPTCollector::IsSupported() { 674 Expected<uint32_t> intel_pt_type = GetOSEventType(); 675 if (!intel_pt_type) { 676 llvm::consumeError(intel_pt_type.takeError()); 677 return false; 678 } 679 return true; 680 } 681 682 bool IntelPTCollector::IsProcessTracingEnabled() const { 683 return (bool)m_process_trace; 684 } 685 686 void IntelPTCollector::Clear() { 687 ClearProcessTracing(); 688 m_thread_traces.Clear(); 689 } 690