1*68d75effSDimitry Andric //===-- sanitizer_stackdepot.cpp ------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 10*68d75effSDimitry Andric // run-time libraries. 11*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 12*68d75effSDimitry Andric 13*68d75effSDimitry Andric #include "sanitizer_stackdepot.h" 14*68d75effSDimitry Andric 15*68d75effSDimitry Andric #include "sanitizer_common.h" 16*68d75effSDimitry Andric #include "sanitizer_hash.h" 17*68d75effSDimitry Andric #include "sanitizer_stackdepotbase.h" 18*68d75effSDimitry Andric 19*68d75effSDimitry Andric namespace __sanitizer { 20*68d75effSDimitry Andric 21*68d75effSDimitry Andric struct StackDepotNode { 22*68d75effSDimitry Andric StackDepotNode *link; 23*68d75effSDimitry Andric u32 id; 24*68d75effSDimitry Andric atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20; 25*68d75effSDimitry Andric u32 size; 26*68d75effSDimitry Andric u32 tag; 27*68d75effSDimitry Andric uptr stack[1]; // [size] 28*68d75effSDimitry Andric 29*68d75effSDimitry Andric static const u32 kTabSizeLog = SANITIZER_ANDROID ? 16 : 20; 30*68d75effSDimitry Andric // Lower kTabSizeLog bits are equal for all items in one bucket. 31*68d75effSDimitry Andric // We use these bits to store the per-stack use counter. 32*68d75effSDimitry Andric static const u32 kUseCountBits = kTabSizeLog; 33*68d75effSDimitry Andric static const u32 kMaxUseCount = 1 << kUseCountBits; 34*68d75effSDimitry Andric static const u32 kUseCountMask = (1 << kUseCountBits) - 1; 35*68d75effSDimitry Andric static const u32 kHashMask = ~kUseCountMask; 36*68d75effSDimitry Andric 37*68d75effSDimitry Andric typedef StackTrace args_type; 38*68d75effSDimitry Andric bool eq(u32 hash, const args_type &args) const { 39*68d75effSDimitry Andric u32 hash_bits = 40*68d75effSDimitry Andric atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask; 41*68d75effSDimitry Andric if ((hash & kHashMask) != hash_bits || args.size != size || args.tag != tag) 42*68d75effSDimitry Andric return false; 43*68d75effSDimitry Andric uptr i = 0; 44*68d75effSDimitry Andric for (; i < size; i++) { 45*68d75effSDimitry Andric if (stack[i] != args.trace[i]) return false; 46*68d75effSDimitry Andric } 47*68d75effSDimitry Andric return true; 48*68d75effSDimitry Andric } 49*68d75effSDimitry Andric static uptr storage_size(const args_type &args) { 50*68d75effSDimitry Andric return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr); 51*68d75effSDimitry Andric } 52*68d75effSDimitry Andric static u32 hash(const args_type &args) { 53*68d75effSDimitry Andric MurMur2HashBuilder H(args.size * sizeof(uptr)); 54*68d75effSDimitry Andric for (uptr i = 0; i < args.size; i++) H.add(args.trace[i]); 55*68d75effSDimitry Andric return H.get(); 56*68d75effSDimitry Andric } 57*68d75effSDimitry Andric static bool is_valid(const args_type &args) { 58*68d75effSDimitry Andric return args.size > 0 && args.trace; 59*68d75effSDimitry Andric } 60*68d75effSDimitry Andric void store(const args_type &args, u32 hash) { 61*68d75effSDimitry Andric atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed); 62*68d75effSDimitry Andric size = args.size; 63*68d75effSDimitry Andric tag = args.tag; 64*68d75effSDimitry Andric internal_memcpy(stack, args.trace, size * sizeof(uptr)); 65*68d75effSDimitry Andric } 66*68d75effSDimitry Andric args_type load() const { 67*68d75effSDimitry Andric return args_type(&stack[0], size, tag); 68*68d75effSDimitry Andric } 69*68d75effSDimitry Andric StackDepotHandle get_handle() { return StackDepotHandle(this); } 70*68d75effSDimitry Andric 71*68d75effSDimitry Andric typedef StackDepotHandle handle_type; 72*68d75effSDimitry Andric }; 73*68d75effSDimitry Andric 74*68d75effSDimitry Andric COMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount); 75*68d75effSDimitry Andric 76*68d75effSDimitry Andric u32 StackDepotHandle::id() { return node_->id; } 77*68d75effSDimitry Andric int StackDepotHandle::use_count() { 78*68d75effSDimitry Andric return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) & 79*68d75effSDimitry Andric StackDepotNode::kUseCountMask; 80*68d75effSDimitry Andric } 81*68d75effSDimitry Andric void StackDepotHandle::inc_use_count_unsafe() { 82*68d75effSDimitry Andric u32 prev = 83*68d75effSDimitry Andric atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) & 84*68d75effSDimitry Andric StackDepotNode::kUseCountMask; 85*68d75effSDimitry Andric CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount); 86*68d75effSDimitry Andric } 87*68d75effSDimitry Andric 88*68d75effSDimitry Andric // FIXME(dvyukov): this single reserved bit is used in TSan. 89*68d75effSDimitry Andric typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog> 90*68d75effSDimitry Andric StackDepot; 91*68d75effSDimitry Andric static StackDepot theDepot; 92*68d75effSDimitry Andric 93*68d75effSDimitry Andric StackDepotStats *StackDepotGetStats() { 94*68d75effSDimitry Andric return theDepot.GetStats(); 95*68d75effSDimitry Andric } 96*68d75effSDimitry Andric 97*68d75effSDimitry Andric u32 StackDepotPut(StackTrace stack) { 98*68d75effSDimitry Andric StackDepotHandle h = theDepot.Put(stack); 99*68d75effSDimitry Andric return h.valid() ? h.id() : 0; 100*68d75effSDimitry Andric } 101*68d75effSDimitry Andric 102*68d75effSDimitry Andric StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) { 103*68d75effSDimitry Andric return theDepot.Put(stack); 104*68d75effSDimitry Andric } 105*68d75effSDimitry Andric 106*68d75effSDimitry Andric StackTrace StackDepotGet(u32 id) { 107*68d75effSDimitry Andric return theDepot.Get(id); 108*68d75effSDimitry Andric } 109*68d75effSDimitry Andric 110*68d75effSDimitry Andric void StackDepotLockAll() { 111*68d75effSDimitry Andric theDepot.LockAll(); 112*68d75effSDimitry Andric } 113*68d75effSDimitry Andric 114*68d75effSDimitry Andric void StackDepotUnlockAll() { 115*68d75effSDimitry Andric theDepot.UnlockAll(); 116*68d75effSDimitry Andric } 117*68d75effSDimitry Andric 118*68d75effSDimitry Andric bool StackDepotReverseMap::IdDescPair::IdComparator( 119*68d75effSDimitry Andric const StackDepotReverseMap::IdDescPair &a, 120*68d75effSDimitry Andric const StackDepotReverseMap::IdDescPair &b) { 121*68d75effSDimitry Andric return a.id < b.id; 122*68d75effSDimitry Andric } 123*68d75effSDimitry Andric 124*68d75effSDimitry Andric StackDepotReverseMap::StackDepotReverseMap() { 125*68d75effSDimitry Andric map_.reserve(StackDepotGetStats()->n_uniq_ids + 100); 126*68d75effSDimitry Andric for (int idx = 0; idx < StackDepot::kTabSize; idx++) { 127*68d75effSDimitry Andric atomic_uintptr_t *p = &theDepot.tab[idx]; 128*68d75effSDimitry Andric uptr v = atomic_load(p, memory_order_consume); 129*68d75effSDimitry Andric StackDepotNode *s = (StackDepotNode*)(v & ~1); 130*68d75effSDimitry Andric for (; s; s = s->link) { 131*68d75effSDimitry Andric IdDescPair pair = {s->id, s}; 132*68d75effSDimitry Andric map_.push_back(pair); 133*68d75effSDimitry Andric } 134*68d75effSDimitry Andric } 135*68d75effSDimitry Andric Sort(map_.data(), map_.size(), &IdDescPair::IdComparator); 136*68d75effSDimitry Andric } 137*68d75effSDimitry Andric 138*68d75effSDimitry Andric StackTrace StackDepotReverseMap::Get(u32 id) { 139*68d75effSDimitry Andric if (!map_.size()) 140*68d75effSDimitry Andric return StackTrace(); 141*68d75effSDimitry Andric IdDescPair pair = {id, nullptr}; 142*68d75effSDimitry Andric uptr idx = 143*68d75effSDimitry Andric InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator); 144*68d75effSDimitry Andric if (idx > map_.size() || map_[idx].id != id) 145*68d75effSDimitry Andric return StackTrace(); 146*68d75effSDimitry Andric return map_[idx].desc->load(); 147*68d75effSDimitry Andric } 148*68d75effSDimitry Andric 149*68d75effSDimitry Andric } // namespace __sanitizer 150