xref: /openbsd-src/gnu/llvm/compiler-rt/lib/tsan/rtl/tsan_external.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- tsan_external.cpp -------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of ThreadSanitizer (TSan), a race detector.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick #include "tsan_rtl.h"
13d89ec533Spatrick #include "sanitizer_common/sanitizer_ptrauth.h"
143cab2bb3Spatrick 
15*810390e3Srobert #if !SANITIZER_GO
16*810390e3Srobert #  include "tsan_interceptors.h"
17*810390e3Srobert #endif
18*810390e3Srobert 
193cab2bb3Spatrick namespace __tsan {
203cab2bb3Spatrick 
213cab2bb3Spatrick #define CALLERPC ((uptr)__builtin_return_address(0))
223cab2bb3Spatrick 
233cab2bb3Spatrick struct TagData {
243cab2bb3Spatrick   const char *object_type;
253cab2bb3Spatrick   const char *header;
263cab2bb3Spatrick };
273cab2bb3Spatrick 
283cab2bb3Spatrick static TagData registered_tags[kExternalTagMax] = {
293cab2bb3Spatrick   {},
303cab2bb3Spatrick   {"Swift variable", "Swift access race"},
313cab2bb3Spatrick };
323cab2bb3Spatrick static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable};
GetTagData(uptr tag)333cab2bb3Spatrick static TagData *GetTagData(uptr tag) {
343cab2bb3Spatrick   // Invalid/corrupted tag?  Better return NULL and let the caller deal with it.
353cab2bb3Spatrick   if (tag >= atomic_load(&used_tags, memory_order_relaxed)) return nullptr;
363cab2bb3Spatrick   return &registered_tags[tag];
373cab2bb3Spatrick }
383cab2bb3Spatrick 
GetObjectTypeFromTag(uptr tag)393cab2bb3Spatrick const char *GetObjectTypeFromTag(uptr tag) {
403cab2bb3Spatrick   TagData *tag_data = GetTagData(tag);
413cab2bb3Spatrick   return tag_data ? tag_data->object_type : nullptr;
423cab2bb3Spatrick }
433cab2bb3Spatrick 
GetReportHeaderFromTag(uptr tag)443cab2bb3Spatrick const char *GetReportHeaderFromTag(uptr tag) {
453cab2bb3Spatrick   TagData *tag_data = GetTagData(tag);
463cab2bb3Spatrick   return tag_data ? tag_data->header : nullptr;
473cab2bb3Spatrick }
483cab2bb3Spatrick 
InsertShadowStackFrameForTag(ThreadState * thr,uptr tag)493cab2bb3Spatrick void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) {
503cab2bb3Spatrick   FuncEntry(thr, (uptr)&registered_tags[tag]);
513cab2bb3Spatrick }
523cab2bb3Spatrick 
TagFromShadowStackFrame(uptr pc)533cab2bb3Spatrick uptr TagFromShadowStackFrame(uptr pc) {
543cab2bb3Spatrick   uptr tag_count = atomic_load(&used_tags, memory_order_relaxed);
553cab2bb3Spatrick   void *pc_ptr = (void *)pc;
563cab2bb3Spatrick   if (pc_ptr < GetTagData(0) || pc_ptr > GetTagData(tag_count - 1))
573cab2bb3Spatrick     return 0;
583cab2bb3Spatrick   return (TagData *)pc_ptr - GetTagData(0);
593cab2bb3Spatrick }
603cab2bb3Spatrick 
613cab2bb3Spatrick #if !SANITIZER_GO
623cab2bb3Spatrick 
ExternalAccess(void * addr,uptr caller_pc,void * tag,AccessType typ)63*810390e3Srobert void ExternalAccess(void *addr, uptr caller_pc, void *tag, AccessType typ) {
643cab2bb3Spatrick   CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
653cab2bb3Spatrick   ThreadState *thr = cur_thread();
66d89ec533Spatrick   if (caller_pc) FuncEntry(thr, caller_pc);
673cab2bb3Spatrick   InsertShadowStackFrameForTag(thr, (uptr)tag);
683cab2bb3Spatrick   bool in_ignored_lib;
69*810390e3Srobert   if (!caller_pc || !libignore()->IsIgnored(caller_pc, &in_ignored_lib))
70*810390e3Srobert     MemoryAccess(thr, CALLERPC, (uptr)addr, 1, typ);
713cab2bb3Spatrick   FuncExit(thr);
723cab2bb3Spatrick   if (caller_pc) FuncExit(thr);
733cab2bb3Spatrick }
743cab2bb3Spatrick 
753cab2bb3Spatrick extern "C" {
763cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__tsan_external_register_tag(const char * object_type)773cab2bb3Spatrick void *__tsan_external_register_tag(const char *object_type) {
783cab2bb3Spatrick   uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed);
793cab2bb3Spatrick   CHECK_LT(new_tag, kExternalTagMax);
803cab2bb3Spatrick   GetTagData(new_tag)->object_type = internal_strdup(object_type);
813cab2bb3Spatrick   char header[127] = {0};
823cab2bb3Spatrick   internal_snprintf(header, sizeof(header), "race on %s", object_type);
833cab2bb3Spatrick   GetTagData(new_tag)->header = internal_strdup(header);
843cab2bb3Spatrick   return (void *)new_tag;
853cab2bb3Spatrick }
863cab2bb3Spatrick 
873cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__tsan_external_register_header(void * tag,const char * header)883cab2bb3Spatrick void __tsan_external_register_header(void *tag, const char *header) {
893cab2bb3Spatrick   CHECK_GE((uptr)tag, kExternalTagFirstUserAvailable);
903cab2bb3Spatrick   CHECK_LT((uptr)tag, kExternalTagMax);
913cab2bb3Spatrick   atomic_uintptr_t *header_ptr =
923cab2bb3Spatrick       (atomic_uintptr_t *)&GetTagData((uptr)tag)->header;
933cab2bb3Spatrick   header = internal_strdup(header);
943cab2bb3Spatrick   char *old_header =
953cab2bb3Spatrick       (char *)atomic_exchange(header_ptr, (uptr)header, memory_order_seq_cst);
96*810390e3Srobert   Free(old_header);
973cab2bb3Spatrick }
983cab2bb3Spatrick 
993cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__tsan_external_assign_tag(void * addr,void * tag)1003cab2bb3Spatrick void __tsan_external_assign_tag(void *addr, void *tag) {
1013cab2bb3Spatrick   CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
1023cab2bb3Spatrick   Allocator *a = allocator();
1033cab2bb3Spatrick   MBlock *b = nullptr;
1043cab2bb3Spatrick   if (a->PointerIsMine((void *)addr)) {
1053cab2bb3Spatrick     void *block_begin = a->GetBlockBegin((void *)addr);
1063cab2bb3Spatrick     if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
1073cab2bb3Spatrick   }
1083cab2bb3Spatrick   if (b) {
1093cab2bb3Spatrick     b->tag = (uptr)tag;
1103cab2bb3Spatrick   }
1113cab2bb3Spatrick }
1123cab2bb3Spatrick 
1133cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__tsan_external_read(void * addr,void * caller_pc,void * tag)1143cab2bb3Spatrick void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
115*810390e3Srobert   ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, kAccessRead);
1163cab2bb3Spatrick }
1173cab2bb3Spatrick 
1183cab2bb3Spatrick SANITIZER_INTERFACE_ATTRIBUTE
__tsan_external_write(void * addr,void * caller_pc,void * tag)1193cab2bb3Spatrick void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
120*810390e3Srobert   ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, kAccessWrite);
1213cab2bb3Spatrick }
1223cab2bb3Spatrick }  // extern "C"
1233cab2bb3Spatrick 
1243cab2bb3Spatrick #endif  // !SANITIZER_GO
1253cab2bb3Spatrick 
1263cab2bb3Spatrick }  // namespace __tsan
127