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 "test_util.h" 27 #include "utils.h" 28 29 #define ELF_NOTE_GNU "GNU" 30 #define NT_GNU_BUILD_ID 3 31 32 using namespace simpleperf; 33 34 TEST(read_elf, GetBuildIdFromNoteSection) { 35 BuildId build_id; 36 std::vector<char> data; 37 // Fail to read build id for no data. 38 ASSERT_FALSE(GetBuildIdFromNoteSection(data.data(), 0, &build_id)); 39 40 // Read build id from data starting from different alignment addresses. 41 char build_id_data[20]; 42 for (int i = 0; i < 20; ++i) { 43 build_id_data[i] = i; 44 } 45 BuildId expected_build_id(build_id_data, 20); 46 data.resize(100, '\0'); 47 48 for (size_t alignment = 0; alignment <= 3; ++alignment) { 49 char* start = data.data() + alignment; 50 char* p = start; 51 uint32_t type = NT_GNU_BUILD_ID; 52 uint32_t namesz = 4; 53 uint32_t descsz = 20; 54 MoveToBinaryFormat(namesz, p); 55 MoveToBinaryFormat(descsz, p); 56 MoveToBinaryFormat(type, p); 57 MoveToBinaryFormat(ELF_NOTE_GNU, 4, p); 58 MoveToBinaryFormat(build_id_data, 20, p); 59 ASSERT_TRUE(GetBuildIdFromNoteSection(start, p - start, &build_id)); 60 ASSERT_TRUE(build_id == expected_build_id); 61 } 62 } 63 64 TEST(read_elf, GetBuildIdFromElfFile) { 65 BuildId build_id; 66 ASSERT_EQ(ElfStatus::NO_ERROR, GetBuildIdFromElfFile(GetTestData(ELF_FILE), &build_id)); 67 ASSERT_EQ(build_id, BuildId(elf_file_build_id)); 68 } 69 70 TEST(read_elf, GetBuildIdFromEmbeddedElfFile) { 71 BuildId build_id; 72 ASSERT_EQ(ElfStatus::NO_ERROR, GetBuildIdFromEmbeddedElfFile(GetTestData(APK_FILE), NATIVELIB_OFFSET_IN_APK, 73 NATIVELIB_SIZE_IN_APK, &build_id)); 74 ASSERT_EQ(build_id, native_lib_build_id); 75 } 76 77 void ParseSymbol(const ElfFileSymbol& symbol, std::map<std::string, ElfFileSymbol>* symbols) { 78 (*symbols)[symbol.name] = symbol; 79 } 80 81 static void CheckGlobalVariableSymbols(const std::map<std::string, ElfFileSymbol>& symbols) { 82 auto pos = symbols.find("GlobalVar"); 83 ASSERT_NE(pos, symbols.end()); 84 ASSERT_FALSE(pos->second.is_func); 85 } 86 87 static void CheckFunctionSymbols(const std::map<std::string, ElfFileSymbol>& symbols) { 88 auto pos = symbols.find("GlobalFunc"); 89 ASSERT_NE(pos, symbols.end()); 90 ASSERT_TRUE(pos->second.is_func); 91 ASSERT_TRUE(pos->second.is_in_text_section); 92 } 93 94 void CheckElfFileSymbols(const std::map<std::string, ElfFileSymbol>& symbols) { 95 CheckGlobalVariableSymbols(symbols); 96 CheckFunctionSymbols(symbols); 97 } 98 99 TEST(read_elf, parse_symbols_from_elf_file_with_correct_build_id) { 100 std::map<std::string, ElfFileSymbol> symbols; 101 ASSERT_EQ(ElfStatus::NO_ERROR, ParseSymbolsFromElfFile(GetTestData(ELF_FILE), elf_file_build_id, 102 std::bind(ParseSymbol, std::placeholders::_1, &symbols))); 103 CheckElfFileSymbols(symbols); 104 } 105 106 TEST(read_elf, parse_symbols_from_elf_file_without_build_id) { 107 std::map<std::string, ElfFileSymbol> symbols; 108 ASSERT_EQ(ElfStatus::NO_ERROR, ParseSymbolsFromElfFile(GetTestData(ELF_FILE), BuildId(), 109 std::bind(ParseSymbol, std::placeholders::_1, &symbols))); 110 CheckElfFileSymbols(symbols); 111 } 112 113 TEST(read_elf, parse_symbols_from_elf_file_with_wrong_build_id) { 114 BuildId build_id("01010101010101010101"); 115 std::map<std::string, ElfFileSymbol> symbols; 116 ASSERT_EQ(ElfStatus::BUILD_ID_MISMATCH, ParseSymbolsFromElfFile(GetTestData(ELF_FILE), build_id, 117 std::bind(ParseSymbol, std::placeholders::_1, &symbols))); 118 } 119 120 TEST(read_elf, ParseSymbolsFromEmbeddedElfFile) { 121 std::map<std::string, ElfFileSymbol> symbols; 122 ASSERT_EQ(ElfStatus::NO_SYMBOL_TABLE, ParseSymbolsFromEmbeddedElfFile(GetTestData(APK_FILE), NATIVELIB_OFFSET_IN_APK, 123 NATIVELIB_SIZE_IN_APK, native_lib_build_id, 124 std::bind(ParseSymbol, std::placeholders::_1, &symbols))); 125 CheckElfFileSymbols(symbols); 126 } 127 128 TEST(read_elf, ParseSymbolFromMiniDebugInfoElfFile) { 129 std::map<std::string, ElfFileSymbol> symbols; 130 ASSERT_EQ(ElfStatus::NO_ERROR, ParseSymbolsFromElfFile(GetTestData(ELF_FILE_WITH_MINI_DEBUG_INFO), BuildId(), 131 std::bind(ParseSymbol, std::placeholders::_1, &symbols))); 132 CheckFunctionSymbols(symbols); 133 } 134 135 TEST(read_elf, arm_mapping_symbol) { 136 ASSERT_TRUE(IsArmMappingSymbol("$a")); 137 ASSERT_FALSE(IsArmMappingSymbol("$b")); 138 ASSERT_TRUE(IsArmMappingSymbol("$a.anything")); 139 ASSERT_FALSE(IsArmMappingSymbol("$a_no_dot")); 140 } 141 142 TEST(read_elf, ElfFile_Open) { 143 auto IsValidElfPath = [](const std::string& path) { 144 ElfStatus status; 145 ElfFile::Open(path, &status); 146 return status; 147 }; 148 ASSERT_NE(ElfStatus::NO_ERROR, IsValidElfPath("/dev/zero")); 149 TemporaryFile tmp_file; 150 ASSERT_EQ(ElfStatus::READ_FAILED, IsValidElfPath(tmp_file.path)); 151 ASSERT_TRUE(android::base::WriteStringToFile("wrong format for elf", tmp_file.path)); 152 ASSERT_EQ(ElfStatus::FILE_MALFORMED, IsValidElfPath(tmp_file.path)); 153 ASSERT_EQ(ElfStatus::NO_ERROR, IsValidElfPath(GetTestData(ELF_FILE))); 154 } 155 156 TEST(read_elf, check_symbol_for_plt_section) { 157 std::map<std::string, ElfFileSymbol> symbols; 158 ASSERT_EQ(ElfStatus::NO_ERROR, ParseSymbolsFromElfFile(GetTestData(ELF_FILE), BuildId(), 159 std::bind(ParseSymbol, std::placeholders::_1, &symbols))); 160 ASSERT_NE(symbols.find("@plt"), symbols.end()); 161 } 162 163 TEST(read_elf, read_elf_with_broken_section_table) { 164 std::string elf_path = GetTestData("libsgmainso-6.4.36.so"); 165 std::map<std::string, ElfFileSymbol> symbols; 166 ASSERT_EQ(ElfStatus::NO_SYMBOL_TABLE, 167 ParseSymbolsFromElfFile(elf_path, BuildId(), 168 std::bind(ParseSymbol, std::placeholders::_1, &symbols))); 169 BuildId build_id; 170 ASSERT_EQ(ElfStatus::NO_BUILD_ID, GetBuildIdFromElfFile(elf_path, &build_id)); 171 uint64_t min_vaddr; 172 uint64_t file_offset_of_min_vaddr; 173 ASSERT_EQ(ElfStatus::NO_ERROR, ReadMinExecutableVirtualAddressFromElfFile( 174 elf_path, BuildId(), &min_vaddr, &file_offset_of_min_vaddr)); 175 ASSERT_EQ(min_vaddr, 0u); 176 ASSERT_EQ(file_offset_of_min_vaddr, 0u); 177 } 178 179 TEST(read_elf, ReadMinExecutableVirtualAddressFromElfFile) { 180 uint64_t min_vaddr; 181 uint64_t file_offset_of_min_vaddr; 182 ASSERT_EQ(ElfStatus::NO_ERROR, ReadMinExecutableVirtualAddressFromElfFile( 183 GetTestData("libc.so"), BuildId(), &min_vaddr, &file_offset_of_min_vaddr)); 184 ASSERT_EQ(min_vaddr, 0x29000u); 185 ASSERT_EQ(file_offset_of_min_vaddr, 0x29000u); 186 } 187 188 TEST(read_elf, NoUndefinedSymbol) { 189 // Check if we read undefined symbols (like dlerror) from libc.so. 190 bool has_dlerror = false; 191 auto parse_symbol = [&](const ElfFileSymbol& symbol) { 192 if (symbol.name == "dlerror") { 193 has_dlerror = true; 194 } 195 }; 196 197 ASSERT_EQ(ElfStatus::NO_ERROR, 198 ParseSymbolsFromElfFile(GetTestData("libc.so"), BuildId(), parse_symbol)); 199 ASSERT_FALSE(has_dlerror); 200 }