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