Bug Summary

File:projects/compiler-rt/lib/xray/xray_basic_logging.cc
Warning:line 422, column 5
Forming reference to null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name xray_basic_logging.cc -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -D XRAY_HAS_EXCEPTIONS=1 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn338205/build-llvm/projects/compiler-rt/lib/xray -I /build/llvm-toolchain-snapshot-7~svn338205/projects/compiler-rt/lib/xray -I /build/llvm-toolchain-snapshot-7~svn338205/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn338205/include -I /build/llvm-toolchain-snapshot-7~svn338205/projects/compiler-rt/lib/xray/.. -I /build/llvm-toolchain-snapshot-7~svn338205/projects/compiler-rt/lib/xray/../../include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/x86_64-linux-gnu/c++/8 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/x86_64-linux-gnu/c++/8 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/lib/gcc/x86_64-linux-gnu/8/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-comment -Wno-unused-parameter -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-comment -Wno-unused-parameter -Wno-variadic-macros -Wno-non-virtual-dtor -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-7~svn338205/build-llvm/projects/compiler-rt/lib/xray -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -fvisibility-inlines-hidden -fno-builtin -fno-rtti -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-07-29-043837-17923-1 -x c++ /build/llvm-toolchain-snapshot-7~svn338205/projects/compiler-rt/lib/xray/xray_basic_logging.cc -faddrsig
1//===-- xray_basic_logging.cc -----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of XRay, a dynamic runtime instrumentation system.
11//
12// Implementation of a simple in-memory log of XRay events. This defines a
13// logging function that's compatible with the XRay handler interface, and
14// routines for exporting data to files.
15//
16//===----------------------------------------------------------------------===//
17
18#include <errno(*__errno_location ()).h>
19#include <fcntl.h>
20#include <pthread.h>
21#include <sys/stat.h>
22#include <sys/syscall.h>
23#include <sys/types.h>
24#include <time.h>
25#include <unistd.h>
26
27#include "sanitizer_common/sanitizer_allocator_internal.h"
28#include "sanitizer_common/sanitizer_libc.h"
29#include "xray/xray_records.h"
30#include "xray_recursion_guard.h"
31#include "xray_basic_flags.h"
32#include "xray_basic_logging.h"
33#include "xray_defs.h"
34#include "xray_flags.h"
35#include "xray_interface_internal.h"
36#include "xray_tsc.h"
37#include "xray_utils.h"
38
39namespace __xray {
40
41SpinMutex LogMutex;
42
43// We use elements of this type to record the entry TSC of every function ID we
44// see as we're tracing a particular thread's execution.
45struct alignas(16) StackEntry {
46 int32_t FuncId;
47 uint16_t Type;
48 uint8_t CPU;
49 uint8_t Padding;
50 uint64_t TSC;
51};
52
53static_assert(sizeof(StackEntry) == 16, "Wrong size for StackEntry");
54
55struct alignas(64) ThreadLocalData {
56 void *InMemoryBuffer = nullptr;
57 size_t BufferSize = 0;
58 size_t BufferOffset = 0;
59 void *ShadowStack = nullptr;
60 size_t StackSize = 0;
61 size_t StackEntries = 0;
62 int Fd = -1;
63};
64
65static pthread_key_t PThreadKey;
66
67static atomic_uint8_t BasicInitialized{0};
68
69BasicLoggingOptions GlobalOptions;
70
71thread_local atomic_uint8_t Guard{0};
72
73static atomic_uint8_t UseRealTSC{0};
74static atomic_uint64_t ThresholdTicks{0};
75static atomic_uint64_t TicksPerSec{0};
76static atomic_uint64_t CycleFrequency{NanosecondsPerSecond};
77
78static int openLogFile() XRAY_NEVER_INSTRUMENT {
79 int F = getLogFD();
80 if (F == -1)
81 return -1;
82
83 static pthread_once_t DetectOnce = PTHREAD_ONCE_INIT0;
84 pthread_once(&DetectOnce, +[] {
85 if (atomic_load(&UseRealTSC, memory_order_acquire))
86 atomic_store(&CycleFrequency, getTSCFrequency(), memory_order_release);
87 });
88
89 // Since we're here, we get to write the header. We set it up so that the
90 // header will only be written once, at the start, and let the threads
91 // logging do writes which just append.
92 XRayFileHeader Header;
93 // Version 2 includes tail exit records.
94 // Version 3 includes pid inside records.
95 Header.Version = 3;
96 Header.Type = FileTypes::NAIVE_LOG;
97 Header.CycleFrequency = atomic_load(&CycleFrequency, memory_order_acquire);
98
99 // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc'
100 // before setting the values in the header.
101 Header.ConstantTSC = 1;
102 Header.NonstopTSC = 1;
103 retryingWriteAll(F, reinterpret_cast<char *>(&Header),
104 reinterpret_cast<char *>(&Header) + sizeof(Header));
105 return F;
106}
107
108static int getGlobalFd() XRAY_NEVER_INSTRUMENT {
109 static pthread_once_t OnceInit = PTHREAD_ONCE_INIT0;
110 static int Fd = 0;
111 pthread_once(&OnceInit, +[] { Fd = openLogFile(); });
112 return Fd;
113}
114
115static ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {
116 thread_local ThreadLocalData TLD;
117 thread_local bool UNUSED__attribute__((unused)) TOnce = [] {
118 if (GlobalOptions.ThreadBufferSize == 0) {
119 if (Verbosity())
120 Report("Not initializing TLD since ThreadBufferSize == 0.\n");
121 return false;
122 }
123 pthread_setspecific(PThreadKey, &TLD);
124 TLD.Fd = getGlobalFd();
125 TLD.InMemoryBuffer = reinterpret_cast<XRayRecord *>(
126 InternalAlloc(sizeof(XRayRecord) * GlobalOptions.ThreadBufferSize,
127 nullptr, alignof(XRayRecord)));
128 TLD.BufferSize = GlobalOptions.ThreadBufferSize;
129 TLD.BufferOffset = 0;
130 if (GlobalOptions.MaxStackDepth == 0) {
131 if (Verbosity())
132 Report("Not initializing the ShadowStack since MaxStackDepth == 0.\n");
133 TLD.StackSize = 0;
134 TLD.StackEntries = 0;
135 TLD.ShadowStack = nullptr;
136 return false;
137 }
138 TLD.ShadowStack = reinterpret_cast<StackEntry *>(
139 InternalAlloc(sizeof(StackEntry) * GlobalOptions.MaxStackDepth, nullptr,
140 alignof(StackEntry)));
141 TLD.StackSize = GlobalOptions.MaxStackDepth;
142 TLD.StackEntries = 0;
143 return false;
144 }();
145 return TLD;
146}
147
148template <class RDTSC>
149void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,
150 RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT {
151 auto &TLD = getThreadLocalData();
152 int Fd = getGlobalFd();
153 if (Fd == -1)
154 return;
155
156 // Use a simple recursion guard, to handle cases where we're already logging
157 // and for one reason or another, this function gets called again in the same
158 // thread.
159 RecursionGuard G(Guard);
160 if (!G)
161 return;
162
163 uint8_t CPU = 0;
164 uint64_t TSC = ReadTSC(CPU);
165
166 switch (Type) {
167 case XRayEntryType::ENTRY:
168 case XRayEntryType::LOG_ARGS_ENTRY: {
169 // Short circuit if we've reached the maximum depth of the stack.
170 if (TLD.StackEntries++ >= TLD.StackSize)
171 return;
172
173 // When we encounter an entry event, we keep track of the TSC and the CPU,
174 // and put it in the stack.
175 StackEntry E;
176 E.FuncId = FuncId;
177 E.CPU = CPU;
178 E.Type = Type;
179 E.TSC = TSC;
180 auto StackEntryPtr = static_cast<char *>(TLD.ShadowStack) +
181 (sizeof(StackEntry) * (TLD.StackEntries - 1));
182 internal_memcpy(StackEntryPtr, &E, sizeof(StackEntry));
183 break;
184 }
185 case XRayEntryType::EXIT:
186 case XRayEntryType::TAIL: {
187 if (TLD.StackEntries == 0)
188 break;
189
190 if (--TLD.StackEntries >= TLD.StackSize)
191 return;
192
193 // When we encounter an exit event, we check whether all the following are
194 // true:
195 //
196 // - The Function ID is the same as the most recent entry in the stack.
197 // - The CPU is the same as the most recent entry in the stack.
198 // - The Delta of the TSCs is less than the threshold amount of time we're
199 // looking to record.
200 //
201 // If all of these conditions are true, we pop the stack and don't write a
202 // record and move the record offset back.
203 StackEntry StackTop;
204 auto StackEntryPtr = static_cast<char *>(TLD.ShadowStack) +
205 (sizeof(StackEntry) * TLD.StackEntries);
206 internal_memcpy(&StackTop, StackEntryPtr, sizeof(StackEntry));
207 if (StackTop.FuncId == FuncId && StackTop.CPU == CPU &&
208 StackTop.TSC < TSC) {
209 auto Delta = TSC - StackTop.TSC;
210 if (Delta < atomic_load(&ThresholdTicks, memory_order_relaxed)) {
211 DCHECK(TLD.BufferOffset > 0);
212 TLD.BufferOffset -= StackTop.Type == XRayEntryType::ENTRY ? 1 : 2;
213 return;
214 }
215 }
216 break;
217 }
218 default:
219 // Should be unreachable.
220 DCHECK(false && "Unsupported XRayEntryType encountered.");
221 break;
222 }
223
224 // First determine whether the delta between the function's enter record and
225 // the exit record is higher than the threshold.
226 XRayRecord R;
227 R.RecordType = RecordTypes::NORMAL;
228 R.CPU = CPU;
229 R.TSC = TSC;
230 R.TId = GetTid();
231 R.PId = internal_getpid();
232 R.Type = Type;
233 R.FuncId = FuncId;
234 auto FirstEntry = reinterpret_cast<XRayRecord *>(TLD.InMemoryBuffer);
235 internal_memcpy(FirstEntry + TLD.BufferOffset, &R, sizeof(R));
236 if (++TLD.BufferOffset == TLD.BufferSize) {
237 SpinMutexLock L(&LogMutex);
238 retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry),
239 reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset));
240 TLD.BufferOffset = 0;
241 TLD.StackEntries = 0;
242 }
243}
244
245template <class RDTSC>
246void InMemoryRawLogWithArg(int32_t FuncId, XRayEntryType Type, uint64_t Arg1,
247 RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT {
248 auto &TLD = getThreadLocalData();
249 auto FirstEntry =
250 reinterpret_cast<XRayArgPayload *>(TLD.InMemoryBuffer);
251 const auto &BuffLen = TLD.BufferSize;
252 int Fd = getGlobalFd();
253 if (Fd == -1)
254 return;
255
256 // First we check whether there's enough space to write the data consecutively
257 // in the thread-local buffer. If not, we first flush the buffer before
258 // attempting to write the two records that must be consecutive.
259 if (TLD.BufferOffset + 2 > BuffLen) {
260 SpinMutexLock L(&LogMutex);
261 retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry),
262 reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset));
263 TLD.BufferOffset = 0;
264 TLD.StackEntries = 0;
265 }
266
267 // Then we write the "we have an argument" record.
268 InMemoryRawLog(FuncId, Type, ReadTSC);
269
270 RecursionGuard G(Guard);
271 if (!G)
272 return;
273
274 // And, from here on write the arg payload.
275 XRayArgPayload R;
276 R.RecordType = RecordTypes::ARG_PAYLOAD;
277 R.FuncId = FuncId;
278 R.TId = GetTid();
279 R.PId = internal_getpid();
280 R.Arg = Arg1;
281 internal_memcpy(FirstEntry + TLD.BufferOffset, &R, sizeof(R));
282 if (++TLD.BufferOffset == BuffLen) {
283 SpinMutexLock L(&LogMutex);
284 retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry),
285 reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset));
286 TLD.BufferOffset = 0;
287 TLD.StackEntries = 0;
288 }
289}
290
291void basicLoggingHandleArg0RealTSC(int32_t FuncId,
292 XRayEntryType Type) XRAY_NEVER_INSTRUMENT {
293 InMemoryRawLog(FuncId, Type, readTSC);
294}
295
296void basicLoggingHandleArg0EmulateTSC(int32_t FuncId, XRayEntryType Type)
297 XRAY_NEVER_INSTRUMENT {
298 InMemoryRawLog(FuncId, Type, [](uint8_t &CPU) XRAY_NEVER_INSTRUMENT {
299 timespec TS;
300 int result = clock_gettime(CLOCK_REALTIME0, &TS);
301 if (result != 0) {
302 Report("clock_gettimg(2) return %d, errno=%d.", result, int(errno(*__errno_location ())));
303 TS = {0, 0};
304 }
305 CPU = 0;
306 return TS.tv_sec * NanosecondsPerSecond + TS.tv_nsec;
307 });
308}
309
310void basicLoggingHandleArg1RealTSC(int32_t FuncId, XRayEntryType Type,
311 uint64_t Arg1) XRAY_NEVER_INSTRUMENT {
312 InMemoryRawLogWithArg(FuncId, Type, Arg1, readTSC);
313}
314
315void basicLoggingHandleArg1EmulateTSC(int32_t FuncId, XRayEntryType Type,
316 uint64_t Arg1) XRAY_NEVER_INSTRUMENT {
317 InMemoryRawLogWithArg(
318 FuncId, Type, Arg1, [](uint8_t &CPU) XRAY_NEVER_INSTRUMENT {
319 timespec TS;
320 int result = clock_gettime(CLOCK_REALTIME0, &TS);
321 if (result != 0) {
322 Report("clock_gettimg(2) return %d, errno=%d.", result, int(errno(*__errno_location ())));
323 TS = {0, 0};
324 }
325 CPU = 0;
326 return TS.tv_sec * NanosecondsPerSecond + TS.tv_nsec;
327 });
328}
329
330static void TLDDestructor(void *P) XRAY_NEVER_INSTRUMENT {
331 ThreadLocalData &TLD = *reinterpret_cast<ThreadLocalData *>(P);
332 auto ExitGuard = at_scope_exit([&TLD] {
333 // Clean up dynamic resources.
334 if (TLD.InMemoryBuffer)
335 InternalFree(TLD.InMemoryBuffer);
336 if (TLD.ShadowStack)
337 InternalFree(TLD.ShadowStack);
338 if (Verbosity())
339 Report("Cleaned up log for TID: %d\n", GetTid());
340 });
341
342 if (TLD.Fd == -1 || TLD.BufferOffset == 0) {
343 if (Verbosity())
344 Report("Skipping buffer for TID: %d; Fd = %d; Offset = %llu\n", GetTid(),
345 TLD.Fd, TLD.BufferOffset);
346 return;
347 }
348
349 {
350 SpinMutexLock L(&LogMutex);
351 retryingWriteAll(TLD.Fd, reinterpret_cast<char *>(TLD.InMemoryBuffer),
352 reinterpret_cast<char *>(TLD.InMemoryBuffer) +
353 (sizeof(XRayRecord) * TLD.BufferOffset));
354 }
355
356 // Because this thread's exit could be the last one trying to write to
357 // the file and that we're not able to close out the file properly, we
358 // sync instead and hope that the pending writes are flushed as the
359 // thread exits.
360 fsync(TLD.Fd);
361}
362
363XRayLogInitStatus basicLoggingInit(size_t BufferSize, size_t BufferMax,
364 void *Options,
365 size_t OptionsSize) XRAY_NEVER_INSTRUMENT {
366 uint8_t Expected = 0;
367 if (!atomic_compare_exchange_strong(&BasicInitialized, &Expected, 1,
1
Taking false branch
368 memory_order_acq_rel)) {
369 if (Verbosity())
370 Report("Basic logging already initialized.\n");
371 return XRayLogInitStatus::XRAY_LOG_INITIALIZED;
372 }
373
374 static pthread_once_t OnceInit = PTHREAD_ONCE_INIT0;
375 pthread_once(&OnceInit, +[] {
376 pthread_key_create(&PThreadKey, TLDDestructor);
377 atomic_store(&UseRealTSC, probeRequiredCPUFeatures(), memory_order_release);
378 // Initialize the global TicksPerSec value.
379 atomic_store(&TicksPerSec,
380 probeRequiredCPUFeatures() ? getTSCFrequency()
381 : NanosecondsPerSecond,
382 memory_order_release);
383 if (!atomic_load(&UseRealTSC, memory_order_relaxed) && Verbosity())
384 Report("WARNING: Required CPU features missing for XRay instrumentation, "
385 "using emulation instead.\n");
386 });
387
388 if (BufferSize == 0 && BufferMax == 0 && Options != nullptr) {
2
Assuming 'BufferSize' is equal to 0
3
Assuming 'BufferMax' is equal to 0
4
Assuming pointer value is null
5
Taking false branch
389 FlagParser P;
390 BasicFlags F;
391 F.setDefaults();
392 registerXRayBasicFlags(&P, &F);
393 P.ParseString(useCompilerDefinedBasicFlags());
394 auto *EnvOpts = GetEnv("XRAY_BASIC_OPTIONS");
395 if (EnvOpts == nullptr)
396 EnvOpts = "";
397
398 P.ParseString(EnvOpts);
399
400 // If XRAY_BASIC_OPTIONS was not defined, then we use the deprecated options
401 // set through XRAY_OPTIONS instead.
402 if (internal_strlen(EnvOpts) == 0) {
403 F.func_duration_threshold_us =
404 flags()->xray_naive_log_func_duration_threshold_us;
405 F.max_stack_depth = flags()->xray_naive_log_max_stack_depth;
406 F.thread_buffer_size = flags()->xray_naive_log_thread_buffer_size;
407 }
408
409 P.ParseString(static_cast<const char *>(Options));
410 GlobalOptions.ThreadBufferSize = F.thread_buffer_size;
411 GlobalOptions.DurationFilterMicros = F.func_duration_threshold_us;
412 GlobalOptions.MaxStackDepth = F.max_stack_depth;
413 *basicFlags() = F;
414 } else if (OptionsSize != sizeof(BasicLoggingOptions)) {
6
Assuming the condition is false
7
Taking false branch
415 Report("Invalid options size, potential ABI mismatch; expected %d got %d",
416 sizeof(BasicLoggingOptions), OptionsSize);
417 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
418 } else {
419 if (Verbosity())
8
Assuming the condition is false
9
Taking false branch
420 Report("XRay Basic: struct-based init is deprecated, please use "
421 "string-based configuration instead.\n");
422 GlobalOptions = *reinterpret_cast<BasicLoggingOptions *>(Options);
10
Forming reference to null pointer
423 }
424
425 atomic_store(&ThresholdTicks,
426 atomic_load(&TicksPerSec, memory_order_acquire) *
427 GlobalOptions.DurationFilterMicros / 1000000,
428 memory_order_release);
429 __xray_set_handler_arg1(atomic_load(&UseRealTSC, memory_order_acquire)
430 ? basicLoggingHandleArg1RealTSC
431 : basicLoggingHandleArg1EmulateTSC);
432 __xray_set_handler(atomic_load(&UseRealTSC, memory_order_acquire)
433 ? basicLoggingHandleArg0RealTSC
434 : basicLoggingHandleArg0EmulateTSC);
435
436 // TODO: Implement custom event and typed event handling support in Basic
437 // Mode.
438 __xray_remove_customevent_handler();
439 __xray_remove_typedevent_handler();
440
441 return XRayLogInitStatus::XRAY_LOG_INITIALIZED;
442}
443
444XRayLogInitStatus basicLoggingFinalize() XRAY_NEVER_INSTRUMENT {
445 uint8_t Expected = 0;
446 if (!atomic_compare_exchange_strong(&BasicInitialized, &Expected, 0,
447 memory_order_acq_rel) &&
448 Verbosity())
449 Report("Basic logging already finalized.\n");
450
451 // Nothing really to do aside from marking state of the global to be
452 // uninitialized.
453
454 return XRayLogInitStatus::XRAY_LOG_FINALIZED;
455}
456
457XRayLogFlushStatus basicLoggingFlush() XRAY_NEVER_INSTRUMENT {
458 // This really does nothing, since flushing the logs happen at the end of a
459 // thread's lifetime, or when the buffers are full.
460 return XRayLogFlushStatus::XRAY_LOG_FLUSHED;
461}
462
463// This is a handler that, effectively, does nothing.
464void basicLoggingHandleArg0Empty(int32_t, XRayEntryType) XRAY_NEVER_INSTRUMENT {
465}
466
467bool basicLogDynamicInitializer() XRAY_NEVER_INSTRUMENT {
468 XRayLogImpl Impl{
469 basicLoggingInit,
470 basicLoggingFinalize,
471 basicLoggingHandleArg0Empty,
472 basicLoggingFlush,
473 };
474 auto RegistrationResult = __xray_log_register_mode("xray-basic", Impl);
475 if (RegistrationResult != XRayLogRegisterStatus::XRAY_REGISTRATION_OK &&
476 Verbosity())
477 Report("Cannot register XRay Basic Mode to 'xray-basic'; error = %d\n",
478 RegistrationResult);
479 if (flags()->xray_naive_log ||
480 !internal_strcmp(flags()->xray_mode, "xray-basic")) {
481 auto SelectResult = __xray_log_select_mode("xray-basic");
482 if (SelectResult != XRayLogRegisterStatus::XRAY_REGISTRATION_OK) {
483 if (Verbosity())
484 Report("Failed selecting XRay Basic Mode; error = %d\n", SelectResult);
485 return false;
486 }
487
488 // We initialize the implementation using the data we get from the
489 // XRAY_BASIC_OPTIONS environment variable, at this point of the
490 // implementation.
491 auto *Env = GetEnv("XRAY_BASIC_OPTIONS");
492 auto InitResult =
493 __xray_log_init_mode("xray-basic", Env == nullptr ? "" : Env);
494 if (InitResult != XRayLogInitStatus::XRAY_LOG_INITIALIZED) {
495 if (Verbosity())
496 Report("Failed initializing XRay Basic Mode; error = %d\n", InitResult);
497 return false;
498 }
499
500 // At this point we know that we've successfully initialized Basic mode
501 // tracing, and the only chance we're going to get for the current thread to
502 // clean-up may be at thread/program exit. To ensure that we're going to get
503 // the cleanup even without calling the finalization routines, we're
504 // registering a program exit function that will do the cleanup.
505 static pthread_once_t DynamicOnce = PTHREAD_ONCE_INIT0;
506 pthread_once(&DynamicOnce, +[] {
507 static void *FakeTLD = nullptr;
508 FakeTLD = &getThreadLocalData();
509 Atexit(+[] { TLDDestructor(FakeTLD); });
510 });
511 }
512 return true;
513}
514
515} // namespace __xray
516
517static auto UNUSED__attribute__((unused)) Unused = __xray::basicLogDynamicInitializer();