1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "symbols_test.h"
17
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <random>
21 #include <unistd.h>
22
23 using namespace testing::ext;
24 using namespace std;
25 #ifndef CONFIG_NO_HILOG
26 using namespace OHOS::HiviewDFX;
27 #endif
28
29 namespace OHOS {
30 namespace Developtools {
31 namespace NativeDaemon {
32 class SymbolsTest : public testing::Test {
33 public:
34 static void SetUpTestCase(void);
35 static void TearDownTestCase(void);
36 void SetUp();
37 void TearDown();
38 void CheckSymbols(const std::unique_ptr<SymbolsFile> &symbolsFile) const;
39 void PrintSymbols(const std::vector<Symbol> &symbol) const;
40 bool KptrRestrict() const;
41
LoadSymbols(SymbolsFileType symbolsFileType)42 std::unique_ptr<SymbolsFile> LoadSymbols(SymbolsFileType symbolsFileType)
43 {
44 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(symbolsFileType);
45 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
46 return symbolsFile;
47 }
48
TestLoadSymbols(SymbolsFileType symbolsFileType,const std::string & path)49 bool TestLoadSymbols(SymbolsFileType symbolsFileType, const std::string &path)
50 {
51 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(symbolsFileType);
52 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
53 return symbolsFile->LoadSymbols(path);
54 }
55 default_random_engine rnd_;
56 };
57
SetUpTestCase()58 void SymbolsTest::SetUpTestCase() {}
59
TearDownTestCase()60 void SymbolsTest::TearDownTestCase() {}
61
SetUp()62 void SymbolsTest::SetUp() {}
63
TearDown()64 void SymbolsTest::TearDown() {}
65
KptrRestrict() const66 bool SymbolsTest::KptrRestrict() const
67 {
68 std::ifstream inputString(KPTR_RESTRICT, std::ios::in);
69 if (inputString) {
70 string kptrRestrict = "1";
71 inputString >> kptrRestrict;
72 if (kptrRestrict == "0") {
73 return false;
74 }
75 }
76 return true;
77 }
78
CheckSymbols(const std::unique_ptr<SymbolsFile> & symbolsFile) const79 void SymbolsTest::CheckSymbols(const std::unique_ptr<SymbolsFile> &symbolsFile) const
80 {
81 auto symbols = symbolsFile->GetSymbols();
82 EXPECT_EQ(symbols.empty(), false);
83 ASSERT_GE(symbols.size(), 1u);
84 PrintSymbols(symbols);
85
86 // first is 0
87 EXPECT_EQ(symbolsFile->GetSymbolWithVaddr(0x0).vaddr_, 0u);
88
89 // last is isValid
90 EXPECT_EQ(symbolsFile->GetSymbolWithVaddr(std::numeric_limits<uint64_t>::max()).isValid(),
91 true);
92
93 constexpr const int radomPosition = 4;
94 uint64_t rndVaddr = symbols[symbols.size() / radomPosition].ipVaddr_;
95 EXPECT_EQ(symbolsFile->GetSymbolWithVaddr(rndVaddr).ipVaddr_, rndVaddr);
96
97 for (auto symbol : symbols) {
98 if (symbol.name_.find("_Z") != std::string::npos) {
99 EXPECT_NE(symbol.demangle_.find("_Z"), 0u);
100 }
101 }
102 }
103
PrintSymbols(const std::vector<Symbol> & symbols) const104 void SymbolsTest::PrintSymbols(const std::vector<Symbol> &symbols) const
105 {
106 size_t printNumber = 15;
107 if (printNumber > symbols.size()) {
108 printNumber = symbols.size();
109 }
110
111 HLOGD("first %zu:", printNumber);
112 for (size_t i = 0; i < printNumber; i++) {
113 HLOGD("%s", symbols[i].ToDebugString().c_str());
114 }
115 if (printNumber < symbols.size()) {
116 HLOGD("last %zu:", printNumber);
117 for (size_t i = printNumber; i > 0; i--) {
118 HLOGD("%s", symbols[symbols.size() - i].ToDebugString().c_str());
119 }
120 }
121 }
122
123 /**
124 * @tc.name: Symbol Name
125 * @tc.desc:
126 * @tc.type: FUNC
127 */
128 HWTEST_F(SymbolsTest, SymbolName, TestSize.Level1)
129 {
130 Symbol symbol;
131 symbol.vaddr_ = 0x1000;
132 symbol.ipVaddr_ = 0x1000;
133
134 EXPECT_EQ((symbol.Name().find("+0x") == std::string::npos), true);
135 symbol.ipVaddr_ = symbol.vaddr_ + 1;
136 EXPECT_EQ((symbol.Name().find("+0x") != std::string::npos), true);
137 symbol.ipVaddr_ = symbol.vaddr_ - 1;
138 EXPECT_EQ((symbol.Name().find("-0x") != std::string::npos), true);
139 }
140
141 /**
142 * @tc.name: setSymbolsFilePath
143 * @tc.desc:
144 * @tc.type: FUNC
145 */
146 HWTEST_F(SymbolsTest, setSymbolsFilePath, TestSize.Level1)
147 {
148 auto symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
149 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_DATA_TEMP), true);
150 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_NOT_EXISTS), false);
151 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_DATA_TEMP_WINDOS), false);
152 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_ILLEGAL), false);
153 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
154 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA_NO_ENDPATH), true);
155 }
156
157 /**
158 * @tc.name: setSymbolsFilePath
159 * @tc.desc:
160 * @tc.type: FUNC
161 */
162 HWTEST_F(SymbolsTest, setSymbolsFilePathVectorSuccess, TestSize.Level1)
163 {
164 auto symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
165 std::vector<std::string> symbolsSearchPaths;
166
167 symbolsSearchPaths.clear();
168 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
169 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), true);
170
171 symbolsSearchPaths.clear();
172 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
173 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
174 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), true);
175
176 symbolsSearchPaths.clear();
177 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
178 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
179 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
180 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), true);
181 }
182
183 /**
184 * @tc.name: setSymbolsFilePath
185 * @tc.desc:
186 * @tc.type: FUNC
187 */
188 HWTEST_F(SymbolsTest, setSymbolsFilePathVectorFailed, TestSize.Level1)
189 {
190 auto symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
191 std::vector<std::string> symbolsSearchPaths;
192
193 symbolsSearchPaths.clear();
194 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
195 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), false);
196
197 symbolsSearchPaths.clear();
198 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
199 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
200 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), false);
201
202 symbolsSearchPaths.clear();
203 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
204 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
205 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
206 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), false);
207 }
208
209 /**
210 * @tc.name: setSymbolsFilePath
211 * @tc.desc:
212 * @tc.type: FUNC
213 */
214 HWTEST_F(SymbolsTest, setSymbolsFilePathVectorMixSucessed, TestSize.Level1)
215 {
216 auto symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
217 std::vector<std::string> symbolsSearchPaths;
218
219 symbolsSearchPaths.clear();
220 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
221 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
222 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), true);
223
224 symbolsSearchPaths.clear();
225 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
226 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
227 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
228 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
229 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), true);
230
231 symbolsSearchPaths.clear();
232 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
233 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
234 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
235 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
236 symbolsSearchPaths.push_back(PATH_DATA_TEMP);
237 symbolsSearchPaths.push_back(PATH_NOT_EXISTS);
238 EXPECT_EQ(symbolsFile->setSymbolsFilePath(symbolsSearchPaths), true);
239 }
240
TestLoadSymbols(SymbolsFileType symbolsFileType,const std::string & path)241 bool TestLoadSymbols(SymbolsFileType symbolsFileType, const std::string &path)
242 {
243 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(symbolsFileType);
244 EXPECT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
245 return symbolsFile->LoadSymbols(path);
246 }
247
248 /**
249 * @tc.name: SymbolsFile Default Virtual
250 * @tc.desc:
251 * @tc.type: FUNC
252 */
253 HWTEST_F(SymbolsTest, SymbolsFileDefaultVirtual, TestSize.Level1)
254 {
255 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
256 uint64_t value = 0;
257 uint8_t *ptr = nullptr;
258 EXPECT_EQ(symbolsFile->LoadSymbols(), false);
259 EXPECT_EQ(symbolsFile->ReadRoMemory(0, ptr, 0), false);
260 EXPECT_EQ(symbolsFile->GetSectionInfo("", value, value, value), false);
261 #ifndef __arm__
262 EXPECT_EQ(symbolsFile->GetHDRSectionInfo(value, value, value), false);
263 #endif
264 }
265
266 /**
267 * @tc.name: LoaderKernelSymbols
268 * @tc.desc:
269 * @tc.type: FUNC
270 */
271 HWTEST_F(SymbolsTest, LoaderKernelSymbols, TestSize.Level1)
272 {
273 // read from kernel runtime
274 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE);
275 ScopeDebugLevel tempLogLevel(LEVEL_VERBOSE);
276 EXPECT_EQ(symbolsFile->LoadSymbols(), true);
277
278 const std::vector<Symbol> &symbols = symbolsFile->GetSymbols();
279
280 if (KptrRestrict()) {
281 EXPECT_EQ(symbols.empty(), true);
282 } else {
283 EXPECT_EQ(symbols.empty(), false);
284 }
285
286 std::string modulesMap = ReadFileToString("/proc/modules");
287 size_t lines = std::count(modulesMap.begin(), modulesMap.end(), '\n');
288 std::set<std::string> modulesCount;
289 for (auto &symbol : symbols) {
290 modulesCount.emplace(symbol.module_);
291 }
292
293 // add [kernel.kallsyms]
294 EXPECT_EQ(modulesCount.size(), lines + 1u);
295 if (HasFailure()) {
296 for (auto &module : modulesCount) {
297 printf("%s\n", module.c_str());
298 }
299 }
300
301 // try vmlinux
302 EXPECT_EQ(TestLoadSymbols(SYMBOL_KERNEL_FILE, TEST_FILE_VMLINUX), true);
303 EXPECT_EQ(TestLoadSymbols(SYMBOL_KERNEL_FILE, TEST_FILE_VMLINUX_STRIPPED), true);
304 EXPECT_EQ(TestLoadSymbols(SYMBOL_KERNEL_FILE, TEST_FILE_VMLINUX_STRIPPED_NOBUILDID), true);
305 // will be load from runtime, still return true
306 EXPECT_EQ(TestLoadSymbols(SYMBOL_KERNEL_FILE, TEST_FILE_VMLINUX_STRIPPED_BROKEN), true);
307 }
308
309 /**
310 * @tc.name: LoaderElfSymbols
311 * @tc.desc:
312 * @tc.type: FUNC
313 */
314 HWTEST_F(SymbolsTest, LoaderElfSymbols, TestSize.Level1)
315 {
316 auto symbolsElfLoader = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
317 auto symbolsElfStrippedLoader = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
318 ScopeDebugLevel tempLogLevel(LEVEL_VERBOSE);
319
320 EXPECT_EQ(symbolsElfLoader->LoadSymbols(), false);
321
322 ASSERT_EQ(symbolsElfLoader->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
323 EXPECT_EQ(symbolsElfLoader->LoadSymbols(TEST_FILE_ELF), true);
324 if (HasFailure()) {
325 PrintSymbols(symbolsElfLoader->GetSymbols());
326 }
327
328 ASSERT_EQ(symbolsElfStrippedLoader->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
329 EXPECT_EQ(symbolsElfStrippedLoader->LoadSymbols(TEST_FILE_ELF_STRIPPED), true);
330 if (HasFailure()) {
331 PrintSymbols(symbolsElfStrippedLoader->GetSymbols());
332 }
333 EXPECT_GT(symbolsElfLoader->GetSymbols().size(), symbolsElfStrippedLoader->GetSymbols().size());
334
335 ASSERT_EQ(symbolsElfStrippedLoader->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
336 EXPECT_EQ(symbolsElfStrippedLoader->LoadSymbols(TEST_FILE_ELF), true);
337 if (HasFailure()) {
338 PrintSymbols(symbolsElfStrippedLoader->GetSymbols());
339 }
340
341 // no symbols not means failed.
342 EXPECT_EQ(TestLoadSymbols(SYMBOL_ELF_FILE, TEST_FILE_ELF_STRIPPED), true);
343
344 // no build id not means failed.
345 EXPECT_EQ(TestLoadSymbols(SYMBOL_ELF_FILE, TEST_FILE_ELF_STRIPPED_NOBUILDID), true);
346
347 EXPECT_EQ(TestLoadSymbols(SYMBOL_ELF_FILE, TEST_FILE_ELF_STRIPPED_BROKEN), false);
348 }
349
350 /**
351 * @tc.name: GetSymbolWithVaddr
352 * @tc.desc:
353 * @tc.type: FUNC
354 */
355 HWTEST_F(SymbolsTest, GetSymbolWithVaddr, TestSize.Level1)
356 {
357 auto symbols = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE);
358
359 if ((0 == getuid())) {
360 HLOGD("in root mode");
361 EXPECT_EQ(symbols->LoadSymbols(), true);
362 CheckSymbols(symbols);
363 } else {
364 EXPECT_EQ(symbols->LoadSymbols(), true);
365 if (!KptrRestrict()) {
366 HLOGD("NOT KptrRestrict");
367 if (!symbols->GetSymbols().empty()) {
368 CheckSymbols(symbols);
369 } else {
370 HLOGD("we found this issue in linux-5.10");
371 }
372 } else {
373 HLOGD("KptrRestrict");
374 ASSERT_EQ(symbols->GetSymbols().empty(), true);
375 }
376 }
377 }
378
379 /**
380 * @tc.name: GetSymbolWithVaddr
381 * @tc.desc:
382 * @tc.type: FUNC
383 */
384 HWTEST_F(SymbolsTest, GetSymbolWithVaddr2, TestSize.Level1)
385 {
386 auto elfSymbols = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
387 ASSERT_EQ(elfSymbols->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
388 EXPECT_EQ(elfSymbols->LoadSymbols(TEST_FILE_ELF), true);
389 ASSERT_EQ(elfSymbols->GetSymbols().empty(), false);
390
391 /*
392 nm -C --defined-only elf_test
393 0000000000002000 t _init
394 00000000000022f0 T _start
395 0000000000002478 T main
396 00000000000023d9 T TestGlobalChildFunction
397 0000000000002447 T TestGlobalParentFunction
398
399 //last one
400 0000000000002aa8 T _fini
401
402 nm -C --defined-only elf32_test
403 00001000 t _init
404 00001320 T _start
405 00001512 T main
406 0000152d __static_initialization_and_destruction_0
407 0000145d T TestGlobalChildFunction
408 000014d9 T TestGlobalParentFunction
409
410 // last one
411 00001b38 T _fini
412 */
413 #ifdef __arm__
414 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
415 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001000).demangle_, "_init");
416 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001001).demangle_, "_init");
417 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001319).demangle_, "_init");
418 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001320).demangle_, "_start");
419 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001321).demangle_, "_start");
420 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001512).demangle_, "main");
421 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x0000145d).demangle_, "TestGlobalChildFunction");
422 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x000014d9).demangle_, "TestGlobalParentFunction");
423 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001b38).demangle_, "_fini");
424 #else
425 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002000).demangle_, "_init");
426 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002001).demangle_, "_init");
427 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x000022ef).demangle_, "_init");
428 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x000022f0).demangle_, "_start");
429 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x000022f1).demangle_, "_start");
430 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002478).demangle_, "main");
431 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002319).demangle_, "main");
432 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x000023d9).demangle_, "TestGlobalChildFunction");
433 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002447).demangle_, "TestGlobalParentFunction");
434 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002aa8).demangle_, "_fini");
435 #endif
436 if (HasFailure()) {
437 PrintSymbols(elfSymbols->GetSymbols());
438 }
439 }
440
441 /**
442 * @tc.name: GetVaddrInSymbols
443 * @tc.desc:
444 * @tc.type: FUNC
445 */
446 HWTEST_F(SymbolsTest, GetVaddrInSymbols, TestSize.Level1)
447 {
448 /*
449 00200000-002c5000 r--p 00000000 08:02 46400311
450 002c5000-00490000 r-xp 000c5000 08:02 4640031
451
452 [14] .text PROGBITS 00000000002c5000 000c5000
453
454 if ip is 0x46e6ab
455 1. find the map range is 002c5000-00490000
456 2. ip - map start(002c5000) = map section offset
457 3. map section offset + map page offset(000c5000) = elf file offset
458 4. elf file offset - exec file offset(000c5000)
459 = ip offset (ip always in exec file offset)
460 5. ip offset + exec begin vaddr(2c5000) = virtual ip in elf
461 */
462 auto elfSymbols = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
463 elfSymbols->textExecVaddrFileOffset_ = 0x000c5000;
464 elfSymbols->textExecVaddr_ = 0x002c5000;
465
466 // most easy case
467 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0x002c5123, 0x002c5000, 0x000c5000), 0x002c5123U);
468
469 // ip and map both change
470 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0xFF2c5123, 0xFF2c5000, 0x000c5000), 0x002c5123U);
471 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0x00000123, 0x00000000, 0x000c5000), 0x002c5123U);
472
473 // map page and offset change
474 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0x002ca123, 0x002c5000, 0x000c0000), 0x002c5123U);
475 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0x002c4123, 0x002c5000, 0x000c6000), 0x002c5123U);
476
477 // kernel dont care offset
478 auto kernelSymbols = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE);
479 EXPECT_EQ(kernelSymbols->GetVaddrInSymbols(0x001234, 0x002c5000, 0x000c5000), 0x001234U);
480 }
481
482 /**
483 * @tc.name: FindSymbolFile
484 * @tc.desc:
485 * @tc.type: FUNC
486 */
487 HWTEST_F(SymbolsTest, FindSymbolFile, TestSize.Level1)
488 {
489 auto symbols = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
490
491 std::vector<std::string> symbolsFileSearchPaths;
492 std::string symboleFilePath;
493
494 symboleFilePath = TEST_FILE_VMLINUX;
495 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), true);
496
497 symbolsFileSearchPaths.emplace_back(PATH_RESOURCE_TEST_DATA);
498 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), false);
499
500 symbolsFileSearchPaths.clear();
501 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), true);
502
503 symboleFilePath = PATH_RESOURCE_TEST_DATA + TEST_FILE_VMLINUX;
504 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), false);
505
506 symbolsFileSearchPaths.emplace_back(PATH_RESOURCE_TEST_DATA);
507 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), false);
508
509 symboleFilePath = TEST_FILE_ELF;
510 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), false);
511
512 symbolsFileSearchPaths.clear();
513 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), true);
514 }
515
516 /**
517 * @tc.name: GetBuildId
518 * @tc.desc:
519 * @tc.type: FUNC
520 */
521 HWTEST_F(SymbolsTest, GetBuildId, TestSize.Level1)
522 {
523 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
524 // empty elf
525 EXPECT_EQ(symbolsFile->GetBuildId().empty(), true);
526 // set search path
527 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
528
529 symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
530 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
531 // kernel elf
532 EXPECT_EQ(symbolsFile->LoadSymbols(TEST_FILE_VMLINUX), true);
533 EXPECT_EQ(symbolsFile->GetBuildId().empty(), false);
534
535 symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
536 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
537 // stripped elf
538 EXPECT_EQ(symbolsFile->LoadSymbols(TEST_FILE_ELF), true);
539 EXPECT_EQ(symbolsFile->GetBuildId().empty(), false);
540
541 symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
542 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
543 // stripped elf
544 EXPECT_EQ(symbolsFile->LoadSymbols(TEST_FILE_ELF_STRIPPED), true);
545 EXPECT_EQ(symbolsFile->GetBuildId().empty(), false);
546 }
547
548 /**
549 * @tc.name: ReadRoMemory
550 * @tc.desc:
551 * @tc.type: FUNC
552 */
553 HWTEST_F(SymbolsTest, ReadRoMemory, TestSize.Level1)
554 {
555 std::unique_ptr<SymbolsFile> defaultSymbolsFile = SymbolsFile::CreateSymbolsFile();
556
557 std::unique_ptr<SymbolsFile> symbolsFile =
558 SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, TEST_FILE_ELF_FULL_PATH);
559
560 std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(TEST_FILE_ELF_FULL_PATH.c_str(), "rb"),
561 fclose);
562
563 ASSERT_NE(symbolsFile, nullptr);
564 ASSERT_NE(fp, nullptr);
565
566 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
567
568 uint8_t freadByte = '\0';
569 uint8_t readRoByte = '\0';
570 uint64_t addr = 0x0;
571
572 // virtual function
573 EXPECT_EQ(defaultSymbolsFile->ReadRoMemory(addr, &readRoByte, 1), 0U);
574
575 // first byte
576 ASSERT_EQ(fread(&freadByte, 1, 1, fp.get()), 1U);
577 ASSERT_EQ(symbolsFile->ReadRoMemory(addr++, &readRoByte, 1), 1U);
578 ASSERT_EQ(freadByte, readRoByte);
579
580 while (fread(&freadByte, 1, 1, fp.get()) == 1U) {
581 EXPECT_EQ(symbolsFile->ReadRoMemory(addr++, &readRoByte, 1), 1U);
582 EXPECT_EQ(freadByte, readRoByte);
583 }
584
585 // EOF , out of file size should return 0
586 ASSERT_EQ(symbolsFile->ReadRoMemory(addr++, &readRoByte, 1), 0U);
587 }
588
589 struct sectionInfo {
590 const std::string name;
591 uint64_t addr;
592 uint64_t size;
593 uint64_t offset;
594 };
595
596 /**
597 * @tc.name: GetSectionInfo
598 * @tc.desc:
599 * @tc.type: FUNC
600 */
601 HWTEST_F(SymbolsTest, GetSectionInfo, TestSize.Level1)
602 {
603 std::unique_ptr<SymbolsFile> symbolsFile =
604 SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, TEST_FILE_ELF_FULL_PATH);
605 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
606
607 /*
608 from readelf -e elf32_test
609 32bit
610 [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
611 [ 0] NULL 00000000 000000 000000 00 0 0 0
612 [ 1] .interp PROGBITS 000001b4 0001b4 000013 00 A 0 0 1
613 [ 2] .note.gnu.build-i NOTE 000001c8 0001c8 000024 00 A 0 0 4
614 [16] .text PROGBITS 00001320 001320 000818 00 AX 0 0 16
615 [19] .eh_frame_hdr PROGBITS 00002034 002034 0000dc 00 A 0 0 4
616 [20] .eh_frame PROGBITS 00002110 002110 0003a0 00 A 0 0 4
617 [29] .symtab SYMTAB 00000000 003034 000710 10 30 50 4
618 [30] .strtab STRTAB 00000000 003744 000c3d 00 0 0 1
619 [31] .shstrtab STRTAB 00000000 004381 00012a 00 0 0 1
620
621 from readelf -e elf_test
622 64bit
623 Section Headers:
624 [Nr] Name Type Address Offset
625 Size EntSize Flags Link Info Align
626 [ 0] NULL 0000000000000000 00000000
627 0000000000000000 0000000000000000 0 0 0
628 [ 1] .interp PROGBITS 0000000000000318 00000318
629 000000000000001c 0000000000000000 A 0 0 1
630 [ 2] .note.gnu.propert NOTE 0000000000000338 00000338
631 0000000000000020 0000000000000000 A 0 0 8
632 [16] .text PROGBITS 00000000000022f0 000022f0
633 00000000000007b5 0000000000000000 AX 0 0 16
634 [19] .eh_frame_hdr PROGBITS 0000000000003034 00003034
635 00000000000000bc 0000000000000000 A 0 0 4
636 [20] .eh_frame PROGBITS 00000000000030f0 000030f0
637 0000000000000320 0000000000000000 A 0 0 8
638 [29] .symtab SYMTAB 0000000000000000 00004040
639 00000000000009f0 0000000000000018 30 50 8
640 [30] .strtab STRTAB 0000000000000000 00004a30
641 0000000000000bbb 0000000000000000 0 0 1
642 [31] .shstrtab STRTAB 0000000000000000 000055eb
643 000000000000012c 0000000000000000 0 0 1
644 */
645 #ifdef __arm__
646 const std::vector<sectionInfo> sectionCheckList = {
647 {".note.gnu.build-id", 0x000001c8, 0x000024, 0x0001c8},
648 {".text", 0x00001320, 0x000818, 0x001320},
649 {".eh_frame_hdr", 0x00002034, 0x0000dc, 0x002034},
650 {".eh_frame", 0x00002110, 0x0003a0, 0x002110},
651 {".symtab", 0x00000000, 0x000710, 0x003034},
652 {".strtab", 0x00000000, 0x000c3d, 0x003744},
653 {".shstrtab", 0x00000000, 0x00012a, 0x004381},
654 };
655 #else
656 const std::vector<sectionInfo> sectionCheckList = {
657 {".note.gnu.build-id", 0x0000000000000338, 0x0000000000000020, 0x00000338},
658 {".text", 0x00000000000022f0, 0x00000000000007b5, 0x000022f0},
659 {".eh_frame_hdr", 0x0000000000003034, 0x00000000000000bc, 0x00003034},
660 {".eh_frame", 0x00000000000030f0, 0x0000000000000320, 0x000030f0},
661 {".symtab", 0x00000000, 0x00000000000009f0, 0x00004040},
662 {".strtab", 0x00000000, 0x0000000000000bbb, 0x00004a30},
663 {".shstrtab", 0x00000000, 0x000000000000012c, 0x000055eb},
664 };
665 #endif
666 for (sectionInfo info : sectionCheckList) {
667 uint64_t addr;
668 uint64_t size;
669 uint64_t offset;
670 EXPECT_EQ(symbolsFile->GetSectionInfo(info.name, addr, size, offset), true);
671 EXPECT_EQ(addr, info.addr);
672 EXPECT_EQ(size, info.size);
673 EXPECT_EQ(offset, info.offset);
674 if (HasFailure()) {
675 HLOGD("sectionInfo check failed at '%s', %" PRIx64 ",%" PRIx64 ",%" PRIx64 "",
676 info.name.c_str(), info.addr, info.size, info.offset);
677 }
678 }
679 }
680
681 #ifndef __arm__
682 /**
683 * @tc.name: GetHDRSectionInfo
684 * @tc.desc:
685 * @tc.type: FUNC
686 */
687 HWTEST_F(SymbolsTest, GetHDRSectionInfo, TestSize.Level1)
688 {
689 std::unique_ptr<SymbolsFile> symbolsFile =
690 SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, TEST_FILE_ELF_FULL_PATH);
691 const constexpr unsigned int fdeTableItemSize = 8;
692
693 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
694
695 uint64_t ehFrameHdrElfOffset;
696 uint64_t fdeTableElfOffset;
697 uint64_t fdeTableSize;
698
699 /*
700 readelf -e elf32_test | grep .eh_frame_hdr
701 [19] .eh_frame_hdr PROGBITS 00002034 002034 0000dc 00 A 0 0 4
702
703 readelf --debug-dump=frames elf32_test | grep FDE | wc -l
704 26
705
706 readelf -e elf_test | grep .eh_frame_hdr
707 [19] .eh_frame_hdr PROGBITS 0000000000003034 00003034
708
709 readelf --debug-dump=frames elf_test | grep FDE | wc -l
710 22
711 */
712 symbolsFile->GetHDRSectionInfo(ehFrameHdrElfOffset, fdeTableElfOffset, fdeTableSize);
713
714 EXPECT_EQ(ehFrameHdrElfOffset, 0x00003034u);
715 EXPECT_EQ(fdeTableSize, 22U * fdeTableItemSize);
716 }
717
718 /**
719 * @tc.name: GetHDRSectionInfo
720 * @tc.desc:
721 * @tc.type: FUNC
722 */
723 HWTEST_F(SymbolsTest, GetHDRSectionInfoStripped, TestSize.Level1)
724 {
725 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE,
726 PATH_RESOURCE_TEST_DATA + TEST_FILE_ELF_STRIPPED_NOEFHDR);
727
728 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
729
730 uint64_t ehFrameHdrElfOffset;
731 uint64_t fdeTableElfOffset;
732 uint64_t fdeTableSize;
733
734 symbolsFile->GetHDRSectionInfo(ehFrameHdrElfOffset, fdeTableElfOffset, fdeTableSize);
735 uint64_t addr = 0;
736 uint64_t size = 0;
737 uint64_t offset = 0;
738 EXPECT_EQ(symbolsFile->GetSectionInfo(EH_FRAME_HR, addr, size, offset), false);
739 EXPECT_EQ(offset, 0U);
740 EXPECT_EQ(size, 0U);
741 EXPECT_EQ(addr, 0U);
742 }
743 #endif
744
745 /**
746 * @tc.name: CreateSymbolsFile
747 * @tc.desc:
748 * @tc.type: FUNC
749 */
750 HWTEST_F(SymbolsTest, CreateSymbolsFile, TestSize.Level1)
751 {
752 EXPECT_NE(SymbolsFile::CreateSymbolsFile(), nullptr);
753 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE), nullptr);
754 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_MODULE_FILE), nullptr);
755 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE), nullptr);
756 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_JAVA_FILE), nullptr);
757 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_JS_FILE), nullptr);
758 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE), nullptr);
759 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SymbolsFileType(-1)), nullptr);
760 EXPECT_EQ(SymbolsFile::CreateSymbolsFile(SymbolsFileType(-2))->symbolFileType_,
761 SYMBOL_UNKNOW_FILE);
762
763 EXPECT_EQ(SymbolsFile::CreateSymbolsFile(KERNEL_MMAP_NAME)->symbolFileType_,
764 SYMBOL_KERNEL_FILE);
765 EXPECT_EQ(SymbolsFile::CreateSymbolsFile(TEST_FILE_ELF_FULL_PATH)->symbolFileType_,
766 SYMBOL_ELF_FILE);
767 }
768
769 /**
770 * @tc.name: LoadSymbolsFromSaved
771 * @tc.desc:
772 * @tc.type: FUNC
773 */
774 HWTEST_F(SymbolsTest, LoadSymbolsFromSaved, TestSize.Level1)
775 {
776 SymbolFileStruct sfs;
777 for (int type = 0; type < SYMBOL_UNKNOW_FILE; type++) {
778 sfs.filePath_ = std::to_string(rnd_());
779 sfs.symbolType_ = type;
780 sfs.textExecVaddrFileOffset_ = rnd_();
781 sfs.textExecVaddr_ = rnd_();
782 sfs.buildId_ = std::to_string(rnd_());
783 int nameIndex = 0;
784 // after LoadSymbolsFromSaved it will sort from low to high
785 // so we make a order item to test
786 constexpr int rndMax = 10000;
787 std::uniform_int_distribution<int> rndLimi(0, rndMax);
788 sfs.symbolStructs_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
789 std::to_string(nameIndex));
790 nameIndex++;
791 sfs.symbolStructs_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
792 std::to_string(nameIndex));
793 nameIndex++;
794 sfs.symbolStructs_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
795 std::to_string(nameIndex));
796 nameIndex++;
797
798 // setup the min vaddr
799
800 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::LoadSymbolsFromSaved(sfs);
801
802 EXPECT_EQ(symbolsFile->filePath_, sfs.filePath_);
803 EXPECT_EQ(symbolsFile->symbolFileType_, sfs.symbolType_);
804 EXPECT_EQ(symbolsFile->textExecVaddr_, sfs.textExecVaddr_);
805 EXPECT_EQ(symbolsFile->textExecVaddrFileOffset_, sfs.textExecVaddrFileOffset_);
806 EXPECT_EQ(symbolsFile->GetBuildId(), sfs.buildId_);
807 EXPECT_EQ(symbolsFile->GetSymbols().size(), sfs.symbolStructs_.size());
808
809 for (Symbol symbol : symbolsFile->GetSymbols()) {
810 SymbolStruct symbolStruct = sfs.symbolStructs_.front();
811 EXPECT_EQ(symbol.vaddr_, symbolStruct.vaddr_);
812 EXPECT_EQ(symbol.len_, symbolStruct.len_);
813 EXPECT_EQ(symbol.name_, symbolStruct.symbolName_);
814 sfs.symbolStructs_.erase(sfs.symbolStructs_.begin());
815 }
816 }
817 }
818
819 /**
820 * @tc.name: exportSymbolToFileFormat
821 * @tc.desc:
822 * @tc.type: FUNC
823 */
824 HWTEST_F(SymbolsTest, exportSymbolToFileFormat, TestSize.Level1)
825 {
826 for (int type = 0; type < SYMBOL_UNKNOW_FILE; type++) {
827 auto symbolsFile = SymbolsFile::CreateSymbolsFile();
828 symbolsFile->filePath_ = std::to_string(rnd_());
829 symbolsFile->symbolFileType_ = static_cast<SymbolsFileType>(type);
830 symbolsFile->textExecVaddrFileOffset_ = rnd_();
831 symbolsFile->buildId_ = std::to_string(rnd_());
832 int nameIndex = 0;
833 // after LoadSymbolsFromSaved it will sort from low to high
834 // so we make a order item to test
835 constexpr int rndMax = 10000;
836 std::uniform_int_distribution<int> rndLimi(0, rndMax);
837 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
838 std::to_string(nameIndex), symbolsFile->filePath_);
839 nameIndex++;
840 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
841 std::to_string(nameIndex), symbolsFile->filePath_);
842 nameIndex++;
843 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
844 std::to_string(nameIndex), symbolsFile->filePath_);
845 nameIndex++;
846
847 // setup the min vaddr
848 symbolsFile->textExecVaddr_ = std::numeric_limits<uint64_t>::max();
849
850 for (auto &symbol : symbolsFile->symbols_) {
851 symbolsFile->textExecVaddr_ = std::min(symbol.vaddr_, symbolsFile->textExecVaddr_);
852 }
853
854 SymbolFileStruct sfs = symbolsFile->exportSymbolToFileFormat(false);
855
856 EXPECT_EQ(symbolsFile->symbolFileType_, sfs.symbolType_);
857 EXPECT_EQ(symbolsFile->textExecVaddr_, sfs.textExecVaddr_);
858 EXPECT_EQ(symbolsFile->textExecVaddrFileOffset_, sfs.textExecVaddrFileOffset_);
859 EXPECT_EQ(symbolsFile->GetBuildId(), sfs.buildId_);
860 EXPECT_EQ(symbolsFile->GetSymbols().size(), sfs.symbolStructs_.size());
861 for (Symbol symbol : symbolsFile->GetSymbols()) {
862 SymbolStruct symbolStruct = sfs.symbolStructs_.front();
863 EXPECT_EQ(symbol.vaddr_, symbolStruct.vaddr_);
864 EXPECT_EQ(symbol.len_, symbolStruct.len_);
865 EXPECT_EQ(symbol.name_, symbolStruct.symbolName_);
866 sfs.symbolStructs_.erase(sfs.symbolStructs_.begin());
867 }
868 }
869 }
870
871 /**
872 * @tc.name: exportSymbolToFileFormatMatched
873 * @tc.desc:
874 * @tc.type: FUNC
875 */
876 HWTEST_F(SymbolsTest, exportSymbolToFileFormatMatched, TestSize.Level1)
877 {
878 for (int type = 0; type < SYMBOL_UNKNOW_FILE; type++) {
879 auto symbolsFile = SymbolsFile::CreateSymbolsFile();
880 symbolsFile->filePath_ = std::to_string(rnd_());
881 symbolsFile->symbolFileType_ = static_cast<SymbolsFileType>(type);
882 symbolsFile->textExecVaddrFileOffset_ = rnd_();
883 symbolsFile->buildId_ = std::to_string(rnd_());
884 int nameIndex = 0;
885 // after LoadSymbolsFromSaved it will sort from low to high
886 // so we make a order item to test
887 constexpr int rndMax = 10000;
888 std::uniform_int_distribution<int> rndLimi(0, rndMax);
889 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
890 std::to_string(nameIndex), symbolsFile->filePath_);
891 nameIndex++;
892 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
893 std::to_string(nameIndex), symbolsFile->filePath_);
894 nameIndex++;
895 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
896 std::to_string(nameIndex), symbolsFile->filePath_);
897 nameIndex++;
898
899 // setup the min vaddr
900 symbolsFile->textExecVaddr_ = std::numeric_limits<uint64_t>::max();
901
902 for (auto &symbol : symbolsFile->symbols_) {
903 symbolsFile->textExecVaddr_ = std::min(symbol.vaddr_, symbolsFile->textExecVaddr_);
904 }
905
906 // access last one to make it as matched.
907 uint64_t matchedVaddr = symbolsFile->symbols_.back().vaddr_;
908 auto symbol = symbolsFile->GetSymbolWithVaddr(matchedVaddr);
909 EXPECT_EQ(symbol.vaddr_, matchedVaddr);
910 if (HasFailure()) {
911 PrintSymbols(symbolsFile->GetSymbols());
912 }
913
914 SymbolFileStruct sfs = symbolsFile->exportSymbolToFileFormat(true);
915
916 EXPECT_EQ(symbolsFile->symbolFileType_, sfs.symbolType_);
917 EXPECT_EQ(symbolsFile->textExecVaddrFileOffset_, sfs.textExecVaddrFileOffset_);
918 EXPECT_EQ(symbolsFile->GetBuildId(), sfs.buildId_);
919
920 // matched one should be remove
921 EXPECT_EQ(sfs.symbolStructs_.size(), 1u);
922 for (SymbolStruct symbolStruct : sfs.symbolStructs_) {
923 // nomore found for matched vaddr
924 EXPECT_EQ(symbolStruct.vaddr_, matchedVaddr);
925 }
926 }
927 }
928
929 /**
930 * @tc.name: UpdateBuildIdIfMatch
931 * @tc.desc:
932 * @tc.type: FUNC
933 */
934 HWTEST_F(SymbolsTest, UpdateBuildIdIfMatch, TestSize.Level1)
935 {
936 auto file = SymbolsFile::CreateSymbolsFile();
937 file->buildId_ = "123";
938 file->UpdateBuildIdIfMatch("456");
939 EXPECT_STREQ(file->buildId_.c_str(), "123");
940 EXPECT_STRNE(file->buildId_.c_str(), "456");
941 }
942 } // namespace NativeDaemon
943 } // namespace Developtools
944 } // namespace OHOS