1 //===-- xray_interface.cpp --------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of XRay, a dynamic runtime instrumentation system.
11 // Implementation of the API functions.
13 //===----------------------------------------------------------------------===//
15 #include "xray_interface_internal.h"
25 #include <zircon/process.h>
26 #include <zircon/sanitizer.h>
27 #include <zircon/status.h>
28 #include <zircon/syscalls.h>
31 #include "sanitizer_common/sanitizer_addrhashmap.h"
32 #include "sanitizer_common/sanitizer_common.h"
34 #include "xray_defs.h"
35 #include "xray_flags.h"
37 extern __sanitizer::SpinMutex XRayInstrMapMutex
;
38 extern __sanitizer::atomic_uint8_t XRayInitialized
;
39 extern __xray::XRaySledMap
*XRayInstrMaps
;
40 extern __sanitizer::atomic_uint32_t XRayNumObjects
;
44 #if defined(__x86_64__)
45 static const int16_t cSledLength
= 12;
46 #elif defined(__aarch64__)
47 static const int16_t cSledLength
= 32;
48 #elif defined(__arm__)
49 static const int16_t cSledLength
= 28;
50 #elif SANITIZER_LOONGARCH64
51 static const int16_t cSledLength
= 48;
52 #elif SANITIZER_MIPS32
53 static const int16_t cSledLength
= 48;
54 #elif SANITIZER_MIPS64
55 static const int16_t cSledLength
= 64;
56 #elif defined(__powerpc64__)
57 static const int16_t cSledLength
= 8;
58 #elif defined(__hexagon__)
59 static const int16_t cSledLength
= 20;
60 #elif defined(__riscv) && (__riscv_xlen == 64)
61 static const int16_t cSledLength
= 68;
62 #elif defined(__riscv) && (__riscv_xlen == 32)
63 static const int16_t cSledLength
= 52;
65 #error "Unsupported CPU Architecture"
66 #endif /* CPU architecture */
68 // This is the function to call when we encounter the entry or exit sleds.
69 atomic_uintptr_t XRayPatchedFunction SANITIZER_INTERFACE_ATTRIBUTE
{0};
71 // This is the function to call from the arg1-enabled sleds/trampolines.
72 atomic_uintptr_t XRayArgLogger SANITIZER_INTERFACE_ATTRIBUTE
{0};
74 // This is the function to call when we encounter a custom event log call.
75 atomic_uintptr_t XRayPatchedCustomEvent SANITIZER_INTERFACE_ATTRIBUTE
{0};
77 // This is the function to call when we encounter a typed event log call.
78 atomic_uintptr_t XRayPatchedTypedEvent SANITIZER_INTERFACE_ATTRIBUTE
{0};
80 // This is the global status to determine whether we are currently
81 // patching/unpatching.
82 atomic_uint8_t XRayPatching
{0};
84 struct TypeDescription
{
86 std::size_t description_string_length
;
89 using TypeDescriptorMapType
= AddrHashMap
<TypeDescription
, 11>;
90 // An address map from immutable descriptors to type ids.
91 TypeDescriptorMapType TypeDescriptorAddressMap
{};
93 atomic_uint32_t TypeEventDescriptorCounter
{0};
95 // MProtectHelper is an RAII wrapper for calls to mprotect(...) that will
96 // undo any successful mprotect(...) changes. This is used to make a page
97 // writeable and executable, and upon destruction if it was successful in
98 // doing so returns the page into a read-only and executable page.
100 // This is only used specifically for runtime-patching of the XRay
101 // instrumentation points. This assumes that the executable pages are
102 // originally read-and-execute only.
103 class MProtectHelper
{
104 void *PageAlignedAddr
;
105 std::size_t MProtectLen
;
109 explicit MProtectHelper(void *PageAlignedAddr
,
110 std::size_t MProtectLen
,
111 std::size_t PageSize
) XRAY_NEVER_INSTRUMENT
112 : PageAlignedAddr(PageAlignedAddr
),
113 MProtectLen(MProtectLen
),
115 #if SANITIZER_FUCHSIA
116 MProtectLen
= RoundUpTo(MProtectLen
, PageSize
);
120 int MakeWriteable() XRAY_NEVER_INSTRUMENT
{
121 #if SANITIZER_FUCHSIA
122 auto R
= __sanitizer_change_code_protection(
123 reinterpret_cast<uintptr_t>(PageAlignedAddr
), MProtectLen
, true);
125 Report("XRay: cannot change code protection: %s\n",
126 _zx_status_get_string(R
));
132 auto R
= mprotect(PageAlignedAddr
, MProtectLen
,
133 PROT_READ
| PROT_WRITE
| PROT_EXEC
);
140 ~MProtectHelper() XRAY_NEVER_INSTRUMENT
{
142 #if SANITIZER_FUCHSIA
143 auto R
= __sanitizer_change_code_protection(
144 reinterpret_cast<uintptr_t>(PageAlignedAddr
), MProtectLen
, false);
146 Report("XRay: cannot change code protection: %s\n",
147 _zx_status_get_string(R
));
150 mprotect(PageAlignedAddr
, MProtectLen
, PROT_READ
| PROT_EXEC
);
158 bool isObjectLoaded(int32_t ObjId
) {
159 SpinMutexLock
Guard(&XRayInstrMapMutex
);
160 if (ObjId
< 0 || static_cast<uint32_t>(ObjId
) >=
161 atomic_load(&XRayNumObjects
, memory_order_acquire
)) {
164 return XRayInstrMaps
[ObjId
].Loaded
;
167 bool patchSled(const XRaySledEntry
&Sled
, bool Enable
, int32_t FuncId
,
168 const XRayTrampolines
&Trampolines
) XRAY_NEVER_INSTRUMENT
{
169 bool Success
= false;
171 case XRayEntryType::ENTRY
:
172 Success
= patchFunctionEntry(Enable
, FuncId
, Sled
, Trampolines
,
175 case XRayEntryType::EXIT
:
176 Success
= patchFunctionExit(Enable
, FuncId
, Sled
, Trampolines
);
178 case XRayEntryType::TAIL
:
179 Success
= patchFunctionTailExit(Enable
, FuncId
, Sled
, Trampolines
);
181 case XRayEntryType::LOG_ARGS_ENTRY
:
182 Success
= patchFunctionEntry(Enable
, FuncId
, Sled
, Trampolines
,
185 case XRayEntryType::CUSTOM_EVENT
:
186 Success
= patchCustomEvent(Enable
, FuncId
, Sled
);
188 case XRayEntryType::TYPED_EVENT
:
189 Success
= patchTypedEvent(Enable
, FuncId
, Sled
);
192 Report("Unsupported sled kind '%" PRIu64
"' @%04x\n", Sled
.Address
,
199 const XRayFunctionSledIndex
200 findFunctionSleds(int32_t FuncId
,
201 const XRaySledMap
&InstrMap
) XRAY_NEVER_INSTRUMENT
{
203 uint64_t LastFnAddr
= 0;
204 XRayFunctionSledIndex Index
= {nullptr, 0};
206 for (std::size_t I
= 0; I
< InstrMap
.Entries
&& CurFn
<= FuncId
; I
++) {
207 const auto &Sled
= InstrMap
.Sleds
[I
];
208 const auto Function
= Sled
.function();
209 if (Function
!= LastFnAddr
) {
211 LastFnAddr
= Function
;
214 if (CurFn
== FuncId
) {
215 if (Index
.Begin
== nullptr)
217 Index
.Size
= &Sled
- Index
.Begin
+ 1;
224 XRayPatchingStatus
patchFunction(int32_t FuncId
, int32_t ObjId
,
225 bool Enable
) XRAY_NEVER_INSTRUMENT
{
226 if (!atomic_load(&XRayInitialized
, memory_order_acquire
))
227 return XRayPatchingStatus::NOT_INITIALIZED
; // Not initialized.
229 uint8_t NotPatching
= false;
230 if (!atomic_compare_exchange_strong(
231 &XRayPatching
, &NotPatching
, true, memory_order_acq_rel
))
232 return XRayPatchingStatus::ONGOING
; // Already patching.
234 // Next, we look for the function index.
235 XRaySledMap InstrMap
;
237 SpinMutexLock
Guard(&XRayInstrMapMutex
);
238 if (ObjId
< 0 || static_cast<uint32_t>(ObjId
) >=
239 atomic_load(&XRayNumObjects
, memory_order_acquire
)) {
240 Report("Unable to patch function: invalid sled map index: %d", ObjId
);
241 return XRayPatchingStatus::FAILED
;
243 InstrMap
= XRayInstrMaps
[ObjId
];
246 // If we don't have an index, we can't patch individual functions.
247 if (InstrMap
.Functions
== 0)
248 return XRayPatchingStatus::NOT_INITIALIZED
;
250 // Check if the corresponding DSO has been unloaded.
251 if (!InstrMap
.Loaded
) {
252 Report("Invalid function id provided: %d\n", FuncId
);
253 return XRayPatchingStatus::NOT_INITIALIZED
;
256 // FuncId must be a positive number, less than the number of functions
258 if (FuncId
<= 0 || static_cast<size_t>(FuncId
) > InstrMap
.Functions
) {
259 Report("Invalid function id provided: %d\n", FuncId
);
260 return XRayPatchingStatus::FAILED
;
263 auto PackedId
= __xray::MakePackedId(FuncId
, ObjId
);
265 // Now we patch ths sleds for this specific function.
266 XRayFunctionSledIndex SledRange
;
267 if (InstrMap
.SledsIndex
) {
268 SledRange
= {InstrMap
.SledsIndex
[FuncId
- 1].fromPCRelative(),
269 InstrMap
.SledsIndex
[FuncId
- 1].Size
};
271 SledRange
= findFunctionSleds(FuncId
, InstrMap
);
274 auto *f
= SledRange
.Begin
;
275 bool SucceedOnce
= false;
276 for (size_t i
= 0; i
!= SledRange
.Size
; ++i
)
277 SucceedOnce
|= patchSled(f
[i
], Enable
, PackedId
, InstrMap
.Trampolines
);
279 atomic_store(&XRayPatching
, false, memory_order_release
);
282 Report("Failed patching any sled for function '%d'.", FuncId
);
283 return XRayPatchingStatus::FAILED
;
286 return XRayPatchingStatus::SUCCESS
;
289 // controlPatching implements the common internals of the patching/unpatching
290 // implementation. |Enable| defines whether we're enabling or disabling the
291 // runtime XRay instrumentation.
292 // This function should only be called after ensuring that XRay is initialized
293 // and no other thread is currently patching.
294 XRayPatchingStatus
controlPatchingObjectUnchecked(bool Enable
, int32_t ObjId
) {
295 XRaySledMap InstrMap
;
297 SpinMutexLock
Guard(&XRayInstrMapMutex
);
298 if (ObjId
< 0 || static_cast<uint32_t>(ObjId
) >=
299 atomic_load(&XRayNumObjects
, memory_order_acquire
)) {
300 Report("Unable to patch functions: invalid sled map index: %d\n", ObjId
);
301 return XRayPatchingStatus::FAILED
;
303 InstrMap
= XRayInstrMaps
[ObjId
];
305 if (InstrMap
.Entries
== 0)
306 return XRayPatchingStatus::NOT_INITIALIZED
;
309 Report("Patching object %d with %d functions.\n", ObjId
, InstrMap
.Entries
);
311 // Check if the corresponding DSO has been unloaded.
312 if (!InstrMap
.Loaded
) {
313 Report("Object is not loaded at index: %d\n", ObjId
);
314 return XRayPatchingStatus::FAILED
;
320 // First we want to find the bounds for which we have instrumentation points,
321 // and try to get as few calls to mprotect(...) as possible. We're assuming
322 // that all the sleds for the instrumentation map are contiguous as a single
323 // set of pages. When we do support dynamic shared object instrumentation,
324 // we'll need to do this for each set of page load offsets per DSO loaded. For
325 // now we're assuming we can mprotect the whole section of text between the
326 // minimum sled address and the maximum sled address (+ the largest sled
328 auto *MinSled
= &InstrMap
.Sleds
[0];
329 auto *MaxSled
= &InstrMap
.Sleds
[InstrMap
.Entries
- 1];
330 for (std::size_t I
= 0; I
< InstrMap
.Entries
; I
++) {
331 const auto &Sled
= InstrMap
.Sleds
[I
];
332 if (Sled
.address() < MinSled
->address())
334 if (Sled
.address() > MaxSled
->address())
338 const size_t PageSize
= flags()->xray_page_size_override
> 0
339 ? flags()->xray_page_size_override
340 : GetPageSizeCached();
341 if ((PageSize
== 0) || ((PageSize
& (PageSize
- 1)) != 0)) {
342 Report("System page size is not a power of two: %zu\n", PageSize
);
343 return XRayPatchingStatus::FAILED
;
346 void *PageAlignedAddr
=
347 reinterpret_cast<void *>(MinSled
->address() & ~(PageSize
- 1));
349 (MaxSled
->address() - reinterpret_cast<uptr
>(PageAlignedAddr
)) +
351 MProtectHelper
Protector(PageAlignedAddr
, MProtectLen
, PageSize
);
352 if (Protector
.MakeWriteable() == -1) {
353 Report("Failed mprotect: %d\n", errno
);
354 return XRayPatchingStatus::FAILED
;
357 for (std::size_t I
= 0; I
< InstrMap
.Entries
; ++I
) {
358 auto &Sled
= InstrMap
.Sleds
[I
];
359 auto F
= Sled
.function();
366 auto PackedId
= __xray::MakePackedId(FuncId
, ObjId
);
367 patchSled(Sled
, Enable
, PackedId
, InstrMap
.Trampolines
);
369 atomic_store(&XRayPatching
, false, memory_order_release
);
370 return XRayPatchingStatus::SUCCESS
;
373 // Controls patching for all registered objects.
374 // Returns: SUCCESS, if patching succeeds for all objects.
375 // NOT_INITIALIZED, if one or more objects returned NOT_INITIALIZED
377 // FAILED, if patching of one or more objects failed.
378 XRayPatchingStatus
controlPatching(bool Enable
) XRAY_NEVER_INSTRUMENT
{
379 if (!atomic_load(&XRayInitialized
, memory_order_acquire
))
380 return XRayPatchingStatus::NOT_INITIALIZED
; // Not initialized.
382 uint8_t NotPatching
= false;
383 if (!atomic_compare_exchange_strong(&XRayPatching
, &NotPatching
, true,
384 memory_order_acq_rel
))
385 return XRayPatchingStatus::ONGOING
; // Already patching.
387 auto XRayPatchingStatusResetter
= at_scope_exit(
388 [] { atomic_store(&XRayPatching
, false, memory_order_release
); });
390 unsigned NumObjects
= __xray_num_objects();
392 XRayPatchingStatus CombinedStatus
{NOT_INITIALIZED
};
393 for (unsigned I
= 0; I
< NumObjects
; ++I
) {
394 if (!isObjectLoaded(I
))
396 auto LastStatus
= controlPatchingObjectUnchecked(Enable
, I
);
397 switch (LastStatus
) {
399 if (CombinedStatus
== NOT_INITIALIZED
)
400 CombinedStatus
= SUCCESS
;
403 // Report failure, but try to patch the remaining objects
404 CombinedStatus
= FAILED
;
406 case NOT_INITIALIZED
:
407 // XRay has been initialized but there are no sleds available for this
408 // object. Try to patch remaining objects.
409 if (CombinedStatus
!= FAILED
)
410 CombinedStatus
= NOT_INITIALIZED
;
413 UNREACHABLE("Status ONGOING should not appear at this point");
416 return CombinedStatus
;
419 // Controls patching for one object.
420 XRayPatchingStatus
controlPatching(bool Enable
,
421 int32_t ObjId
) XRAY_NEVER_INSTRUMENT
{
423 if (!atomic_load(&XRayInitialized
, memory_order_acquire
))
424 return XRayPatchingStatus::NOT_INITIALIZED
; // Not initialized.
426 uint8_t NotPatching
= false;
427 if (!atomic_compare_exchange_strong(&XRayPatching
, &NotPatching
, true,
428 memory_order_acq_rel
))
429 return XRayPatchingStatus::ONGOING
; // Already patching.
431 auto XRayPatchingStatusResetter
= at_scope_exit(
432 [] { atomic_store(&XRayPatching
, false, memory_order_release
); });
434 return controlPatchingObjectUnchecked(Enable
, ObjId
);
437 XRayPatchingStatus
mprotectAndPatchFunction(int32_t FuncId
, int32_t ObjId
,
438 bool Enable
) XRAY_NEVER_INSTRUMENT
{
439 XRaySledMap InstrMap
;
441 SpinMutexLock
Guard(&XRayInstrMapMutex
);
442 if (ObjId
< 0 || static_cast<uint32_t>(ObjId
) >=
443 atomic_load(&XRayNumObjects
, memory_order_acquire
)) {
444 Report("Unable to patch function: invalid sled map index: %d\n", ObjId
);
445 return XRayPatchingStatus::FAILED
;
447 InstrMap
= XRayInstrMaps
[ObjId
];
450 // Check if the corresponding DSO has been unloaded.
451 if (!InstrMap
.Loaded
) {
452 Report("Object is not loaded at index: %d\n", ObjId
);
453 return XRayPatchingStatus::FAILED
;
456 // FuncId must be a positive number, less than the number of functions
458 if (FuncId
<= 0 || static_cast<size_t>(FuncId
) > InstrMap
.Functions
) {
459 Report("Invalid function id provided: %d\n", FuncId
);
460 return XRayPatchingStatus::FAILED
;
463 const size_t PageSize
= flags()->xray_page_size_override
> 0
464 ? flags()->xray_page_size_override
465 : GetPageSizeCached();
466 if ((PageSize
== 0) || ((PageSize
& (PageSize
- 1)) != 0)) {
467 Report("Provided page size is not a power of two: %zu\n", PageSize
);
468 return XRayPatchingStatus::FAILED
;
471 // Here we compute the minimum sled and maximum sled associated with a
472 // particular function ID.
473 XRayFunctionSledIndex SledRange
;
474 if (InstrMap
.SledsIndex
) {
475 SledRange
= {InstrMap
.SledsIndex
[FuncId
- 1].fromPCRelative(),
476 InstrMap
.SledsIndex
[FuncId
- 1].Size
};
478 SledRange
= findFunctionSleds(FuncId
, InstrMap
);
480 auto *f
= SledRange
.Begin
;
481 auto *e
= SledRange
.Begin
+ SledRange
.Size
;
483 auto *MaxSled
= e
- 1;
485 if (f
->address() < MinSled
->address())
487 if (f
->address() > MaxSled
->address())
492 void *PageAlignedAddr
=
493 reinterpret_cast<void *>(MinSled
->address() & ~(PageSize
- 1));
495 (MaxSled
->address() - reinterpret_cast<uptr
>(PageAlignedAddr
)) +
497 MProtectHelper
Protector(PageAlignedAddr
, MProtectLen
, PageSize
);
498 if (Protector
.MakeWriteable() == -1) {
499 Report("Failed mprotect: %d\n", errno
);
500 return XRayPatchingStatus::FAILED
;
502 return patchFunction(FuncId
, ObjId
, Enable
);
507 } // namespace __xray
509 using namespace __xray
;
511 // The following functions are declared `extern "C" {...}` in the header, hence
512 // they're defined in the global namespace.
514 int __xray_set_handler(void (*entry
)(int32_t,
515 XRayEntryType
)) XRAY_NEVER_INSTRUMENT
{
516 if (atomic_load(&XRayInitialized
, memory_order_acquire
)) {
518 atomic_store(&__xray::XRayPatchedFunction
,
519 reinterpret_cast<uintptr_t>(entry
), memory_order_release
);
525 int __xray_set_customevent_handler(void (*entry
)(void *, size_t))
526 XRAY_NEVER_INSTRUMENT
{
527 if (atomic_load(&XRayInitialized
, memory_order_acquire
)) {
528 atomic_store(&__xray::XRayPatchedCustomEvent
,
529 reinterpret_cast<uintptr_t>(entry
), memory_order_release
);
535 int __xray_set_typedevent_handler(void (*entry
)(size_t, const void *,
536 size_t)) XRAY_NEVER_INSTRUMENT
{
537 if (atomic_load(&XRayInitialized
, memory_order_acquire
)) {
538 atomic_store(&__xray::XRayPatchedTypedEvent
,
539 reinterpret_cast<uintptr_t>(entry
), memory_order_release
);
545 int __xray_remove_handler() XRAY_NEVER_INSTRUMENT
{
546 return __xray_set_handler(nullptr);
549 int __xray_remove_customevent_handler() XRAY_NEVER_INSTRUMENT
{
550 return __xray_set_customevent_handler(nullptr);
553 int __xray_remove_typedevent_handler() XRAY_NEVER_INSTRUMENT
{
554 return __xray_set_typedevent_handler(nullptr);
557 uint16_t __xray_register_event_type(
558 const char *const event_type
) XRAY_NEVER_INSTRUMENT
{
559 TypeDescriptorMapType::Handle
h(&TypeDescriptorAddressMap
, (uptr
)event_type
);
561 h
->type_id
= atomic_fetch_add(
562 &TypeEventDescriptorCounter
, 1, memory_order_acq_rel
);
563 h
->description_string_length
= strnlen(event_type
, 1024);
568 XRayPatchingStatus
__xray_patch() XRAY_NEVER_INSTRUMENT
{
569 return controlPatching(true);
572 XRayPatchingStatus
__xray_patch_object(int32_t ObjId
) XRAY_NEVER_INSTRUMENT
{
573 return controlPatching(true, ObjId
);
576 XRayPatchingStatus
__xray_unpatch() XRAY_NEVER_INSTRUMENT
{
577 return controlPatching(false);
580 XRayPatchingStatus
__xray_unpatch_object(int32_t ObjId
) XRAY_NEVER_INSTRUMENT
{
581 return controlPatching(false, ObjId
);
584 XRayPatchingStatus
__xray_patch_function(int32_t FuncId
) XRAY_NEVER_INSTRUMENT
{
585 auto Ids
= __xray::UnpackId(FuncId
);
586 auto ObjId
= Ids
.first
;
587 auto FnId
= Ids
.second
;
588 return mprotectAndPatchFunction(FnId
, ObjId
, true);
592 __xray_patch_function_in_object(int32_t FuncId
,
593 int32_t ObjId
) XRAY_NEVER_INSTRUMENT
{
594 return mprotectAndPatchFunction(FuncId
, ObjId
, true);
598 __xray_unpatch_function(int32_t FuncId
) XRAY_NEVER_INSTRUMENT
{
599 auto Ids
= __xray::UnpackId(FuncId
);
600 auto ObjId
= Ids
.first
;
601 auto FnId
= Ids
.second
;
602 return mprotectAndPatchFunction(FnId
, ObjId
, false);
606 __xray_unpatch_function_in_object(int32_t FuncId
,
607 int32_t ObjId
) XRAY_NEVER_INSTRUMENT
{
608 return mprotectAndPatchFunction(FuncId
, ObjId
, false);
611 int __xray_set_handler_arg1(void (*entry
)(int32_t, XRayEntryType
, uint64_t)) {
612 if (!atomic_load(&XRayInitialized
, memory_order_acquire
))
615 // A relaxed write might not be visible even if the current thread gets
616 // scheduled on a different CPU/NUMA node. We need to wait for everyone to
617 // have this handler installed for consistency of collected data across CPUs.
618 atomic_store(&XRayArgLogger
, reinterpret_cast<uint64_t>(entry
),
619 memory_order_release
);
623 int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); }
626 __xray_function_address(int32_t CombinedFuncId
) XRAY_NEVER_INSTRUMENT
{
627 auto Ids
= __xray::UnpackId(CombinedFuncId
);
628 return __xray_function_address_in_object(Ids
.second
, Ids
.first
);
631 uintptr_t __xray_function_address_in_object(int32_t FuncId
, int32_t ObjId
)
632 XRAY_NEVER_INSTRUMENT
{
633 XRaySledMap InstrMap
;
635 SpinMutexLock
Guard(&XRayInstrMapMutex
);
636 auto count
= atomic_load(&XRayNumObjects
, memory_order_acquire
);
637 if (ObjId
< 0 || static_cast<uint32_t>(ObjId
) >= count
) {
638 Report("Unable to determine function address: invalid sled map index %d "
643 InstrMap
= XRayInstrMaps
[ObjId
];
646 if (FuncId
<= 0 || static_cast<size_t>(FuncId
) > InstrMap
.Functions
)
648 const XRaySledEntry
*Sled
=
649 InstrMap
.SledsIndex
? InstrMap
.SledsIndex
[FuncId
- 1].fromPCRelative()
650 : findFunctionSleds(FuncId
, InstrMap
).Begin
;
651 return Sled
->function()
652 // On PPC, function entries are always aligned to 16 bytes. The beginning of a
653 // sled might be a local entry, which is always +8 based on the global entry.
654 // Always return the global entry.
661 size_t __xray_max_function_id() XRAY_NEVER_INSTRUMENT
{
662 return __xray_max_function_id_in_object(0);
665 size_t __xray_max_function_id_in_object(int32_t ObjId
) XRAY_NEVER_INSTRUMENT
{
666 SpinMutexLock
Guard(&XRayInstrMapMutex
);
667 if (ObjId
< 0 || static_cast<uint32_t>(ObjId
) >=
668 atomic_load(&XRayNumObjects
, memory_order_acquire
))
670 return XRayInstrMaps
[ObjId
].Functions
;
673 size_t __xray_num_objects() XRAY_NEVER_INSTRUMENT
{
674 SpinMutexLock
Guard(&XRayInstrMapMutex
);
675 return atomic_load(&XRayNumObjects
, memory_order_acquire
);
678 int32_t __xray_unpack_function_id(int32_t PackedId
) {
679 return __xray::UnpackId(PackedId
).second
;
682 int32_t __xray_unpack_object_id(int32_t PackedId
) {
683 return __xray::UnpackId(PackedId
).first
;
686 int32_t __xray_pack_id(int32_t FuncId
, int32_t ObjId
) {
687 return __xray::MakePackedId(FuncId
, ObjId
);