Path: blob/main/contrib/llvm-project/llvm/lib/XRay/RecordInitializer.cpp
35234 views
//===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7#include "llvm/XRay/FDRRecords.h"89namespace llvm {10namespace xray {1112Error RecordInitializer::visit(BufferExtents &R) {13if (!E.isValidOffsetForDataOfSize(OffsetPtr, sizeof(uint64_t)))14return createStringError(15std::make_error_code(std::errc::bad_address),16"Invalid offset for a buffer extent (%" PRId64 ").", OffsetPtr);1718auto PreReadOffset = OffsetPtr;19R.Size = E.getU64(&OffsetPtr);20if (PreReadOffset == OffsetPtr)21return createStringError(std::make_error_code(std::errc::invalid_argument),22"Cannot read buffer extent at offset %" PRId64 ".",23OffsetPtr);2425OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);26return Error::success();27}2829Error RecordInitializer::visit(WallclockRecord &R) {30if (!E.isValidOffsetForDataOfSize(OffsetPtr,31MetadataRecord::kMetadataBodySize))32return createStringError(33std::make_error_code(std::errc::bad_address),34"Invalid offset for a wallclock record (%" PRId64 ").", OffsetPtr);35auto BeginOffset = OffsetPtr;36auto PreReadOffset = OffsetPtr;37R.Seconds = E.getU64(&OffsetPtr);38if (OffsetPtr == PreReadOffset)39return createStringError(40std::make_error_code(std::errc::invalid_argument),41"Cannot read wall clock 'seconds' field at offset %" PRId64 ".",42OffsetPtr);4344PreReadOffset = OffsetPtr;45R.Nanos = E.getU32(&OffsetPtr);46if (OffsetPtr == PreReadOffset)47return createStringError(48std::make_error_code(std::errc::invalid_argument),49"Cannot read wall clock 'nanos' field at offset %" PRId64 ".",50OffsetPtr);5152// Align to metadata record size boundary.53assert(OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);54OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);55return Error::success();56}5758Error RecordInitializer::visit(NewCPUIDRecord &R) {59if (!E.isValidOffsetForDataOfSize(OffsetPtr,60MetadataRecord::kMetadataBodySize))61return createStringError(62std::make_error_code(std::errc::bad_address),63"Invalid offset for a new cpu id record (%" PRId64 ").", OffsetPtr);64auto BeginOffset = OffsetPtr;65auto PreReadOffset = OffsetPtr;66R.CPUId = E.getU16(&OffsetPtr);67if (OffsetPtr == PreReadOffset)68return createStringError(std::make_error_code(std::errc::invalid_argument),69"Cannot read CPU id at offset %" PRId64 ".",70OffsetPtr);7172PreReadOffset = OffsetPtr;73R.TSC = E.getU64(&OffsetPtr);74if (OffsetPtr == PreReadOffset)75return createStringError(std::make_error_code(std::errc::invalid_argument),76"Cannot read CPU TSC at offset %" PRId64 ".",77OffsetPtr);7879OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);80return Error::success();81}8283Error RecordInitializer::visit(TSCWrapRecord &R) {84if (!E.isValidOffsetForDataOfSize(OffsetPtr,85MetadataRecord::kMetadataBodySize))86return createStringError(87std::make_error_code(std::errc::bad_address),88"Invalid offset for a new TSC wrap record (%" PRId64 ").", OffsetPtr);8990auto PreReadOffset = OffsetPtr;91R.BaseTSC = E.getU64(&OffsetPtr);92if (PreReadOffset == OffsetPtr)93return createStringError(94std::make_error_code(std::errc::invalid_argument),95"Cannot read TSC wrap record at offset %" PRId64 ".", OffsetPtr);9697OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);98return Error::success();99}100101Error RecordInitializer::visit(CustomEventRecord &R) {102if (!E.isValidOffsetForDataOfSize(OffsetPtr,103MetadataRecord::kMetadataBodySize))104return createStringError(105std::make_error_code(std::errc::bad_address),106"Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);107108auto BeginOffset = OffsetPtr;109auto PreReadOffset = OffsetPtr;110R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));111if (PreReadOffset == OffsetPtr)112return createStringError(113std::make_error_code(std::errc::invalid_argument),114"Cannot read a custom event record size field offset %" PRId64 ".",115OffsetPtr);116117if (R.Size <= 0)118return createStringError(119std::make_error_code(std::errc::bad_address),120"Invalid size for custom event (size = %d) at offset %" PRId64 ".",121R.Size, OffsetPtr);122123PreReadOffset = OffsetPtr;124R.TSC = E.getU64(&OffsetPtr);125if (PreReadOffset == OffsetPtr)126return createStringError(127std::make_error_code(std::errc::invalid_argument),128"Cannot read a custom event TSC field at offset %" PRId64 ".",129OffsetPtr);130131// For version 4 onwards, of the FDR log, we want to also capture the CPU ID132// of the custom event.133if (Version >= 4) {134PreReadOffset = OffsetPtr;135R.CPU = E.getU16(&OffsetPtr);136if (PreReadOffset == OffsetPtr)137return createStringError(138std::make_error_code(std::errc::invalid_argument),139"Missing CPU field at offset %" PRId64 ".", OffsetPtr);140}141142assert(OffsetPtr > BeginOffset &&143OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);144OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);145146// Next we read in a fixed chunk of data from the given offset.147if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))148return createStringError(149std::make_error_code(std::errc::bad_address),150"Cannot read %d bytes of custom event data from offset %" PRId64 ".",151R.Size, OffsetPtr);152153std::vector<uint8_t> Buffer;154Buffer.resize(R.Size);155PreReadOffset = OffsetPtr;156if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())157return createStringError(158std::make_error_code(std::errc::invalid_argument),159"Failed reading data into buffer of size %d at offset %" PRId64 ".",160R.Size, OffsetPtr);161162assert(OffsetPtr >= PreReadOffset);163if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))164return createStringError(165std::make_error_code(std::errc::invalid_argument),166"Failed reading enough bytes for the custom event payload -- read "167"%" PRId64 " expecting %d bytes at offset %" PRId64 ".",168OffsetPtr - PreReadOffset, R.Size, PreReadOffset);169170R.Data.assign(Buffer.begin(), Buffer.end());171return Error::success();172}173174Error RecordInitializer::visit(CustomEventRecordV5 &R) {175if (!E.isValidOffsetForDataOfSize(OffsetPtr,176MetadataRecord::kMetadataBodySize))177return createStringError(178std::make_error_code(std::errc::bad_address),179"Invalid offset for a custom event record (%" PRId64 ").", OffsetPtr);180181auto BeginOffset = OffsetPtr;182auto PreReadOffset = OffsetPtr;183184R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));185if (PreReadOffset == OffsetPtr)186return createStringError(187std::make_error_code(std::errc::invalid_argument),188"Cannot read a custom event record size field offset %" PRId64 ".",189OffsetPtr);190191if (R.Size <= 0)192return createStringError(193std::make_error_code(std::errc::bad_address),194"Invalid size for custom event (size = %d) at offset %" PRId64 ".",195R.Size, OffsetPtr);196197PreReadOffset = OffsetPtr;198R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));199if (PreReadOffset == OffsetPtr)200return createStringError(201std::make_error_code(std::errc::invalid_argument),202"Cannot read a custom event record TSC delta field at offset "203"%" PRId64 ".",204OffsetPtr);205206assert(OffsetPtr > BeginOffset &&207OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);208OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);209210// Next we read in a fixed chunk of data from the given offset.211if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))212return createStringError(213std::make_error_code(std::errc::bad_address),214"Cannot read %d bytes of custom event data from offset %" PRId64 ".",215R.Size, OffsetPtr);216217std::vector<uint8_t> Buffer;218Buffer.resize(R.Size);219PreReadOffset = OffsetPtr;220if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())221return createStringError(222std::make_error_code(std::errc::invalid_argument),223"Failed reading data into buffer of size %d at offset %" PRId64 ".",224R.Size, OffsetPtr);225226assert(OffsetPtr >= PreReadOffset);227if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))228return createStringError(229std::make_error_code(std::errc::invalid_argument),230"Failed reading enough bytes for the custom event payload -- read "231"%" PRId64 " expecting %d bytes at offset %" PRId64 ".",232OffsetPtr - PreReadOffset, R.Size, PreReadOffset);233234R.Data.assign(Buffer.begin(), Buffer.end());235return Error::success();236}237238Error RecordInitializer::visit(TypedEventRecord &R) {239if (!E.isValidOffsetForDataOfSize(OffsetPtr,240MetadataRecord::kMetadataBodySize))241return createStringError(242std::make_error_code(std::errc::bad_address),243"Invalid offset for a typed event record (%" PRId64 ").", OffsetPtr);244245auto BeginOffset = OffsetPtr;246auto PreReadOffset = OffsetPtr;247248R.Size = E.getSigned(&OffsetPtr, sizeof(int32_t));249if (PreReadOffset == OffsetPtr)250return createStringError(251std::make_error_code(std::errc::invalid_argument),252"Cannot read a typed event record size field offset %" PRId64 ".",253OffsetPtr);254255if (R.Size <= 0)256return createStringError(257std::make_error_code(std::errc::bad_address),258"Invalid size for typed event (size = %d) at offset %" PRId64 ".",259R.Size, OffsetPtr);260261PreReadOffset = OffsetPtr;262R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));263if (PreReadOffset == OffsetPtr)264return createStringError(265std::make_error_code(std::errc::invalid_argument),266"Cannot read a typed event record TSC delta field at offset "267"%" PRId64 ".",268OffsetPtr);269270PreReadOffset = OffsetPtr;271R.EventType = E.getU16(&OffsetPtr);272if (PreReadOffset == OffsetPtr)273return createStringError(274std::make_error_code(std::errc::invalid_argument),275"Cannot read a typed event record type field at offset %" PRId64 ".",276OffsetPtr);277278assert(OffsetPtr > BeginOffset &&279OffsetPtr - BeginOffset <= MetadataRecord::kMetadataBodySize);280OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - BeginOffset);281282// Next we read in a fixed chunk of data from the given offset.283if (!E.isValidOffsetForDataOfSize(OffsetPtr, R.Size))284return createStringError(285std::make_error_code(std::errc::bad_address),286"Cannot read %d bytes of custom event data from offset %" PRId64 ".",287R.Size, OffsetPtr);288289std::vector<uint8_t> Buffer;290Buffer.resize(R.Size);291PreReadOffset = OffsetPtr;292if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())293return createStringError(294std::make_error_code(std::errc::invalid_argument),295"Failed reading data into buffer of size %d at offset %" PRId64 ".",296R.Size, OffsetPtr);297298assert(OffsetPtr >= PreReadOffset);299if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))300return createStringError(301std::make_error_code(std::errc::invalid_argument),302"Failed reading enough bytes for the typed event payload -- read "303"%" PRId64 " expecting %d bytes at offset %" PRId64 ".",304OffsetPtr - PreReadOffset, R.Size, PreReadOffset);305306R.Data.assign(Buffer.begin(), Buffer.end());307return Error::success();308}309310Error RecordInitializer::visit(CallArgRecord &R) {311if (!E.isValidOffsetForDataOfSize(OffsetPtr,312MetadataRecord::kMetadataBodySize))313return createStringError(314std::make_error_code(std::errc::bad_address),315"Invalid offset for a call argument record (%" PRId64 ").",316OffsetPtr);317318auto PreReadOffset = OffsetPtr;319R.Arg = E.getU64(&OffsetPtr);320if (PreReadOffset == OffsetPtr)321return createStringError(322std::make_error_code(std::errc::invalid_argument),323"Cannot read a call arg record at offset %" PRId64 ".", OffsetPtr);324325OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);326return Error::success();327}328329Error RecordInitializer::visit(PIDRecord &R) {330if (!E.isValidOffsetForDataOfSize(OffsetPtr,331MetadataRecord::kMetadataBodySize))332return createStringError(333std::make_error_code(std::errc::bad_address),334"Invalid offset for a process ID record (%" PRId64 ").", OffsetPtr);335336auto PreReadOffset = OffsetPtr;337R.PID = E.getSigned(&OffsetPtr, 4);338if (PreReadOffset == OffsetPtr)339return createStringError(340std::make_error_code(std::errc::invalid_argument),341"Cannot read a process ID record at offset %" PRId64 ".", OffsetPtr);342343OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);344return Error::success();345}346347Error RecordInitializer::visit(NewBufferRecord &R) {348if (!E.isValidOffsetForDataOfSize(OffsetPtr,349MetadataRecord::kMetadataBodySize))350return createStringError(351std::make_error_code(std::errc::bad_address),352"Invalid offset for a new buffer record (%" PRId64 ").", OffsetPtr);353354auto PreReadOffset = OffsetPtr;355R.TID = E.getSigned(&OffsetPtr, sizeof(int32_t));356if (PreReadOffset == OffsetPtr)357return createStringError(358std::make_error_code(std::errc::invalid_argument),359"Cannot read a new buffer record at offset %" PRId64 ".", OffsetPtr);360361OffsetPtr += MetadataRecord::kMetadataBodySize - (OffsetPtr - PreReadOffset);362return Error::success();363}364365Error RecordInitializer::visit(EndBufferRecord &R) {366if (!E.isValidOffsetForDataOfSize(OffsetPtr,367MetadataRecord::kMetadataBodySize))368return createStringError(369std::make_error_code(std::errc::bad_address),370"Invalid offset for an end-of-buffer record (%" PRId64 ").",371OffsetPtr);372373OffsetPtr += MetadataRecord::kMetadataBodySize;374return Error::success();375}376377Error RecordInitializer::visit(FunctionRecord &R) {378// For function records, we need to retreat one byte back to read a full379// unsigned 32-bit value. The first four bytes will have the following380// layout:381//382// bit 0 : function record indicator (must be 0)383// bits 1..3 : function record type384// bits 4..32 : function id385//386if (OffsetPtr == 0 || !E.isValidOffsetForDataOfSize(387--OffsetPtr, FunctionRecord::kFunctionRecordSize))388return createStringError(389std::make_error_code(std::errc::bad_address),390"Invalid offset for a function record (%" PRId64 ").", OffsetPtr);391392auto BeginOffset = OffsetPtr;393auto PreReadOffset = BeginOffset;394uint32_t Buffer = E.getU32(&OffsetPtr);395if (PreReadOffset == OffsetPtr)396return createStringError(397std::make_error_code(std::errc::bad_address),398"Cannot read function id field from offset %" PRId64 ".", OffsetPtr);399400// To get the function record type, we shift the buffer one to the right401// (truncating the function record indicator) then take the three bits402// (0b0111) to get the record type as an unsigned value.403unsigned FunctionType = (Buffer >> 1) & 0x07u;404switch (FunctionType) {405case static_cast<unsigned>(RecordTypes::ENTER):406case static_cast<unsigned>(RecordTypes::ENTER_ARG):407case static_cast<unsigned>(RecordTypes::EXIT):408case static_cast<unsigned>(RecordTypes::TAIL_EXIT):409R.Kind = static_cast<RecordTypes>(FunctionType);410break;411default:412return createStringError(413std::make_error_code(std::errc::invalid_argument),414"Unknown function record type '%d' at offset %" PRId64 ".",415FunctionType, BeginOffset);416}417418R.FuncId = Buffer >> 4;419PreReadOffset = OffsetPtr;420R.Delta = E.getU32(&OffsetPtr);421if (OffsetPtr == PreReadOffset)422return createStringError(423std::make_error_code(std::errc::invalid_argument),424"Failed reading TSC delta from offset %" PRId64 ".", OffsetPtr);425assert(FunctionRecord::kFunctionRecordSize == (OffsetPtr - BeginOffset));426return Error::success();427}428429} // namespace xray430} // namespace llvm431432433