1 : // Copyright 2015 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 : #include "syzygy/refinery/types/typed_data.h"
15 :
16 : #include "base/logging.h"
17 : #include "syzygy/refinery/types/type_repository.h"
18 :
19 : namespace refinery {
20 :
21 : namespace {
22 :
23 E : bool IsFieldOf(TypePtr type, const UserDefinedType::Field& field) {
24 E : UserDefinedTypePtr udt;
25 E : if (!type->CastTo(&udt))
26 i : return false;
27 :
28 E : for (auto f : udt->fields()) {
29 E : if (f == field)
30 E : return true;
31 E : }
32 :
33 i : return false;
34 E : }
35 :
36 : } // namespace
37 :
38 E : TypedData::TypedData() : bit_source_(nullptr) {
39 E : }
40 :
41 : TypedData::TypedData(BitSource* bit_source, TypePtr type, Address addr)
42 : : bit_source_(bit_source),
43 : type_(type),
44 : addr_(addr),
45 : bit_pos_(0),
46 E : bit_len_(0) {
47 E : DCHECK(bit_source_);
48 E : DCHECK(type_);
49 E : }
50 :
51 : TypedData::TypedData(BitSource* bit_source,
52 : TypePtr type,
53 : Address addr,
54 : size_t bit_pos,
55 : size_t bit_len)
56 : : bit_source_(bit_source),
57 : type_(type),
58 : addr_(addr),
59 : bit_pos_(bit_pos),
60 E : bit_len_(bit_len) {
61 E : DCHECK(bit_source_);
62 E : DCHECK(type_);
63 E : DCHECK(bit_pos >= 0 && bit_pos < type_->size() * 8);
64 E : DCHECK(bit_len >= 0 && bit_len < type_->size() * 8);
65 E : }
66 :
67 E : bool TypedData::IsValid() const {
68 E : return bit_source_ != nullptr && type_ != nullptr;
69 E : }
70 :
71 E : bool TypedData::IsPrimitiveType() const {
72 E : DCHECK(type_);
73 E : switch (type_->kind()) {
74 : case Type::BASIC_TYPE_KIND:
75 : case Type::POINTER_TYPE_KIND:
76 E : return true;
77 :
78 : default:
79 E : return false;
80 : }
81 E : }
82 :
83 E : bool TypedData::IsPointerType() const {
84 E : DCHECK(type_);
85 E : return type_->kind() == Type::POINTER_TYPE_KIND;
86 E : }
87 :
88 E : bool TypedData::IsArrayType() const {
89 E : DCHECK(type_);
90 E : return type_->kind() == Type::ARRAY_TYPE_KIND;
91 E : }
92 :
93 : bool TypedData::GetNamedField(const base::StringPiece16& name,
94 E : TypedData* out) const {
95 E : DCHECK(out);
96 : // TODO(siggi): Does it ever make sense to request a nameless field?
97 E : DCHECK(!name.empty());
98 E : DCHECK(type_);
99 :
100 E : UserDefinedTypePtr udt;
101 E : if (!type_->CastTo(&udt))
102 i : return false;
103 :
104 E : for (size_t i = 0; i < udt->fields().size(); ++i) {
105 E : const UserDefinedType::Field& field = udt->fields()[i];
106 E : if (name == field.name()) {
107 E : TypePtr field_type = udt->GetFieldType(i);
108 E : DCHECK(field_type);
109 : *out = TypedData(bit_source_, field_type, addr() + field.offset(),
110 E : field.bit_pos(), field.bit_len());
111 E : return true;
112 : }
113 E : }
114 :
115 i : return false;
116 E : }
117 :
118 : bool TypedData::GetField(const UserDefinedType::Field& field,
119 E : TypedData* out) const {
120 E : DCHECK(out);
121 E : DCHECK(type_);
122 E : DCHECK(!IsPrimitiveType());
123 E : DCHECK(IsFieldOf(type_, field));
124 :
125 E : TypePtr field_type = type_->repository()->GetType(field.type_id());
126 E : *out = TypedData(bit_source_, field_type, addr() + field.offset());
127 E : return true;
128 E : }
129 :
130 E : bool TypedData::GetSignedValue(int64_t* value) const {
131 E : DCHECK(value);
132 E : DCHECK(IsPrimitiveType());
133 E : DCHECK(bit_source_);
134 :
135 E : int64 ret = 0;
136 E : switch (type_->size()) {
137 : case sizeof(int8_t): {
138 i : int8_t v8 = 0;
139 i : if (!GetData(&v8))
140 i : return false;
141 :
142 i : ret = v8;
143 i : break;
144 : }
145 :
146 : case sizeof(int16_t): {
147 i : int16_t v16 = 0;
148 i : if (!GetData(&v16))
149 i : return false;
150 :
151 i : ret = v16;
152 i : break;
153 : }
154 :
155 : case sizeof(int32_t): {
156 E : int32_t v32 = 0;
157 E : if (!GetData(&v32))
158 i : return false;
159 :
160 E : ret = v32;
161 E : break;
162 : }
163 :
164 : case sizeof(int64_t): {
165 i : int64_t v64 = 0;
166 i : if (!GetData(&v64))
167 i : return false;
168 :
169 i : ret = v64;
170 i : break;
171 : }
172 :
173 : default:
174 : // Wonky size - no can do this. Maybe this type is a float or such?
175 i : return false;
176 : }
177 :
178 : // Shift, mask and sign-extend bit fields.
179 E : if (bit_len_ != 0) {
180 : // Shift the bits into place.
181 E : ret >>= bit_pos_;
182 :
183 : // Mask to the used bits.
184 E : const uint64_t mask = (1ll << bit_len_) - 1;
185 E : ret &= mask;
186 :
187 : // Check the sign bit and extend out if set.
188 E : if (ret & (mask ^ (mask >> 1)))
189 E : ret |= (-1ll & ~mask);
190 : }
191 :
192 E : *value = ret;
193 E : return true;
194 E : }
195 :
196 E : bool TypedData::GetUnsignedValue(uint64_t* value) const {
197 E : DCHECK(value);
198 E : DCHECK(IsPrimitiveType());
199 E : DCHECK(bit_source_);
200 :
201 E : uint64 ret = 0;
202 E : switch (type_->size()) {
203 : case sizeof(uint8_t): {
204 E : uint8_t v8 = 0;
205 E : if (!GetData(&v8))
206 i : return false;
207 :
208 E : ret = v8;
209 E : break;
210 : }
211 :
212 : case sizeof(uint16_t): {
213 i : uint16_t v16 = 0;
214 i : if (!GetData(&v16))
215 i : return false;
216 :
217 i : ret = v16;
218 i : break;
219 : }
220 :
221 : case sizeof(uint32_t): {
222 E : uint32_t v32 = 0;
223 E : if (!GetData(&v32))
224 E : return false;
225 :
226 E : ret = v32;
227 E : break;
228 : }
229 :
230 : case sizeof(uint64_t): {
231 i : uint64_t v64 = 0;
232 i : if (!GetData(&v64))
233 i : return false;
234 :
235 i : ret = v64;
236 i : break;
237 : }
238 :
239 : default:
240 : // Wonky size - no can do this. Maybe this type is a float or such?
241 i : return false;
242 : }
243 :
244 : // Shift & mask bit fields.
245 E : if (bit_len_ != 0) {
246 : // Shift the bits uinto place.
247 E : ret >>= bit_pos_;
248 :
249 : // Mask to the used bits.
250 E : const uint64_t mask = (1ull << bit_len_) - 1;
251 E : ret &= mask;
252 : }
253 :
254 E : *value = ret;
255 E : return true;
256 E : }
257 :
258 E : bool TypedData::GetPointerValue(Address* value) const {
259 E : DCHECK(value);
260 E : DCHECK(IsPointerType());
261 E : DCHECK_EQ(0, bit_len_); // Bitfields need not apply for pointer.
262 E : DCHECK(bit_source_);
263 :
264 E : PointerTypePtr ptr_type;
265 E : if (!type_->CastTo(&ptr_type))
266 i : return false;
267 :
268 : // Cater for 32- and 64-bit pointers.
269 E : if (ptr_type->size() == sizeof(uint32_t)) {
270 : // The pointer size is 32 bit.
271 E : uint32_t addr_32 = 0;
272 E : if (GetData(&addr_32)) {
273 E : *value = addr_32;
274 E : return true;
275 E : }
276 i : } else if (ptr_type->size() == sizeof(uint64_t)) {
277 : // The pointer size is 64 bit.
278 i : if (GetData(value))
279 i : return true;
280 : }
281 :
282 : // The pointer size is strange or we failed on retrieving the value.
283 E : return false;
284 E : }
285 :
286 E : bool TypedData::Dereference(TypedData* referenced_data) const {
287 E : DCHECK(referenced_data);
288 E : DCHECK(IsPointerType());
289 E : DCHECK(bit_source_);
290 :
291 E : PointerTypePtr ptr_type;
292 E : if (!type_->CastTo(&ptr_type))
293 i : return false;
294 :
295 E : TypePtr content_type = ptr_type->GetContentType();
296 E : if (!content_type)
297 i : return false;
298 :
299 E : Address addr = 0;
300 E : if (!GetPointerValue(&addr))
301 E : return false;
302 :
303 E : *referenced_data = TypedData(bit_source_, content_type, addr);
304 :
305 E : return true;
306 E : }
307 :
308 E : bool TypedData::GetArrayElement(size_t index, TypedData* element_data) const {
309 E : DCHECK(element_data);
310 E : DCHECK(IsArrayType());
311 E : DCHECK(bit_source_);
312 :
313 E : ArrayTypePtr array_ptr;
314 E : if (!type_->CastTo(&array_ptr))
315 i : return false;
316 :
317 E : if (index >= array_ptr->num_elements())
318 E : return false;
319 :
320 E : TypePtr element_type = array_ptr->GetElementType();
321 E : if (!element_type)
322 i : return false;
323 :
324 : *element_data = TypedData(bit_source_, element_type,
325 E : addr() + index * element_type->size());
326 :
327 E : return true;
328 E : }
329 :
330 : bool TypedData::OffsetAndCast(ptrdiff_t offs,
331 : TypePtr new_type,
332 E : TypedData* output) const {
333 E : DCHECK(output);
334 E : if (!new_type)
335 i : return false;
336 E : if (!IsValid())
337 i : return false;
338 :
339 E : return OffsetBytesAndCast(offs * type()->size(), new_type, output);
340 E : }
341 :
342 : bool TypedData::OffsetBytesAndCast(ptrdiff_t offs,
343 : TypePtr new_type,
344 E : TypedData* output) const {
345 E : DCHECK(output);
346 E : if (!new_type)
347 i : return false;
348 E : if (!IsValid())
349 i : return false;
350 :
351 : // TODO(siggi): Validate the new range against the bit source with a new
352 : // interface.
353 E : *output = TypedData(bit_source(), new_type, addr() + offs);
354 E : return true;
355 E : }
356 :
357 E : AddressRange TypedData::GetRange() const {
358 E : return AddressRange(addr(), type()->size());
359 E : }
360 :
361 E : bool TypedData::GetDataImpl(void* data, size_t data_size) const {
362 E : DCHECK(data);
363 E : DCHECK(IsPrimitiveType());
364 E : DCHECK(bit_source_);
365 :
366 E : if (data_size != type_->size())
367 i : return false;
368 :
369 E : return bit_source_->GetAll(GetRange(), data);
370 E : }
371 :
372 : } // namespace refinery
|