1//===-- copyprof_shadow.cpp ----------------------------------------------===//
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///
9/// This file implements the shadow memory management for CopyProf, tracking
10/// the copy status and modification state of application memory.
11///
12//===----------------------------------------------------------------------===//
13
14#include "copyprof_shadow.h"
15
16#include "sanitizer_common/sanitizer_internal_defs.h"
17
18namespace __copyprof {
19namespace {
20
21constexpr uptr kBitsPerShadowByte = 8;
22static_assert(
23 1 << kShadowScale == kBitsPerShadowByte,
24 "CopyProf tracks 1 bit per application byte (8 bits per shadow byte)");
25
26// Tracks whether application memory is marked as a copy.
27ShadowMemory g_copy_shadow;
28
29// Returns a mask with bits [`start_bit`, `end_bit`) set.
30unsigned char BitMask(uptr start_bit, uptr end_bit) {
31 CHECK_LE(start_bit, end_bit);
32 return static_cast<unsigned char>((1 << end_bit) - (1 << start_bit));
33}
34
35// Whether bits [`start_bit`, `end_bit`) of `shadow_byte` are all set.
36bool AllBitsSet(unsigned char shadow_byte, uptr start_bit, uptr end_bit) {
37 const unsigned char mask = BitMask(start_bit, end_bit);
38 return (shadow_byte & mask) == mask;
39}
40
41// Sets (or clears) bits [`start_bit`, `end_bit`) of `*shadow_byte`.
42void SetBits(unsigned char* shadow_byte, uptr start_bit, uptr end_bit,
43 bool is_copy) {
44 const unsigned char mask = BitMask(start_bit, end_bit);
45 if (is_copy)
46 *shadow_byte |= mask;
47 else
48 *shadow_byte &= static_cast<unsigned char>(~mask);
49}
50
51uptr BytesToShadowBits(uptr num_bytes) {
52 // Each application byte maps to one shadow bit.
53 return num_bytes;
54}
55
56} // namespace
57
58void InitializeShadowMemory() {
59 g_copy_shadow = ShadowMemory::Create(name: "copyprof");
60}
61
62void MarkApplicationMemory(const void* app_addr, uptr num_bytes, bool is_copy) {
63 CHECK_GT(num_bytes, 0);
64 const uptr addr = reinterpret_cast<uptr>(app_addr);
65 unsigned char* shadow =
66 reinterpret_cast<unsigned char*>(g_copy_shadow.MemToShadow(p: addr));
67
68 // An application range need not start on a shadow byte boundary, so it is
69 // updated in three steps: the leading (possibly partial) shadow byte, the
70 // whole shadow bytes in the middle, and the trailing partial byte.
71 uptr num_shadow_bits = BytesToShadowBits(num_bytes);
72 if (uptr start_bit = addr % kBitsPerShadowByte; start_bit > 0) {
73 uptr end_bit =
74 start_bit + Min(a: kBitsPerShadowByte - start_bit, b: num_shadow_bits);
75 SetBits(shadow_byte: shadow++, start_bit, end_bit, is_copy);
76 num_shadow_bits -= end_bit - start_bit;
77 }
78 if (uptr full_bytes = num_shadow_bits / kBitsPerShadowByte; full_bytes > 0) {
79 internal_memset(s: shadow, c: is_copy ? 0xFF : 0, n: full_bytes);
80 shadow += full_bytes;
81 num_shadow_bits -= full_bytes * kBitsPerShadowByte;
82 }
83 if (num_shadow_bits > 0)
84 SetBits(shadow_byte: shadow, /*start_bit=*/0, end_bit: num_shadow_bits, is_copy);
85}
86
87bool IsMarkedAsCopy(const void* app_addr, uptr num_bytes) {
88 CHECK_GT(num_bytes, 0);
89 const uptr addr = reinterpret_cast<uptr>(app_addr);
90 const auto* shadow =
91 reinterpret_cast<const unsigned char*>(g_copy_shadow.MemToShadow(p: addr));
92
93 uptr num_shadow_bits = BytesToShadowBits(num_bytes);
94 if (uptr start_bit = addr % kBitsPerShadowByte; start_bit > 0) {
95 uptr end_bit =
96 start_bit + Min(a: kBitsPerShadowByte - start_bit, b: num_shadow_bits);
97 if (!AllBitsSet(shadow_byte: *shadow++, start_bit, end_bit))
98 return false;
99 num_shadow_bits -= end_bit - start_bit;
100 }
101 uptr full_bytes = num_shadow_bits / kBitsPerShadowByte;
102 for (uptr i = 0; i < full_bytes; ++i) {
103 if (shadow[i] != 0xFF)
104 return false;
105 }
106 shadow += full_bytes;
107 num_shadow_bits -= full_bytes * kBitsPerShadowByte;
108 return num_shadow_bits == 0 ||
109 AllBitsSet(shadow_byte: *shadow, /*start_bit=*/0, end_bit: num_shadow_bits);
110}
111
112} // namespace __copyprof
113