blob: 18ddc86e0c1b5c26ce353bb32f05298b79ff5a23 [file] [log] [blame]
Jeff Haoec7f1a92017-03-13 16:24:24 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Implementation file of dex ir verifier.
17 *
18 * Compares two dex files at the IR level, allowing differences in layout, but not in data.
19 */
20
21#include "dex_verify.h"
22
Jeff Haocc829592017-03-14 16:13:39 -070023#include <inttypes.h>
24
Jeff Haoec7f1a92017-03-13 16:24:24 -070025#include "android-base/stringprintf.h"
26
27namespace art {
28
29using android::base::StringPrintf;
30
31bool VerifyOutputDexFile(dex_ir::Header* orig_header,
32 dex_ir::Header* output_header,
33 std::string* error_msg) {
34 dex_ir::Collections& orig = orig_header->GetCollections();
35 dex_ir::Collections& output = output_header->GetCollections();
36
Jeff Haocc829592017-03-14 16:13:39 -070037 // Compare all id sections. They have a defined order that can't be changed by dexlayout.
Jeff Haoec7f1a92017-03-13 16:24:24 -070038 if (!VerifyIds(orig.StringIds(), output.StringIds(), "string ids", error_msg) ||
39 !VerifyIds(orig.TypeIds(), output.TypeIds(), "type ids", error_msg) ||
40 !VerifyIds(orig.ProtoIds(), output.ProtoIds(), "proto ids", error_msg) ||
41 !VerifyIds(orig.FieldIds(), output.FieldIds(), "field ids", error_msg) ||
42 !VerifyIds(orig.MethodIds(), output.MethodIds(), "method ids", error_msg)) {
43 return false;
44 }
Jeff Haocc829592017-03-14 16:13:39 -070045 // Compare class defs. The order may have been changed by dexlayout.
46 if (!VerifyClassDefs(orig.ClassDefs(), output.ClassDefs(), error_msg)) {
47 return false;
48 }
Jeff Haoec7f1a92017-03-13 16:24:24 -070049 return true;
50}
51
52template<class T> bool VerifyIds(std::vector<std::unique_ptr<T>>& orig,
53 std::vector<std::unique_ptr<T>>& output,
54 const char* section_name,
55 std::string* error_msg) {
56 if (orig.size() != output.size()) {
57 *error_msg = StringPrintf(
Jeff Haocc829592017-03-14 16:13:39 -070058 "Mismatched size for %s section: %zu vs %zu.", section_name, orig.size(), output.size());
Jeff Haoec7f1a92017-03-13 16:24:24 -070059 return false;
60 }
61 for (size_t i = 0; i < orig.size(); ++i) {
62 if (!VerifyId(orig[i].get(), output[i].get(), error_msg)) {
63 return false;
64 }
65 }
66 return true;
67}
68
69bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg) {
70 if (strcmp(orig->Data(), output->Data()) != 0) {
Jeff Haocc829592017-03-14 16:13:39 -070071 *error_msg = StringPrintf("Mismatched string data for string id %u at offset %x: %s vs %s.",
Jeff Haoec7f1a92017-03-13 16:24:24 -070072 orig->GetIndex(),
73 orig->GetOffset(),
74 orig->Data(),
75 output->Data());
76 return false;
77 }
78 return true;
79}
80
81bool VerifyId(dex_ir::TypeId* orig, dex_ir::TypeId* output, std::string* error_msg) {
82 if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
Jeff Haocc829592017-03-14 16:13:39 -070083 *error_msg = StringPrintf("Mismatched string index for type id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -070084 orig->GetIndex(),
85 orig->GetOffset(),
86 orig->GetStringId()->GetIndex(),
87 output->GetStringId()->GetIndex());
88 return false;
89 }
90 return true;
91}
92
93bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg) {
94 if (orig->Shorty()->GetIndex() != output->Shorty()->GetIndex()) {
Jeff Haocc829592017-03-14 16:13:39 -070095 *error_msg = StringPrintf("Mismatched string index for proto id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -070096 orig->GetIndex(),
97 orig->GetOffset(),
98 orig->Shorty()->GetIndex(),
99 output->Shorty()->GetIndex());
100 return false;
101 }
102 if (orig->ReturnType()->GetIndex() != output->ReturnType()->GetIndex()) {
Jeff Haocc829592017-03-14 16:13:39 -0700103 *error_msg = StringPrintf("Mismatched type index for proto id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -0700104 orig->GetIndex(),
105 orig->GetOffset(),
106 orig->ReturnType()->GetIndex(),
107 output->ReturnType()->GetIndex());
108 return false;
109 }
110 if (!VerifyTypeList(orig->Parameters(), output->Parameters())) {
Jeff Haocc829592017-03-14 16:13:39 -0700111 *error_msg = StringPrintf("Mismatched type list for proto id %u at offset %x.",
Jeff Haoec7f1a92017-03-13 16:24:24 -0700112 orig->GetIndex(),
113 orig->GetOffset());
114 }
115 return true;
116}
117
118bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg) {
119 if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
120 *error_msg =
Jeff Haocc829592017-03-14 16:13:39 -0700121 StringPrintf("Mismatched class type index for field id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -0700122 orig->GetIndex(),
123 orig->GetOffset(),
124 orig->Class()->GetIndex(),
125 output->Class()->GetIndex());
126 return false;
127 }
128 if (orig->Type()->GetIndex() != output->Type()->GetIndex()) {
Jeff Haocc829592017-03-14 16:13:39 -0700129 *error_msg = StringPrintf("Mismatched type index for field id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -0700130 orig->GetIndex(),
131 orig->GetOffset(),
132 orig->Class()->GetIndex(),
133 output->Class()->GetIndex());
134 return false;
135 }
136 if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
Jeff Haocc829592017-03-14 16:13:39 -0700137 *error_msg = StringPrintf("Mismatched string index for field id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -0700138 orig->GetIndex(),
139 orig->GetOffset(),
140 orig->Name()->GetIndex(),
141 output->Name()->GetIndex());
142 return false;
143 }
144 return true;
145}
146
147bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg) {
148 if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
Jeff Haocc829592017-03-14 16:13:39 -0700149 *error_msg = StringPrintf("Mismatched type index for method id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -0700150 orig->GetIndex(),
151 orig->GetOffset(),
152 orig->Class()->GetIndex(),
153 output->Class()->GetIndex());
154 return false;
155 }
156 if (orig->Proto()->GetIndex() != output->Proto()->GetIndex()) {
Jeff Haocc829592017-03-14 16:13:39 -0700157 *error_msg = StringPrintf("Mismatched proto index for method id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -0700158 orig->GetIndex(),
159 orig->GetOffset(),
160 orig->Class()->GetIndex(),
161 output->Class()->GetIndex());
162 return false;
163 }
164 if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
165 *error_msg =
Jeff Haocc829592017-03-14 16:13:39 -0700166 StringPrintf("Mismatched string index for method id %u at offset %x: %u vs %u.",
Jeff Haoec7f1a92017-03-13 16:24:24 -0700167 orig->GetIndex(),
168 orig->GetOffset(),
169 orig->Name()->GetIndex(),
170 output->Name()->GetIndex());
171 return false;
172 }
173 return true;
174}
175
Jeff Haocc829592017-03-14 16:13:39 -0700176struct ClassDefCompare {
177 bool operator()(dex_ir::ClassDef* lhs, dex_ir::ClassDef* rhs) const {
178 return lhs->ClassType()->GetIndex() < rhs->ClassType()->GetIndex();
179 }
180};
181
182// The class defs may have a new order due to dexlayout. Use the class's class_idx to uniquely
183// identify them and sort them for comparison.
184bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
185 std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
186 std::string* error_msg) {
187 if (orig.size() != output.size()) {
188 *error_msg = StringPrintf(
189 "Mismatched size for class defs section: %zu vs %zu.", orig.size(), output.size());
190 return false;
191 }
192 // Store the class defs into sets sorted by the class's type index.
193 std::set<dex_ir::ClassDef*, ClassDefCompare> orig_set;
194 std::set<dex_ir::ClassDef*, ClassDefCompare> output_set;
195 for (size_t i = 0; i < orig.size(); ++i) {
196 orig_set.insert(orig[i].get());
197 output_set.insert(output[i].get());
198 }
199 auto orig_iter = orig_set.begin();
200 auto output_iter = output_set.begin();
201 while (orig_iter != orig_set.end() && output_iter != output_set.end()) {
202 if (!VerifyClassDef(*orig_iter, *output_iter, error_msg)) {
203 return false;
204 }
205 orig_iter++;
206 output_iter++;
207 }
208 return true;
209}
210
211bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg) {
212 if (orig->ClassType()->GetIndex() != output->ClassType()->GetIndex()) {
213 *error_msg =
214 StringPrintf("Mismatched class type index for class def %u at offset %x: %u vs %u.",
215 orig->GetIndex(),
216 orig->GetOffset(),
217 orig->ClassType()->GetIndex(),
218 output->ClassType()->GetIndex());
219 return false;
220 }
221 if (orig->GetAccessFlags() != output->GetAccessFlags()) {
222 *error_msg =
223 StringPrintf("Mismatched access flags for class def %u at offset %x: %x vs %x.",
224 orig->GetIndex(),
225 orig->GetOffset(),
226 orig->GetAccessFlags(),
227 output->GetAccessFlags());
228 return false;
229 }
230 uint32_t orig_super = orig->Superclass() == nullptr ? 0 : orig->Superclass()->GetIndex();
231 uint32_t output_super = output->Superclass() == nullptr ? 0 : output->Superclass()->GetIndex();
232 if (orig_super != output_super) {
233 *error_msg =
234 StringPrintf("Mismatched super class for class def %u at offset %x: %u vs %u.",
235 orig->GetIndex(),
236 orig->GetOffset(),
237 orig_super,
238 output_super);
239 return false;
240 }
241 if (!VerifyTypeList(orig->Interfaces(), output->Interfaces())) {
242 *error_msg = StringPrintf("Mismatched type list for class def %u at offset %x.",
243 orig->GetIndex(),
244 orig->GetOffset());
245 return false;
246 }
247 const char* orig_source = orig->SourceFile() == nullptr ? "" : orig->SourceFile()->Data();
248 const char* output_source = output->SourceFile() == nullptr ? "" : output->SourceFile()->Data();
249 if (strcmp(orig_source, output_source) != 0) {
250 *error_msg = StringPrintf("Mismatched source file for class def %u at offset %x: %s vs %s.",
251 orig->GetIndex(),
252 orig->GetOffset(),
253 orig_source,
254 output_source);
255 return false;
256 }
257 if (!VerifyAnnotationsDirectory(orig->Annotations(), output->Annotations(), error_msg)) {
258 return false;
259 }
260 if (!VerifyClassData(orig->GetClassData(), output->GetClassData(), error_msg)) {
261 return false;
262 }
263 return VerifyEncodedArray(orig->StaticValues(), output->StaticValues(), error_msg);
264}
265
Jeff Haoec7f1a92017-03-13 16:24:24 -0700266bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output) {
267 if (orig == nullptr || output == nullptr) {
268 return orig == output;
269 }
270 const dex_ir::TypeIdVector* orig_list = orig->GetTypeList();
271 const dex_ir::TypeIdVector* output_list = output->GetTypeList();
272 if (orig_list->size() != output_list->size()) {
273 return false;
274 }
275 for (size_t i = 0; i < orig_list->size(); ++i) {
276 if ((*orig_list)[i]->GetIndex() != (*output_list)[i]->GetIndex()) {
277 return false;
278 }
279 }
280 return true;
281}
282
Jeff Haocc829592017-03-14 16:13:39 -0700283bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig,
284 dex_ir::AnnotationsDirectoryItem* output,
285 std::string* error_msg) {
286 if (orig == nullptr || output == nullptr) {
287 if (orig != output) {
288 *error_msg = "Found unexpected empty annotations directory.";
289 return false;
290 }
291 return true;
292 }
293 if (!VerifyAnnotationSet(orig->GetClassAnnotation(), output->GetClassAnnotation(), error_msg)) {
294 return false;
295 }
296 if (!VerifyFieldAnnotations(orig->GetFieldAnnotations(),
297 output->GetFieldAnnotations(),
298 orig->GetOffset(),
299 error_msg)) {
300 return false;
301 }
302 if (!VerifyMethodAnnotations(orig->GetMethodAnnotations(),
303 output->GetMethodAnnotations(),
304 orig->GetOffset(),
305 error_msg)) {
306 return false;
307 }
308 return VerifyParameterAnnotations(orig->GetParameterAnnotations(),
309 output->GetParameterAnnotations(),
310 orig->GetOffset(),
311 error_msg);
312}
313
314bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig,
315 dex_ir::FieldAnnotationVector* output,
316 uint32_t orig_offset,
317 std::string* error_msg) {
318 if (orig == nullptr || output == nullptr) {
319 if (orig != output) {
320 *error_msg = StringPrintf(
321 "Found unexpected empty field annotations for annotations directory at offset %x.",
322 orig_offset);
323 return false;
324 }
325 return true;
326 }
327 if (orig->size() != output->size()) {
328 *error_msg = StringPrintf(
329 "Mismatched field annotations size for annotations directory at offset %x: %zu vs %zu.",
330 orig_offset,
331 orig->size(),
332 output->size());
333 return false;
334 }
335 for (size_t i = 0; i < orig->size(); ++i) {
336 dex_ir::FieldAnnotation* orig_field = (*orig)[i].get();
337 dex_ir::FieldAnnotation* output_field = (*output)[i].get();
338 if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
339 *error_msg = StringPrintf(
340 "Mismatched field annotation index for annotations directory at offset %x: %u vs %u.",
341 orig_offset,
342 orig_field->GetFieldId()->GetIndex(),
343 output_field->GetFieldId()->GetIndex());
344 return false;
345 }
346 if (!VerifyAnnotationSet(orig_field->GetAnnotationSetItem(),
347 output_field->GetAnnotationSetItem(),
348 error_msg)) {
349 return false;
350 }
351 }
352 return true;
353}
354
355bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig,
356 dex_ir::MethodAnnotationVector* output,
357 uint32_t orig_offset,
358 std::string* error_msg) {
359 if (orig == nullptr || output == nullptr) {
360 if (orig != output) {
361 *error_msg = StringPrintf(
362 "Found unexpected empty method annotations for annotations directory at offset %x.",
363 orig_offset);
364 return false;
365 }
366 return true;
367 }
368 if (orig->size() != output->size()) {
369 *error_msg = StringPrintf(
370 "Mismatched method annotations size for annotations directory at offset %x: %zu vs %zu.",
371 orig_offset,
372 orig->size(),
373 output->size());
374 return false;
375 }
376 for (size_t i = 0; i < orig->size(); ++i) {
377 dex_ir::MethodAnnotation* orig_method = (*orig)[i].get();
378 dex_ir::MethodAnnotation* output_method = (*output)[i].get();
379 if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
380 *error_msg = StringPrintf(
381 "Mismatched method annotation index for annotations directory at offset %x: %u vs %u.",
382 orig_offset,
383 orig_method->GetMethodId()->GetIndex(),
384 output_method->GetMethodId()->GetIndex());
385 return false;
386 }
387 if (!VerifyAnnotationSet(orig_method->GetAnnotationSetItem(),
388 output_method->GetAnnotationSetItem(),
389 error_msg)) {
390 return false;
391 }
392 }
393 return true;
394}
395
396bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig,
397 dex_ir::ParameterAnnotationVector* output,
398 uint32_t orig_offset,
399 std::string* error_msg) {
400 if (orig == nullptr || output == nullptr) {
401 if (orig != output) {
402 *error_msg = StringPrintf(
403 "Found unexpected empty parameter annotations for annotations directory at offset %x.",
404 orig_offset);
405 return false;
406 }
407 return true;
408 }
409 if (orig->size() != output->size()) {
410 *error_msg = StringPrintf(
411 "Mismatched parameter annotations size for annotations directory at offset %x: %zu vs %zu.",
412 orig_offset,
413 orig->size(),
414 output->size());
415 return false;
416 }
417 for (size_t i = 0; i < orig->size(); ++i) {
418 dex_ir::ParameterAnnotation* orig_param = (*orig)[i].get();
419 dex_ir::ParameterAnnotation* output_param = (*output)[i].get();
420 if (orig_param->GetMethodId()->GetIndex() != output_param->GetMethodId()->GetIndex()) {
421 *error_msg = StringPrintf(
422 "Mismatched parameter annotation index for annotations directory at offset %x: %u vs %u.",
423 orig_offset,
424 orig_param->GetMethodId()->GetIndex(),
425 output_param->GetMethodId()->GetIndex());
426 return false;
427 }
428 if (!VerifyAnnotationSetRefList(orig_param->GetAnnotations(),
429 output_param->GetAnnotations(),
430 error_msg)) {
431 return false;
432 }
433 }
434 return true;
435}
436
437bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig,
438 dex_ir::AnnotationSetRefList* output,
439 std::string* error_msg) {
440 std::vector<dex_ir::AnnotationSetItem*>* orig_items = orig->GetItems();
441 std::vector<dex_ir::AnnotationSetItem*>* output_items = output->GetItems();
442 if (orig_items->size() != output_items->size()) {
443 *error_msg = StringPrintf(
444 "Mismatched annotation set ref list size at offset %x: %zu vs %zu.",
445 orig->GetOffset(),
446 orig_items->size(),
447 output_items->size());
448 return false;
449 }
450 for (size_t i = 0; i < orig_items->size(); ++i) {
451 if (!VerifyAnnotationSet((*orig_items)[i], (*output_items)[i], error_msg)) {
452 return false;
453 }
454 }
455 return true;
456}
457
458bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig,
459 dex_ir::AnnotationSetItem* output,
460 std::string* error_msg) {
461 if (orig == nullptr || output == nullptr) {
462 if (orig != output) {
463 *error_msg = "Found unexpected empty annotation set.";
464 return false;
465 }
466 return true;
467 }
468 std::vector<dex_ir::AnnotationItem*>* orig_items = orig->GetItems();
469 std::vector<dex_ir::AnnotationItem*>* output_items = output->GetItems();
470 if (orig_items->size() != output_items->size()) {
471 *error_msg = StringPrintf("Mismatched size for annotation set at offset %x: %zu vs %zu.",
472 orig->GetOffset(),
473 orig_items->size(),
474 output_items->size());
475 return false;
476 }
477 for (size_t i = 0; i < orig_items->size(); ++i) {
478 if (!VerifyAnnotation((*orig_items)[i], (*output_items)[i], error_msg)) {
479 return false;
480 }
481 }
482 return true;
483}
484
485bool VerifyAnnotation(dex_ir::AnnotationItem* orig,
486 dex_ir::AnnotationItem* output,
487 std::string* error_msg) {
488 if (orig->GetVisibility() != output->GetVisibility()) {
489 *error_msg = StringPrintf("Mismatched visibility for annotation at offset %x: %u vs %u.",
490 orig->GetOffset(),
491 orig->GetVisibility(),
492 output->GetVisibility());
493 return false;
494 }
495 return VerifyEncodedAnnotation(orig->GetAnnotation(),
496 output->GetAnnotation(),
497 orig->GetOffset(),
498 error_msg);
499}
500
501bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig,
502 dex_ir::EncodedAnnotation* output,
503 uint32_t orig_offset,
504 std::string* error_msg) {
505 if (orig->GetType()->GetIndex() != output->GetType()->GetIndex()) {
506 *error_msg = StringPrintf(
507 "Mismatched encoded annotation type for annotation at offset %x: %u vs %u.",
508 orig_offset,
509 orig->GetType()->GetIndex(),
510 output->GetType()->GetIndex());
511 return false;
512 }
513 dex_ir::AnnotationElementVector* orig_elements = orig->GetAnnotationElements();
514 dex_ir::AnnotationElementVector* output_elements = output->GetAnnotationElements();
515 if (orig_elements->size() != output_elements->size()) {
516 *error_msg = StringPrintf(
517 "Mismatched encoded annotation size for annotation at offset %x: %zu vs %zu.",
518 orig_offset,
519 orig_elements->size(),
520 output_elements->size());
521 return false;
522 }
523 for (size_t i = 0; i < orig_elements->size(); ++i) {
524 if (!VerifyAnnotationElement((*orig_elements)[i].get(),
525 (*output_elements)[i].get(),
526 orig_offset,
527 error_msg)) {
528 return false;
529 }
530 }
531 return true;
532}
533
534bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig,
535 dex_ir::AnnotationElement* output,
536 uint32_t orig_offset,
537 std::string* error_msg) {
538 if (orig->GetName()->GetIndex() != output->GetName()->GetIndex()) {
539 *error_msg = StringPrintf(
540 "Mismatched annotation element name for annotation at offset %x: %u vs %u.",
541 orig_offset,
542 orig->GetName()->GetIndex(),
543 output->GetName()->GetIndex());
544 return false;
545 }
546 return VerifyEncodedValue(orig->GetValue(), output->GetValue(), orig_offset, error_msg);
547}
548
549bool VerifyEncodedValue(dex_ir::EncodedValue* orig,
550 dex_ir::EncodedValue* output,
551 uint32_t orig_offset,
552 std::string* error_msg) {
553 if (orig->Type() != output->Type()) {
554 *error_msg = StringPrintf(
555 "Mismatched encoded value type for annotation or encoded array at offset %x: %d vs %d.",
556 orig_offset,
557 orig->Type(),
558 output->Type());
559 return false;
560 }
561 switch (orig->Type()) {
562 case DexFile::kDexAnnotationByte:
563 if (orig->GetByte() != output->GetByte()) {
564 *error_msg = StringPrintf("Mismatched encoded byte for annotation at offset %x: %d vs %d.",
565 orig_offset,
566 orig->GetByte(),
567 output->GetByte());
568 return false;
569 }
570 break;
571 case DexFile::kDexAnnotationShort:
572 if (orig->GetShort() != output->GetShort()) {
573 *error_msg = StringPrintf("Mismatched encoded short for annotation at offset %x: %d vs %d.",
574 orig_offset,
575 orig->GetShort(),
576 output->GetShort());
577 return false;
578 }
579 break;
580 case DexFile::kDexAnnotationChar:
581 if (orig->GetChar() != output->GetChar()) {
582 *error_msg = StringPrintf("Mismatched encoded char for annotation at offset %x: %c vs %c.",
583 orig_offset,
584 orig->GetChar(),
585 output->GetChar());
586 return false;
587 }
588 break;
589 case DexFile::kDexAnnotationInt:
590 if (orig->GetInt() != output->GetInt()) {
591 *error_msg = StringPrintf("Mismatched encoded int for annotation at offset %x: %d vs %d.",
592 orig_offset,
593 orig->GetInt(),
594 output->GetInt());
595 return false;
596 }
597 break;
598 case DexFile::kDexAnnotationLong:
599 if (orig->GetLong() != output->GetLong()) {
600 *error_msg = StringPrintf(
601 "Mismatched encoded long for annotation at offset %x: %" PRId64 " vs %" PRId64 ".",
602 orig_offset,
603 orig->GetLong(),
604 output->GetLong());
605 return false;
606 }
607 break;
608 case DexFile::kDexAnnotationFloat:
609 // The float value is encoded, so compare as if it's an int.
610 if (orig->GetInt() != output->GetInt()) {
611 *error_msg = StringPrintf(
612 "Mismatched encoded float for annotation at offset %x: %x (encoded) vs %x (encoded).",
613 orig_offset,
614 orig->GetInt(),
615 output->GetInt());
616 return false;
617 }
618 break;
619 case DexFile::kDexAnnotationDouble:
620 // The double value is encoded, so compare as if it's a long.
621 if (orig->GetLong() != output->GetLong()) {
622 *error_msg = StringPrintf(
623 "Mismatched encoded double for annotation at offset %x: %" PRIx64
624 " (encoded) vs %" PRIx64 " (encoded).",
625 orig_offset,
626 orig->GetLong(),
627 output->GetLong());
628 return false;
629 }
630 break;
631 case DexFile::kDexAnnotationString:
632 if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
633 *error_msg = StringPrintf(
634 "Mismatched encoded string for annotation at offset %x: %s vs %s.",
635 orig_offset,
636 orig->GetStringId()->Data(),
637 output->GetStringId()->Data());
638 return false;
639 }
640 break;
641 case DexFile::kDexAnnotationType:
642 if (orig->GetTypeId()->GetIndex() != output->GetTypeId()->GetIndex()) {
643 *error_msg = StringPrintf("Mismatched encoded type for annotation at offset %x: %u vs %u.",
644 orig_offset,
645 orig->GetTypeId()->GetIndex(),
646 output->GetTypeId()->GetIndex());
647 return false;
648 }
649 break;
650 case DexFile::kDexAnnotationField:
651 case DexFile::kDexAnnotationEnum:
652 if (orig->GetFieldId()->GetIndex() != output->GetFieldId()->GetIndex()) {
653 *error_msg = StringPrintf("Mismatched encoded field for annotation at offset %x: %u vs %u.",
654 orig_offset,
655 orig->GetFieldId()->GetIndex(),
656 output->GetFieldId()->GetIndex());
657 return false;
658 }
659 break;
660 case DexFile::kDexAnnotationMethod:
661 if (orig->GetMethodId()->GetIndex() != output->GetMethodId()->GetIndex()) {
662 *error_msg = StringPrintf(
663 "Mismatched encoded method for annotation at offset %x: %u vs %u.",
664 orig_offset,
665 orig->GetMethodId()->GetIndex(),
666 output->GetMethodId()->GetIndex());
667 return false;
668 }
669 break;
670 case DexFile::kDexAnnotationArray:
671 if (!VerifyEncodedArray(orig->GetEncodedArray(), output->GetEncodedArray(), error_msg)) {
672 return false;
673 }
674 break;
675 case DexFile::kDexAnnotationAnnotation:
676 if (!VerifyEncodedAnnotation(orig->GetEncodedAnnotation(),
677 output->GetEncodedAnnotation(),
678 orig_offset,
679 error_msg)) {
680 return false;
681 }
682 break;
683 case DexFile::kDexAnnotationNull:
684 break;
685 case DexFile::kDexAnnotationBoolean:
686 if (orig->GetBoolean() != output->GetBoolean()) {
687 *error_msg = StringPrintf(
688 "Mismatched encoded boolean for annotation at offset %x: %d vs %d.",
689 orig_offset,
690 orig->GetBoolean(),
691 output->GetBoolean());
692 return false;
693 }
694 break;
695 default:
696 break;
697 }
698 return true;
699}
700
701bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig,
702 dex_ir::EncodedArrayItem* output,
703 std::string* error_msg) {
704 if (orig == nullptr || output == nullptr) {
705 if (orig != output) {
706 *error_msg = "Found unexpected empty encoded array.";
707 return false;
708 }
709 return true;
710 }
711 dex_ir::EncodedValueVector* orig_vector = orig->GetEncodedValues();
712 dex_ir::EncodedValueVector* output_vector = output->GetEncodedValues();
713 if (orig_vector->size() != output_vector->size()) {
714 *error_msg = StringPrintf("Mismatched size for encoded array at offset %x: %zu vs %zu.",
715 orig->GetOffset(),
716 orig_vector->size(),
717 output_vector->size());
718 return false;
719 }
720 for (size_t i = 0; i < orig_vector->size(); ++i) {
721 if (!VerifyEncodedValue((*orig_vector)[i].get(),
722 (*output_vector)[i].get(),
723 orig->GetOffset(),
724 error_msg)) {
725 return false;
726 }
727 }
728 return true;
729}
730
731bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg) {
732 if (orig == nullptr || output == nullptr) {
733 if (orig != output) {
734 *error_msg = "Found unexpected empty class data.";
735 return false;
736 }
737 return true;
738 }
739 if (!VerifyFields(orig->StaticFields(), output->StaticFields(), orig->GetOffset(), error_msg)) {
740 return false;
741 }
742 if (!VerifyFields(orig->InstanceFields(),
743 output->InstanceFields(),
744 orig->GetOffset(),
745 error_msg)) {
746 return false;
747 }
748 if (!VerifyMethods(orig->DirectMethods(),
749 output->DirectMethods(),
750 orig->GetOffset(),
751 error_msg)) {
752 return false;
753 }
754 return VerifyMethods(orig->VirtualMethods(),
755 output->VirtualMethods(),
756 orig->GetOffset(),
757 error_msg);
758}
759
760bool VerifyFields(dex_ir::FieldItemVector* orig,
761 dex_ir::FieldItemVector* output,
762 uint32_t orig_offset,
763 std::string* error_msg) {
764 if (orig->size() != output->size()) {
765 *error_msg = StringPrintf("Mismatched fields size for class data at offset %x: %zu vs %zu.",
766 orig_offset,
767 orig->size(),
768 output->size());
769 return false;
770 }
771 for (size_t i = 0; i < orig->size(); ++i) {
772 dex_ir::FieldItem* orig_field = (*orig)[i].get();
773 dex_ir::FieldItem* output_field = (*output)[i].get();
774 if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
775 *error_msg = StringPrintf("Mismatched field index for class data at offset %x: %u vs %u.",
776 orig_offset,
777 orig_field->GetFieldId()->GetIndex(),
778 output_field->GetFieldId()->GetIndex());
779 return false;
780 }
781 if (orig_field->GetAccessFlags() != output_field->GetAccessFlags()) {
782 *error_msg = StringPrintf(
783 "Mismatched field access flags for class data at offset %x: %u vs %u.",
784 orig_offset,
785 orig_field->GetAccessFlags(),
786 output_field->GetAccessFlags());
787 return false;
788 }
789 }
790 return true;
791}
792
793bool VerifyMethods(dex_ir::MethodItemVector* orig,
794 dex_ir::MethodItemVector* output,
795 uint32_t orig_offset,
796 std::string* error_msg) {
797 if (orig->size() != output->size()) {
798 *error_msg = StringPrintf("Mismatched methods size for class data at offset %x: %zu vs %zu.",
799 orig_offset,
800 orig->size(),
801 output->size());
802 return false;
803 }
804 for (size_t i = 0; i < orig->size(); ++i) {
805 dex_ir::MethodItem* orig_method = (*orig)[i].get();
806 dex_ir::MethodItem* output_method = (*output)[i].get();
807 if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
808 *error_msg = StringPrintf("Mismatched method index for class data at offset %x: %u vs %u.",
809 orig_offset,
810 orig_method->GetMethodId()->GetIndex(),
811 output_method->GetMethodId()->GetIndex());
812 return false;
813 }
814 if (orig_method->GetAccessFlags() != output_method->GetAccessFlags()) {
815 *error_msg = StringPrintf(
816 "Mismatched method access flags for class data at offset %x: %u vs %u.",
817 orig_offset,
818 orig_method->GetAccessFlags(),
819 output_method->GetAccessFlags());
820 return false;
821 }
822 if (!VerifyCode(orig_method->GetCodeItem(), output_method->GetCodeItem(), error_msg)) {
823 return false;
824 }
825 }
826 return true;
827}
828
829bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg) {
830 if (orig == nullptr || output == nullptr) {
831 if (orig != output) {
832 *error_msg = "Found unexpected empty code item.";
833 return false;
834 }
835 return true;
836 }
837 if (orig->RegistersSize() != output->RegistersSize()) {
838 *error_msg = StringPrintf("Mismatched registers size for code item at offset %x: %u vs %u.",
839 orig->GetOffset(),
840 orig->RegistersSize(),
841 output->RegistersSize());
842 return false;
843 }
844 if (orig->InsSize() != output->InsSize()) {
845 *error_msg = StringPrintf("Mismatched ins size for code item at offset %x: %u vs %u.",
846 orig->GetOffset(),
847 orig->InsSize(),
848 output->InsSize());
849 return false;
850 }
851 if (orig->OutsSize() != output->OutsSize()) {
852 *error_msg = StringPrintf("Mismatched outs size for code item at offset %x: %u vs %u.",
853 orig->GetOffset(),
854 orig->OutsSize(),
855 output->OutsSize());
856 return false;
857 }
858 if (orig->TriesSize() != output->TriesSize()) {
859 *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %u vs %u.",
860 orig->GetOffset(),
861 orig->TriesSize(),
862 output->TriesSize());
863 return false;
864 }
865 if (!VerifyDebugInfo(orig->DebugInfo(), output->DebugInfo(), error_msg)) {
866 return false;
867 }
868 if (orig->InsnsSize() != output->InsnsSize()) {
869 *error_msg = StringPrintf("Mismatched insns size for code item at offset %x: %u vs %u.",
870 orig->GetOffset(),
871 orig->InsnsSize(),
872 output->InsnsSize());
873 return false;
874 }
875 if (memcmp(orig->Insns(), output->Insns(), orig->InsnsSize()) != 0) {
876 *error_msg = StringPrintf("Mismatched insns for code item at offset %x.",
877 orig->GetOffset());
878 return false;
879 }
880 if (!VerifyTries(orig->Tries(), output->Tries(), orig->GetOffset(), error_msg)) {
881 return false;
882 }
883 return VerifyHandlers(orig->Handlers(), output->Handlers(), orig->GetOffset(), error_msg);
884}
885
886bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig,
887 dex_ir::DebugInfoItem* output,
888 std::string* error_msg) {
889 if (orig == nullptr || output == nullptr) {
890 if (orig != output) {
891 *error_msg = "Found unexpected empty debug info.";
892 return false;
893 }
894 return true;
895 }
David Sehraa6abb02017-10-12 08:25:11 -0700896 // TODO: Test for debug equivalence rather than byte array equality.
897 uint32_t orig_size = orig->GetDebugInfoSize();
898 uint32_t output_size = output->GetDebugInfoSize();
899 if (orig_size != output_size) {
900 *error_msg = "DebugInfoSize disagreed.";
Jeff Haocc829592017-03-14 16:13:39 -0700901 return false;
902 }
David Sehraa6abb02017-10-12 08:25:11 -0700903 uint8_t* orig_data = orig->GetDebugInfo();
904 uint8_t* output_data = output->GetDebugInfo();
905 if ((orig_data == nullptr && output_data != nullptr) ||
906 (orig_data != nullptr && output_data == nullptr)) {
907 *error_msg = "DebugInfo null/non-null mismatch.";
Jeff Haocc829592017-03-14 16:13:39 -0700908 return false;
909 }
David Sehraa6abb02017-10-12 08:25:11 -0700910 if (memcmp(orig_data, output_data, orig_size) != 0) {
911 *error_msg = "DebugInfo bytes mismatch.";
Jeff Haocc829592017-03-14 16:13:39 -0700912 return false;
913 }
Jeff Haocc829592017-03-14 16:13:39 -0700914 return true;
915}
916
917bool VerifyTries(dex_ir::TryItemVector* orig,
918 dex_ir::TryItemVector* output,
919 uint32_t orig_offset,
920 std::string* error_msg) {
921 if (orig == nullptr || output == nullptr) {
922 if (orig != output) {
923 *error_msg = "Found unexpected empty try items.";
924 return false;
925 }
926 return true;
927 }
928 if (orig->size() != output->size()) {
929 *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %zu vs %zu.",
930 orig_offset,
931 orig->size(),
932 output->size());
933 return false;
934 }
935 for (size_t i = 0; i < orig->size(); ++i) {
936 const dex_ir::TryItem* orig_try = (*orig)[i].get();
937 const dex_ir::TryItem* output_try = (*output)[i].get();
938 if (orig_try->StartAddr() != output_try->StartAddr()) {
939 *error_msg = StringPrintf(
940 "Mismatched try item start addr for code item at offset %x: %u vs %u.",
941 orig_offset,
942 orig_try->StartAddr(),
943 output_try->StartAddr());
944 return false;
945 }
946 if (orig_try->InsnCount() != output_try->InsnCount()) {
947 *error_msg = StringPrintf(
948 "Mismatched try item insn count for code item at offset %x: %u vs %u.",
949 orig_offset,
950 orig_try->InsnCount(),
951 output_try->InsnCount());
952 return false;
953 }
954 if (!VerifyHandler(orig_try->GetHandlers(),
955 output_try->GetHandlers(),
956 orig_offset,
957 error_msg)) {
958 return false;
959 }
960 }
961 return true;
962}
963
964bool VerifyHandlers(dex_ir::CatchHandlerVector* orig,
965 dex_ir::CatchHandlerVector* output,
966 uint32_t orig_offset,
967 std::string* error_msg) {
968 if (orig == nullptr || output == nullptr) {
969 if (orig != output) {
970 *error_msg = "Found unexpected empty catch handlers.";
971 return false;
972 }
973 return true;
974 }
975 if (orig->size() != output->size()) {
976 *error_msg = StringPrintf(
977 "Mismatched catch handlers size for code item at offset %x: %zu vs %zu.",
978 orig_offset,
979 orig->size(),
980 output->size());
981 return false;
982 }
983 for (size_t i = 0; i < orig->size(); ++i) {
984 if (!VerifyHandler((*orig)[i].get(), (*output)[i].get(), orig_offset, error_msg)) {
985 return false;
986 }
987 }
988 return true;
989}
990
991bool VerifyHandler(const dex_ir::CatchHandler* orig,
992 const dex_ir::CatchHandler* output,
993 uint32_t orig_offset,
994 std::string* error_msg) {
995 dex_ir::TypeAddrPairVector* orig_handlers = orig->GetHandlers();
996 dex_ir::TypeAddrPairVector* output_handlers = output->GetHandlers();
997 if (orig_handlers->size() != output_handlers->size()) {
998 *error_msg = StringPrintf(
999 "Mismatched number of catch handlers for code item at offset %x: %zu vs %zu.",
1000 orig_offset,
1001 orig_handlers->size(),
1002 output_handlers->size());
1003 return false;
1004 }
1005 for (size_t i = 0; i < orig_handlers->size(); ++i) {
1006 const dex_ir::TypeAddrPair* orig_handler = (*orig_handlers)[i].get();
1007 const dex_ir::TypeAddrPair* output_handler = (*output_handlers)[i].get();
1008 if (orig_handler->GetTypeId() == nullptr || output_handler->GetTypeId() == nullptr) {
1009 if (orig_handler->GetTypeId() != output_handler->GetTypeId()) {
1010 *error_msg = StringPrintf(
1011 "Found unexpected catch all catch handler for code item at offset %x.",
1012 orig_offset);
1013 return false;
1014 }
1015 } else if (orig_handler->GetTypeId()->GetIndex() != output_handler->GetTypeId()->GetIndex()) {
1016 *error_msg = StringPrintf(
1017 "Mismatched catch handler type for code item at offset %x: %u vs %u.",
1018 orig_offset,
1019 orig_handler->GetTypeId()->GetIndex(),
1020 output_handler->GetTypeId()->GetIndex());
1021 return false;
1022 }
1023 if (orig_handler->GetAddress() != output_handler->GetAddress()) {
1024 *error_msg = StringPrintf(
1025 "Mismatched catch handler address for code item at offset %x: %u vs %u.",
1026 orig_offset,
1027 orig_handler->GetAddress(),
1028 output_handler->GetAddress());
1029 return false;
1030 }
1031 }
1032 return true;
1033}
1034
Jeff Haoec7f1a92017-03-13 16:24:24 -07001035} // namespace art