xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cpp (revision 4824e7fd18a1223177218d4aec1b3c6c5c4a444e)
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