11b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov//===-- sanitizer_stackdepot.cc -------------------------------------------===//
21b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov//
31b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov//                     The LLVM Compiler Infrastructure
41b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov//
51b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov// This file is distributed under the University of Illinois Open Source
61b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov// License. See LICENSE.TXT for details.
71b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov//
81b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov//===----------------------------------------------------------------------===//
91b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov//
101b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov// This file is shared between AddressSanitizer and ThreadSanitizer
111b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov// run-time libraries.
121b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov//===----------------------------------------------------------------------===//
131b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
141b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov#include "sanitizer_stackdepot.h"
152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
161b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov#include "sanitizer_common.h"
172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_stackdepotbase.h"
181b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
191b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukovnamespace __sanitizer {
201b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstruct StackDepotNode {
222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  StackDepotNode *link;
231b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov  u32 id;
242d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20;
2586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  u32 size;
2686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  u32 tag;
2784112a3553bfe10dd4c9e20567495804a15f4545Dmitry Vyukov  uptr stack[1];  // [size]
281b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
296a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  static const u32 kTabSizeLog = 20;
306a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  // Lower kTabSizeLog bits are equal for all items in one bucket.
316a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  // We use these bits to store the per-stack use counter.
326a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  static const u32 kUseCountBits = kTabSizeLog;
332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  static const u32 kMaxUseCount = 1 << kUseCountBits;
342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  static const u32 kUseCountMask = (1 << kUseCountBits) - 1;
352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  static const u32 kHashMask = ~kUseCountMask;
362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
376d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  typedef StackTrace args_type;
382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  bool eq(u32 hash, const args_type &args) const {
392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    u32 hash_bits =
402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask;
4186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    if ((hash & kHashMask) != hash_bits || args.size != size || args.tag != tag)
4286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      return false;
432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    uptr i = 0;
442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (; i < size; i++) {
456d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      if (stack[i] != args.trace[i]) return false;
462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return true;
482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  static uptr storage_size(const args_type &args) {
502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr);
512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
526d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  static u32 hash(const args_type &args) {
536d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    // murmur2
546d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    const u32 m = 0x5bd1e995;
556d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    const u32 seed = 0x9747b28c;
566d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    const u32 r = 24;
576d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    u32 h = seed ^ (args.size * sizeof(uptr));
586d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    for (uptr i = 0; i < args.size; i++) {
596d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      u32 k = args.trace[i];
606d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      k *= m;
616d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      k ^= k >> r;
626d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      k *= m;
636d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      h *= m;
646d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      h ^= k;
656d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    }
666d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    h ^= h >> 13;
676d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    h *= m;
686d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    h ^= h >> 15;
696d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    return h;
706d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  }
716d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  static bool is_valid(const args_type &args) {
726d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    return args.size > 0 && args.trace;
736d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  }
742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  void store(const args_type &args, u32 hash) {
752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed);
762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    size = args.size;
7786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    tag = args.tag;
786d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    internal_memcpy(stack, args.trace, size * sizeof(uptr));
792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  args_type load() const {
8186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    return args_type(&stack[0], size, tag);
822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  StackDepotHandle get_handle() { return StackDepotHandle(this); }
841b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  typedef StackDepotHandle handle_type;
862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines};
879e3bd38388a7c182db57f6e3fc0943e6d12f012eKostya Serebryany
882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesCOMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount);
899e3bd38388a7c182db57f6e3fc0943e6d12f012eKostya Serebryany
902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesu32 StackDepotHandle::id() { return node_->id; }
912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesint StackDepotHandle::use_count() {
922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) &
932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines         StackDepotNode::kUseCountMask;
9484112a3553bfe10dd4c9e20567495804a15f4545Dmitry Vyukov}
952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid StackDepotHandle::inc_use_count_unsafe() {
962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  u32 prev =
972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) &
982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      StackDepotNode::kUseCountMask;
992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount);
1001b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov}
1011b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
1022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// FIXME(dvyukov): this single reserved bit is used in TSan.
1036a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinestypedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog>
1046a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines    StackDepot;
1052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic StackDepot theDepot;
10684112a3553bfe10dd4c9e20567495804a15f4545Dmitry Vyukov
1072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesStackDepotStats *StackDepotGetStats() {
1082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return theDepot.GetStats();
10984112a3553bfe10dd4c9e20567495804a15f4545Dmitry Vyukov}
11084112a3553bfe10dd4c9e20567495804a15f4545Dmitry Vyukov
1116d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesu32 StackDepotPut(StackTrace stack) {
1126d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  StackDepotHandle h = theDepot.Put(stack);
1132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return h.valid() ? h.id() : 0;
1141b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov}
1151b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
1166d1862363c88c183b0ed7740fca876342cf0474bStephen HinesStackDepotHandle StackDepotPut_WithHandle(StackTrace stack) {
1176d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return theDepot.Put(stack);
1181b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov}
1191b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
1206d1862363c88c183b0ed7740fca876342cf0474bStephen HinesStackTrace StackDepotGet(u32 id) {
1216d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return theDepot.Get(id);
1226d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
1236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
1246d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid StackDepotLockAll() {
1256d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  theDepot.LockAll();
1266d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
1276d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
1286d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid StackDepotUnlockAll() {
1296d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  theDepot.UnlockAll();
1301b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov}
1311b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov
132384a448fbe081352f7b3bb927093412ad1725cffSergey Matveevbool StackDepotReverseMap::IdDescPair::IdComparator(
133384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev    const StackDepotReverseMap::IdDescPair &a,
134384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev    const StackDepotReverseMap::IdDescPair &b) {
135384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev  return a.id < b.id;
136384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev}
137384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev
138384a448fbe081352f7b3bb927093412ad1725cffSergey MatveevStackDepotReverseMap::StackDepotReverseMap()
139384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev    : map_(StackDepotGetStats()->n_uniq_ids + 100) {
1402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  for (int idx = 0; idx < StackDepot::kTabSize; idx++) {
1412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    atomic_uintptr_t *p = &theDepot.tab[idx];
142384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev    uptr v = atomic_load(p, memory_order_consume);
1432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    StackDepotNode *s = (StackDepotNode*)(v & ~1);
144384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev    for (; s; s = s->link) {
145384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev      IdDescPair pair = {s->id, s};
146384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev      map_.push_back(pair);
147384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev    }
148384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev  }
149384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev  InternalSort(&map_, map_.size(), IdDescPair::IdComparator);
150384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev}
151384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev
1526d1862363c88c183b0ed7740fca876342cf0474bStephen HinesStackTrace StackDepotReverseMap::Get(u32 id) {
1536d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (!map_.size())
1546d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    return StackTrace();
155384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev  IdDescPair pair = {id, 0};
156384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev  uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
157384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev                                  IdDescPair::IdComparator);
1586d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (idx > map_.size())
1596d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    return StackTrace();
1606d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return map_[idx].desc->load();
161384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev}
162384a448fbe081352f7b3bb927093412ad1725cffSergey Matveev
1631b37017f0216d0b8f3ae3a7dea8b3cc20d74db25Dmitry Vyukov}  // namespace __sanitizer
164