You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
830 lines
37 KiB
830 lines
37 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "base/common_art_test.h"
|
|
#include "base/unix_file/fd_file.h"
|
|
#include "base/utils.h"
|
|
#include "dex/art_dex_file_loader.h"
|
|
#include "dex/base64_test_util.h"
|
|
#include "dex/class_accessor-inl.h"
|
|
#include "dex/code_item_accessors-inl.h"
|
|
#include "dex/dex_file-inl.h"
|
|
#include "dex/dex_file_loader.h"
|
|
#include "dexlayout.h"
|
|
#include "exec_utils.h"
|
|
#include "profile/profile_compilation_info.h"
|
|
|
|
namespace art {
|
|
|
|
static const char kDexFileLayoutInputDex[] =
|
|
"ZGV4CjAzNQD1KW3+B8NAB0f2A/ZVIBJ0aHrGIqcpVTAUAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAH"
|
|
"AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAUAQAAAAEAADAB"
|
|
"AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA"
|
|
"AAAAAAABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAEAAAAAAAAAdQEAAAAAAAABAAAA"
|
|
"AAAAAAIAAAAAAAAAAgAAAAAAAAB/AQAAAAAAAAEAAQABAAAAaQEAAAQAAABwEAIAAAAOAAEAAQAB"
|
|
"AAAAbwEAAAQAAABwEAIAAAAOAAY8aW5pdD4ABkEuamF2YQAGQi5qYXZhAANMQTsAA0xCOwASTGph"
|
|
"dmEvbGFuZy9PYmplY3Q7AAFWAAQABw48AAQABw48AAAAAQAAgIAEgAIAAAEAAYCABJgCAAAACwAA"
|
|
"AAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAAEAAAAjAAAAAMAAAABAAAAnAAAAAUAAAADAAAA"
|
|
"qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC"
|
|
"AAAAdQEAAAAQAAABAAAAjAEAAA==";
|
|
|
|
// Dex file with catch handler unreferenced by try blocks.
|
|
// Constructed by building a dex file with try/catch blocks and hex editing.
|
|
static const char kUnreferencedCatchHandlerInputDex[] =
|
|
"ZGV4CjAzNQD+exd52Y0f9nY5x5GmInXq5nXrO6Kl2RV4AwAAcAAAAHhWNBIAAAAAAAAAANgCAAAS"
|
|
"AAAAcAAAAAgAAAC4AAAAAwAAANgAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAA0AgAARAEAANYB"
|
|
"AADeAQAA5gEAAO4BAAAAAgAADwIAACYCAAA9AgAAUQIAAGUCAAB5AgAAfwIAAIUCAACIAgAAjAIA"
|
|
"AKECAACnAgAArAIAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAwAAAAOAAAADAAAAAYAAAAAAAAA"
|
|
"DQAAAAYAAADIAQAADQAAAAYAAADQAQAABQABABAAAAAAAAAAAAAAAAAAAgAPAAAAAQABABEAAAAD"
|
|
"AAAAAAAAAAAAAAABAAAAAwAAAAAAAAADAAAAAAAAAMgCAAAAAAAAAQABAAEAAAC1AgAABAAAAHAQ"
|
|
"AwAAAA4AAwABAAIAAgC6AgAAIQAAAGIAAAAaAQoAbiACABAAYgAAABoBCwBuIAIAEAAOAA0AYgAA"
|
|
"ABoBAQBuIAIAEAAo8A0AYgAAABoBAgBuIAIAEAAo7gAAAAAAAAcAAQAHAAAABwABAAIBAg8BAhgA"
|
|
"AQAAAAQAAAABAAAABwAGPGluaXQ+AAZDYXRjaDEABkNhdGNoMgAQSGFuZGxlclRlc3QuamF2YQAN"
|
|
"TEhhbmRsZXJUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABVMamF2YS9sYW5nL0V4Y2VwdGlv"
|
|
"bjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5"
|
|
"c3RlbTsABFRyeTEABFRyeTIAAVYAAlZMABNbTGphdmEvbGFuZy9TdHJpbmc7AARtYWluAANvdXQA"
|
|
"B3ByaW50bG4AAQAHDgAEAQAHDn17AncdHoseAAAAAgAAgYAExAIBCdwCAAANAAAAAAAAAAEAAAAA"
|
|
"AAAAAQAAABIAAABwAAAAAgAAAAgAAAC4AAAAAwAAAAMAAADYAAAABAAAAAEAAAD8AAAABQAAAAQA"
|
|
"AAAEAQAABgAAAAEAAAAkAQAAASAAAAIAAABEAQAAARAAAAIAAADIAQAAAiAAABIAAADWAQAAAyAA"
|
|
"AAIAAAC1AgAAACAAAAEAAADIAgAAABAAAAEAAADYAgAA";
|
|
|
|
// Dex file with 0-size (catch all only) catch handler unreferenced by try blocks.
|
|
// Constructed by building a dex file with try/catch blocks and hex editing.
|
|
static const char kUnreferenced0SizeCatchHandlerInputDex[] =
|
|
"ZGV4CjAzNQCEbEEvMstSNpQpjPdfMEfUBS48cis2QRJoAwAAcAAAAHhWNBIAAAAAAAAAAMgCAAAR"
|
|
"AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAQAAAD8AAAAAQAAABwBAAAsAgAAPAEAAOoB"
|
|
"AADyAQAABAIAABMCAAAqAgAAPgIAAFICAABmAgAAaQIAAG0CAACCAgAAhgIAAIoCAACQAgAAlQIA"
|
|
"AJ4CAACiAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACQAAAAcAAAAFAAAAAAAAAAgAAAAFAAAA"
|
|
"3AEAAAgAAAAFAAAA5AEAAAQAAQANAAAAAAAAAAAAAAAAAAIADAAAAAEAAQAOAAAAAgAAAAAAAAAA"
|
|
"AAAAAQAAAAIAAAAAAAAAAQAAAAAAAAC5AgAAAAAAAAEAAQABAAAApgIAAAQAAABwEAMAAAAOAAQA"
|
|
"AQACAAIAqwIAAC8AAABiAAAAGgEPAG4gAgAQAGIAAAAaAQoAbiACABAAYgAAABoBEABuIAIAEABi"
|
|
"AAAAGgELAG4gAgAQAA4ADQBiAQAAGgIKAG4gAgAhACcADQBiAQAAGgILAG4gAgAhACcAAAAAAAAA"
|
|
"BwABAA4AAAAHAAEAAgAdACYAAAABAAAAAwAAAAEAAAAGAAY8aW5pdD4AEEhhbmRsZXJUZXN0Lmph"
|
|
"dmEADUxIYW5kbGVyVGVzdDsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmpl"
|
|
"Y3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwABVgACVkwAE1tMamF2"
|
|
"YS9sYW5nL1N0cmluZzsAAmYxAAJmMgAEbWFpbgADb3V0AAdwcmludGxuAAJ0MQACdDIAAQAHDgAE"
|
|
"AQAHDnl7eXkCeB2bAAAAAgAAgYAEvAIBCdQCAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAAC"
|
|
"AAAABwAAALQAAAADAAAAAwAAANAAAAAEAAAAAQAAAPQAAAAFAAAABAAAAPwAAAAGAAAAAQAAABwB"
|
|
"AAABIAAAAgAAADwBAAABEAAAAgAAANwBAAACIAAAEQAAAOoBAAADIAAAAgAAAKYCAAAAIAAAAQAA"
|
|
"ALkCAAAAEAAAAQAAAMgCAAA=";
|
|
|
|
// Dex file with an unreferenced catch handler at end of code item.
|
|
// Constructed by building a dex file with try/catch blocks and hex editing.
|
|
static const char kUnreferencedEndingCatchHandlerInputDex[] =
|
|
"ZGV4CjAzNQCEflufI6xGTDDRmLpbfYi6ujPrDLIwvYcEBAAAcAAAAHhWNBIAAAAAAAAAAGQDAAAT"
|
|
"AAAAcAAAAAgAAAC8AAAAAwAAANwAAAABAAAAAAEAAAUAAAAIAQAAAQAAADABAAC0AgAAUAEAAE4C"
|
|
"AABWAgAAXgIAAGYCAAB4AgAAhwIAAJ4CAAC1AgAAyQIAAN0CAADxAgAA9wIAAP0CAAAAAwAABAMA"
|
|
"ABkDAAAcAwAAIgMAACcDAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAADgAAAAwAAAAGAAAA"
|
|
"AAAAAA0AAAAGAAAAQAIAAA0AAAAGAAAASAIAAAUAAQARAAAAAAAAAAAAAAAAAAAADwAAAAAAAgAQ"
|
|
"AAAAAQABABIAAAADAAAAAAAAAAAAAAABAAAAAwAAAAAAAAADAAAAAAAAAFADAAAAAAAAAQABAAEA"
|
|
"AAAwAwAABAAAAHAQBAAAAA4AAgAAAAIAAgA1AwAAIQAAAGIAAAAaAQoAbiADABAAYgAAABoBCwBu"
|
|
"IAMAEAAOAA0AYgAAABoBAQBuIAMAEAAo8A0AYgAAABoBAgBuIAMAEAAo7gAAAAAAAAcAAQAHAAAA"
|
|
"BwABAAIBAg8BAhgAAwABAAIAAgBCAwAAIQAAAGIAAAAaAQoAbiADABAAYgAAABoBCwBuIAMAEAAO"
|
|
"AA0AYgAAABoBAQBuIAMAEAAo8A0AYgAAABoBAgBuIAMAEAAo7gAAAAAAAAcAAQAHAAAABwABAAIB"
|
|
"Ag8BAhgAAQAAAAQAAAABAAAABwAGPGluaXQ+AAZDYXRjaDEABkNhdGNoMgAQSGFuZGxlclRlc3Qu"
|
|
"amF2YQANTEhhbmRsZXJUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABVMamF2YS9sYW5nL0V4"
|
|
"Y2VwdGlvbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9s"
|
|
"YW5nL1N5c3RlbTsABFRyeTEABFRyeTIAAVYAAlZMABNbTGphdmEvbGFuZy9TdHJpbmc7AAFhAARt"
|
|
"YWluAANvdXQAB3ByaW50bG4AAQAHDgAEAAcOfHsCeB0eih4AEQEABw59ewJ3HR6LHgAAAAMAAIGA"
|
|
"BNACAQnoAgEJ1AMAAA0AAAAAAAAAAQAAAAAAAAABAAAAEwAAAHAAAAACAAAACAAAALwAAAADAAAA"
|
|
"AwAAANwAAAAEAAAAAQAAAAABAAAFAAAABQAAAAgBAAAGAAAAAQAAADABAAABIAAAAwAAAFABAAAB"
|
|
"EAAAAgAAAEACAAACIAAAEwAAAE4CAAADIAAAAwAAADADAAAAIAAAAQAAAFADAAAAEAAAAQAAAGQD"
|
|
"AAA=";
|
|
|
|
// Dex file with multiple code items that have the same debug_info_off_. Constructed by a modified
|
|
// dexlayout on XandY.
|
|
static const char kDexFileDuplicateOffset[] =
|
|
"ZGV4CjAzNwAQfXfPCB8qCxo7MqdFhmHZQwCv8+udHD8MBAAAcAAAAHhWNBIAAAAAAAAAAFQDAAAT"
|
|
"AAAAcAAAAAgAAAC8AAAAAQAAANwAAAABAAAA6AAAAAUAAADwAAAAAwAAABgBAACUAgAAeAEAABQC"
|
|
"AAAeAgAAJgIAACsCAAAyAgAANwIAAFsCAAB7AgAAngIAALICAAC1AgAAvQIAAMUCAADIAgAA1QIA"
|
|
"AOkCAADvAgAA9QIAAPwCAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAkAAAAHAAAA"
|
|
"AAAAAAIAAQASAAAAAAAAAAEAAAABAAAAAQAAAAIAAAAAAAAAAgAAAAEAAAAGAAAAAQAAAAAAAAAA"
|
|
"AAAABgAAAAAAAAAKAAAAAAAAACsDAAAAAAAAAQAAAAAAAAAGAAAAAAAAAAsAAAD0AQAANQMAAAAA"
|
|
"AAACAAAAAAAAAAAAAAAAAAAACwAAAAQCAAA/AwAAAAAAAAIAAAAUAwAAGgMAAAEAAAAjAwAAAQAB"
|
|
"AAEAAAAFAAAABAAAAHAQBAAAAA4AAQABAAEAAAAFAAAABAAAAHAQBAAAAA4AAQAAAAEAAAAFAAAA"
|
|
"CAAAACIAAQBwEAEAAABpAAAADgABAAEAAQAAAAUAAAAEAAAAcBAAAAAADgB4AQAAAAAAAAAAAAAA"
|
|
"AAAAhAEAAAAAAAAAAAAAAAAAAAg8Y2xpbml0PgAGPGluaXQ+AANMWDsABUxZJFo7AANMWTsAIkxk"
|
|
"YWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5l"
|
|
"ckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNzZXM7ABJMamF2YS9sYW5nL09i"
|
|
"amVjdDsAAVYABlguamF2YQAGWS5qYXZhAAFaAAthY2Nlc3NGbGFncwASZW1pdHRlcjogamFjay00"
|
|
"LjI1AARuYW1lAAR0aGlzAAV2YWx1ZQABegARAAcOABMABw4AEgAHDnYAEQAHDgACAwERGAICBAIN"
|
|
"BAgPFwwCBQERHAEYAQAAAQAAgIAEjAMAAAEAAYCABKQDAQACAAAIAoiABLwDAYCABNwDAAAADwAA"
|
|
"AAAAAAABAAAAAAAAAAEAAAATAAAAcAAAAAIAAAAIAAAAvAAAAAMAAAABAAAA3AAAAAQAAAABAAAA"
|
|
"6AAAAAUAAAAFAAAA8AAAAAYAAAADAAAAGAEAAAMQAAACAAAAeAEAAAEgAAAEAAAAjAEAAAYgAAAC"
|
|
"AAAA9AEAAAIgAAATAAAAFAIAAAMgAAAEAAAA/wIAAAQgAAADAAAAFAMAAAAgAAADAAAAKwMAAAAQ"
|
|
"AAABAAAAVAMAAA==";
|
|
|
|
// Dex file with null value for annotations_off in the annotation_set_ref_list.
|
|
// Constructed by building a dex file with annotations and hex editing.
|
|
static const char kNullSetRefListElementInputDex[] =
|
|
"ZGV4CjAzNQB1iA+7ZwgkF+7E6ZesYFc2lRAR3qnRAanwAwAAcAAAAHhWNBIAAAAAAAAAACADAAAS"
|
|
"AAAAcAAAAAgAAAC4AAAAAwAAANgAAAABAAAA/AAAAAQAAAAEAQAAAgAAACQBAACMAgAAZAEAAOgB"
|
|
"AADwAQAAAAIAAAMCAAAQAgAAIAIAADQCAABIAgAAawIAAI0CAAC1AgAAyAIAANECAADUAgAA2QIA"
|
|
"ANwCAADjAgAA6QIAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAAAgAAAAMAAAAAAAAA"
|
|
"DAAAAAcAAAAAAAAADQAAAAcAAADgAQAABgAGAAsAAAAAAAEAAAAAAAAAAgAOAAAAAQAAABAAAAAC"
|
|
"AAEAAAAAAAAAAAAAAAAAAgAAAAAAAAABAAAAsAEAAAgDAAAAAAAAAQAAAAEmAAACAAAA2AEAAAoA"
|
|
"AADIAQAAFgMAAAAAAAACAAAAAAAAAHwBAAABAAAA/AIAAAAAAAABAAAAAgMAAAEAAQABAAAA8AIA"
|
|
"AAQAAABwEAMAAAAOAAIAAgAAAAAA9QIAAAEAAAAOAAAAAAAAAAAAAAAAAAAAAQAAAAEAAABkAQAA"
|
|
"cAEAAAAAAAAAAAAAAAAAAAEAAAAEAAAAAgAAAAMAAwAGPGluaXQ+AA5Bbm5vQ2xhc3MuamF2YQAB"
|
|
"TAALTEFubm9DbGFzczsADkxNeUFubm90YXRpb247ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZh"
|
|
"L2xhbmcvU3RyaW5nOwAhTGphdmEvbGFuZy9hbm5vdGF0aW9uL0Fubm90YXRpb247ACBMamF2YS9s"
|
|
"YW5nL2Fubm90YXRpb24vUmV0ZW50aW9uOwAmTGphdmEvbGFuZy9hbm5vdGF0aW9uL1JldGVudGlv"
|
|
"blBvbGljeTsAEU15QW5ub3RhdGlvbi5qYXZhAAdSVU5USU1FAAFWAANWTEwAAWEABWFOYW1lAARu"
|
|
"YW1lAAV2YWx1ZQABAAcOAAICAAAHDgABBQERGwABAQEQFw8AAAIAAICABIQDAQmcAwAAAAECgQgA"
|
|
"AAARAAAAAAAAAAEAAAAAAAAAAQAAABIAAABwAAAAAgAAAAgAAAC4AAAAAwAAAAMAAADYAAAABAAA"
|
|
"AAEAAAD8AAAABQAAAAQAAAAEAQAABgAAAAIAAAAkAQAAAhAAAAEAAABkAQAAAxAAAAMAAABwAQAA"
|
|
"ASAAAAIAAACEAQAABiAAAAIAAACwAQAAARAAAAIAAADYAQAAAiAAABIAAADoAQAAAyAAAAIAAADw"
|
|
"AgAABCAAAAIAAAD8AgAAACAAAAIAAAAIAwAAABAAAAEAAAAgAwAA";
|
|
|
|
// Dex file with shared empty class data item for multiple class defs.
|
|
// Constructing by building a dex file with multiple classes and hex editing.
|
|
static const char kMultiClassDataInputDex[] =
|
|
"ZGV4CjAzNQALJgF9TtnLq748xVe/+wyxETrT9lTEiW6YAQAAcAAAAHhWNBIAAAAAAAAAADQBAAAI"
|
|
"AAAAcAAAAAQAAACQAAAAAAAAAAAAAAACAAAAoAAAAAAAAAAAAAAAAgAAALAAAACoAAAA8AAAAPAA"
|
|
"AAD4AAAAAAEAAAMBAAAIAQAADQEAACEBAAAkAQAAAgAAAAMAAAAEAAAABQAAAAEAAAAGAAAAAgAA"
|
|
"AAcAAAABAAAAAQYAAAMAAAAAAAAAAAAAAAAAAAAnAQAAAAAAAAIAAAABBgAAAwAAAAAAAAABAAAA"
|
|
"AAAAACcBAAAAAAAABkEuamF2YQAGQi5qYXZhAAFJAANMQTsAA0xCOwASTGphdmEvbGFuZy9PYmpl"
|
|
"Y3Q7AAFhAAFiAAAAAAABAAAAARkAAAAIAAAAAAAAAAEAAAAAAAAAAQAAAAgAAABwAAAAAgAAAAQA"
|
|
"AACQAAAABAAAAAIAAACgAAAABgAAAAIAAACwAAAAAiAAAAgAAADwAAAAACAAAAIAAAAnAQAAABAA"
|
|
"AAEAAAA0AQAA";
|
|
|
|
// Dex file with code info followed by non 4-byte aligned section.
|
|
// Constructed a dex file with code info followed by string data and hex edited.
|
|
static const char kUnalignedCodeInfoInputDex[] =
|
|
"ZGV4CjAzNQDXJzXNb4iWn2SLhmLydW/8h1K9moERIw7UAQAAcAAAAHhWNBIAAAAAAAAAAEwBAAAG"
|
|
"AAAAcAAAAAMAAACIAAAAAQAAAJQAAAAAAAAAAAAAAAMAAACgAAAAAQAAALgAAAD8AAAA2AAAAAIB"
|
|
"AAAKAQAAEgEAABcBAAArAQAALgEAAAIAAAADAAAABAAAAAQAAAACAAAAAAAAAAAAAAAAAAAAAAAA"
|
|
"AAUAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAABAAAAAAAAADsBAAAAAAAAAQABAAEAAAAxAQAA"
|
|
"BAAAAHAQAgAAAA4AAQABAAAAAAA2AQAAAQAAAA4ABjxpbml0PgAGQS5qYXZhAANMQTsAEkxqYXZh"
|
|
"L2xhbmcvT2JqZWN0OwABVgABYQABAAcOAAMABw4AAAABAQCBgATYAQEB8AEAAAALAAAAAAAAAAEA"
|
|
"AAAAAAAAAQAAAAYAAABwAAAAAgAAAAMAAACIAAAAAwAAAAEAAACUAAAABQAAAAMAAACgAAAABgAA"
|
|
"AAEAAAC4AAAAASAAAAIAAADYAAAAAiAAAAYAAAACAQAAAyAAAAIAAAAxAQAAACAAAAEAAAA7AQAA"
|
|
"ABAAAAEAAABMAQAA";
|
|
|
|
// Dex file with class data section preceding code items.
|
|
// Constructed by passing dex file through dexmerger tool and hex editing.
|
|
static const char kClassDataBeforeCodeInputDex[] =
|
|
"ZGV4CjAzNQCZKmCu3XXn4zvxCh5VH0gZNNobEAcsc49EAgAAcAAAAHhWNBIAAAAAAAAAAAQBAAAJ"
|
|
"AAAAcAAAAAQAAACUAAAAAgAAAKQAAAAAAAAAAAAAAAUAAAC8AAAAAQAAAOQAAABAAQAABAEAAPgB"
|
|
"AAAAAgAACAIAAAsCAAAQAgAAJAIAACcCAAAqAgAALQIAAAIAAAADAAAABAAAAAUAAAACAAAAAAAA"
|
|
"AAAAAAAFAAAAAwAAAAAAAAABAAEAAAAAAAEAAAAGAAAAAQAAAAcAAAABAAAACAAAAAIAAQAAAAAA"
|
|
"AQAAAAEAAAACAAAAAAAAAAEAAAAAAAAAjAEAAAAAAAALAAAAAAAAAAEAAAAAAAAAAQAAAAkAAABw"
|
|
"AAAAAgAAAAQAAACUAAAAAwAAAAIAAACkAAAABQAAAAUAAAC8AAAABgAAAAEAAADkAAAAABAAAAEA"
|
|
"AAAEAQAAACAAAAEAAACMAQAAASAAAAQAAACkAQAAAiAAAAkAAAD4AQAAAyAAAAQAAAAwAgAAAAAB"
|
|
"AwCBgASkAwEBvAMBAdADAQHkAwAAAQABAAEAAAAwAgAABAAAAHAQBAAAAA4AAgABAAAAAAA1AgAA"
|
|
"AgAAABIQDwACAAEAAAAAADoCAAACAAAAEiAPAAIAAQAAAAAAPwIAAAIAAAASMA8ABjxpbml0PgAG"
|
|
"QS5qYXZhAAFJAANMQTsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgABYQABYgABYwABAAcOAAMABw4A"
|
|
"BgAHDgAJAAcOAA==";
|
|
|
|
// Dex file with local info containing a null type descriptor.
|
|
// Constructed a dex file with debug info sequence containing DBG_RESTART_LOCAL without any
|
|
// DBG_START_LOCAL to give it a declared type.
|
|
static const char kUnknownTypeDebugInfoInputDex[] =
|
|
"ZGV4CjAzNQBtKqZfzjHLNSNwW2A6Bz9FuCEX0sL+FF38AQAAcAAAAHhWNBIAAAAAAAAAAHQBAAAI"
|
|
"AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAMAQAA8AAAABwB"
|
|
"AAAkAQAALAEAAC8BAAA0AQAASAEAAEsBAABOAQAAAgAAAAMAAAAEAAAABQAAAAIAAAAAAAAAAAAA"
|
|
"AAUAAAADAAAAAAAAAAEAAQAAAAAAAQAAAAYAAAACAAEAAAAAAAEAAAABAAAAAgAAAAAAAAABAAAA"
|
|
"AAAAAGMBAAAAAAAAAQABAAEAAABUAQAABAAAAHAQAgAAAA4AAgABAAAAAABZAQAAAgAAABIQDwAG"
|
|
"PGluaXQ+AAZBLmphdmEAAUkAA0xBOwASTGphdmEvbGFuZy9PYmplY3Q7AAFWAAFhAAR0aGlzAAEA"
|
|
"Bw4AAwAHDh4GAAYAAAAAAQEAgYAE8AEBAYgCAAAACwAAAAAAAAABAAAAAAAAAAEAAAAIAAAAcAAA"
|
|
"AAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAAuAAAAAYAAAABAAAA0AAAAAEgAAACAAAA"
|
|
"8AAAAAIgAAAIAAAAHAEAAAMgAAACAAAAVAEAAAAgAAABAAAAYwEAAAAQAAABAAAAdAEAAA==";
|
|
|
|
// Dex file with multiple class data items pointing to the same code item.
|
|
// Constructed by hex editing.
|
|
static const char kDuplicateCodeItemInputDex[] =
|
|
"ZGV4CjAzNQCwKtVglQOmLWuHwldN5jkBOInC7mTMhJMAAgAAcAAAAHhWNBIAAAAAAAAAAHgBAAAH"
|
|
"AAAAcAAAAAMAAACMAAAAAQAAAJgAAAAAAAAAAAAAAAQAAACkAAAAAQAAAMQAAAAcAQAA5AAAACQB"
|
|
"AAAsAQAANAEAADkBAABNAQAAUAEAAFMBAAACAAAAAwAAAAQAAAAEAAAAAgAAAAAAAAAAAAAAAAAA"
|
|
"AAAAAAAFAAAAAAAAAAYAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAABAAAAAAAAAGUBAAAAAAAA"
|
|
"AQABAAEAAABWAQAABAAAAHAQAwAAAA4AAQABAAAAAABbAQAAAQAAAA4AAAABAAEAAAAAAGABAAAB"
|
|
"AAAADgAAAAY8aW5pdD4ABkEuamF2YQADTEE7ABJMamF2YS9sYW5nL09iamVjdDsAAVYAAWEAAWIA"
|
|
"AQAHDgADAAcOAAUABw4AAAABAgCBgATkAQEA/AEBAPwBAAsAAAAAAAAAAQAAAAAAAAABAAAABwAA"
|
|
"AHAAAAACAAAAAwAAAIwAAAADAAAAAQAAAJgAAAAFAAAABAAAAKQAAAAGAAAAAQAAAMQAAAABIAAA"
|
|
"AwAAAOQAAAACIAAABwAAACQBAAADIAAAAwAAAFYBAAAAIAAAAQAAAGUBAAAAEAAAAQAAAHgBAAA=";
|
|
|
|
// Returns the default compact dex option for dexlayout based on kDefaultCompactDexLevel.
|
|
static std::vector<std::string> DefaultCompactDexOption() {
|
|
return (kDefaultCompactDexLevel == CompactDexLevel::kCompactDexLevelFast) ?
|
|
std::vector<std::string>{"-x", "fast"} : std::vector<std::string>{"-x", "none"};
|
|
}
|
|
|
|
static void WriteBase64ToFile(const char* base64, File* file) {
|
|
// Decode base64.
|
|
CHECK(base64 != nullptr);
|
|
size_t length;
|
|
std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
|
|
CHECK(bytes != nullptr);
|
|
if (!file->WriteFully(bytes.get(), length)) {
|
|
PLOG(FATAL) << "Failed to write base64 as file";
|
|
}
|
|
}
|
|
|
|
static void WriteFileBase64(const char* base64, const char* location) {
|
|
// Write to provided file.
|
|
std::unique_ptr<File> file(OS::CreateEmptyFile(location));
|
|
CHECK(file != nullptr);
|
|
WriteBase64ToFile(base64, file.get());
|
|
if (file->FlushCloseOrErase() != 0) {
|
|
PLOG(FATAL) << "Could not flush and close test file.";
|
|
}
|
|
}
|
|
|
|
class DexLayoutTest : public CommonArtTest {
|
|
protected:
|
|
std::string GetDexLayoutPath() {
|
|
return GetArtBinDir() + "/dexlayoutd";
|
|
}
|
|
|
|
// Runs FullPlainOutput test.
|
|
bool FullPlainOutputExec(std::string* error_msg) {
|
|
ScratchFile dexdump_output;
|
|
const std::string& dexdump_filename = dexdump_output.GetFilename();
|
|
std::string dexdump = GetArtBinDir() + "/dexdump";
|
|
EXPECT_TRUE(OS::FileExists(dexdump.c_str())) << dexdump << " should be a valid file path";
|
|
|
|
ScratchFile dexlayout_output;
|
|
const std::string& dexlayout_filename = dexlayout_output.GetFilename();
|
|
|
|
for (const std::string& dex_file : GetLibCoreDexFileNames()) {
|
|
std::vector<std::string> dexdump_exec_argv =
|
|
{ dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file };
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
|
|
if (!::art::Exec(dexdump_exec_argv, error_msg)) {
|
|
return false;
|
|
}
|
|
if (!DexLayoutExec(dexlayout_args, error_msg)) {
|
|
return false;
|
|
}
|
|
std::vector<std::string> diff_exec_argv =
|
|
{ "/usr/bin/diff", dexdump_filename, dexlayout_filename };
|
|
if (!::art::Exec(diff_exec_argv, error_msg)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Runs DexFileOutput test.
|
|
bool DexFileOutputExec(std::string* error_msg) {
|
|
ScratchFile tmp_file;
|
|
const std::string& tmp_name = tmp_file.GetFilename();
|
|
size_t tmp_last_slash = tmp_name.rfind('/');
|
|
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
|
|
std::string unzip_dir = tmp_dir + "unzip/";
|
|
|
|
for (const std::string& dex_file : GetLibCoreDexFileNames()) {
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-w", tmp_dir, "-o", tmp_name, dex_file };
|
|
if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) {
|
|
return false;
|
|
}
|
|
std::string dex_file_name = "classes.dex";
|
|
std::vector<std::string> unzip_exec_argv =
|
|
{ "/usr/bin/unzip", dex_file, "classes.dex", "-d", unzip_dir};
|
|
if (!::art::Exec(unzip_exec_argv, error_msg)) {
|
|
return false;
|
|
}
|
|
std::vector<std::string> diff_exec_argv =
|
|
{ "/usr/bin/diff", tmp_dir + "classes.dex" , unzip_dir + dex_file_name };
|
|
if (!::art::Exec(diff_exec_argv, error_msg)) {
|
|
return false;
|
|
}
|
|
if (!UnlinkFile(unzip_dir + "classes.dex")) {
|
|
return false;
|
|
}
|
|
if (!UnlinkFile(tmp_dir + dex_file_name)) {
|
|
return false;
|
|
}
|
|
// Remove the unzip temp directory so that unlinking android_data doesn't fail.
|
|
EXPECT_EQ(rmdir(unzip_dir.c_str()), 0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Create a profile with some subset of methods and classes.
|
|
void CreateProfile(const std::string& input_dex,
|
|
const std::string& out_profile) {
|
|
std::vector<std::unique_ptr<const DexFile>> dex_files;
|
|
std::string error_msg;
|
|
const ArtDexFileLoader dex_file_loader;
|
|
bool result = dex_file_loader.Open(input_dex.c_str(),
|
|
input_dex,
|
|
/*verify=*/ true,
|
|
/*verify_checksum=*/ false,
|
|
&error_msg,
|
|
&dex_files);
|
|
|
|
ASSERT_TRUE(result) << error_msg;
|
|
ASSERT_GE(dex_files.size(), 1u);
|
|
|
|
size_t profile_methods = 0;
|
|
size_t profile_classes = 0;
|
|
ProfileCompilationInfo pfi;
|
|
for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
|
|
for (uint32_t i = 0; i < dex_file->NumMethodIds(); i += 2) {
|
|
uint8_t flags = 0u;
|
|
|
|
if ((i & 3) != 0) {
|
|
flags |= ProfileCompilationInfo::MethodHotness::kFlagHot;
|
|
++profile_methods;
|
|
} else if ((i & 2) != 0) {
|
|
flags |= ProfileCompilationInfo::MethodHotness::kFlagStartup;
|
|
++profile_methods;
|
|
}
|
|
pfi.AddMethod(ProfileMethodInfo(MethodReference(dex_file.get(), /*index=*/ i)),
|
|
static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags));
|
|
}
|
|
// Add every even class too.
|
|
std::set<dex::TypeIndex> classes;
|
|
for (uint32_t i = 0; i < dex_file->NumClassDefs(); i += 1) {
|
|
if ((i & 2) == 0) {
|
|
classes.insert(dex::TypeIndex(dex_file->GetClassDef(i).class_idx_));
|
|
++profile_classes;
|
|
}
|
|
}
|
|
if (!classes.empty()) {
|
|
pfi.AddClassesForDex(dex_file.get(), classes.begin(), classes.end());
|
|
}
|
|
}
|
|
// Write to provided file.
|
|
std::unique_ptr<File> file(OS::CreateEmptyFile(out_profile.c_str()));
|
|
ASSERT_TRUE(file != nullptr);
|
|
pfi.Save(file->Fd());
|
|
if (file->FlushCloseOrErase() != 0) {
|
|
PLOG(FATAL) << "Could not flush and close test file.";
|
|
}
|
|
EXPECT_GE(profile_methods, 0u);
|
|
EXPECT_GE(profile_classes, 0u);
|
|
}
|
|
|
|
// Runs DexFileLayout test.
|
|
bool DexFileLayoutExec(std::string* error_msg) {
|
|
ScratchFile tmp_file;
|
|
const std::string& tmp_name = tmp_file.GetFilename();
|
|
size_t tmp_last_slash = tmp_name.rfind('/');
|
|
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
|
|
|
|
// Write inputs and expected outputs.
|
|
std::string dex_file = tmp_dir + "classes.dex";
|
|
WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str());
|
|
std::string profile_file = tmp_dir + "primary.prof";
|
|
CreateProfile(dex_file, profile_file);
|
|
// WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
|
|
std::string output_dex = tmp_dir + "classes.dex.new";
|
|
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
|
|
if (!DexLayoutExec(dexlayout_args, error_msg)) {
|
|
return false;
|
|
}
|
|
|
|
// -v makes sure that the layout did not corrupt the dex file.
|
|
if (!UnlinkFile(dex_file) || !UnlinkFile(profile_file) || !UnlinkFile(output_dex)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Runs DexFileLayout test twice (second time is run on output of first time)
|
|
// for behavior consistency.
|
|
bool DexFileLayoutFixedPointExec(std::string* error_msg) {
|
|
ScratchFile tmp_file;
|
|
const std::string& tmp_name = tmp_file.GetFilename();
|
|
size_t tmp_last_slash = tmp_name.rfind('/');
|
|
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
|
|
|
|
// Unzip the test dex file to the classes.dex destination. It is required to unzip since
|
|
// opening from jar recalculates the dex location checksum.
|
|
std::string dex_file = tmp_dir + "classes.dex";
|
|
|
|
std::vector<std::string> unzip_args = {
|
|
"/usr/bin/unzip",
|
|
GetTestDexFileName("ManyMethods"),
|
|
"classes.dex",
|
|
"-d",
|
|
tmp_dir,
|
|
};
|
|
if (!art::Exec(unzip_args, error_msg)) {
|
|
LOG(ERROR) << "Failed to unzip dex";
|
|
return false;
|
|
}
|
|
|
|
std::string profile_file = tmp_dir + "primary.prof";
|
|
CreateProfile(dex_file, profile_file);
|
|
std::string output_dex = tmp_dir + "classes.dex.new";
|
|
std::string second_output_dex = tmp_dir + "classes.dex.new.new";
|
|
|
|
// -v makes sure that the layout did not corrupt the dex file.
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
|
|
if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) {
|
|
return false;
|
|
}
|
|
|
|
// Recreate the profile with the new dex location. This is required so that the profile dex
|
|
// location matches.
|
|
CreateProfile(output_dex, profile_file);
|
|
// -v makes sure that the layout did not corrupt the dex file.
|
|
// -i since the checksum won't match from the first layout.
|
|
std::vector<std::string> second_dexlayout_args =
|
|
{ "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
|
|
if (!DexLayoutExec(second_dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) {
|
|
return false;
|
|
}
|
|
|
|
bool diff_result = true;
|
|
std::vector<std::string> diff_exec_argv =
|
|
{ "/usr/bin/diff", output_dex, second_output_dex };
|
|
if (!::art::Exec(diff_exec_argv, error_msg)) {
|
|
diff_result = false;
|
|
}
|
|
|
|
std::vector<std::string> test_files = { dex_file, profile_file, output_dex, second_output_dex };
|
|
for (const std::string& test_file : test_files) {
|
|
if (!UnlinkFile(test_file)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return diff_result;
|
|
}
|
|
|
|
// Runs UnreferencedCatchHandlerTest & Unreferenced0SizeCatchHandlerTest.
|
|
bool UnreferencedCatchHandlerExec(std::string* error_msg, const char* filename) {
|
|
ScratchFile tmp_file;
|
|
const std::string& tmp_name = tmp_file.GetFilename();
|
|
size_t tmp_last_slash = tmp_name.rfind('/');
|
|
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
|
|
|
|
// Write inputs and expected outputs.
|
|
std::string input_dex = tmp_dir + "classes.dex";
|
|
WriteFileBase64(filename, input_dex.c_str());
|
|
std::string output_dex = tmp_dir + "classes.dex.new";
|
|
|
|
std::vector<std::string> dexlayout_args = { "-w", tmp_dir, "-o", "/dev/null", input_dex };
|
|
if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) {
|
|
return false;
|
|
}
|
|
|
|
// Diff input and output. They should be the same.
|
|
std::vector<std::string> diff_exec_argv = { "/usr/bin/diff", input_dex, output_dex };
|
|
if (!::art::Exec(diff_exec_argv, error_msg)) {
|
|
return false;
|
|
}
|
|
|
|
std::vector<std::string> dex_files = { input_dex, output_dex };
|
|
for (const std::string& dex_file : dex_files) {
|
|
if (!UnlinkFile(dex_file)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool DexLayoutExec(ScratchFile* dex_file,
|
|
const char* dex_filename,
|
|
ScratchFile* profile_file,
|
|
const std::vector<std::string>& dexlayout_args) {
|
|
if (dex_filename != nullptr) {
|
|
WriteBase64ToFile(dex_filename, dex_file->GetFile());
|
|
EXPECT_EQ(dex_file->GetFile()->Flush(), 0);
|
|
}
|
|
if (profile_file != nullptr) {
|
|
CreateProfile(dex_file->GetFilename(), profile_file->GetFilename());
|
|
}
|
|
|
|
std::string error_msg;
|
|
const bool result = DexLayoutExec(dexlayout_args, &error_msg);
|
|
if (!result) {
|
|
LOG(ERROR) << "Error: " << error_msg;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool DexLayoutExec(const std::vector<std::string>& dexlayout_args,
|
|
std::string* error_msg,
|
|
bool pass_default_cdex_option = true) {
|
|
std::vector<std::string> argv;
|
|
|
|
std::string dexlayout = GetDexLayoutPath();
|
|
CHECK(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
|
|
argv.push_back(dexlayout);
|
|
if (pass_default_cdex_option) {
|
|
std::vector<std::string> cdex_level = DefaultCompactDexOption();
|
|
argv.insert(argv.end(), cdex_level.begin(), cdex_level.end());
|
|
}
|
|
|
|
argv.insert(argv.end(), dexlayout_args.begin(), dexlayout_args.end());
|
|
|
|
return ::art::Exec(argv, error_msg);
|
|
}
|
|
|
|
bool UnlinkFile(const std::string& file_path) {
|
|
return unix_file::FdFile(file_path, 0, false).Unlink();
|
|
}
|
|
};
|
|
|
|
|
|
TEST_F(DexLayoutTest, FullPlainOutput) {
|
|
// Disable test on target.
|
|
TEST_DISABLED_FOR_TARGET();
|
|
std::string error_msg;
|
|
ASSERT_TRUE(FullPlainOutputExec(&error_msg)) << error_msg;
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, DexFileOutput) {
|
|
// Disable test on target.
|
|
TEST_DISABLED_FOR_TARGET();
|
|
std::string error_msg;
|
|
ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg;
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, DexFileLayout) {
|
|
// Disable test on target.
|
|
TEST_DISABLED_FOR_TARGET();
|
|
std::string error_msg;
|
|
ASSERT_TRUE(DexFileLayoutExec(&error_msg)) << error_msg;
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, DexFileLayoutFixedPoint) {
|
|
// Disable test on target.
|
|
TEST_DISABLED_FOR_TARGET();
|
|
std::string error_msg;
|
|
ASSERT_TRUE(DexFileLayoutFixedPointExec(&error_msg)) << error_msg;
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, UnreferencedCatchHandler) {
|
|
// Disable test on target.
|
|
TEST_DISABLED_FOR_TARGET();
|
|
std::string error_msg;
|
|
ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg,
|
|
kUnreferencedCatchHandlerInputDex)) << error_msg;
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, Unreferenced0SizeCatchHandler) {
|
|
// Disable test on target.
|
|
TEST_DISABLED_FOR_TARGET();
|
|
std::string error_msg;
|
|
ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg,
|
|
kUnreferenced0SizeCatchHandlerInputDex)) << error_msg;
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, UnreferencedEndingCatchHandler) {
|
|
// Disable test on target.
|
|
TEST_DISABLED_FOR_TARGET();
|
|
std::string error_msg;
|
|
ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg,
|
|
kUnreferencedEndingCatchHandlerInputDex)) << error_msg;
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, DuplicateOffset) {
|
|
ScratchFile temp_dex;
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-a", "-i", "-o", "/dev/null", temp_dex.GetFilename() };
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
kDexFileDuplicateOffset,
|
|
/* profile_file= */ nullptr,
|
|
dexlayout_args));
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, NullSetRefListElement) {
|
|
ScratchFile temp_dex;
|
|
std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
kNullSetRefListElementInputDex,
|
|
/* profile_file= */ nullptr,
|
|
dexlayout_args));
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, MultiClassData) {
|
|
ScratchFile temp_dex;
|
|
ScratchFile temp_profile;
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
kMultiClassDataInputDex,
|
|
&temp_profile,
|
|
dexlayout_args));
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, UnalignedCodeInfo) {
|
|
ScratchFile temp_dex;
|
|
ScratchFile temp_profile;
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
kUnalignedCodeInfoInputDex,
|
|
&temp_profile,
|
|
dexlayout_args));
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, ClassDataBeforeCode) {
|
|
ScratchFile temp_dex;
|
|
ScratchFile temp_profile;
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
kClassDataBeforeCodeInputDex,
|
|
&temp_profile,
|
|
dexlayout_args));
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, UnknownTypeDebugInfo) {
|
|
ScratchFile temp_dex;
|
|
std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
kUnknownTypeDebugInfoInputDex,
|
|
/* profile_file= */ nullptr,
|
|
dexlayout_args));
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, DuplicateCodeItem) {
|
|
ScratchFile temp_dex;
|
|
std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() };
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
kDuplicateCodeItemInputDex,
|
|
/* profile_file= */ nullptr,
|
|
dexlayout_args));
|
|
}
|
|
|
|
// Test that instructions that go past the end of the code items don't cause crashes.
|
|
TEST_F(DexLayoutTest, CodeItemOverrun) {
|
|
ScratchFile temp_dex;
|
|
MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("ManyMethods"), [] (DexFile* dex) {
|
|
bool mutated_successfully = false;
|
|
// Change the dex instructions to make an opcode that spans past the end of the code item.
|
|
for (ClassAccessor accessor : dex->GetClasses()) {
|
|
for (const ClassAccessor::Method& method : accessor.GetMethods()) {
|
|
dex::CodeItem* item = const_cast<dex::CodeItem*>(method.GetCodeItem());
|
|
if (item != nullptr) {
|
|
CodeItemInstructionAccessor instructions(*dex, item);
|
|
if (instructions.begin() != instructions.end()) {
|
|
DexInstructionIterator last_instruction = instructions.begin();
|
|
for (auto dex_it = instructions.begin(); dex_it != instructions.end(); ++dex_it) {
|
|
last_instruction = dex_it;
|
|
}
|
|
if (last_instruction->SizeInCodeUnits() == 1) {
|
|
// Set the opcode to something that will go past the end of the code item.
|
|
const_cast<Instruction&>(last_instruction.Inst()).SetOpcode(
|
|
Instruction::CONST_STRING_JUMBO);
|
|
mutated_successfully = true;
|
|
// Test that the safe iterator doesn't go past the end.
|
|
SafeDexInstructionIterator it2(instructions.begin(), instructions.end());
|
|
while (!it2.IsErrorState()) {
|
|
++it2;
|
|
}
|
|
EXPECT_TRUE(it2 == last_instruction);
|
|
EXPECT_TRUE(it2 < instructions.end());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
CHECK(mutated_successfully)
|
|
<< "Failed to find candidate code item with only one code unit in last instruction.";
|
|
});
|
|
|
|
std::string error_msg;
|
|
|
|
ScratchFile tmp_file;
|
|
const std::string& tmp_name = tmp_file.GetFilename();
|
|
size_t tmp_last_slash = tmp_name.rfind('/');
|
|
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
|
|
ScratchFile profile_file;
|
|
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-i",
|
|
"-v",
|
|
"-w", tmp_dir,
|
|
"-o", tmp_name,
|
|
"-p", profile_file.GetFilename(),
|
|
temp_dex.GetFilename()
|
|
};
|
|
// -v makes sure that the layout did not corrupt the dex file.
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
/*dex_filename=*/ nullptr,
|
|
&profile_file,
|
|
dexlayout_args));
|
|
ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new"));
|
|
}
|
|
|
|
// Test that link data is written out (or at least the header is updated).
|
|
TEST_F(DexLayoutTest, LinkData) {
|
|
TEST_DISABLED_FOR_TARGET();
|
|
ScratchFile temp_dex;
|
|
size_t file_size = 0;
|
|
MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("ManyMethods"), [&] (DexFile* dex) {
|
|
DexFile::Header& header = const_cast<DexFile::Header&>(dex->GetHeader());
|
|
header.link_off_ = header.file_size_;
|
|
header.link_size_ = 16 * KB;
|
|
header.file_size_ += header.link_size_;
|
|
file_size = header.file_size_;
|
|
});
|
|
TEMP_FAILURE_RETRY(temp_dex.GetFile()->SetLength(file_size));
|
|
|
|
std::string error_msg;
|
|
|
|
ScratchFile tmp_file;
|
|
const std::string& tmp_name = tmp_file.GetFilename();
|
|
size_t tmp_last_slash = tmp_name.rfind('/');
|
|
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
|
|
ScratchFile profile_file;
|
|
|
|
std::vector<std::string> dexlayout_args =
|
|
{ "-i",
|
|
"-v",
|
|
"-w", tmp_dir,
|
|
"-o", tmp_name,
|
|
"-p", profile_file.GetFilename(),
|
|
temp_dex.GetFilename()
|
|
};
|
|
// -v makes sure that the layout did not corrupt the dex file.
|
|
ASSERT_TRUE(DexLayoutExec(&temp_dex,
|
|
/*dex_filename=*/ nullptr,
|
|
&profile_file,
|
|
dexlayout_args));
|
|
ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new"));
|
|
}
|
|
|
|
TEST_F(DexLayoutTest, ClassFilter) {
|
|
std::vector<std::unique_ptr<const DexFile>> dex_files;
|
|
std::string error_msg;
|
|
const ArtDexFileLoader dex_file_loader;
|
|
const std::string input_jar = GetTestDexFileName("ManyMethods");
|
|
CHECK(dex_file_loader.Open(input_jar.c_str(),
|
|
input_jar.c_str(),
|
|
/*verify=*/ true,
|
|
/*verify_checksum=*/ true,
|
|
&error_msg,
|
|
&dex_files)) << error_msg;
|
|
ASSERT_EQ(dex_files.size(), 1u);
|
|
for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
|
|
EXPECT_GT(dex_file->NumClassDefs(), 1u);
|
|
for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
|
|
const dex::ClassDef& class_def = dex_file->GetClassDef(i);
|
|
LOG(INFO) << dex_file->GetClassDescriptor(class_def);
|
|
}
|
|
Options options;
|
|
// Filter out all the classes other than the one below based on class descriptor.
|
|
options.class_filter_.insert("LManyMethods$Strings;");
|
|
DexLayout dexlayout(options,
|
|
/*info=*/ nullptr,
|
|
/*out_file=*/ nullptr,
|
|
/*header=*/ nullptr);
|
|
std::unique_ptr<DexContainer> out;
|
|
bool result = dexlayout.ProcessDexFile(
|
|
dex_file->GetLocation().c_str(),
|
|
dex_file.get(),
|
|
/*dex_file_index=*/ 0,
|
|
&out,
|
|
&error_msg);
|
|
ASSERT_TRUE(result) << "Failed to run dexlayout " << error_msg;
|
|
std::unique_ptr<const DexFile> output_dex_file(
|
|
dex_file_loader.OpenWithDataSection(
|
|
out->GetMainSection()->Begin(),
|
|
out->GetMainSection()->Size(),
|
|
out->GetDataSection()->Begin(),
|
|
out->GetDataSection()->Size(),
|
|
dex_file->GetLocation().c_str(),
|
|
/* location_checksum= */ 0,
|
|
/*oat_dex_file=*/ nullptr,
|
|
/* verify= */ true,
|
|
/*verify_checksum=*/ false,
|
|
&error_msg));
|
|
ASSERT_TRUE(output_dex_file != nullptr);
|
|
|
|
ASSERT_EQ(output_dex_file->NumClassDefs(), options.class_filter_.size());
|
|
for (uint32_t i = 0; i < output_dex_file->NumClassDefs(); ++i) {
|
|
// Check that every class in the output dex file is in the filter.
|
|
const dex::ClassDef& class_def = output_dex_file->GetClassDef(i);
|
|
ASSERT_TRUE(options.class_filter_.find(output_dex_file->GetClassDescriptor(class_def)) !=
|
|
options.class_filter_.end());
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace art
|