122 lines · c
1//===-- sanitizer_stack_store.h ---------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef SANITIZER_STACK_STORE_H10#define SANITIZER_STACK_STORE_H11 12#include "sanitizer_atomic.h"13#include "sanitizer_common.h"14#include "sanitizer_internal_defs.h"15#include "sanitizer_mutex.h"16#include "sanitizer_stacktrace.h"17 18namespace __sanitizer {19 20class StackStore {21 static constexpr uptr kBlockSizeFrames = 0x100000;22 static constexpr uptr kBlockCount = 0x1000;23 static constexpr uptr kBlockSizeBytes = kBlockSizeFrames * sizeof(uptr);24 25 public:26 enum class Compression : u8 {27 None = 0,28 Delta,29 LZW,30 };31 32 constexpr StackStore() = default;33 34 using Id = u32; // Enough for 2^32 * sizeof(uptr) bytes of traces.35 static_assert(u64(kBlockCount) * kBlockSizeFrames == 1ull << (sizeof(Id) * 8),36 "");37 38 Id Store(const StackTrace &trace,39 uptr *pack /* number of blocks completed by this call */);40 StackTrace Load(Id id);41 uptr Allocated() const;42 43 // Packs all blocks which don't expect any more writes. A block is going to be44 // packed once. As soon trace from that block was requested, it will unpack45 // and stay unpacked after that.46 // Returns the number of released bytes.47 uptr Pack(Compression type);48 49 void LockAll();50 void UnlockAll();51 52 void TestOnlyUnmap();53 54 private:55 friend class StackStoreTest;56 static constexpr uptr GetBlockIdx(uptr frame_idx) {57 return frame_idx / kBlockSizeFrames;58 }59 60 static constexpr uptr GetInBlockIdx(uptr frame_idx) {61 return frame_idx % kBlockSizeFrames;62 }63 64 static constexpr uptr IdToOffset(Id id) {65 CHECK_NE(id, 0);66 return id - 1; // Avoid zero as id.67 }68 69 static constexpr uptr OffsetToId(Id id) {70 // This makes UINT32_MAX to 0 and it will be retrived as and empty stack.71 // But this is not a problem as we will not be able to store anything after72 // that anyway.73 return id + 1; // Avoid zero as id.74 }75 76 uptr *Alloc(uptr count, uptr *idx, uptr *pack);77 78 void *Map(uptr size, const char *mem_type);79 void Unmap(void *addr, uptr size);80 81 // Total number of allocated frames.82 atomic_uintptr_t total_frames_ = {};83 84 // Tracks total allocated memory in bytes.85 atomic_uintptr_t allocated_ = {};86 87 // Each block will hold pointer to exactly kBlockSizeFrames.88 class BlockInfo {89 atomic_uintptr_t data_;90 // Counter to track store progress to know when we can Pack() the block.91 atomic_uint32_t stored_;92 // Protects alloc of new blocks.93 mutable StaticSpinMutex mtx_;94 95 enum class State : u8 {96 Storing = 0,97 Packed,98 Unpacked,99 };100 State state SANITIZER_GUARDED_BY(mtx_);101 102 uptr *Create(StackStore *store);103 104 public:105 uptr *Get() const;106 uptr *GetOrCreate(StackStore *store);107 uptr *GetOrUnpack(StackStore *store);108 uptr Pack(Compression type, StackStore *store);109 void TestOnlyUnmap(StackStore *store);110 bool Stored(uptr n);111 bool IsPacked() const;112 void Lock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Lock(); }113 void Unlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Unlock(); }114 };115 116 BlockInfo blocks_[kBlockCount] = {};117};118 119} // namespace __sanitizer120 121#endif // SANITIZER_STACK_STORE_H122