168d75effSDimitry Andric //===-- sanitizer_stackdepot.cpp ------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries. 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric 1368d75effSDimitry Andric #include "sanitizer_stackdepot.h" 1468d75effSDimitry Andric 1568d75effSDimitry Andric #include "sanitizer_common.h" 1668d75effSDimitry Andric #include "sanitizer_hash.h" 17349cc55cSDimitry Andric #include "sanitizer_stack_store.h" 1868d75effSDimitry Andric #include "sanitizer_stackdepotbase.h" 1968d75effSDimitry Andric 2068d75effSDimitry Andric namespace __sanitizer { 2168d75effSDimitry Andric 2268d75effSDimitry Andric struct StackDepotNode { 23349cc55cSDimitry Andric using hash_type = u64; 24349cc55cSDimitry Andric hash_type stack_hash; 25349cc55cSDimitry Andric u32 link; 26*4824e7fdSDimitry Andric StackStore::Id store_id; 2768d75effSDimitry Andric 2868d75effSDimitry Andric static const u32 kTabSizeLog = SANITIZER_ANDROID ? 16 : 20; 2968d75effSDimitry Andric 3068d75effSDimitry Andric typedef StackTrace args_type; 31349cc55cSDimitry Andric bool eq(hash_type hash, const args_type &args) const { 32349cc55cSDimitry Andric return hash == stack_hash; 3368d75effSDimitry Andric } 34349cc55cSDimitry Andric static uptr allocated(); 35349cc55cSDimitry Andric static hash_type hash(const args_type &args) { 36349cc55cSDimitry Andric MurMur2Hash64Builder H(args.size * sizeof(uptr)); 3768d75effSDimitry Andric for (uptr i = 0; i < args.size; i++) H.add(args.trace[i]); 38349cc55cSDimitry Andric H.add(args.tag); 3968d75effSDimitry Andric return H.get(); 4068d75effSDimitry Andric } 4168d75effSDimitry Andric static bool is_valid(const args_type &args) { 4268d75effSDimitry Andric return args.size > 0 && args.trace; 4368d75effSDimitry Andric } 44349cc55cSDimitry Andric void store(u32 id, const args_type &args, hash_type hash); 45349cc55cSDimitry Andric args_type load(u32 id) const; 46349cc55cSDimitry Andric static StackDepotHandle get_handle(u32 id); 4768d75effSDimitry Andric 4868d75effSDimitry Andric typedef StackDepotHandle handle_type; 4968d75effSDimitry Andric }; 5068d75effSDimitry Andric 51349cc55cSDimitry Andric static StackStore stackStore; 5268d75effSDimitry Andric 5368d75effSDimitry Andric // FIXME(dvyukov): this single reserved bit is used in TSan. 5468d75effSDimitry Andric typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog> 5568d75effSDimitry Andric StackDepot; 5668d75effSDimitry Andric static StackDepot theDepot; 57349cc55cSDimitry Andric // Keep mutable data out of frequently access nodes to improve caching 58349cc55cSDimitry Andric // efficiency. 59349cc55cSDimitry Andric static TwoLevelMap<atomic_uint32_t, StackDepot::kNodesSize1, 60349cc55cSDimitry Andric StackDepot::kNodesSize2> 61349cc55cSDimitry Andric useCounts; 6268d75effSDimitry Andric 63349cc55cSDimitry Andric int StackDepotHandle::use_count() const { 64349cc55cSDimitry Andric return atomic_load_relaxed(&useCounts[id_]); 6568d75effSDimitry Andric } 6668d75effSDimitry Andric 67349cc55cSDimitry Andric void StackDepotHandle::inc_use_count_unsafe() { 68349cc55cSDimitry Andric atomic_fetch_add(&useCounts[id_], 1, memory_order_relaxed); 6968d75effSDimitry Andric } 7068d75effSDimitry Andric 71349cc55cSDimitry Andric uptr StackDepotNode::allocated() { 72*4824e7fdSDimitry Andric return stackStore.Allocated() + useCounts.MemoryUsage(); 73349cc55cSDimitry Andric } 74349cc55cSDimitry Andric 75349cc55cSDimitry Andric void StackDepotNode::store(u32 id, const args_type &args, hash_type hash) { 76349cc55cSDimitry Andric stack_hash = hash; 77*4824e7fdSDimitry Andric uptr pack = 0; 78*4824e7fdSDimitry Andric store_id = stackStore.Store(args, &pack); 79*4824e7fdSDimitry Andric if (pack) 80*4824e7fdSDimitry Andric stackStore.Pack(StackStore::Compression::None); 81349cc55cSDimitry Andric } 82349cc55cSDimitry Andric 83349cc55cSDimitry Andric StackDepotNode::args_type StackDepotNode::load(u32 id) const { 84349cc55cSDimitry Andric if (!store_id) 85349cc55cSDimitry Andric return {}; 86349cc55cSDimitry Andric return stackStore.Load(store_id); 87349cc55cSDimitry Andric } 88349cc55cSDimitry Andric 89349cc55cSDimitry Andric StackDepotStats StackDepotGetStats() { return theDepot.GetStats(); } 90349cc55cSDimitry Andric 91349cc55cSDimitry Andric u32 StackDepotPut(StackTrace stack) { return theDepot.Put(stack); } 92349cc55cSDimitry Andric 9368d75effSDimitry Andric StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) { 94349cc55cSDimitry Andric return StackDepotNode::get_handle(theDepot.Put(stack)); 9568d75effSDimitry Andric } 9668d75effSDimitry Andric 9768d75effSDimitry Andric StackTrace StackDepotGet(u32 id) { 9868d75effSDimitry Andric return theDepot.Get(id); 9968d75effSDimitry Andric } 10068d75effSDimitry Andric 10168d75effSDimitry Andric void StackDepotLockAll() { 10268d75effSDimitry Andric theDepot.LockAll(); 10368d75effSDimitry Andric } 10468d75effSDimitry Andric 10568d75effSDimitry Andric void StackDepotUnlockAll() { 10668d75effSDimitry Andric theDepot.UnlockAll(); 10768d75effSDimitry Andric } 10868d75effSDimitry Andric 109e8d8bef9SDimitry Andric void StackDepotPrintAll() { 110e8d8bef9SDimitry Andric #if !SANITIZER_GO 111e8d8bef9SDimitry Andric theDepot.PrintAll(); 112e8d8bef9SDimitry Andric #endif 113e8d8bef9SDimitry Andric } 114e8d8bef9SDimitry Andric 115349cc55cSDimitry Andric StackDepotHandle StackDepotNode::get_handle(u32 id) { 116349cc55cSDimitry Andric return StackDepotHandle(&theDepot.nodes[id], id); 11768d75effSDimitry Andric } 11868d75effSDimitry Andric 119349cc55cSDimitry Andric void StackDepotTestOnlyUnmap() { 120349cc55cSDimitry Andric theDepot.TestOnlyUnmap(); 121349cc55cSDimitry Andric stackStore.TestOnlyUnmap(); 12268d75effSDimitry Andric } 12368d75effSDimitry Andric 12468d75effSDimitry Andric } // namespace __sanitizer 125