1 : // Copyright 2011 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #ifndef SYZYGY_CORE_ADDRESS_H_
16 : #define SYZYGY_CORE_ADDRESS_H_
17 :
18 : #include <stdint.h>
19 : #include <iosfwd>
20 :
21 : #include "base/logging.h"
22 : #include "syzygy/common/align.h"
23 : #include "syzygy/core/serialization.h"
24 :
25 : namespace core {
26 :
27 : enum AddressType : uint8_t {
28 : kRelativeAddressType,
29 : kAbsoluteAddressType,
30 : kFileOffsetAddressType,
31 : };
32 :
33 : namespace detail {
34 :
35 : // This class implements an address in a PE image file.
36 : // Addresses are of three varieties:
37 : // - Relative addresses are relative to the base of the image, and thus do not
38 : // change when the image is relocated. Bulk of the addresses in the PE image
39 : // format itself are of this variety, and that's where relative addresses
40 : // crop up most frequently.
41 : // - Absolute addresses are as the name indicates absolute, and those change
42 : // when an image is relocated. Absolute addresses mostly occur in initialized
43 : // data, and for each absolute datum in an image file, there will be a
44 : // relocation entry calling out its location in the image.
45 : // - File offset addresses occur only in the debug data directory that I'm
46 : // aware of, where the debug data is referred to both by a relative address
47 : // and (presumably for convenience) by a file offset address.
48 : // This class is a lightweight wrapper for an integer, which can be freely
49 : // copied. The different address types are deliberately assignment
50 : // incompatible, which helps to avoid confusion when handling different
51 : // types of addresses in implementation.
52 : template <AddressType kType>
53 : class AddressImpl {
54 : public:
55 : static const AddressImpl kInvalidAddress;
56 :
57 E : AddressImpl() : value_(0) {}
58 E : explicit AddressImpl(size_t value) : value_(value) {}
59 E : AddressImpl(const AddressImpl<kType>& other) // NOLINT
60 E : : value_(other.value_) {}
61 :
62 E : AddressImpl<kType>& operator=(const AddressImpl<kType>& other) {
63 E : value_ = other.value_;
64 E : return *this;
65 E : }
66 :
67 : // Comparison operators to other concrete addresses.
68 E : bool operator<(const AddressImpl<kType>& other) const {
69 E : return value_ < other.value_;
70 E : }
71 E : bool operator<=(const AddressImpl<kType>& other) const {
72 E : return value_ <= other.value_;
73 E : }
74 E : bool operator>(const AddressImpl<kType>& other) const {
75 E : return value_ > other.value_;
76 E : }
77 E : bool operator>=(const AddressImpl<kType>& other) const {
78 E : return value_ >= other.value_;
79 E : }
80 E : bool operator==(const AddressImpl<kType>& other) const {
81 E : return value_ == other.value_;
82 E : }
83 E : bool operator!=(const AddressImpl<kType>& other) const {
84 E : return value_ != other.value_;
85 E : }
86 :
87 : // Arithmetic operators.
88 E : void operator+=(intptr_t offset) { value_ += offset; }
89 E : void operator-=(intptr_t offset) { value_ -= offset; }
90 E : AddressImpl<kType> operator+(size_t offset) const {
91 E : return AddressImpl<kType>(value_ + offset);
92 E : }
93 E : AddressImpl<kType> operator-(size_t offset) const {
94 E : return AddressImpl<kType>(value_ - offset);
95 E : }
96 E : intptr_t operator-(const AddressImpl<kType>& other) const {
97 E : return value_ - other.value_;
98 E : }
99 :
100 : // Accessors and mutators.
101 E : static AddressType type() { return kType; }
102 E : uintptr_t value() const { return value_; }
103 E : void set_value(uintptr_t value) { value_ = value; }
104 :
105 : // @param alignment the alignment to be provided.
106 : // @returns an address that has been increased minimally to have the requested
107 : // @p alignment.
108 E : AddressImpl<kType> AlignUp(size_t alignment) const {
109 E : return AddressImpl<kType>(common::AlignUp(value_, alignment));
110 E : }
111 :
112 : // Determines if this address has the provided @p alignment.
113 : // @param alignment the alignment to be tested against.
114 : // @returns true if the address is aligned to @p alignment, false otherwise.
115 E : bool IsAligned(size_t alignment) const {
116 E : return common::IsAligned(value_, alignment);
117 E : }
118 :
119 : // Determines the address alignment. If the value of the address is 0 then we
120 : // return the maximum alignment for a 32-bit address (0x80000000).
121 : // @returns the alignment of the address.
122 E : size_t GetAlignment() const { return common::GetAlignment(value_); }
123 :
124 : // For serialization.
125 E : bool Save(OutArchive *out_archive) const {
126 E : return out_archive->Save(value_);
127 E : }
128 E : bool Load(InArchive *in_archive) {
129 E : return in_archive->Load(&value_);
130 E : }
131 :
132 : friend std::ostream& operator<<(std::ostream& str,
133 : const AddressImpl<kType>& addr);
134 :
135 : private:
136 : uintptr_t value_;
137 : };
138 :
139 : } // namespace detail
140 :
141 : // These types represent the different addressing formats used in PE images.
142 :
143 : // A virtual address relative to the image base, often termed RVA in
144 : // documentation and in data structure comments.
145 E : using RelativeAddress = detail::AddressImpl<kRelativeAddressType>;
146 : // An absolute address.
147 : using AbsoluteAddress = detail::AddressImpl<kAbsoluteAddressType>;
148 : // A file offset within an image file.
149 : using FileOffsetAddress = detail::AddressImpl<kFileOffsetAddressType>;
150 :
151 : // An address variant that can house any of the concrete address types.
152 : class AddressVariant {
153 : public:
154 E : AddressVariant() : type_(kRelativeAddressType), value_(0) {}
155 E : AddressVariant(AddressType type, size_t value) : type_(type), value_(value) {}
156 E : AddressVariant(const AddressVariant& other) // NOLINT
157 E : : type_(other.type_), value_(other.value_) {}
158 : template <AddressType kType>
159 : explicit AddressVariant(const detail::AddressImpl<kType>& other)
160 : : type_(kType), value_(other.value()) {}
161 :
162 : // Allow assignment from any address type.
163 : template <AddressType kType>
164 E : AddressVariant& operator=(const detail::AddressImpl<kType>& other) {
165 E : type_ = kType;
166 E : value_ = other.value();
167 E : return *this;
168 E : }
169 : AddressVariant& operator=(const AddressVariant& other);
170 :
171 : // Accessors and mutators.
172 E : AddressType type() const { return type_; }
173 E : uintptr_t value() const { return value_; }
174 E : void set_type(AddressType type) { type_ = type; }
175 E : void set_value(uintptr_t value) { value_ = value; }
176 :
177 : // Comparison operators.
178 : bool operator<(const AddressVariant& other) const;
179 : bool operator<=(const AddressVariant& other) const;
180 : bool operator>(const AddressVariant& other) const;
181 : bool operator>=(const AddressVariant& other) const;
182 : bool operator==(const AddressVariant& other) const;
183 : bool operator!=(const AddressVariant& other) const;
184 :
185 : // Arithmetic operators.
186 E : void operator+=(intptr_t offset) { value_ += offset; }
187 E : void operator-=(intptr_t offset) { value_ -= offset; }
188 E : AddressVariant operator+(size_t offset) const {
189 E : return AddressVariant(type_, value_ + offset);
190 E : }
191 : AddressVariant operator-(size_t offset) const {
192 : return AddressVariant(type_, value_ - offset);
193 : }
194 :
195 : // NOTE: No operator-(const AddressVariant&) is provided as the types may
196 : // not be consistent and the result may not make sense.
197 :
198 : // For extracting concrete address types.
199 : // @tparam kType the concrete address type.
200 : // @param addr the concrete address instance to be populated with the
201 : // address in this variant.
202 : // @returns true on success (the type of this variant matches the type of
203 : // the concrete class), false otherwise.
204 : template <AddressType kType>
205 E : bool Extract(detail::AddressImpl<kType>* addr) const {
206 E : DCHECK_NE(static_cast<detail::AddressImpl<kType>*>(nullptr), addr);
207 E : if (kType != type_)
208 E : return false;
209 E : addr->set_value(value_);
210 E : return true;
211 E : }
212 :
213 : // @param alignment the alignment to be provided.
214 : // @returns an address that has been increased minimally to have the requested
215 : // @p alignment.
216 E : AddressVariant AlignUp(size_t alignment) const {
217 E : return AddressVariant(type_, common::AlignUp(value_, alignment));
218 E : }
219 :
220 : // Determines if this address has the provided @p alignment.
221 : // @param alignment the alignment to be tested against.
222 : // @returns true if the address is aligned to @p alignment, false otherwise.
223 : bool IsAligned(size_t alignment) const {
224 : return common::IsAligned(value_, alignment);
225 : }
226 :
227 : // Determines the address alignment. If the value of the address is 0 then we
228 : // return the maximum alignment for a 32-bit address (0x80000000).
229 : // @returns the alignment of the address.
230 : size_t GetAlignment() const { return common::GetAlignment(value_); }
231 :
232 : // For serialization.
233 : bool Save(OutArchive* out_archive) const;
234 : bool Load(InArchive* in_archive);
235 :
236 : friend std::ostream& operator<<(std::ostream& str,
237 : const AddressVariant& addr);
238 :
239 : private:
240 : AddressType type_;
241 : size_t value_;
242 : };
243 :
244 : } // namespace core
245 :
246 : #endif // SYZYGY_CORE_ADDRESS_H_
|