]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/xray/xray_x86_64.cc
Update the GNU DTS file from Linux 4.11
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / xray / xray_x86_64.cc
1 #include "sanitizer_common/sanitizer_common.h"
2 #include "xray_defs.h"
3 #include "xray_interface_internal.h"
4 #include <atomic>
5 #include <cstdint>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <iterator>
9 #include <limits>
10 #include <tuple>
11 #include <unistd.h>
12
13 namespace __xray {
14
15 static std::pair<ssize_t, bool>
16 retryingReadSome(int Fd, char *Begin, char *End) XRAY_NEVER_INSTRUMENT {
17   auto BytesToRead = std::distance(Begin, End);
18   ssize_t BytesRead;
19   ssize_t TotalBytesRead = 0;
20   while (BytesToRead && (BytesRead = read(Fd, Begin, BytesToRead))) {
21     if (BytesRead == -1) {
22       if (errno == EINTR)
23         continue;
24       Report("Read error; errno = %d\n", errno);
25       return std::make_pair(TotalBytesRead, false);
26     }
27
28     TotalBytesRead += BytesRead;
29     BytesToRead -= BytesRead;
30     Begin += BytesRead;
31   }
32   return std::make_pair(TotalBytesRead, true);
33 }
34
35 static bool readValueFromFile(const char *Filename,
36                               long long *Value) XRAY_NEVER_INSTRUMENT {
37   int Fd = open(Filename, O_RDONLY | O_CLOEXEC);
38   if (Fd == -1)
39     return false;
40   static constexpr size_t BufSize = 256;
41   char Line[BufSize] = {};
42   ssize_t BytesRead;
43   bool Success;
44   std::tie(BytesRead, Success) = retryingReadSome(Fd, Line, Line + BufSize);
45   if (!Success)
46     return false;
47   close(Fd);
48   char *End = nullptr;
49   long long Tmp = internal_simple_strtoll(Line, &End, 10);
50   bool Result = false;
51   if (Line[0] != '\0' && (*End == '\n' || *End == '\0')) {
52     *Value = Tmp;
53     Result = true;
54   }
55   return Result;
56 }
57
58 uint64_t cycleFrequency() XRAY_NEVER_INSTRUMENT {
59   long long CPUFrequency = -1;
60   if (readValueFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz",
61                         &CPUFrequency)) {
62     CPUFrequency *= 1000;
63   } else if (readValueFromFile(
64       "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
65       &CPUFrequency)) {
66     CPUFrequency *= 1000;
67   } else {
68     Report("Unable to determine CPU frequency for TSC accounting.\n");
69   }
70   return CPUFrequency == -1 ? 0 : static_cast<uint64_t>(CPUFrequency);
71 }
72
73 static constexpr uint8_t CallOpCode = 0xe8;
74 static constexpr uint16_t MovR10Seq = 0xba41;
75 static constexpr uint16_t Jmp9Seq = 0x09eb;
76 static constexpr uint8_t JmpOpCode = 0xe9;
77 static constexpr uint8_t RetOpCode = 0xc3;
78
79 static constexpr int64_t MinOffset{std::numeric_limits<int32_t>::min()};
80 static constexpr int64_t MaxOffset{std::numeric_limits<int32_t>::max()};
81
82 bool patchFunctionEntry(const bool Enable, const uint32_t FuncId,
83                         const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
84   // Here we do the dance of replacing the following sled:
85   //
86   // xray_sled_n:
87   //   jmp +9
88   //   <9 byte nop>
89   //
90   // With the following:
91   //
92   //   mov r10d, <function id>
93   //   call <relative 32bit offset to entry trampoline>
94   //
95   // We need to do this in the following order:
96   //
97   // 1. Put the function id first, 2 bytes from the start of the sled (just
98   // after the 2-byte jmp instruction).
99   // 2. Put the call opcode 6 bytes from the start of the sled.
100   // 3. Put the relative offset 7 bytes from the start of the sled.
101   // 4. Do an atomic write over the jmp instruction for the "mov r10d"
102   // opcode and first operand.
103   //
104   // Prerequisite is to compute the relative offset to the
105   // __xray_FunctionEntry function's address.
106   int64_t TrampolineOffset = reinterpret_cast<int64_t>(__xray_FunctionEntry) -
107                              (static_cast<int64_t>(Sled.Address) + 11);
108   if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
109     Report("XRay Entry trampoline (%p) too far from sled (%p)\n",
110            __xray_FunctionEntry, reinterpret_cast<void *>(Sled.Address));
111     return false;
112   }
113   if (Enable) {
114     *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
115     *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
116     *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
117     std::atomic_store_explicit(
118         reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
119         std::memory_order_release);
120   } else {
121     std::atomic_store_explicit(
122         reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp9Seq,
123         std::memory_order_release);
124     // FIXME: Write out the nops still?
125   }
126   return true;
127 }
128
129 bool patchFunctionExit(const bool Enable, const uint32_t FuncId,
130                        const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
131   // Here we do the dance of replacing the following sled:
132   //
133   // xray_sled_n:
134   //   ret
135   //   <10 byte nop>
136   //
137   // With the following:
138   //
139   //   mov r10d, <function id>
140   //   jmp <relative 32bit offset to exit trampoline>
141   //
142   // 1. Put the function id first, 2 bytes from the start of the sled (just
143   // after the 1-byte ret instruction).
144   // 2. Put the jmp opcode 6 bytes from the start of the sled.
145   // 3. Put the relative offset 7 bytes from the start of the sled.
146   // 4. Do an atomic write over the jmp instruction for the "mov r10d"
147   // opcode and first operand.
148   //
149   // Prerequisite is to compute the relative offset fo the
150   // __xray_FunctionExit function's address.
151   int64_t TrampolineOffset = reinterpret_cast<int64_t>(__xray_FunctionExit) -
152                              (static_cast<int64_t>(Sled.Address) + 11);
153   if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
154     Report("XRay Exit trampoline (%p) too far from sled (%p)\n",
155            __xray_FunctionExit, reinterpret_cast<void *>(Sled.Address));
156     return false;
157   }
158   if (Enable) {
159     *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
160     *reinterpret_cast<uint8_t *>(Sled.Address + 6) = JmpOpCode;
161     *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
162     std::atomic_store_explicit(
163         reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
164         std::memory_order_release);
165   } else {
166     std::atomic_store_explicit(
167         reinterpret_cast<std::atomic<uint8_t> *>(Sled.Address), RetOpCode,
168         std::memory_order_release);
169     // FIXME: Write out the nops still?
170   }
171   return true;
172 }
173
174 bool patchFunctionTailExit(const bool Enable, const uint32_t FuncId,
175                            const XRaySledEntry &Sled) XRAY_NEVER_INSTRUMENT {
176   // Here we do the dance of replacing the tail call sled with a similar
177   // sequence as the entry sled, but calls the tail exit sled instead.
178   int64_t TrampolineOffset =
179       reinterpret_cast<int64_t>(__xray_FunctionTailExit) -
180       (static_cast<int64_t>(Sled.Address) + 11);
181   if (TrampolineOffset < MinOffset || TrampolineOffset > MaxOffset) {
182     Report("XRay Exit trampoline (%p) too far from sled (%p)\n",
183            __xray_FunctionExit, reinterpret_cast<void *>(Sled.Address));
184     return false;
185   }
186   if (Enable) {
187     *reinterpret_cast<uint32_t *>(Sled.Address + 2) = FuncId;
188     *reinterpret_cast<uint8_t *>(Sled.Address + 6) = CallOpCode;
189     *reinterpret_cast<uint32_t *>(Sled.Address + 7) = TrampolineOffset;
190     std::atomic_store_explicit(
191         reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), MovR10Seq,
192         std::memory_order_release);
193   } else {
194     std::atomic_store_explicit(
195         reinterpret_cast<std::atomic<uint16_t> *>(Sled.Address), Jmp9Seq,
196         std::memory_order_release);
197     // FIXME: Write out the nops still?
198   }
199   return true;
200 }
201
202 } // namespace __xray