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