692 lines · cpp
1//===-- xray_interface.cpp --------------------------------------*- C++ -*-===//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//9// This file is a part of XRay, a dynamic runtime instrumentation system.10//11// Implementation of the API functions.12//13//===----------------------------------------------------------------------===//14 15#include "xray_interface_internal.h"16 17#include <cinttypes>18#include <cstdio>19#include <errno.h>20#include <limits>21#include <string.h>22#include <sys/mman.h>23 24#if SANITIZER_FUCHSIA25#include <zircon/process.h>26#include <zircon/sanitizer.h>27#include <zircon/status.h>28#include <zircon/syscalls.h>29#endif30 31#include "sanitizer_common/sanitizer_addrhashmap.h"32#include "sanitizer_common/sanitizer_common.h"33 34#include "xray_defs.h"35#include "xray_flags.h"36 37extern __sanitizer::SpinMutex XRayInstrMapMutex;38extern __sanitizer::atomic_uint8_t XRayInitialized;39extern __xray::XRaySledMap *XRayInstrMaps;40extern __sanitizer::atomic_uint32_t XRayNumObjects;41 42namespace __xray {43 44#if defined(__x86_64__)45static const int16_t cSledLength = 12;46#elif defined(__aarch64__)47static const int16_t cSledLength = 32;48#elif defined(__arm__)49static const int16_t cSledLength = 28;50#elif SANITIZER_LOONGARCH6451static const int16_t cSledLength = 48;52#elif SANITIZER_MIPS3253static const int16_t cSledLength = 48;54#elif SANITIZER_MIPS6455static const int16_t cSledLength = 64;56#elif defined(__powerpc64__)57static const int16_t cSledLength = 8;58#elif defined(__hexagon__)59static const int16_t cSledLength = 20;60#elif defined(__riscv) && (__riscv_xlen == 64)61static const int16_t cSledLength = 68;62#elif defined(__riscv) && (__riscv_xlen == 32)63static const int16_t cSledLength = 52;64#elif defined(__s390x__)65static const int16_t cSledLength = 18;66#else67#error "Unsupported CPU Architecture"68#endif /* CPU architecture */69 70// This is the function to call when we encounter the entry or exit sleds.71atomic_uintptr_t XRayPatchedFunction SANITIZER_INTERFACE_ATTRIBUTE{0};72 73// This is the function to call from the arg1-enabled sleds/trampolines.74atomic_uintptr_t XRayArgLogger SANITIZER_INTERFACE_ATTRIBUTE{0};75 76// This is the function to call when we encounter a custom event log call.77atomic_uintptr_t XRayPatchedCustomEvent SANITIZER_INTERFACE_ATTRIBUTE{0};78 79// This is the function to call when we encounter a typed event log call.80atomic_uintptr_t XRayPatchedTypedEvent SANITIZER_INTERFACE_ATTRIBUTE{0};81 82// This is the global status to determine whether we are currently83// patching/unpatching.84atomic_uint8_t XRayPatching{0};85 86struct TypeDescription {87 uint32_t type_id;88 std::size_t description_string_length;89};90 91using TypeDescriptorMapType = AddrHashMap<TypeDescription, 11>;92// An address map from immutable descriptors to type ids.93TypeDescriptorMapType TypeDescriptorAddressMap{};94 95atomic_uint32_t TypeEventDescriptorCounter{0};96 97// MProtectHelper is an RAII wrapper for calls to mprotect(...) that will98// undo any successful mprotect(...) changes. This is used to make a page99// writeable and executable, and upon destruction if it was successful in100// doing so returns the page into a read-only and executable page.101//102// This is only used specifically for runtime-patching of the XRay103// instrumentation points. This assumes that the executable pages are104// originally read-and-execute only.105class MProtectHelper {106 void *PageAlignedAddr;107 std::size_t MProtectLen;108 bool MustCleanup;109 110public:111 explicit MProtectHelper(void *PageAlignedAddr,112 std::size_t MProtectLen,113 std::size_t PageSize) XRAY_NEVER_INSTRUMENT114 : PageAlignedAddr(PageAlignedAddr),115 MProtectLen(MProtectLen),116 MustCleanup(false) {117#if SANITIZER_FUCHSIA118 MProtectLen = RoundUpTo(MProtectLen, PageSize);119#endif120 }121 122 int MakeWriteable() XRAY_NEVER_INSTRUMENT {123#if SANITIZER_FUCHSIA124 auto R = __sanitizer_change_code_protection(125 reinterpret_cast<uintptr_t>(PageAlignedAddr), MProtectLen, true);126 if (R != ZX_OK) {127 Report("XRay: cannot change code protection: %s\n",128 _zx_status_get_string(R));129 return -1;130 }131 MustCleanup = true;132 return 0;133#else134 auto R = mprotect(PageAlignedAddr, MProtectLen,135 PROT_READ | PROT_WRITE | PROT_EXEC);136 if (R != -1)137 MustCleanup = true;138 return R;139#endif140 }141 142 ~MProtectHelper() XRAY_NEVER_INSTRUMENT {143 if (MustCleanup) {144#if SANITIZER_FUCHSIA145 auto R = __sanitizer_change_code_protection(146 reinterpret_cast<uintptr_t>(PageAlignedAddr), MProtectLen, false);147 if (R != ZX_OK) {148 Report("XRay: cannot change code protection: %s\n",149 _zx_status_get_string(R));150 }151#else152 mprotect(PageAlignedAddr, MProtectLen, PROT_READ | PROT_EXEC);153#endif154 }155 }156};157 158namespace {159 160bool isObjectLoaded(int32_t ObjId) {161 SpinMutexLock Guard(&XRayInstrMapMutex);162 if (ObjId < 0 || static_cast<uint32_t>(ObjId) >=163 atomic_load(&XRayNumObjects, memory_order_acquire)) {164 return false;165 }166 return XRayInstrMaps[ObjId].Loaded;167}168 169bool patchSled(const XRaySledEntry &Sled, bool Enable, int32_t FuncId,170 const XRayTrampolines &Trampolines) XRAY_NEVER_INSTRUMENT {171 bool Success = false;172 switch (Sled.Kind) {173 case XRayEntryType::ENTRY:174 Success = patchFunctionEntry(Enable, FuncId, Sled, Trampolines,175 /*LogArgs=*/false);176 break;177 case XRayEntryType::EXIT:178 Success = patchFunctionExit(Enable, FuncId, Sled, Trampolines);179 break;180 case XRayEntryType::TAIL:181 Success = patchFunctionTailExit(Enable, FuncId, Sled, Trampolines);182 break;183 case XRayEntryType::LOG_ARGS_ENTRY:184 Success = patchFunctionEntry(Enable, FuncId, Sled, Trampolines,185 /*LogArgs=*/true);186 break;187 case XRayEntryType::CUSTOM_EVENT:188 Success = patchCustomEvent(Enable, FuncId, Sled);189 break;190 case XRayEntryType::TYPED_EVENT:191 Success = patchTypedEvent(Enable, FuncId, Sled);192 break;193 default:194 Report("Unsupported sled kind '%" PRIu64 "' @%04x\n", Sled.Address,195 int(Sled.Kind));196 return false;197 }198 return Success;199}200 201const XRayFunctionSledIndex202findFunctionSleds(int32_t FuncId,203 const XRaySledMap &InstrMap) XRAY_NEVER_INSTRUMENT {204 int32_t CurFn = 0;205 uint64_t LastFnAddr = 0;206 XRayFunctionSledIndex Index = {nullptr, 0};207 208 for (std::size_t I = 0; I < InstrMap.Entries && CurFn <= FuncId; I++) {209 const auto &Sled = InstrMap.Sleds[I];210 const auto Function = Sled.function();211 if (Function != LastFnAddr) {212 CurFn++;213 LastFnAddr = Function;214 }215 216 if (CurFn == FuncId) {217 if (Index.Begin == nullptr)218 Index.Begin = &Sled;219 Index.Size = &Sled - Index.Begin + 1;220 }221 }222 223 return Index;224}225 226XRayPatchingStatus patchFunction(int32_t FuncId, int32_t ObjId,227 bool Enable) XRAY_NEVER_INSTRUMENT {228 if (!atomic_load(&XRayInitialized, memory_order_acquire))229 return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.230 231 uint8_t NotPatching = false;232 if (!atomic_compare_exchange_strong(233 &XRayPatching, &NotPatching, true, memory_order_acq_rel))234 return XRayPatchingStatus::ONGOING; // Already patching.235 236 // Next, we look for the function index.237 XRaySledMap InstrMap;238 {239 SpinMutexLock Guard(&XRayInstrMapMutex);240 if (ObjId < 0 || static_cast<uint32_t>(ObjId) >=241 atomic_load(&XRayNumObjects, memory_order_acquire)) {242 Report("Unable to patch function: invalid sled map index: %d", ObjId);243 return XRayPatchingStatus::FAILED;244 }245 InstrMap = XRayInstrMaps[ObjId];246 }247 248 // If we don't have an index, we can't patch individual functions.249 if (InstrMap.Functions == 0)250 return XRayPatchingStatus::NOT_INITIALIZED;251 252 // Check if the corresponding DSO has been unloaded.253 if (!InstrMap.Loaded) {254 Report("Invalid function id provided: %d\n", FuncId);255 return XRayPatchingStatus::NOT_INITIALIZED;256 }257 258 // FuncId must be a positive number, less than the number of functions259 // instrumented.260 if (FuncId <= 0 || static_cast<size_t>(FuncId) > InstrMap.Functions) {261 Report("Invalid function id provided: %d\n", FuncId);262 return XRayPatchingStatus::FAILED;263 }264 265 auto PackedId = __xray::MakePackedId(FuncId, ObjId);266 267 // Now we patch ths sleds for this specific function.268 XRayFunctionSledIndex SledRange;269 if (InstrMap.SledsIndex) {270 SledRange = {InstrMap.SledsIndex[FuncId - 1].fromPCRelative(),271 InstrMap.SledsIndex[FuncId - 1].Size};272 } else {273 SledRange = findFunctionSleds(FuncId, InstrMap);274 }275 276 auto *f = SledRange.Begin;277 bool SucceedOnce = false;278 for (size_t i = 0; i != SledRange.Size; ++i)279 SucceedOnce |= patchSled(f[i], Enable, PackedId, InstrMap.Trampolines);280 281 atomic_store(&XRayPatching, false, memory_order_release);282 283 if (!SucceedOnce) {284 Report("Failed patching any sled for function '%d'.", FuncId);285 return XRayPatchingStatus::FAILED;286 }287 288 return XRayPatchingStatus::SUCCESS;289}290 291// controlPatching implements the common internals of the patching/unpatching292// implementation. |Enable| defines whether we're enabling or disabling the293// runtime XRay instrumentation.294// This function should only be called after ensuring that XRay is initialized295// and no other thread is currently patching.296XRayPatchingStatus controlPatchingObjectUnchecked(bool Enable, int32_t ObjId) {297 XRaySledMap InstrMap;298 {299 SpinMutexLock Guard(&XRayInstrMapMutex);300 if (ObjId < 0 || static_cast<uint32_t>(ObjId) >=301 atomic_load(&XRayNumObjects, memory_order_acquire)) {302 Report("Unable to patch functions: invalid sled map index: %d\n", ObjId);303 return XRayPatchingStatus::FAILED;304 }305 InstrMap = XRayInstrMaps[ObjId];306 }307 if (InstrMap.Entries == 0)308 return XRayPatchingStatus::NOT_INITIALIZED;309 310 if (Verbosity())311 Report("Patching object %d with %d functions.\n", ObjId,312 (int)InstrMap.Entries);313 314 // Check if the corresponding DSO has been unloaded.315 if (!InstrMap.Loaded) {316 Report("Object is not loaded at index: %d\n", ObjId);317 return XRayPatchingStatus::FAILED;318 }319 320 uint32_t FuncId = 1;321 uint64_t CurFun = 0;322 323 // First we want to find the bounds for which we have instrumentation points,324 // and try to get as few calls to mprotect(...) as possible. We're assuming325 // that all the sleds for the instrumentation map are contiguous as a single326 // set of pages. When we do support dynamic shared object instrumentation,327 // we'll need to do this for each set of page load offsets per DSO loaded. For328 // now we're assuming we can mprotect the whole section of text between the329 // minimum sled address and the maximum sled address (+ the largest sled330 // size).331 auto *MinSled = &InstrMap.Sleds[0];332 auto *MaxSled = &InstrMap.Sleds[InstrMap.Entries - 1];333 for (std::size_t I = 0; I < InstrMap.Entries; I++) {334 const auto &Sled = InstrMap.Sleds[I];335 if (Sled.address() < MinSled->address())336 MinSled = &Sled;337 if (Sled.address() > MaxSled->address())338 MaxSled = &Sled;339 }340 341 const size_t PageSize = flags()->xray_page_size_override > 0342 ? flags()->xray_page_size_override343 : GetPageSizeCached();344 if ((PageSize == 0) || ((PageSize & (PageSize - 1)) != 0)) {345 Report("System page size is not a power of two: %zu\n", PageSize);346 return XRayPatchingStatus::FAILED;347 }348 349 void *PageAlignedAddr =350 reinterpret_cast<void *>(MinSled->address() & ~(PageSize - 1));351 size_t MProtectLen =352 (MaxSled->address() - reinterpret_cast<uptr>(PageAlignedAddr)) +353 cSledLength;354 MProtectHelper Protector(PageAlignedAddr, MProtectLen, PageSize);355 if (Protector.MakeWriteable() == -1) {356 Report("Failed mprotect: %d\n", errno);357 return XRayPatchingStatus::FAILED;358 }359 360 for (std::size_t I = 0; I < InstrMap.Entries; ++I) {361 auto &Sled = InstrMap.Sleds[I];362 auto F = Sled.function();363 if (CurFun == 0)364 CurFun = F;365 if (F != CurFun) {366 ++FuncId;367 CurFun = F;368 }369 auto PackedId = __xray::MakePackedId(FuncId, ObjId);370 patchSled(Sled, Enable, PackedId, InstrMap.Trampolines);371 }372 atomic_store(&XRayPatching, false, memory_order_release);373 return XRayPatchingStatus::SUCCESS;374}375 376// Controls patching for all registered objects.377// Returns: SUCCESS, if patching succeeds for all objects.378// NOT_INITIALIZED, if one or more objects returned NOT_INITIALIZED379// but none failed.380// FAILED, if patching of one or more objects failed.381XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT {382 if (!atomic_load(&XRayInitialized, memory_order_acquire))383 return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.384 385 uint8_t NotPatching = false;386 if (!atomic_compare_exchange_strong(&XRayPatching, &NotPatching, true,387 memory_order_acq_rel))388 return XRayPatchingStatus::ONGOING; // Already patching.389 390 auto XRayPatchingStatusResetter = at_scope_exit(391 [] { atomic_store(&XRayPatching, false, memory_order_release); });392 393 unsigned NumObjects = __xray_num_objects();394 395 XRayPatchingStatus CombinedStatus{NOT_INITIALIZED};396 for (unsigned I = 0; I < NumObjects; ++I) {397 if (!isObjectLoaded(I))398 continue;399 auto LastStatus = controlPatchingObjectUnchecked(Enable, I);400 switch (LastStatus) {401 case SUCCESS:402 if (CombinedStatus == NOT_INITIALIZED)403 CombinedStatus = SUCCESS;404 break;405 case FAILED:406 // Report failure, but try to patch the remaining objects407 CombinedStatus = FAILED;408 break;409 case NOT_INITIALIZED:410 // XRay has been initialized but there are no sleds available for this411 // object. Try to patch remaining objects.412 if (CombinedStatus != FAILED)413 CombinedStatus = NOT_INITIALIZED;414 break;415 case ONGOING:416 UNREACHABLE("Status ONGOING should not appear at this point");417 }418 }419 return CombinedStatus;420}421 422// Controls patching for one object.423XRayPatchingStatus controlPatching(bool Enable,424 int32_t ObjId) XRAY_NEVER_INSTRUMENT {425 426 if (!atomic_load(&XRayInitialized, memory_order_acquire))427 return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized.428 429 uint8_t NotPatching = false;430 if (!atomic_compare_exchange_strong(&XRayPatching, &NotPatching, true,431 memory_order_acq_rel))432 return XRayPatchingStatus::ONGOING; // Already patching.433 434 auto XRayPatchingStatusResetter = at_scope_exit(435 [] { atomic_store(&XRayPatching, false, memory_order_release); });436 437 return controlPatchingObjectUnchecked(Enable, ObjId);438}439 440XRayPatchingStatus mprotectAndPatchFunction(int32_t FuncId, int32_t ObjId,441 bool Enable) XRAY_NEVER_INSTRUMENT {442 XRaySledMap InstrMap;443 {444 SpinMutexLock Guard(&XRayInstrMapMutex);445 if (ObjId < 0 || static_cast<uint32_t>(ObjId) >=446 atomic_load(&XRayNumObjects, memory_order_acquire)) {447 Report("Unable to patch function: invalid sled map index: %d\n", ObjId);448 return XRayPatchingStatus::FAILED;449 }450 InstrMap = XRayInstrMaps[ObjId];451 }452 453 // Check if the corresponding DSO has been unloaded.454 if (!InstrMap.Loaded) {455 Report("Object is not loaded at index: %d\n", ObjId);456 return XRayPatchingStatus::FAILED;457 }458 459 // FuncId must be a positive number, less than the number of functions460 // instrumented.461 if (FuncId <= 0 || static_cast<size_t>(FuncId) > InstrMap.Functions) {462 Report("Invalid function id provided: %d\n", FuncId);463 return XRayPatchingStatus::FAILED;464 }465 466 const size_t PageSize = flags()->xray_page_size_override > 0467 ? flags()->xray_page_size_override468 : GetPageSizeCached();469 if ((PageSize == 0) || ((PageSize & (PageSize - 1)) != 0)) {470 Report("Provided page size is not a power of two: %zu\n", PageSize);471 return XRayPatchingStatus::FAILED;472 }473 474 // Here we compute the minimum sled and maximum sled associated with a475 // particular function ID.476 XRayFunctionSledIndex SledRange;477 if (InstrMap.SledsIndex) {478 SledRange = {InstrMap.SledsIndex[FuncId - 1].fromPCRelative(),479 InstrMap.SledsIndex[FuncId - 1].Size};480 } else {481 SledRange = findFunctionSleds(FuncId, InstrMap);482 }483 auto *f = SledRange.Begin;484 auto *e = SledRange.Begin + SledRange.Size;485 auto *MinSled = f;486 auto *MaxSled = e - 1;487 while (f != e) {488 if (f->address() < MinSled->address())489 MinSled = f;490 if (f->address() > MaxSled->address())491 MaxSled = f;492 ++f;493 }494 495 void *PageAlignedAddr =496 reinterpret_cast<void *>(MinSled->address() & ~(PageSize - 1));497 size_t MProtectLen =498 (MaxSled->address() - reinterpret_cast<uptr>(PageAlignedAddr)) +499 cSledLength;500 MProtectHelper Protector(PageAlignedAddr, MProtectLen, PageSize);501 if (Protector.MakeWriteable() == -1) {502 Report("Failed mprotect: %d\n", errno);503 return XRayPatchingStatus::FAILED;504 }505 return patchFunction(FuncId, ObjId, Enable);506}507 508} // namespace509 510} // namespace __xray511 512using namespace __xray;513 514// The following functions are declared `extern "C" {...}` in the header, hence515// they're defined in the global namespace.516 517int __xray_set_handler(void (*entry)(int32_t,518 XRayEntryType)) XRAY_NEVER_INSTRUMENT {519 if (atomic_load(&XRayInitialized, memory_order_acquire)) {520 521 atomic_store(&__xray::XRayPatchedFunction,522 reinterpret_cast<uintptr_t>(entry), memory_order_release);523 return 1;524 }525 return 0;526}527 528int __xray_set_customevent_handler(void (*entry)(void *, size_t))529 XRAY_NEVER_INSTRUMENT {530 if (atomic_load(&XRayInitialized, memory_order_acquire)) {531 atomic_store(&__xray::XRayPatchedCustomEvent,532 reinterpret_cast<uintptr_t>(entry), memory_order_release);533 return 1;534 }535 return 0;536}537 538int __xray_set_typedevent_handler(void (*entry)(size_t, const void *,539 size_t)) XRAY_NEVER_INSTRUMENT {540 if (atomic_load(&XRayInitialized, memory_order_acquire)) {541 atomic_store(&__xray::XRayPatchedTypedEvent,542 reinterpret_cast<uintptr_t>(entry), memory_order_release);543 return 1;544 }545 return 0;546}547 548int __xray_remove_handler() XRAY_NEVER_INSTRUMENT {549 return __xray_set_handler(nullptr);550}551 552int __xray_remove_customevent_handler() XRAY_NEVER_INSTRUMENT {553 return __xray_set_customevent_handler(nullptr);554}555 556int __xray_remove_typedevent_handler() XRAY_NEVER_INSTRUMENT {557 return __xray_set_typedevent_handler(nullptr);558}559 560uint16_t __xray_register_event_type(561 const char *const event_type) XRAY_NEVER_INSTRUMENT {562 TypeDescriptorMapType::Handle h(&TypeDescriptorAddressMap, (uptr)event_type);563 if (h.created()) {564 h->type_id = atomic_fetch_add(565 &TypeEventDescriptorCounter, 1, memory_order_acq_rel);566 h->description_string_length = strnlen(event_type, 1024);567 }568 return h->type_id;569}570 571XRayPatchingStatus __xray_patch() XRAY_NEVER_INSTRUMENT {572 return controlPatching(true);573}574 575XRayPatchingStatus __xray_patch_object(int32_t ObjId) XRAY_NEVER_INSTRUMENT {576 return controlPatching(true, ObjId);577}578 579XRayPatchingStatus __xray_unpatch() XRAY_NEVER_INSTRUMENT {580 return controlPatching(false);581}582 583XRayPatchingStatus __xray_unpatch_object(int32_t ObjId) XRAY_NEVER_INSTRUMENT {584 return controlPatching(false, ObjId);585}586 587XRayPatchingStatus __xray_patch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT {588 auto Ids = __xray::UnpackId(FuncId);589 auto ObjId = Ids.first;590 auto FnId = Ids.second;591 return mprotectAndPatchFunction(FnId, ObjId, true);592}593 594XRayPatchingStatus595__xray_patch_function_in_object(int32_t FuncId,596 int32_t ObjId) XRAY_NEVER_INSTRUMENT {597 return mprotectAndPatchFunction(FuncId, ObjId, true);598}599 600XRayPatchingStatus601__xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT {602 auto Ids = __xray::UnpackId(FuncId);603 auto ObjId = Ids.first;604 auto FnId = Ids.second;605 return mprotectAndPatchFunction(FnId, ObjId, false);606}607 608XRayPatchingStatus609__xray_unpatch_function_in_object(int32_t FuncId,610 int32_t ObjId) XRAY_NEVER_INSTRUMENT {611 return mprotectAndPatchFunction(FuncId, ObjId, false);612}613 614int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType, uint64_t)) {615 if (!atomic_load(&XRayInitialized, memory_order_acquire))616 return 0;617 618 // A relaxed write might not be visible even if the current thread gets619 // scheduled on a different CPU/NUMA node. We need to wait for everyone to620 // have this handler installed for consistency of collected data across CPUs.621 atomic_store(&XRayArgLogger, reinterpret_cast<uint64_t>(entry),622 memory_order_release);623 return 1;624}625 626int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); }627 628uintptr_t629__xray_function_address(int32_t CombinedFuncId) XRAY_NEVER_INSTRUMENT {630 auto Ids = __xray::UnpackId(CombinedFuncId);631 return __xray_function_address_in_object(Ids.second, Ids.first);632}633 634uintptr_t __xray_function_address_in_object(int32_t FuncId, int32_t ObjId)635 XRAY_NEVER_INSTRUMENT {636 XRaySledMap InstrMap;637 {638 SpinMutexLock Guard(&XRayInstrMapMutex);639 auto count = atomic_load(&XRayNumObjects, memory_order_acquire);640 if (ObjId < 0 || static_cast<uint32_t>(ObjId) >= count) {641 Report("Unable to determine function address: invalid sled map index %d "642 "(size is %d)\n",643 ObjId, (int)count);644 return 0;645 }646 InstrMap = XRayInstrMaps[ObjId];647 }648 649 if (FuncId <= 0 || static_cast<size_t>(FuncId) > InstrMap.Functions)650 return 0;651 const XRaySledEntry *Sled =652 InstrMap.SledsIndex ? InstrMap.SledsIndex[FuncId - 1].fromPCRelative()653 : findFunctionSleds(FuncId, InstrMap).Begin;654 return Sled->function()655// On PPC, function entries are always aligned to 16 bytes. The beginning of a656// sled might be a local entry, which is always +8 based on the global entry.657// Always return the global entry.658#ifdef __PPC__659 & ~0xf660#endif661 ;662}663 664size_t __xray_max_function_id() XRAY_NEVER_INSTRUMENT {665 return __xray_max_function_id_in_object(0);666}667 668size_t __xray_max_function_id_in_object(int32_t ObjId) XRAY_NEVER_INSTRUMENT {669 SpinMutexLock Guard(&XRayInstrMapMutex);670 if (ObjId < 0 || static_cast<uint32_t>(ObjId) >=671 atomic_load(&XRayNumObjects, memory_order_acquire))672 return 0;673 return XRayInstrMaps[ObjId].Functions;674}675 676size_t __xray_num_objects() XRAY_NEVER_INSTRUMENT {677 SpinMutexLock Guard(&XRayInstrMapMutex);678 return atomic_load(&XRayNumObjects, memory_order_acquire);679}680 681int32_t __xray_unpack_function_id(int32_t PackedId) {682 return __xray::UnpackId(PackedId).second;683}684 685int32_t __xray_unpack_object_id(int32_t PackedId) {686 return __xray::UnpackId(PackedId).first;687}688 689int32_t __xray_pack_id(int32_t FuncId, int32_t ObjId) {690 return __xray::MakePackedId(FuncId, ObjId);691}692