sanitizer_stack_store.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #ifndef SANITIZER_STACK_STORE_H
  9. #define SANITIZER_STACK_STORE_H
  10. #include "sanitizer_atomic.h"
  11. #include "sanitizer_common.h"
  12. #include "sanitizer_internal_defs.h"
  13. #include "sanitizer_mutex.h"
  14. #include "sanitizer_stacktrace.h"
  15. namespace __sanitizer {
  16. class StackStore {
  17. static constexpr uptr kBlockSizeFrames = 0x100000;
  18. static constexpr uptr kBlockCount = 0x1000;
  19. static constexpr uptr kBlockSizeBytes = kBlockSizeFrames * sizeof(uptr);
  20. public:
  21. enum class Compression : u8 {
  22. None = 0,
  23. Delta,
  24. LZW,
  25. };
  26. constexpr StackStore() = default;
  27. using Id = u32; // Enough for 2^32 * sizeof(uptr) bytes of traces.
  28. static_assert(u64(kBlockCount) * kBlockSizeFrames == 1ull << (sizeof(Id) * 8),
  29. "");
  30. Id Store(const StackTrace &trace,
  31. uptr *pack /* number of blocks completed by this call */);
  32. StackTrace Load(Id id);
  33. uptr Allocated() const;
  34. // Packs all blocks which don't expect any more writes. A block is going to be
  35. // packed once. As soon trace from that block was requested, it will unpack
  36. // and stay unpacked after that.
  37. // Returns the number of released bytes.
  38. uptr Pack(Compression type);
  39. void LockAll();
  40. void UnlockAll();
  41. void TestOnlyUnmap();
  42. private:
  43. friend class StackStoreTest;
  44. static constexpr uptr GetBlockIdx(uptr frame_idx) {
  45. return frame_idx / kBlockSizeFrames;
  46. }
  47. static constexpr uptr GetInBlockIdx(uptr frame_idx) {
  48. return frame_idx % kBlockSizeFrames;
  49. }
  50. static constexpr uptr IdToOffset(Id id) {
  51. CHECK_NE(id, 0);
  52. return id - 1; // Avoid zero as id.
  53. }
  54. static constexpr uptr OffsetToId(Id id) {
  55. // This makes UINT32_MAX to 0 and it will be retrived as and empty stack.
  56. // But this is not a problem as we will not be able to store anything after
  57. // that anyway.
  58. return id + 1; // Avoid zero as id.
  59. }
  60. uptr *Alloc(uptr count, uptr *idx, uptr *pack);
  61. void *Map(uptr size, const char *mem_type);
  62. void Unmap(void *addr, uptr size);
  63. // Total number of allocated frames.
  64. atomic_uintptr_t total_frames_ = {};
  65. // Tracks total allocated memory in bytes.
  66. atomic_uintptr_t allocated_ = {};
  67. // Each block will hold pointer to exactly kBlockSizeFrames.
  68. class BlockInfo {
  69. atomic_uintptr_t data_;
  70. // Counter to track store progress to know when we can Pack() the block.
  71. atomic_uint32_t stored_;
  72. // Protects alloc of new blocks.
  73. mutable StaticSpinMutex mtx_;
  74. enum class State : u8 {
  75. Storing = 0,
  76. Packed,
  77. Unpacked,
  78. };
  79. State state SANITIZER_GUARDED_BY(mtx_);
  80. uptr *Create(StackStore *store);
  81. public:
  82. uptr *Get() const;
  83. uptr *GetOrCreate(StackStore *store);
  84. uptr *GetOrUnpack(StackStore *store);
  85. uptr Pack(Compression type, StackStore *store);
  86. void TestOnlyUnmap(StackStore *store);
  87. bool Stored(uptr n);
  88. bool IsPacked() const;
  89. void Lock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Lock(); }
  90. void Unlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mtx_.Unlock(); }
  91. };
  92. BlockInfo blocks_[kBlockCount] = {};
  93. };
  94. } // namespace __sanitizer
  95. #endif // SANITIZER_STACK_STORE_H