sanitizer_stackdepot.cc revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===-- sanitizer_stackdepot.cc -------------------------------------------===//
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                     The LLVM Compiler Infrastructure
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// License. See LICENSE.TXT for details.
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)//
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)//===----------------------------------------------------------------------===//
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is shared between AddressSanitizer and ThreadSanitizer
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// run-time libraries.
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch//===----------------------------------------------------------------------===//
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_stackdepot.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_common.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sanitizer_stackdepotbase.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace __sanitizer {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct StackDepotDesc {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uptr *stack;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uptr size;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  u32 hash() const {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // murmur2
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const u32 m = 0x5bd1e995;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const u32 seed = 0x9747b28c;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const u32 r = 24;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    u32 h = seed ^ (size * sizeof(uptr));
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (uptr i = 0; i < size; i++) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      u32 k = stack[i];
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      k *= m;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      k ^= k >> r;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      k *= m;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      h *= m;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      h ^= k;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    h ^= h >> 13;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    h *= m;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    h ^= h >> 15;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return h;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_valid() { return size > 0 && stack; }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct StackDepotNode {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StackDepotNode *link;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  u32 id;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uptr size;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uptr stack[1];  // [size]
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const u32 kTabSizeLog = 20;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Lower kTabSizeLog bits are equal for all items in one bucket.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We use these bits to store the per-stack use counter.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const u32 kUseCountBits = kTabSizeLog;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const u32 kMaxUseCount = 1 << kUseCountBits;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const u32 kUseCountMask = (1 << kUseCountBits) - 1;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const u32 kHashMask = ~kUseCountMask;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef StackDepotDesc args_type;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool eq(u32 hash, const args_type &args) const {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    u32 hash_bits =
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((hash & kHashMask) != hash_bits || args.size != size) return false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uptr i = 0;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (; i < size; i++) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (stack[i] != args.stack[i]) return false;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static uptr storage_size(const args_type &args) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void store(const args_type &args, u32 hash) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed);
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    size = args.size;
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    internal_memcpy(stack, args.stack, size * sizeof(uptr));
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args_type load() const {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args_type ret = {&stack[0], size};
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret;
83  }
84  StackDepotHandle get_handle() { return StackDepotHandle(this); }
85
86  typedef StackDepotHandle handle_type;
87};
88
89COMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount);
90
91u32 StackDepotHandle::id() { return node_->id; }
92int StackDepotHandle::use_count() {
93  return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) &
94         StackDepotNode::kUseCountMask;
95}
96void StackDepotHandle::inc_use_count_unsafe() {
97  u32 prev =
98      atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) &
99      StackDepotNode::kUseCountMask;
100  CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount);
101}
102uptr StackDepotHandle::size() { return node_->size; }
103uptr *StackDepotHandle::stack() { return &node_->stack[0]; }
104
105// FIXME(dvyukov): this single reserved bit is used in TSan.
106typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog>
107    StackDepot;
108static StackDepot theDepot;
109
110StackDepotStats *StackDepotGetStats() {
111  return theDepot.GetStats();
112}
113
114u32 StackDepotPut(const uptr *stack, uptr size) {
115  StackDepotDesc desc = {stack, size};
116  StackDepotHandle h = theDepot.Put(desc);
117  return h.valid() ? h.id() : 0;
118}
119
120StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size) {
121  StackDepotDesc desc = {stack, size};
122  return theDepot.Put(desc);
123}
124
125const uptr *StackDepotGet(u32 id, uptr *size) {
126  StackDepotDesc desc = theDepot.Get(id);
127  *size = desc.size;
128  return desc.stack;
129}
130
131bool StackDepotReverseMap::IdDescPair::IdComparator(
132    const StackDepotReverseMap::IdDescPair &a,
133    const StackDepotReverseMap::IdDescPair &b) {
134  return a.id < b.id;
135}
136
137StackDepotReverseMap::StackDepotReverseMap()
138    : map_(StackDepotGetStats()->n_uniq_ids + 100) {
139  for (int idx = 0; idx < StackDepot::kTabSize; idx++) {
140    atomic_uintptr_t *p = &theDepot.tab[idx];
141    uptr v = atomic_load(p, memory_order_consume);
142    StackDepotNode *s = (StackDepotNode*)(v & ~1);
143    for (; s; s = s->link) {
144      IdDescPair pair = {s->id, s};
145      map_.push_back(pair);
146    }
147  }
148  InternalSort(&map_, map_.size(), IdDescPair::IdComparator);
149}
150
151const uptr *StackDepotReverseMap::Get(u32 id, uptr *size) {
152  if (!map_.size()) return 0;
153  IdDescPair pair = {id, 0};
154  uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
155                                  IdDescPair::IdComparator);
156  if (idx > map_.size()) {
157    *size = 0;
158    return 0;
159  }
160  StackDepotNode *desc = map_[idx].desc;
161  *size = desc->size;
162  return desc->stack;
163}
164
165}  // namespace __sanitizer
166