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 <iosfwd>
19 : #include "base/basictypes.h"
20 : #include "base/logging.h"
21 : #include "syzygy/common/align.h"
22 : #include "syzygy/core/serialization.h"
23 :
24 : namespace core {
25 :
26 : enum AddressType : uint8_t {
27 : kRelativeAddressType,
28 : kAbsoluteAddressType,
29 : kFileOffsetAddressType,
30 : };
31 :
32 : namespace detail {
33 :
34 : // This class implements an address in a PE image file.
35 : // Addresses are of three varieties:
36 : // - Relative addresses are relative to the base of the image, and thus do not
37 : // change when the image is relocated. Bulk of the addresses in the PE image
38 : // format itself are of this variety, and that's where relative addresses
39 : // crop up most frequently.
40 : // - Absolute addresses are as the name indicates absolute, and those change
41 : // when an image is relocated. Absolute addresses mostly occur in initialized
42 : // data, and for each absolute datum in an image file, there will be a
43 : // relocation entry calling out its location in the image.
44 : // - File offset addresses occur only in the debug data directory that I'm
45 : // aware of, where the debug data is referred to both by a relative address
46 : // and (presumably for convenience) by a file offset address.
47 : // This class is a lightweight wrapper for an integer, which can be freely
48 : // copied. The different address types are deliberately assignment
49 : // incompatible, which helps to avoid confusion when handling different
50 : // types of addresses in implementation.
51 : template <AddressType kType>
52 : class AddressImpl {
53 : public:
54 : static const AddressImpl kInvalidAddress;
55 :
56 E : AddressImpl() : value_(0) {}
57 E : explicit AddressImpl(uint32_t value) : value_(value) {}
58 E : AddressImpl(const AddressImpl<kType>& other) // NOLINT
59 : : value_(other.value_) {}
60 :
61 E : AddressImpl<kType>& operator=(const AddressImpl<kType>& other) {
62 E : value_ = other.value_;
63 E : return *this;
64 E : }
65 :
66 : // Comparison operators to other concrete addresses.
67 E : bool operator<(const AddressImpl<kType>& other) const {
68 E : return value_ < other.value_;
69 E : }
70 E : bool operator<=(const AddressImpl<kType>& other) const {
71 E : return value_ <= other.value_;
72 E : }
73 E : bool operator>(const AddressImpl<kType>& other) const {
74 E : return value_ > other.value_;
75 E : }
76 E : bool operator>=(const AddressImpl<kType>& other) const {
77 E : return value_ >= other.value_;
78 E : }
79 E : bool operator==(const AddressImpl<kType>& other) const {
80 E : return value_ == other.value_;
81 E : }
82 E : bool operator!=(const AddressImpl<kType>& other) const {
83 E : return value_ != other.value_;
84 E : }
85 :
86 : // Arithmetic operators.
87 E : void operator+=(int32_t offset) { value_ += offset; }
88 E : void operator-=(int32_t offset) { value_ -= offset; }
89 E : AddressImpl<kType> operator+(size_t offset) const {
90 E : return AddressImpl<kType>(value_ + offset);
91 E : }
92 E : AddressImpl<kType> operator-(size_t offset) const {
93 E : return AddressImpl<kType>(value_ - offset);
94 E : }
95 E : int32_t operator-(const AddressImpl<kType>& other) const {
96 E : return value_ - other.value_;
97 E : }
98 :
99 : // Accessors and mutators.
100 E : static AddressType type() { return kType; }
101 E : uint32_t value() const { return value_; }
102 E : void set_value(uint32_t value) { value_ = value; }
103 :
104 : // @param alignment the alignment to be provided.
105 : // @returns an address that has been increased minimally to have the requested
106 : // @p alignment.
107 E : AddressImpl<kType> AlignUp(size_t alignment) const {
108 E : return AddressImpl<kType>(common::AlignUp(value_, alignment));
109 E : }
110 :
111 : // Determines if this address has the provided @p alignment.
112 : // @param alignment the alignment to be tested against.
113 : // @returns true if the address is aligned to @p alignment, false otherwise.
114 E : bool IsAligned(size_t alignment) const {
115 E : return common::IsAligned(value_, alignment);
116 E : }
117 :
118 : // Determines the address alignment. If the value of the address is 0 then we
119 : // return the maximum alignment for a 32-bit address (0x80000000).
120 : // @returns the alignment of the address.
121 E : uint32_t GetAlignment() const { return common::GetAlignment(value_); }
122 :
123 : // For serialization.
124 E : bool Save(OutArchive *out_archive) const {
125 E : return out_archive->Save(value_);
126 E : }
127 E : bool Load(InArchive *in_archive) {
128 E : return in_archive->Load(&value_);
129 E : }
130 :
131 : friend std::ostream& operator<<(std::ostream& str,
132 : const AddressImpl<kType>& addr);
133 :
134 : private:
135 : uint32_t value_;
136 : };
137 :
138 : } // namespace detail
139 :
140 : // These types represent the different addressing formats used in PE images.
141 :
142 : // A virtual address relative to the image base, often termed RVA in
143 : // documentation and in data structure comments.
144 : using RelativeAddress = detail::AddressImpl<kRelativeAddressType>;
145 : // An absolute address.
146 : using AbsoluteAddress = detail::AddressImpl<kAbsoluteAddressType>;
147 : // A file offset within an image file.
148 : using FileOffsetAddress = detail::AddressImpl<kFileOffsetAddressType>;
149 :
150 : // An address variant that can house any of the concrete address types.
151 : class AddressVariant {
152 : public:
153 E : AddressVariant() : type_(kRelativeAddressType), value_(0) {}
154 E : AddressVariant(AddressType type, uint32_t value)
155 : : type_(type), value_(value) {}
156 E : AddressVariant(const AddressVariant& other) // NOLINT
157 : : 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 : uint32_t value() const { return value_; }
174 E : void set_type(AddressType type) { type_ = type; }
175 E : void set_value(uint32_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+=(int32_t offset) { value_ += offset; }
187 E : void operator-=(int32_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 : uint32_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 : uint32_t value_;
242 : };
243 :
244 : } // namespace core
245 :
246 : #endif // SYZYGY_CORE_ADDRESS_H_
|