1349cc55cSDimitry Andric //===-- sanitizer_stack_store.h ---------------------------------*- C++ -*-===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric 9349cc55cSDimitry Andric #ifndef SANITIZER_STACK_STORE_H 10349cc55cSDimitry Andric #define SANITIZER_STACK_STORE_H 11349cc55cSDimitry Andric 12349cc55cSDimitry Andric #include "sanitizer_atomic.h" 134824e7fdSDimitry Andric #include "sanitizer_common.h" 14349cc55cSDimitry Andric #include "sanitizer_internal_defs.h" 15349cc55cSDimitry Andric #include "sanitizer_mutex.h" 16349cc55cSDimitry Andric #include "sanitizer_stacktrace.h" 17349cc55cSDimitry Andric 18349cc55cSDimitry Andric namespace __sanitizer { 19349cc55cSDimitry Andric 20349cc55cSDimitry Andric class StackStore { 214824e7fdSDimitry Andric static constexpr uptr kBlockSizeFrames = 0x100000; 224824e7fdSDimitry Andric static constexpr uptr kBlockCount = 0x1000; 234824e7fdSDimitry Andric static constexpr uptr kBlockSizeBytes = kBlockSizeFrames * sizeof(uptr); 244824e7fdSDimitry Andric 25349cc55cSDimitry Andric public: 264824e7fdSDimitry Andric enum class Compression : u8 { 274824e7fdSDimitry Andric None = 0, 280eae32dcSDimitry Andric Delta, 290eae32dcSDimitry Andric LZW, 304824e7fdSDimitry Andric }; 314824e7fdSDimitry Andric 32349cc55cSDimitry Andric constexpr StackStore() = default; 33349cc55cSDimitry Andric 344824e7fdSDimitry Andric using Id = u32; // Enough for 2^32 * sizeof(uptr) bytes of traces. 354824e7fdSDimitry Andric static_assert(u64(kBlockCount) * kBlockSizeFrames == 1ull << (sizeof(Id) * 8), 364824e7fdSDimitry Andric ""); 37349cc55cSDimitry Andric 384824e7fdSDimitry Andric Id Store(const StackTrace &trace, 394824e7fdSDimitry Andric uptr *pack /* number of blocks completed by this call */); 40349cc55cSDimitry Andric StackTrace Load(Id id); 414824e7fdSDimitry Andric uptr Allocated() const; 424824e7fdSDimitry Andric 434824e7fdSDimitry Andric // Packs all blocks which don't expect any more writes. A block is going to be 444824e7fdSDimitry Andric // packed once. As soon trace from that block was requested, it will unpack 454824e7fdSDimitry Andric // and stay unpacked after that. 464824e7fdSDimitry Andric // Returns the number of released bytes. 474824e7fdSDimitry Andric uptr Pack(Compression type); 48349cc55cSDimitry Andric 490eae32dcSDimitry Andric void LockAll(); 500eae32dcSDimitry Andric void UnlockAll(); 510eae32dcSDimitry Andric 52349cc55cSDimitry Andric void TestOnlyUnmap(); 53349cc55cSDimitry Andric 54349cc55cSDimitry Andric private: 554824e7fdSDimitry Andric friend class StackStoreTest; GetBlockIdx(uptr frame_idx)564824e7fdSDimitry Andric static constexpr uptr GetBlockIdx(uptr frame_idx) { 574824e7fdSDimitry Andric return frame_idx / kBlockSizeFrames; 584824e7fdSDimitry Andric } 59349cc55cSDimitry Andric GetInBlockIdx(uptr frame_idx)604824e7fdSDimitry Andric static constexpr uptr GetInBlockIdx(uptr frame_idx) { 614824e7fdSDimitry Andric return frame_idx % kBlockSizeFrames; 624824e7fdSDimitry Andric } 634824e7fdSDimitry Andric IdToOffset(Id id)644824e7fdSDimitry Andric static constexpr uptr IdToOffset(Id id) { 654824e7fdSDimitry Andric CHECK_NE(id, 0); 664824e7fdSDimitry Andric return id - 1; // Avoid zero as id. 674824e7fdSDimitry Andric } 684824e7fdSDimitry Andric OffsetToId(Id id)694824e7fdSDimitry Andric static constexpr uptr OffsetToId(Id id) { 704824e7fdSDimitry Andric // This makes UINT32_MAX to 0 and it will be retrived as and empty stack. 714824e7fdSDimitry Andric // But this is not a problem as we will not be able to store anything after 724824e7fdSDimitry Andric // that anyway. 734824e7fdSDimitry Andric return id + 1; // Avoid zero as id. 744824e7fdSDimitry Andric } 754824e7fdSDimitry Andric 764824e7fdSDimitry Andric uptr *Alloc(uptr count, uptr *idx, uptr *pack); 774824e7fdSDimitry Andric 780eae32dcSDimitry Andric void *Map(uptr size, const char *mem_type); 790eae32dcSDimitry Andric void Unmap(void *addr, uptr size); 800eae32dcSDimitry Andric 814824e7fdSDimitry Andric // Total number of allocated frames. 824824e7fdSDimitry Andric atomic_uintptr_t total_frames_ = {}; 834824e7fdSDimitry Andric 840eae32dcSDimitry Andric // Tracks total allocated memory in bytes. 850eae32dcSDimitry Andric atomic_uintptr_t allocated_ = {}; 860eae32dcSDimitry Andric 874824e7fdSDimitry Andric // Each block will hold pointer to exactly kBlockSizeFrames. 884824e7fdSDimitry Andric class BlockInfo { 894824e7fdSDimitry Andric atomic_uintptr_t data_; 904824e7fdSDimitry Andric // Counter to track store progress to know when we can Pack() the block. 914824e7fdSDimitry Andric atomic_uint32_t stored_; 924824e7fdSDimitry Andric // Protects alloc of new blocks. 934824e7fdSDimitry Andric mutable StaticSpinMutex mtx_; 944824e7fdSDimitry Andric 954824e7fdSDimitry Andric enum class State : u8 { 964824e7fdSDimitry Andric Storing = 0, 974824e7fdSDimitry Andric Packed, 984824e7fdSDimitry Andric Unpacked, 99349cc55cSDimitry Andric }; 100*04eeddc0SDimitry Andric State state SANITIZER_GUARDED_BY(mtx_); 1014824e7fdSDimitry Andric 1020eae32dcSDimitry Andric uptr *Create(StackStore *store); 1034824e7fdSDimitry Andric 1044824e7fdSDimitry Andric public: 1054824e7fdSDimitry Andric uptr *Get() const; 1060eae32dcSDimitry Andric uptr *GetOrCreate(StackStore *store); 1070eae32dcSDimitry Andric uptr *GetOrUnpack(StackStore *store); 1080eae32dcSDimitry Andric uptr Pack(Compression type, StackStore *store); 1090eae32dcSDimitry Andric void TestOnlyUnmap(StackStore *store); 1104824e7fdSDimitry Andric bool Stored(uptr n); 1114824e7fdSDimitry Andric bool IsPacked() const; Lock()112*04eeddc0SDimitry Andric void Lock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Lock(); } Unlock()113*04eeddc0SDimitry Andric void Unlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Unlock(); } 1144824e7fdSDimitry Andric }; 1154824e7fdSDimitry Andric 1164824e7fdSDimitry Andric BlockInfo blocks_[kBlockCount] = {}; 117349cc55cSDimitry Andric }; 118349cc55cSDimitry Andric 119349cc55cSDimitry Andric } // namespace __sanitizer 120349cc55cSDimitry Andric 121349cc55cSDimitry Andric #endif // SANITIZER_STACK_STORE_H 122