mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-23 10:54:07 +08:00
122 lines
3.4 KiB
C++
122 lines
3.4 KiB
C++
//===-- sanitizer_stack_store.h ---------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SANITIZER_STACK_STORE_H
|
|
#define SANITIZER_STACK_STORE_H
|
|
|
|
#include "sanitizer_atomic.h"
|
|
#include "sanitizer_common.h"
|
|
#include "sanitizer_internal_defs.h"
|
|
#include "sanitizer_mutex.h"
|
|
#include "sanitizer_stacktrace.h"
|
|
|
|
namespace __sanitizer {
|
|
|
|
class StackStore {
|
|
static constexpr uptr kBlockSizeFrames = 0x100000;
|
|
static constexpr uptr kBlockCount = 0x1000;
|
|
static constexpr uptr kBlockSizeBytes = kBlockSizeFrames * sizeof(uptr);
|
|
|
|
public:
|
|
enum class Compression : u8 {
|
|
None = 0,
|
|
Delta,
|
|
LZW,
|
|
};
|
|
|
|
constexpr StackStore() = default;
|
|
|
|
using Id = u32; // Enough for 2^32 * sizeof(uptr) bytes of traces.
|
|
static_assert(u64(kBlockCount) * kBlockSizeFrames == 1ull << (sizeof(Id) * 8),
|
|
"");
|
|
|
|
Id Store(const StackTrace &trace,
|
|
uptr *pack /* number of blocks completed by this call */);
|
|
StackTrace Load(Id id);
|
|
uptr Allocated() const;
|
|
|
|
// Packs all blocks which don't expect any more writes. A block is going to be
|
|
// packed once. As soon trace from that block was requested, it will unpack
|
|
// and stay unpacked after that.
|
|
// Returns the number of released bytes.
|
|
uptr Pack(Compression type);
|
|
|
|
void LockAll();
|
|
void UnlockAll();
|
|
|
|
void TestOnlyUnmap();
|
|
|
|
private:
|
|
friend class StackStoreTest;
|
|
static constexpr uptr GetBlockIdx(uptr frame_idx) {
|
|
return frame_idx / kBlockSizeFrames;
|
|
}
|
|
|
|
static constexpr uptr GetInBlockIdx(uptr frame_idx) {
|
|
return frame_idx % kBlockSizeFrames;
|
|
}
|
|
|
|
static constexpr uptr IdToOffset(Id id) {
|
|
CHECK_NE(id, 0);
|
|
return id - 1; // Avoid zero as id.
|
|
}
|
|
|
|
static constexpr uptr OffsetToId(Id id) {
|
|
// This makes UINT32_MAX to 0 and it will be retrived as and empty stack.
|
|
// But this is not a problem as we will not be able to store anything after
|
|
// that anyway.
|
|
return id + 1; // Avoid zero as id.
|
|
}
|
|
|
|
uptr *Alloc(uptr count, uptr *idx, uptr *pack);
|
|
|
|
void *Map(uptr size, const char *mem_type);
|
|
void Unmap(void *addr, uptr size);
|
|
|
|
// Total number of allocated frames.
|
|
atomic_uintptr_t total_frames_ = {};
|
|
|
|
// Tracks total allocated memory in bytes.
|
|
atomic_uintptr_t allocated_ = {};
|
|
|
|
// Each block will hold pointer to exactly kBlockSizeFrames.
|
|
class BlockInfo {
|
|
atomic_uintptr_t data_;
|
|
// Counter to track store progress to know when we can Pack() the block.
|
|
atomic_uint32_t stored_;
|
|
// Protects alloc of new blocks.
|
|
mutable StaticSpinMutex mtx_;
|
|
|
|
enum class State : u8 {
|
|
Storing = 0,
|
|
Packed,
|
|
Unpacked,
|
|
};
|
|
State state SANITIZER_GUARDED_BY(mtx_);
|
|
|
|
uptr *Create(StackStore *store);
|
|
|
|
public:
|
|
uptr *Get() const;
|
|
uptr *GetOrCreate(StackStore *store);
|
|
uptr *GetOrUnpack(StackStore *store);
|
|
uptr Pack(Compression type, StackStore *store);
|
|
void TestOnlyUnmap(StackStore *store);
|
|
bool Stored(uptr n);
|
|
bool IsPacked() const;
|
|
void Lock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Lock(); }
|
|
void Unlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Unlock(); }
|
|
};
|
|
|
|
BlockInfo blocks_[kBlockCount] = {};
|
|
};
|
|
|
|
} // namespace __sanitizer
|
|
|
|
#endif // SANITIZER_STACK_STORE_H
|