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