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 }