1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
//===-- msan_chained_origin_depot.cc -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// A storage for chained origins.
//===----------------------------------------------------------------------===//
#include "msan_chained_origin_depot.h"
#include "sanitizer_common/sanitizer_stackdepotbase.h"
namespace __msan {
struct ChainedOriginDepotDesc {
u32 here_id;
u32 prev_id;
};
struct ChainedOriginDepotNode {
ChainedOriginDepotNode *link;
u32 id;
u32 here_id;
u32 prev_id;
typedef ChainedOriginDepotDesc args_type;
bool eq(u32 hash, const args_type &args) const {
return here_id == args.here_id && prev_id == args.prev_id;
}
static uptr storage_size(const args_type &args) {
return sizeof(ChainedOriginDepotNode);
}
/* This is murmur2 hash for the 64->32 bit case.
It does not behave all that well because the keys have a very biased
distribution (I've seen 7-element buckets with the table only 14% full).
here_id is built of
* (1 bits) Reserved, zero.
* (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
* (23 bits) Sequential number (each part has each own sequence).
prev_id has either the same distribution as here_id (but with 3:8:21)
split, or one of two reserved values (-1) or (-2). Either case can
dominate depending on the workload.
*/
static u32 hash(const args_type &args) {
const u32 m = 0x5bd1e995;
const u32 seed = 0x9747b28c;
const u32 r = 24;
u32 h = seed;
u32 k = args.here_id;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
k = args.prev_id;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
static bool is_valid(const args_type &args) { return true; }
void store(const args_type &args, u32 other_hash) {
here_id = args.here_id;
prev_id = args.prev_id;
}
args_type load() const {
args_type ret = {here_id, prev_id};
return ret;
}
struct Handle {
ChainedOriginDepotNode *node_;
Handle() : node_(nullptr) {}
explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
bool valid() { return node_; }
u32 id() { return node_->id; }
int here_id() { return node_->here_id; }
int prev_id() { return node_->prev_id; }
};
Handle get_handle() { return Handle(this); }
typedef Handle handle_type;
};
static StackDepotBase<ChainedOriginDepotNode, 4, 20> chainedOriginDepot;
StackDepotStats *ChainedOriginDepotGetStats() {
return chainedOriginDepot.GetStats();
}
bool ChainedOriginDepotPut(u32 here_id, u32 prev_id, u32 *new_id) {
ChainedOriginDepotDesc desc = {here_id, prev_id};
bool inserted;
ChainedOriginDepotNode::Handle h = chainedOriginDepot.Put(desc, &inserted);
*new_id = h.valid() ? h.id() : 0;
return inserted;
}
// Retrieves a stored stack trace by the id.
u32 ChainedOriginDepotGet(u32 id, u32 *other) {
ChainedOriginDepotDesc desc = chainedOriginDepot.Get(id);
*other = desc.prev_id;
return desc.here_id;
}
void ChainedOriginDepotLockAll() {
chainedOriginDepot.LockAll();
}
void ChainedOriginDepotUnlockAll() {
chainedOriginDepot.UnlockAll();
}
} // namespace __msan
|