1 #include "sanitizer_common/sanitizer_common.h"
3 #include "xray_interface_internal.h"
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);
19 ssize_t TotalBytesRead = 0;
20 while (BytesToRead && (BytesRead = read(Fd, Begin, BytesToRead))) {
21 if (BytesRead == -1) {
24 Report("Read error; errno = %d\n", errno);
25 return std::make_pair(TotalBytesRead, false);
28 TotalBytesRead += BytesRead;
29 BytesToRead -= BytesRead;
32 return std::make_pair(TotalBytesRead, true);
35 static bool readValueFromFile(const char *Filename,
36 long long *Value) XRAY_NEVER_INSTRUMENT {
37 int Fd = open(Filename, O_RDONLY | O_CLOEXEC);
40 static constexpr size_t BufSize = 256;
41 char Line[BufSize] = {};
44 std::tie(BytesRead, Success) = retryingReadSome(Fd, Line, Line + BufSize);
49 long long Tmp = internal_simple_strtoll(Line, &End, 10);
51 if (Line[0] != '\0' && (*End == '\n' || *End == '\0')) {
58 uint64_t cycleFrequency() XRAY_NEVER_INSTRUMENT {
59 long long CPUFrequency = -1;
60 if (readValueFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz",
63 } else if (readValueFromFile(
64 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
68 Report("Unable to determine CPU frequency for TSC accounting.\n");
70 return CPUFrequency == -1 ? 0 : static_cast<uint64_t>(CPUFrequency);
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;
79 static constexpr int64_t MinOffset{std::numeric_limits<int32_t>::min()};
80 static constexpr int64_t MaxOffset{std::numeric_limits<int32_t>::max()};
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:
90 // With the following:
92 // mov r10d, <function id>
93 // call <relative 32bit offset to entry trampoline>
95 // We need to do this in the following order:
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.
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));
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);
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?
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:
137 // With the following:
139 // mov r10d, <function id>
140 // jmp <relative 32bit offset to exit trampoline>
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.
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));
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);
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?
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));
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);
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?
202 } // namespace __xray