brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.6 KiB · 83d5f14 Raw
429 lines · cpp
1//===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//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-exception6//7//===----------------------------------------------------------------------===//8#include "llvm/XRay/FDRRecords.h"9 10using namespace llvm;11using namespace llvm::xray;12 13Error RecordInitializer::visit(BufferExtents &R) {14  if (!E.isValidOffsetForDataOfSize(OffsetPtr, sizeof(uint64_t)))15    return createStringError(16        std::make_error_code(std::errc::bad_address),17        "Invalid offset for a buffer extent (%" PRId64 ").", OffsetPtr);18 19  auto PreReadOffset = OffsetPtr;20  R.Size = E.getU64(&OffsetPtr);21  if (PreReadOffset == OffsetPtr)22    return createStringError(std::make_error_code(std::errc::invalid_argument),23                             "Cannot read buffer extent at offset %" PRId64 ".",24                             OffsetPtr);25 26  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);27  return Error::success();28}29 30Error RecordInitializer::visit(WallclockRecord &R) {31  if (!E.isValidOffsetForDataOfSize(OffsetPtr,32                                    MetadataRecord::kMetadataBodySize))33    return createStringError(34        std::make_error_code(std::errc::bad_address),35        "Invalid offset for a wallclock record (%" PRId64 ").", OffsetPtr);36  auto BeginOffset = OffsetPtr;37  auto PreReadOffset = OffsetPtr;38  R.Seconds = E.getU64(&OffsetPtr);39  if (OffsetPtr == PreReadOffset)40    return createStringError(41        std::make_error_code(std::errc::invalid_argument),42        "Cannot read wall clock 'seconds' field at offset %" PRId64 ".",43        OffsetPtr);44 45  PreReadOffset = OffsetPtr;46  R.Nanos = E.getU32(&OffsetPtr);47  if (OffsetPtr == PreReadOffset)48    return createStringError(49        std::make_error_code(std::errc::invalid_argument),50        "Cannot read wall clock 'nanos' field at offset %" PRId64 ".",51        OffsetPtr);52 53  // Align to metadata record size boundary.54  assert(OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);55  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);56  return Error::success();57}58 59Error RecordInitializer::visit(NewCPUIDRecord &R) {60  if (!E.isValidOffsetForDataOfSize(OffsetPtr,61                                    MetadataRecord::kMetadataBodySize))62    return createStringError(63        std::make_error_code(std::errc::bad_address),64        "Invalid offset for a new cpu id record (%" PRId64 ").", OffsetPtr);65  auto BeginOffset = OffsetPtr;66  auto PreReadOffset = OffsetPtr;67  R.CPUId = E.getU16(&OffsetPtr);68  if (OffsetPtr == PreReadOffset)69    return createStringError(std::make_error_code(std::errc::invalid_argument),70                             "Cannot read CPU id at offset %" PRId64 ".",71                             OffsetPtr);72 73  PreReadOffset = OffsetPtr;74  R.TSC = E.getU64(&OffsetPtr);75  if (OffsetPtr == PreReadOffset)76    return createStringError(std::make_error_code(std::errc::invalid_argument),77                             "Cannot read CPU TSC at offset %" PRId64 ".",78                             OffsetPtr);79 80  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);81  return Error::success();82}83 84Error RecordInitializer::visit(TSCWrapRecord &R) {85  if (!E.isValidOffsetForDataOfSize(OffsetPtr,86                                    MetadataRecord::kMetadataBodySize))87    return createStringError(88        std::make_error_code(std::errc::bad_address),89        "Invalid offset for a new TSC wrap record (%" PRId64 ").", OffsetPtr);90 91  auto PreReadOffset = OffsetPtr;92  R.BaseTSC = E.getU64(&OffsetPtr);93  if (PreReadOffset == OffsetPtr)94    return createStringError(95        std::make_error_code(std::errc::invalid_argument),96        "Cannot read TSC wrap record at offset %" PRId64 ".", OffsetPtr);97 98  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);99  return Error::success();100}101 102Error RecordInitializer::visit(CustomEventRecord &R) {103  if (!E.isValidOffsetForDataOfSize(OffsetPtr,104                                    MetadataRecord::kMetadataBodySize))105    return createStringError(106        std::make_error_code(std::errc::bad_address),107        "Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);108 109  auto BeginOffset = OffsetPtr;110  auto PreReadOffset = OffsetPtr;111  R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));112  if (PreReadOffset == OffsetPtr)113    return createStringError(114        std::make_error_code(std::errc::invalid_argument),115        "Cannot read a custom event record size field offset %" PRId64 ".",116        OffsetPtr);117 118  if (R.Size <= 0)119    return createStringError(120        std::make_error_code(std::errc::bad_address),121        "Invalid size for custom event (size = %d) at offset %" PRId64 ".",122        R.Size, OffsetPtr);123 124  PreReadOffset = OffsetPtr;125  R.TSC = E.getU64(&OffsetPtr);126  if (PreReadOffset == OffsetPtr)127    return createStringError(128        std::make_error_code(std::errc::invalid_argument),129        "Cannot read a custom event TSC field at offset %" PRId64 ".",130        OffsetPtr);131 132  // For version 4 onwards, of the FDR log, we want to also capture the CPU ID133  // of the custom event.134  if (Version >= 4) {135    PreReadOffset = OffsetPtr;136    R.CPU = E.getU16(&OffsetPtr);137    if (PreReadOffset == OffsetPtr)138      return createStringError(139          std::make_error_code(std::errc::invalid_argument),140          "Missing CPU field at offset %" PRId64 ".", OffsetPtr);141  }142 143  assert(OffsetPtr > BeginOffset &&144         OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);145  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);146 147  // Next we read in a fixed chunk of data from the given offset.148  if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))149    return createStringError(150        std::make_error_code(std::errc::bad_address),151        "Cannot read %d bytes of custom event data from offset %" PRId64 ".",152        R.Size, OffsetPtr);153 154  std::vector<uint8_t> Buffer;155  Buffer.resize(R.Size);156  PreReadOffset = OffsetPtr;157  if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())158    return createStringError(159        std::make_error_code(std::errc::invalid_argument),160        "Failed reading data into buffer of size %d at offset %" PRId64 ".",161        R.Size, OffsetPtr);162 163  assert(OffsetPtr >= PreReadOffset);164  if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))165    return createStringError(166        std::make_error_code(std::errc::invalid_argument),167        "Failed reading enough bytes for the custom event payload -- read "168        "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",169        OffsetPtr - PreReadOffset, R.Size, PreReadOffset);170 171  R.Data.assign(Buffer.begin(), Buffer.end());172  return Error::success();173}174 175Error RecordInitializer::visit(CustomEventRecordV5 &R) {176  if (!E.isValidOffsetForDataOfSize(OffsetPtr,177                                    MetadataRecord::kMetadataBodySize))178    return createStringError(179        std::make_error_code(std::errc::bad_address),180        "Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);181 182  auto BeginOffset = OffsetPtr;183  auto PreReadOffset = OffsetPtr;184 185  R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));186  if (PreReadOffset == OffsetPtr)187    return createStringError(188        std::make_error_code(std::errc::invalid_argument),189        "Cannot read a custom event record size field offset %" PRId64 ".",190        OffsetPtr);191 192  if (R.Size <= 0)193    return createStringError(194        std::make_error_code(std::errc::bad_address),195        "Invalid size for custom event (size = %d) at offset %" PRId64 ".",196        R.Size, OffsetPtr);197 198  PreReadOffset = OffsetPtr;199  R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));200  if (PreReadOffset == OffsetPtr)201    return createStringError(202        std::make_error_code(std::errc::invalid_argument),203        "Cannot read a custom event record TSC delta field at offset "204        "%" PRId64 ".",205        OffsetPtr);206 207  assert(OffsetPtr > BeginOffset &&208         OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);209  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);210 211  // Next we read in a fixed chunk of data from the given offset.212  if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))213    return createStringError(214        std::make_error_code(std::errc::bad_address),215        "Cannot read %d bytes of custom event data from offset %" PRId64 ".",216        R.Size, OffsetPtr);217 218  std::vector<uint8_t> Buffer;219  Buffer.resize(R.Size);220  PreReadOffset = OffsetPtr;221  if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())222    return createStringError(223        std::make_error_code(std::errc::invalid_argument),224        "Failed reading data into buffer of size %d at offset %" PRId64 ".",225        R.Size, OffsetPtr);226 227  assert(OffsetPtr >= PreReadOffset);228  if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))229    return createStringError(230        std::make_error_code(std::errc::invalid_argument),231        "Failed reading enough bytes for the custom event payload -- read "232        "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",233        OffsetPtr - PreReadOffset, R.Size, PreReadOffset);234 235  R.Data.assign(Buffer.begin(), Buffer.end());236  return Error::success();237}238 239Error RecordInitializer::visit(TypedEventRecord &R) {240  if (!E.isValidOffsetForDataOfSize(OffsetPtr,241                                    MetadataRecord::kMetadataBodySize))242    return createStringError(243        std::make_error_code(std::errc::bad_address),244        "Invalid offset for a typed event record (%" PRId64 ").", OffsetPtr);245 246  auto BeginOffset = OffsetPtr;247  auto PreReadOffset = OffsetPtr;248 249  R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));250  if (PreReadOffset == OffsetPtr)251    return createStringError(252        std::make_error_code(std::errc::invalid_argument),253        "Cannot read a typed event record size field offset %" PRId64 ".",254        OffsetPtr);255 256  if (R.Size <= 0)257    return createStringError(258        std::make_error_code(std::errc::bad_address),259        "Invalid size for typed event (size = %d) at offset %" PRId64 ".",260        R.Size, OffsetPtr);261 262  PreReadOffset = OffsetPtr;263  R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));264  if (PreReadOffset == OffsetPtr)265    return createStringError(266        std::make_error_code(std::errc::invalid_argument),267        "Cannot read a typed event record TSC delta field at offset "268        "%" PRId64 ".",269        OffsetPtr);270 271  PreReadOffset = OffsetPtr;272  R.EventType = E.getU16(&OffsetPtr);273  if (PreReadOffset == OffsetPtr)274    return createStringError(275        std::make_error_code(std::errc::invalid_argument),276        "Cannot read a typed event record type field at offset %" PRId64 ".",277        OffsetPtr);278 279  assert(OffsetPtr > BeginOffset &&280         OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);281  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);282 283  // Next we read in a fixed chunk of data from the given offset.284  if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))285    return createStringError(286        std::make_error_code(std::errc::bad_address),287        "Cannot read %d bytes of custom event data from offset %" PRId64 ".",288        R.Size, OffsetPtr);289 290  std::vector<uint8_t> Buffer;291  Buffer.resize(R.Size);292  PreReadOffset = OffsetPtr;293  if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())294    return createStringError(295        std::make_error_code(std::errc::invalid_argument),296        "Failed reading data into buffer of size %d at offset %" PRId64 ".",297        R.Size, OffsetPtr);298 299  assert(OffsetPtr >= PreReadOffset);300  if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))301    return createStringError(302        std::make_error_code(std::errc::invalid_argument),303        "Failed reading enough bytes for the typed event payload -- read "304        "%" PRId64 " expecting %d bytes at offset %" PRId64 ".",305        OffsetPtr - PreReadOffset, R.Size, PreReadOffset);306 307  R.Data.assign(Buffer.begin(), Buffer.end());308  return Error::success();309}310 311Error RecordInitializer::visit(CallArgRecord &R) {312  if (!E.isValidOffsetForDataOfSize(OffsetPtr,313                                    MetadataRecord::kMetadataBodySize))314    return createStringError(315        std::make_error_code(std::errc::bad_address),316        "Invalid offset for a call argument record (%" PRId64 ").",317        OffsetPtr);318 319  auto PreReadOffset = OffsetPtr;320  R.Arg = E.getU64(&OffsetPtr);321  if (PreReadOffset == OffsetPtr)322    return createStringError(323        std::make_error_code(std::errc::invalid_argument),324        "Cannot read a call arg record at offset %" PRId64 ".", OffsetPtr);325 326  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);327  return Error::success();328}329 330Error RecordInitializer::visit(PIDRecord &R) {331  if (!E.isValidOffsetForDataOfSize(OffsetPtr,332                                    MetadataRecord::kMetadataBodySize))333    return createStringError(334        std::make_error_code(std::errc::bad_address),335        "Invalid offset for a process ID record (%" PRId64 ").", OffsetPtr);336 337  auto PreReadOffset = OffsetPtr;338  R.PID = E.getSigned(&OffsetPtr, 4);339  if (PreReadOffset == OffsetPtr)340    return createStringError(341        std::make_error_code(std::errc::invalid_argument),342        "Cannot read a process ID record at offset %" PRId64 ".", OffsetPtr);343 344  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);345  return Error::success();346}347 348Error RecordInitializer::visit(NewBufferRecord &R) {349  if (!E.isValidOffsetForDataOfSize(OffsetPtr,350                                    MetadataRecord::kMetadataBodySize))351    return createStringError(352        std::make_error_code(std::errc::bad_address),353        "Invalid offset for a new buffer record (%" PRId64 ").", OffsetPtr);354 355  auto PreReadOffset = OffsetPtr;356  R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));357  if (PreReadOffset == OffsetPtr)358    return createStringError(359        std::make_error_code(std::errc::invalid_argument),360        "Cannot read a new buffer record at offset %" PRId64 ".", OffsetPtr);361 362  OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);363  return Error::success();364}365 366Error RecordInitializer::visit(EndBufferRecord &R) {367  if (!E.isValidOffsetForDataOfSize(OffsetPtr,368                                    MetadataRecord::kMetadataBodySize))369    return createStringError(370        std::make_error_code(std::errc::bad_address),371        "Invalid offset for an end-of-buffer record (%" PRId64 ").",372        OffsetPtr);373 374  OffsetPtr += MetadataRecord::kMetadataBodySize;375  return Error::success();376}377 378Error RecordInitializer::visit(FunctionRecord &R) {379  // For function records, we need to retreat one byte back to read a full380  // unsigned 32-bit value. The first four bytes will have the following381  // layout:382  //383  //   bit  0     : function record indicator (must be 0)384  //   bits 1..3  : function record type385  //   bits 4..32 : function id386  //387  if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(388                            --OffsetPtr, FunctionRecord::kFunctionRecordSize))389    return createStringError(390        std::make_error_code(std::errc::bad_address),391        "Invalid offset for a function record (%" PRId64 ").", OffsetPtr);392 393  auto BeginOffset = OffsetPtr;394  auto PreReadOffset = BeginOffset;395  uint32_t Buffer = E.getU32(&OffsetPtr);396  if (PreReadOffset == OffsetPtr)397    return createStringError(398        std::make_error_code(std::errc::bad_address),399        "Cannot read function id field from offset %" PRId64 ".", OffsetPtr);400 401  // To get the function record type, we shift the buffer one to the right402  // (truncating the function record indicator) then take the three bits403  // (0b0111) to get the record type as an unsigned value.404  unsigned FunctionType = (Buffer >> 1) & 0x07u;405  switch (FunctionType) {406  case static_cast<unsigned>(RecordTypes::ENTER):407  case static_cast<unsigned>(RecordTypes::ENTER_ARG):408  case static_cast<unsigned>(RecordTypes::EXIT):409  case static_cast<unsigned>(RecordTypes::TAIL_EXIT):410    R.Kind = static_cast<RecordTypes>(FunctionType);411    break;412  default:413    return createStringError(414        std::make_error_code(std::errc::invalid_argument),415        "Unknown function record type '%d' at offset %" PRId64 ".",416        FunctionType, BeginOffset);417  }418 419  R.FuncId = Buffer >> 4;420  PreReadOffset = OffsetPtr;421  R.Delta = E.getU32(&OffsetPtr);422  if (OffsetPtr == PreReadOffset)423    return createStringError(424        std::make_error_code(std::errc::invalid_argument),425        "Failed reading TSC delta from offset %" PRId64 ".", OffsetPtr);426  assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));427  return Error::success();428}429