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