1 /*
2 * Copyright (C) 2015 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 "read_elf.h"
18
19 #include <gtest/gtest.h>
20
21 #include <map>
22
23 #include <android-base/file.h>
24
25 #include "get_test_data.h"
26 #include "read_apk.h"
27 #include "test_util.h"
28 #include "utils.h"
29
30 #define ELF_NOTE_GNU "GNU"
31 #define NT_GNU_BUILD_ID 3
32
33 using namespace simpleperf;
34
35 // @CddTest = 6.1/C-0-2
TEST(read_elf,GetBuildIdFromNoteSection)36 TEST(read_elf, GetBuildIdFromNoteSection) {
37 BuildId build_id;
38 std::vector<char> data;
39 // Fail to read build id for no data.
40 ASSERT_FALSE(GetBuildIdFromNoteSection(data.data(), 0, &build_id));
41
42 // Read build id from data starting from different alignment addresses.
43 char build_id_data[20];
44 for (int i = 0; i < 20; ++i) {
45 build_id_data[i] = i;
46 }
47 BuildId expected_build_id(build_id_data, 20);
48 data.resize(100, '\0');
49
50 for (size_t alignment = 0; alignment <= 3; ++alignment) {
51 char* start = data.data() + alignment;
52 char* p = start;
53 uint32_t type = NT_GNU_BUILD_ID;
54 uint32_t namesz = 4;
55 uint32_t descsz = 20;
56 MoveToBinaryFormat(namesz, p);
57 MoveToBinaryFormat(descsz, p);
58 MoveToBinaryFormat(type, p);
59 MoveToBinaryFormat(ELF_NOTE_GNU, 4, p);
60 MoveToBinaryFormat(build_id_data, 20, p);
61 ASSERT_TRUE(GetBuildIdFromNoteSection(start, p - start, &build_id));
62 ASSERT_TRUE(build_id == expected_build_id);
63 }
64 }
65
66 // @CddTest = 6.1/C-0-2
TEST(read_elf,GetBuildIdFromElfFile)67 TEST(read_elf, GetBuildIdFromElfFile) {
68 BuildId build_id;
69 ElfStatus status;
70 auto elf = ElfFile::Open(GetTestData(ELF_FILE), &status);
71 ASSERT_EQ(status, ElfStatus::NO_ERROR);
72 ASSERT_EQ(ElfStatus::NO_ERROR, elf->GetBuildId(&build_id));
73 ASSERT_EQ(build_id, BuildId(elf_file_build_id));
74 }
75
76 // @CddTest = 6.1/C-0-2
TEST(read_elf,GetBuildIdFromEmbeddedElfFile)77 TEST(read_elf, GetBuildIdFromEmbeddedElfFile) {
78 BuildId build_id;
79 ElfStatus status;
80 std::string path = GetUrlInApk(APK_FILE, NATIVELIB_IN_APK);
81 auto elf = ElfFile::Open(GetTestData(path), &status);
82 ASSERT_EQ(status, ElfStatus::NO_ERROR);
83 ASSERT_EQ(ElfStatus::NO_ERROR, elf->GetBuildId(&build_id));
84 ASSERT_EQ(build_id, native_lib_build_id);
85 }
86
ParseSymbol(const ElfFileSymbol & symbol,std::map<std::string,ElfFileSymbol> * symbols)87 void ParseSymbol(const ElfFileSymbol& symbol, std::map<std::string, ElfFileSymbol>* symbols) {
88 (*symbols)[symbol.name] = symbol;
89 }
90
CheckGlobalVariableSymbols(const std::map<std::string,ElfFileSymbol> & symbols)91 static void CheckGlobalVariableSymbols(const std::map<std::string, ElfFileSymbol>& symbols) {
92 auto pos = symbols.find("GlobalVar");
93 ASSERT_NE(pos, symbols.end());
94 ASSERT_FALSE(pos->second.is_func);
95 }
96
CheckFunctionSymbols(const std::map<std::string,ElfFileSymbol> & symbols)97 static void CheckFunctionSymbols(const std::map<std::string, ElfFileSymbol>& symbols) {
98 auto pos = symbols.find("GlobalFunc");
99 ASSERT_NE(pos, symbols.end());
100 ASSERT_TRUE(pos->second.is_func);
101 ASSERT_TRUE(pos->second.is_in_text_section);
102 }
103
CheckElfFileSymbols(const std::map<std::string,ElfFileSymbol> & symbols)104 void CheckElfFileSymbols(const std::map<std::string, ElfFileSymbol>& symbols) {
105 CheckGlobalVariableSymbols(symbols);
106 CheckFunctionSymbols(symbols);
107 }
108
109 // @CddTest = 6.1/C-0-2
TEST(read_elf,parse_symbols_from_elf_file_with_correct_build_id)110 TEST(read_elf, parse_symbols_from_elf_file_with_correct_build_id) {
111 std::map<std::string, ElfFileSymbol> symbols;
112 ElfStatus status;
113 auto elf = ElfFile::Open(GetTestData(ELF_FILE), &elf_file_build_id, &status);
114 ASSERT_EQ(ElfStatus::NO_ERROR, status);
115 ASSERT_EQ(ElfStatus::NO_ERROR,
116 elf->ParseSymbols(std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
117 CheckElfFileSymbols(symbols);
118 }
119
120 // @CddTest = 6.1/C-0-2
TEST(read_elf,parse_symbols_from_elf_file_without_build_id)121 TEST(read_elf, parse_symbols_from_elf_file_without_build_id) {
122 std::map<std::string, ElfFileSymbol> symbols;
123 ElfStatus status;
124 // Test no build_id.
125 auto elf = ElfFile::Open(GetTestData(ELF_FILE), &status);
126 ASSERT_EQ(ElfStatus::NO_ERROR, status);
127 ASSERT_EQ(ElfStatus::NO_ERROR,
128 elf->ParseSymbols(std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
129 CheckElfFileSymbols(symbols);
130
131 // Test empty build id.
132 symbols.clear();
133 BuildId build_id;
134 elf = ElfFile::Open(GetTestData(ELF_FILE), &build_id, &status);
135 ASSERT_EQ(ElfStatus::NO_ERROR, status);
136 ASSERT_EQ(ElfStatus::NO_ERROR,
137 elf->ParseSymbols(std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
138 CheckElfFileSymbols(symbols);
139 }
140
141 // @CddTest = 6.1/C-0-2
TEST(read_elf,parse_symbols_from_elf_file_with_wrong_build_id)142 TEST(read_elf, parse_symbols_from_elf_file_with_wrong_build_id) {
143 BuildId build_id("01010101010101010101");
144 std::map<std::string, ElfFileSymbol> symbols;
145 ElfStatus status;
146 auto elf = ElfFile::Open(GetTestData(ELF_FILE), &build_id, &status);
147 ASSERT_EQ(ElfStatus::BUILD_ID_MISMATCH, status);
148 }
149
150 // @CddTest = 6.1/C-0-2
TEST(read_elf,ParseSymbolsFromEmbeddedElfFile)151 TEST(read_elf, ParseSymbolsFromEmbeddedElfFile) {
152 std::map<std::string, ElfFileSymbol> symbols;
153 ElfStatus status;
154 std::string path = GetUrlInApk(APK_FILE, NATIVELIB_IN_APK);
155 auto elf = ElfFile::Open(GetTestData(path), &native_lib_build_id, &status);
156 ASSERT_EQ(status, ElfStatus::NO_ERROR);
157 ASSERT_EQ(ElfStatus::NO_SYMBOL_TABLE,
158 elf->ParseSymbols(std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
159 CheckElfFileSymbols(symbols);
160 }
161
162 // @CddTest = 6.1/C-0-2
TEST(read_elf,ParseSymbolFromMiniDebugInfoElfFile)163 TEST(read_elf, ParseSymbolFromMiniDebugInfoElfFile) {
164 std::map<std::string, ElfFileSymbol> symbols;
165 ElfStatus status;
166 auto elf = ElfFile::Open(GetTestData(ELF_FILE_WITH_MINI_DEBUG_INFO), &status);
167 ASSERT_EQ(ElfStatus::NO_ERROR, status);
168 ASSERT_EQ(ElfStatus::NO_ERROR,
169 elf->ParseSymbols(std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
170 CheckFunctionSymbols(symbols);
171 }
172
173 // @CddTest = 6.1/C-0-2
TEST(read_elf,arm_mapping_symbol)174 TEST(read_elf, arm_mapping_symbol) {
175 ASSERT_TRUE(IsArmMappingSymbol("$a"));
176 ASSERT_FALSE(IsArmMappingSymbol("$b"));
177 ASSERT_TRUE(IsArmMappingSymbol("$a.anything"));
178 ASSERT_FALSE(IsArmMappingSymbol("$a_no_dot"));
179 }
180
181 // @CddTest = 6.1/C-0-2
TEST(read_elf,ElfFile_Open)182 TEST(read_elf, ElfFile_Open) {
183 auto IsValidElfPath = [](const std::string& path) {
184 ElfStatus status;
185 ElfFile::Open(path, &status);
186 return status;
187 };
188 ASSERT_NE(ElfStatus::NO_ERROR, IsValidElfPath("/dev/zero"));
189 TemporaryFile tmp_file;
190 ASSERT_EQ(ElfStatus::READ_FAILED, IsValidElfPath(tmp_file.path));
191 ASSERT_TRUE(android::base::WriteStringToFile("wrong format for elf", tmp_file.path));
192 ASSERT_EQ(ElfStatus::FILE_MALFORMED, IsValidElfPath(tmp_file.path));
193 ASSERT_EQ(ElfStatus::NO_ERROR, IsValidElfPath(GetTestData(ELF_FILE)));
194 }
195
196 // @CddTest = 6.1/C-0-2
TEST(read_elf,check_symbol_for_plt_section)197 TEST(read_elf, check_symbol_for_plt_section) {
198 std::map<std::string, ElfFileSymbol> symbols;
199 ElfStatus status;
200 auto elf = ElfFile::Open(GetTestData(ELF_FILE), &status);
201 ASSERT_EQ(ElfStatus::NO_ERROR, status);
202 ASSERT_EQ(ElfStatus::NO_ERROR,
203 elf->ParseSymbols(std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
204 ASSERT_NE(symbols.find("@plt"), symbols.end());
205 }
206
207 // @CddTest = 6.1/C-0-2
TEST(read_elf,read_elf_with_broken_section_table)208 TEST(read_elf, read_elf_with_broken_section_table) {
209 std::string elf_path = GetTestData("libsgmainso-6.4.36.so");
210 std::map<std::string, ElfFileSymbol> symbols;
211 ElfStatus status;
212 auto elf = ElfFile::Open(elf_path, &status);
213 ASSERT_EQ(ElfStatus::NO_ERROR, status);
214 ASSERT_EQ(ElfStatus::NO_SYMBOL_TABLE,
215 elf->ParseSymbols(std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
216
217 BuildId build_id;
218 ASSERT_EQ(ElfStatus::NO_BUILD_ID, elf->GetBuildId(&build_id));
219
220 uint64_t file_offset_of_min_vaddr;
221 uint64_t min_vaddr = elf->ReadMinExecutableVaddr(&file_offset_of_min_vaddr);
222 ASSERT_EQ(min_vaddr, 0u);
223 ASSERT_EQ(file_offset_of_min_vaddr, 0u);
224 }
225
226 // @CddTest = 6.1/C-0-2
TEST(read_elf,ReadMinExecutableVaddr)227 TEST(read_elf, ReadMinExecutableVaddr) {
228 ElfStatus status;
229 auto elf = ElfFile::Open(GetTestData("libc.so"), &status);
230 ASSERT_EQ(status, ElfStatus::NO_ERROR);
231 uint64_t file_offset_of_min_vaddr;
232 uint64_t min_vaddr = elf->ReadMinExecutableVaddr(&file_offset_of_min_vaddr);
233 ASSERT_EQ(min_vaddr, 0x29000u);
234 ASSERT_EQ(file_offset_of_min_vaddr, 0x29000u);
235 }
236
237 // @CddTest = 6.1/C-0-2
TEST(read_elf,NoUndefinedSymbol)238 TEST(read_elf, NoUndefinedSymbol) {
239 // Check if we read undefined symbols (like dlerror) from libc.so.
240 bool has_dlerror = false;
241 auto parse_symbol = [&](const ElfFileSymbol& symbol) {
242 if (symbol.name == "dlerror") {
243 has_dlerror = true;
244 }
245 };
246
247 ElfStatus status;
248 auto elf = ElfFile::Open(GetTestData("libc.so"), &status);
249 ASSERT_EQ(status, ElfStatus::NO_ERROR);
250 ASSERT_EQ(ElfStatus::NO_ERROR, elf->ParseSymbols(parse_symbol));
251 ASSERT_FALSE(has_dlerror);
252 }
253
254 // @CddTest = 6.1/C-0-2
TEST(read_elf,VaddrToOff)255 TEST(read_elf, VaddrToOff) {
256 auto elf = ElfFile::Open(GetTestData(ELF_FILE));
257 ASSERT_TRUE(elf != nullptr);
258 uint64_t off;
259 ASSERT_TRUE(elf->VaddrToOff(0x400200, &off));
260 ASSERT_EQ(off, 0x200);
261 ASSERT_FALSE(elf->VaddrToOff(0x300200, &off));
262 ASSERT_FALSE(elf->VaddrToOff(0x420000, &off));
263 }
264
265 // @CddTest = 6.1/C-0-2
TEST(read_elf,GetSectionHeader)266 TEST(read_elf, GetSectionHeader) {
267 auto elf = ElfFile::Open(GetTestData(ELF_FILE));
268 ASSERT_TRUE(elf != nullptr);
269 std::vector<ElfSection> sections = elf->GetSectionHeader();
270 ASSERT_EQ(sections.size(), 30);
271 ASSERT_EQ(sections[13].name, ".text");
272 ASSERT_EQ(sections[13].vaddr, 0x400400);
273 ASSERT_EQ(sections[13].file_offset, 0x400);
274 ASSERT_EQ(sections[13].size, 0x1b2);
275 }
276