1 /* 2 * Copyright (C) 2016 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 <elf.h> 18 #include <errno.h> 19 #include <signal.h> 20 #include <stdint.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <sys/mman.h> 24 #include <sys/ptrace.h> 25 #include <sys/types.h> 26 #include <time.h> 27 #include <unistd.h> 28 29 #include <vector> 30 31 #include <android-base/file.h> 32 #include <android-base/test_utils.h> 33 #include <gtest/gtest.h> 34 35 #include <unwindstack/Memory.h> 36 37 #include "MemoryFake.h" 38 #include "Symbols.h" 39 40 namespace unwindstack { 41 42 template <typename TypeParam> 43 class SymbolsTest : public ::testing::Test { 44 protected: 45 void SetUp() override { memory_.Clear(); } 46 47 void InitSym(TypeParam* sym, uint32_t st_value, uint32_t st_size, uint32_t st_name) { 48 memset(sym, 0, sizeof(*sym)); 49 sym->st_info = STT_FUNC; 50 sym->st_value = st_value; 51 sym->st_size = st_size; 52 sym->st_name = st_name; 53 sym->st_shndx = SHN_COMMON; 54 } 55 56 MemoryFake memory_; 57 }; 58 TYPED_TEST_CASE_P(SymbolsTest); 59 60 TYPED_TEST_P(SymbolsTest, function_bounds_check) { 61 Symbols symbols(0x1000, sizeof(TypeParam), sizeof(TypeParam), 0x2000, 0x100); 62 63 TypeParam sym; 64 this->InitSym(&sym, 0x5000, 0x10, 0x40); 65 uint64_t offset = 0x1000; 66 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 67 68 std::string fake_name("fake_function"); 69 this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1); 70 71 std::string name; 72 uint64_t func_offset; 73 ASSERT_TRUE(symbols.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset)); 74 ASSERT_EQ("fake_function", name); 75 ASSERT_EQ(0U, func_offset); 76 77 name.clear(); 78 ASSERT_TRUE(symbols.GetName<TypeParam>(0x500f, 0, &this->memory_, &name, &func_offset)); 79 ASSERT_EQ("fake_function", name); 80 ASSERT_EQ(0xfU, func_offset); 81 82 // Check one before and one after the function. 83 ASSERT_FALSE(symbols.GetName<TypeParam>(0x4fff, 0, &this->memory_, &name, &func_offset)); 84 ASSERT_FALSE(symbols.GetName<TypeParam>(0x5010, 0, &this->memory_, &name, &func_offset)); 85 } 86 87 TYPED_TEST_P(SymbolsTest, no_symbol) { 88 Symbols symbols(0x1000, sizeof(TypeParam), sizeof(TypeParam), 0x2000, 0x100); 89 90 TypeParam sym; 91 this->InitSym(&sym, 0x5000, 0x10, 0x40); 92 uint64_t offset = 0x1000; 93 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 94 95 std::string fake_name("fake_function"); 96 this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1); 97 98 // First verify that we can get the name. 99 std::string name; 100 uint64_t func_offset; 101 ASSERT_TRUE(symbols.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset)); 102 ASSERT_EQ("fake_function", name); 103 ASSERT_EQ(0U, func_offset); 104 105 // Now modify the info field so it's no longer a function. 106 sym.st_info = 0; 107 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 108 // Clear the cache to force the symbol data to be re-read. 109 symbols.ClearCache(); 110 ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset)); 111 112 // Set the function back, and set the shndx to UNDEF. 113 sym.st_info = STT_FUNC; 114 sym.st_shndx = SHN_UNDEF; 115 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 116 // Clear the cache to force the symbol data to be re-read. 117 symbols.ClearCache(); 118 ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset)); 119 } 120 121 TYPED_TEST_P(SymbolsTest, multiple_entries) { 122 Symbols symbols(0x1000, sizeof(TypeParam) * 3, sizeof(TypeParam), 0x2000, 0x500); 123 124 TypeParam sym; 125 uint64_t offset = 0x1000; 126 std::string fake_name; 127 128 this->InitSym(&sym, 0x5000, 0x10, 0x40); 129 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 130 fake_name = "function_one"; 131 this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1); 132 offset += sizeof(sym); 133 134 this->InitSym(&sym, 0x3004, 0x200, 0x100); 135 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 136 fake_name = "function_two"; 137 this->memory_.SetMemory(0x2100, fake_name.c_str(), fake_name.size() + 1); 138 offset += sizeof(sym); 139 140 this->InitSym(&sym, 0xa010, 0x20, 0x230); 141 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 142 fake_name = "function_three"; 143 this->memory_.SetMemory(0x2230, fake_name.c_str(), fake_name.size() + 1); 144 145 std::string name; 146 uint64_t func_offset; 147 ASSERT_TRUE(symbols.GetName<TypeParam>(0x3005, 0, &this->memory_, &name, &func_offset)); 148 ASSERT_EQ("function_two", name); 149 ASSERT_EQ(1U, func_offset); 150 151 name.clear(); 152 ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, 0, &this->memory_, &name, &func_offset)); 153 ASSERT_EQ("function_one", name); 154 ASSERT_EQ(4U, func_offset); 155 156 name.clear(); 157 ASSERT_TRUE(symbols.GetName<TypeParam>(0xa011, 0, &this->memory_, &name, &func_offset)); 158 ASSERT_EQ("function_three", name); 159 ASSERT_EQ(1U, func_offset); 160 161 // Reget some of the others to verify getting one function name doesn't 162 // affect any of the next calls. 163 name.clear(); 164 ASSERT_TRUE(symbols.GetName<TypeParam>(0x5008, 0, &this->memory_, &name, &func_offset)); 165 ASSERT_EQ("function_one", name); 166 ASSERT_EQ(8U, func_offset); 167 168 name.clear(); 169 ASSERT_TRUE(symbols.GetName<TypeParam>(0x3008, 0, &this->memory_, &name, &func_offset)); 170 ASSERT_EQ("function_two", name); 171 ASSERT_EQ(4U, func_offset); 172 173 name.clear(); 174 ASSERT_TRUE(symbols.GetName<TypeParam>(0xa01a, 0, &this->memory_, &name, &func_offset)); 175 ASSERT_EQ("function_three", name); 176 ASSERT_EQ(0xaU, func_offset); 177 } 178 179 TYPED_TEST_P(SymbolsTest, multiple_entries_nonstandard_size) { 180 uint64_t entry_size = sizeof(TypeParam) + 5; 181 Symbols symbols(0x1000, entry_size * 3, entry_size, 0x2000, 0x500); 182 183 TypeParam sym; 184 uint64_t offset = 0x1000; 185 std::string fake_name; 186 187 this->InitSym(&sym, 0x5000, 0x10, 0x40); 188 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 189 fake_name = "function_one"; 190 this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1); 191 offset += entry_size; 192 193 this->InitSym(&sym, 0x3004, 0x200, 0x100); 194 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 195 fake_name = "function_two"; 196 this->memory_.SetMemory(0x2100, fake_name.c_str(), fake_name.size() + 1); 197 offset += entry_size; 198 199 this->InitSym(&sym, 0xa010, 0x20, 0x230); 200 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 201 fake_name = "function_three"; 202 this->memory_.SetMemory(0x2230, fake_name.c_str(), fake_name.size() + 1); 203 204 std::string name; 205 uint64_t func_offset; 206 ASSERT_TRUE(symbols.GetName<TypeParam>(0x3005, 0, &this->memory_, &name, &func_offset)); 207 ASSERT_EQ("function_two", name); 208 ASSERT_EQ(1U, func_offset); 209 210 name.clear(); 211 ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, 0, &this->memory_, &name, &func_offset)); 212 ASSERT_EQ("function_one", name); 213 ASSERT_EQ(4U, func_offset); 214 215 name.clear(); 216 ASSERT_TRUE(symbols.GetName<TypeParam>(0xa011, 0, &this->memory_, &name, &func_offset)); 217 ASSERT_EQ("function_three", name); 218 ASSERT_EQ(1U, func_offset); 219 } 220 221 TYPED_TEST_P(SymbolsTest, load_bias) { 222 Symbols symbols(0x1000, sizeof(TypeParam), sizeof(TypeParam), 0x2000, 0x100); 223 224 TypeParam sym; 225 this->InitSym(&sym, 0x5000, 0x10, 0x40); 226 uint64_t offset = 0x1000; 227 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 228 229 std::string fake_name("fake_function"); 230 this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1); 231 232 // Set a non-zero load_bias that should be a valid function offset. 233 std::string name; 234 uint64_t func_offset; 235 ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, 0x1000, &this->memory_, &name, &func_offset)); 236 ASSERT_EQ("fake_function", name); 237 ASSERT_EQ(4U, func_offset); 238 239 // Set a flag that should cause the load_bias to be ignored. 240 sym.st_shndx = SHN_ABS; 241 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 242 // Clear the cache to force the symbol data to be re-read. 243 symbols.ClearCache(); 244 ASSERT_FALSE(symbols.GetName<TypeParam>(0x5004, 0x1000, &this->memory_, &name, &func_offset)); 245 } 246 247 TYPED_TEST_P(SymbolsTest, symtab_value_out_of_bounds) { 248 Symbols symbols_end_at_100(0x1000, sizeof(TypeParam) * 2, sizeof(TypeParam), 0x2000, 0x100); 249 Symbols symbols_end_at_200(0x1000, sizeof(TypeParam) * 2, sizeof(TypeParam), 0x2000, 0x200); 250 251 TypeParam sym; 252 uint64_t offset = 0x1000; 253 254 this->InitSym(&sym, 0x5000, 0x10, 0xfb); 255 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 256 offset += sizeof(sym); 257 258 this->InitSym(&sym, 0x3000, 0x10, 0x100); 259 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 260 261 // Put the name across the end of the tab. 262 std::string fake_name("fake_function"); 263 this->memory_.SetMemory(0x20fb, fake_name.c_str(), fake_name.size() + 1); 264 265 std::string name; 266 uint64_t func_offset; 267 // Verify that we can get the function name properly for both entries. 268 ASSERT_TRUE(symbols_end_at_200.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset)); 269 ASSERT_EQ("fake_function", name); 270 ASSERT_EQ(0U, func_offset); 271 ASSERT_TRUE(symbols_end_at_200.GetName<TypeParam>(0x3000, 0, &this->memory_, &name, &func_offset)); 272 ASSERT_EQ("function", name); 273 ASSERT_EQ(0U, func_offset); 274 275 // Now use the symbol table that ends at 0x100. 276 ASSERT_FALSE( 277 symbols_end_at_100.GetName<TypeParam>(0x5000, 0, &this->memory_, &name, &func_offset)); 278 ASSERT_FALSE( 279 symbols_end_at_100.GetName<TypeParam>(0x3000, 0, &this->memory_, &name, &func_offset)); 280 } 281 282 // Verify the entire func table is cached. 283 TYPED_TEST_P(SymbolsTest, symtab_read_cached) { 284 Symbols symbols(0x1000, 3 * sizeof(TypeParam), sizeof(TypeParam), 0xa000, 0x1000); 285 286 TypeParam sym; 287 uint64_t offset = 0x1000; 288 289 // Make sure that these entries are not in ascending order. 290 this->InitSym(&sym, 0x5000, 0x10, 0x100); 291 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 292 offset += sizeof(sym); 293 294 this->InitSym(&sym, 0x2000, 0x300, 0x200); 295 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 296 offset += sizeof(sym); 297 298 this->InitSym(&sym, 0x1000, 0x100, 0x300); 299 this->memory_.SetMemory(offset, &sym, sizeof(sym)); 300 offset += sizeof(sym); 301 302 // Do call that should cache all of the entries (except the string data). 303 std::string name; 304 uint64_t func_offset; 305 ASSERT_FALSE(symbols.GetName<TypeParam>(0x6000, 0, &this->memory_, &name, &func_offset)); 306 this->memory_.Clear(); 307 ASSERT_FALSE(symbols.GetName<TypeParam>(0x6000, 0, &this->memory_, &name, &func_offset)); 308 309 // Clear the memory and only put the symbol data string data in memory. 310 this->memory_.Clear(); 311 312 std::string fake_name; 313 fake_name = "first_entry"; 314 this->memory_.SetMemory(0xa100, fake_name.c_str(), fake_name.size() + 1); 315 fake_name = "second_entry"; 316 this->memory_.SetMemory(0xa200, fake_name.c_str(), fake_name.size() + 1); 317 fake_name = "third_entry"; 318 this->memory_.SetMemory(0xa300, fake_name.c_str(), fake_name.size() + 1); 319 320 ASSERT_TRUE(symbols.GetName<TypeParam>(0x5001, 0, &this->memory_, &name, &func_offset)); 321 ASSERT_EQ("first_entry", name); 322 ASSERT_EQ(1U, func_offset); 323 324 ASSERT_TRUE(symbols.GetName<TypeParam>(0x2002, 0, &this->memory_, &name, &func_offset)); 325 ASSERT_EQ("second_entry", name); 326 ASSERT_EQ(2U, func_offset); 327 328 ASSERT_TRUE(symbols.GetName<TypeParam>(0x1003, 0, &this->memory_, &name, &func_offset)); 329 ASSERT_EQ("third_entry", name); 330 ASSERT_EQ(3U, func_offset); 331 } 332 333 REGISTER_TYPED_TEST_CASE_P(SymbolsTest, function_bounds_check, no_symbol, multiple_entries, 334 multiple_entries_nonstandard_size, load_bias, symtab_value_out_of_bounds, 335 symtab_read_cached); 336 337 typedef ::testing::Types<Elf32_Sym, Elf64_Sym> SymbolsTestTypes; 338 INSTANTIATE_TYPED_TEST_CASE_P(, SymbolsTest, SymbolsTestTypes); 339 340 } // namespace unwindstack 341