1 /*
2 * Copyright (C) 2018 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
17 #include <stdint.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20
21 #include <unordered_map>
22
23 #include <android-base/test_utils.h>
24
25 #include <unwindstack/MapInfo.h>
26 #include <unwindstack/Memory.h>
27
28 #include <dex/code_item_accessors-inl.h>
29 #include <dex/standard_dex_file.h>
30
31 #include <gtest/gtest.h>
32
33 #include "DexFile.h"
34
35 #include "DexFileData.h"
36 #include "MemoryFake.h"
37
38 namespace unwindstack {
39
TEST(DexFileTest,from_file_open_non_exist)40 TEST(DexFileTest, from_file_open_non_exist) {
41 DexFileFromFile dex_file;
42 ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
43 }
44
TEST(DexFileTest,from_file_open_too_small)45 TEST(DexFileTest, from_file_open_too_small) {
46 TemporaryFile tf;
47 ASSERT_TRUE(tf.fd != -1);
48
49 ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
50 static_cast<size_t>(
51 TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
52
53 // Header too small.
54 DexFileFromFile dex_file;
55 ASSERT_FALSE(dex_file.Open(0, tf.path));
56
57 // Header correct, file too small.
58 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
59 ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
60 tf.fd, kDexData, sizeof(art::DexFile::Header)))));
61 ASSERT_FALSE(dex_file.Open(0, tf.path));
62 }
63
TEST(DexFileTest,from_file_open)64 TEST(DexFileTest, from_file_open) {
65 TemporaryFile tf;
66 ASSERT_TRUE(tf.fd != -1);
67
68 ASSERT_EQ(sizeof(kDexData),
69 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
70
71 DexFileFromFile dex_file;
72 ASSERT_TRUE(dex_file.Open(0, tf.path));
73 }
74
TEST(DexFileTest,from_file_open_non_zero_offset)75 TEST(DexFileTest, from_file_open_non_zero_offset) {
76 TemporaryFile tf;
77 ASSERT_TRUE(tf.fd != -1);
78
79 ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
80 ASSERT_EQ(sizeof(kDexData),
81 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
82
83 DexFileFromFile dex_file;
84 ASSERT_TRUE(dex_file.Open(0x100, tf.path));
85 }
86
TEST(DexFileTest,from_memory_fail_too_small_for_header)87 TEST(DexFileTest, from_memory_fail_too_small_for_header) {
88 MemoryFake memory;
89
90 memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
91 DexFileFromMemory dex_file;
92
93 ASSERT_FALSE(dex_file.Open(0x1000, &memory));
94 }
95
TEST(DexFileTest,from_memory_fail_too_small_for_data)96 TEST(DexFileTest, from_memory_fail_too_small_for_data) {
97 MemoryFake memory;
98
99 memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
100 DexFileFromMemory dex_file;
101
102 ASSERT_FALSE(dex_file.Open(0x1000, &memory));
103 }
104
TEST(DexFileTest,from_memory_open)105 TEST(DexFileTest, from_memory_open) {
106 MemoryFake memory;
107
108 memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
109 DexFileFromMemory dex_file;
110
111 ASSERT_TRUE(dex_file.Open(0x1000, &memory));
112 }
113
TEST(DexFileTest,create_using_file)114 TEST(DexFileTest, create_using_file) {
115 TemporaryFile tf;
116 ASSERT_TRUE(tf.fd != -1);
117
118 ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
119 ASSERT_EQ(sizeof(kDexData),
120 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
121
122 MemoryFake memory;
123 MapInfo info(0, 0x10000, 0, 0x5, tf.path);
124 std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
125 ASSERT_TRUE(dex_file != nullptr);
126 }
127
TEST(DexFileTest,create_using_file_non_zero_start)128 TEST(DexFileTest, create_using_file_non_zero_start) {
129 TemporaryFile tf;
130 ASSERT_TRUE(tf.fd != -1);
131
132 ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
133 ASSERT_EQ(sizeof(kDexData),
134 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
135
136 MemoryFake memory;
137 MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
138 std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
139 ASSERT_TRUE(dex_file != nullptr);
140 }
141
TEST(DexFileTest,create_using_file_non_zero_offset)142 TEST(DexFileTest, create_using_file_non_zero_offset) {
143 TemporaryFile tf;
144 ASSERT_TRUE(tf.fd != -1);
145
146 ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
147 ASSERT_EQ(sizeof(kDexData),
148 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
149
150 MemoryFake memory;
151 MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
152 std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
153 ASSERT_TRUE(dex_file != nullptr);
154 }
155
TEST(DexFileTest,create_using_memory_empty_file)156 TEST(DexFileTest, create_using_memory_empty_file) {
157 MemoryFake memory;
158 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
159 MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
160 std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
161 ASSERT_TRUE(dex_file != nullptr);
162 }
163
TEST(DexFileTest,create_using_memory_file_does_not_exist)164 TEST(DexFileTest, create_using_memory_file_does_not_exist) {
165 MemoryFake memory;
166 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
167 MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
168 std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
169 ASSERT_TRUE(dex_file != nullptr);
170 }
171
TEST(DexFileTest,create_using_memory_file_is_malformed)172 TEST(DexFileTest, create_using_memory_file_is_malformed) {
173 TemporaryFile tf;
174 ASSERT_TRUE(tf.fd != -1);
175
176 ASSERT_EQ(sizeof(kDexData) - 10,
177 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
178
179 MemoryFake memory;
180 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
181 MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
182 std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
183 ASSERT_TRUE(dex_file != nullptr);
184
185 // Check it came from memory by clearing memory and verifying it fails.
186 memory.Clear();
187 dex_file.reset(DexFile::Create(0x4000, &memory, &info));
188 ASSERT_TRUE(dex_file == nullptr);
189 }
190
TEST(DexFileTest,get_method_not_opened)191 TEST(DexFileTest, get_method_not_opened) {
192 std::string method("something");
193 uint64_t method_offset = 100;
194 DexFile dex_file;
195 dex_file.GetMethodInformation(0x100, &method, &method_offset);
196 EXPECT_EQ("something", method);
197 EXPECT_EQ(100U, method_offset);
198 }
199
TEST(DexFileTest,get_method)200 TEST(DexFileTest, get_method) {
201 MemoryFake memory;
202 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
203 MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
204 std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
205 ASSERT_TRUE(dex_file != nullptr);
206
207 std::string method;
208 uint64_t method_offset;
209 dex_file->GetMethodInformation(0x102, &method, &method_offset);
210 EXPECT_EQ("Main.<init>", method);
211 EXPECT_EQ(2U, method_offset);
212
213 method = "not_in_a_method";
214 method_offset = 0x123;
215 dex_file->GetMethodInformation(0x100000, &method, &method_offset);
216 EXPECT_EQ("not_in_a_method", method);
217 EXPECT_EQ(0x123U, method_offset);
218 }
219
220 } // namespace unwindstack
221