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