168d75effSDimitry Andric //===-- xray_powerpc64.cpp --------------------------------------*- C++ -*-===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of XRay, a dynamic runtime instrumentation system.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Implementation of powerpc64 and powerpc64le routines.
1268d75effSDimitry Andric //
1368d75effSDimitry Andric //===----------------------------------------------------------------------===//
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
1568d75effSDimitry Andric #include "xray_defs.h"
1668d75effSDimitry Andric #include "xray_interface_internal.h"
1768d75effSDimitry Andric #include "xray_utils.h"
1868d75effSDimitry Andric #include <atomic>
1968d75effSDimitry Andric #include <cassert>
2068d75effSDimitry Andric #include <cstring>
2168d75effSDimitry Andric
2268d75effSDimitry Andric #ifndef __LITTLE_ENDIAN__
2368d75effSDimitry Andric #error powerpc64 big endian is not supported for now.
2468d75effSDimitry Andric #endif
2568d75effSDimitry Andric
2668d75effSDimitry Andric namespace {
2768d75effSDimitry Andric
2868d75effSDimitry Andric constexpr unsigned long long JumpOverInstNum = 7;
2968d75effSDimitry Andric
clearCache(void * Addr,size_t Len)3068d75effSDimitry Andric void clearCache(void *Addr, size_t Len) {
3168d75effSDimitry Andric const size_t LineSize = 32;
3268d75effSDimitry Andric
3368d75effSDimitry Andric const intptr_t Mask = ~(LineSize - 1);
3468d75effSDimitry Andric const intptr_t StartLine = ((intptr_t)Addr) & Mask;
3568d75effSDimitry Andric const intptr_t EndLine = ((intptr_t)Addr + Len + LineSize - 1) & Mask;
3668d75effSDimitry Andric
3768d75effSDimitry Andric for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
3868d75effSDimitry Andric asm volatile("dcbf 0, %0" : : "r"(Line));
3968d75effSDimitry Andric asm volatile("sync");
4068d75effSDimitry Andric
4168d75effSDimitry Andric for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize)
4268d75effSDimitry Andric asm volatile("icbi 0, %0" : : "r"(Line));
4368d75effSDimitry Andric asm volatile("isync");
4468d75effSDimitry Andric }
4568d75effSDimitry Andric
4668d75effSDimitry Andric } // namespace
4768d75effSDimitry Andric
4868d75effSDimitry Andric extern "C" void __clear_cache(void *start, void *end);
4968d75effSDimitry Andric
5068d75effSDimitry Andric namespace __xray {
5168d75effSDimitry Andric
patchFunctionEntry(const bool Enable,uint32_t FuncId,const XRaySledEntry & Sled,void (* Trampoline)())5268d75effSDimitry Andric bool patchFunctionEntry(const bool Enable, uint32_t FuncId,
5368d75effSDimitry Andric const XRaySledEntry &Sled,
5468d75effSDimitry Andric void (*Trampoline)()) XRAY_NEVER_INSTRUMENT {
55*5ffd83dbSDimitry Andric const uint64_t Address = Sled.address();
5668d75effSDimitry Andric if (Enable) {
5768d75effSDimitry Andric // lis 0, FuncId[16..32]
5868d75effSDimitry Andric // li 0, FuncId[0..15]
59*5ffd83dbSDimitry Andric *reinterpret_cast<uint64_t *>(Address) =
6068d75effSDimitry Andric (0x3c000000ull + (FuncId >> 16)) +
6168d75effSDimitry Andric ((0x60000000ull + (FuncId & 0xffff)) << 32);
6268d75effSDimitry Andric } else {
6368d75effSDimitry Andric // b +JumpOverInstNum instructions.
64*5ffd83dbSDimitry Andric *reinterpret_cast<uint32_t *>(Address) =
6568d75effSDimitry Andric 0x48000000ull + (JumpOverInstNum << 2);
6668d75effSDimitry Andric }
67*5ffd83dbSDimitry Andric clearCache(reinterpret_cast<void *>(Address), 8);
6868d75effSDimitry Andric return true;
6968d75effSDimitry Andric }
7068d75effSDimitry Andric
patchFunctionExit(const bool Enable,uint32_t FuncId,const XRaySledEntry & Sled)7168d75effSDimitry Andric bool patchFunctionExit(const bool Enable, uint32_t FuncId,
7268d75effSDimitry Andric const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
73*5ffd83dbSDimitry Andric const uint64_t Address = Sled.address();
7468d75effSDimitry Andric if (Enable) {
7568d75effSDimitry Andric // lis 0, FuncId[16..32]
7668d75effSDimitry Andric // li 0, FuncId[0..15]
77*5ffd83dbSDimitry Andric *reinterpret_cast<uint64_t *>(Address) =
7868d75effSDimitry Andric (0x3c000000ull + (FuncId >> 16)) +
7968d75effSDimitry Andric ((0x60000000ull + (FuncId & 0xffff)) << 32);
8068d75effSDimitry Andric } else {
8168d75effSDimitry Andric // Copy the blr/b instruction after JumpOverInstNum instructions.
82*5ffd83dbSDimitry Andric *reinterpret_cast<uint32_t *>(Address) =
83*5ffd83dbSDimitry Andric *(reinterpret_cast<uint32_t *>(Address) + JumpOverInstNum);
8468d75effSDimitry Andric }
85*5ffd83dbSDimitry Andric clearCache(reinterpret_cast<void *>(Address), 8);
8668d75effSDimitry Andric return true;
8768d75effSDimitry Andric }
8868d75effSDimitry Andric
patchFunctionTailExit(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)8968d75effSDimitry Andric bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
9068d75effSDimitry Andric const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
9168d75effSDimitry Andric return patchFunctionExit(Enable, FuncId, Sled);
9268d75effSDimitry Andric }
9368d75effSDimitry Andric
9468d75effSDimitry Andric // FIXME: Maybe implement this better?
probeRequiredCPUFeatures()9568d75effSDimitry Andric bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
9668d75effSDimitry Andric
patchCustomEvent(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)9768d75effSDimitry Andric bool patchCustomEvent(const bool Enable, const uint32_t FuncId,
9868d75effSDimitry Andric const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
9968d75effSDimitry Andric // FIXME: Implement in powerpc64?
10068d75effSDimitry Andric return false;
10168d75effSDimitry Andric }
10268d75effSDimitry Andric
patchTypedEvent(const bool Enable,const uint32_t FuncId,const XRaySledEntry & Sled)10368d75effSDimitry Andric bool patchTypedEvent(const bool Enable, const uint32_t FuncId,
10468d75effSDimitry Andric const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
10568d75effSDimitry Andric // FIXME: Implement in powerpc64?
10668d75effSDimitry Andric return false;
10768d75effSDimitry Andric }
10868d75effSDimitry Andric
10968d75effSDimitry Andric } // namespace __xray
11068d75effSDimitry Andric
__xray_ArgLoggerEntry()11168d75effSDimitry Andric extern "C" void __xray_ArgLoggerEntry() XRAY_NEVER_INSTRUMENT {
11268d75effSDimitry Andric // FIXME: this will have to be implemented in the trampoline assembly file
11368d75effSDimitry Andric }
114