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 printf("cannot access /sys/kernel/notes\n");
253 return;
254 }
255 // read from kernel runtime
256 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE);
257 ScopeDebugLevel tempLogLevel(LEVEL_VERBOSE);
258 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
259
260 const std::vector<DfxSymbol> &symbols = symbolsFile->GetSymbols();
261 EXPECT_EQ(symbols.empty(), false);
262
263 std::string modulesMap = ReadFileToString("/proc/modules");
264 int lines = std::count(modulesMap.begin(), modulesMap.end(), '\n');
265 if (lines < 0) {
266 return;
267 }
268 std::set<std::string> modulesCount;
269 for (auto &symbol : symbols) {
270 if (symbol.module_.length()) {
271 modulesCount.emplace(symbol.module_);
272 }
273 }
274
275 // add [kernel.kallsyms]
276 if (modulesCount.size() != lines + 1u) {
277 printf("warn: modulesCount != lines + 1, modulesCount: %zu\n", modulesCount.size());
278 }
279 if (HasFailure()) {
280 for (auto &module : modulesCount) {
281 printf("%s\n", module.c_str());
282 }
283 }
284
285 // try vmlinux
286 EXPECT_EQ(TestLoadSymbols(SYMBOL_KERNEL_FILE, TEST_FILE_VMLINUX), true);
287 EXPECT_EQ(TestLoadSymbols(SYMBOL_KERNEL_FILE, TEST_FILE_VMLINUX_STRIPPED), true);
288 EXPECT_EQ(TestLoadSymbols(SYMBOL_KERNEL_FILE, TEST_FILE_VMLINUX_STRIPPED_NOBUILDID), true);
289 // will be load from runtime, still return true
290 EXPECT_EQ(TestLoadSymbols(SYMBOL_KERNEL_FILE, TEST_FILE_VMLINUX_STRIPPED_BROKEN), true);
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 printf("cannot access /sys/kernel/notes\n");
343 return;
344 }
345
346 auto symbols = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE);
347 if ((0 == getuid())) {
348 HLOGD("in root mode");
349 EXPECT_EQ(symbols->LoadSymbols(), true);
350 CheckSymbols(symbols);
351 } else {
352 EXPECT_EQ(symbols->LoadSymbols(), true);
353 if (!KptrRestrict()) {
354 HLOGD("NOT KptrRestrict");
355 if (!symbols->GetSymbols().empty()) {
356 CheckSymbols(symbols);
357 } else {
358 printf("we found this issue in linux-5.10\n");
359 }
360 } else {
361 HLOGD("KptrRestrict");
362 ASSERT_EQ(symbols->GetSymbols().empty(), true);
363 }
364 }
365 }
366
367 /**
368 * @tc.name: GetSymbolWithVaddr
369 * @tc.desc:
370 * @tc.type: FUNC
371 */
372 HWTEST_F(SymbolsFileTest, GetSymbolWithVaddr2, TestSize.Level1)
373 {
374 auto elfSymbols = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
375 ASSERT_EQ(elfSymbols->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
376 EXPECT_EQ(elfSymbols->LoadSymbols(nullptr, TEST_FILE_ELF), true);
377 ASSERT_EQ(elfSymbols->GetSymbols().empty(), false);
378
379 /*
380 part of elf32_test's symbols
381 vaddr(hex) size(dec) name
382 00001000 0 _init
383 00001030 0
384 00001320 58 _start
385 00001512 27 main
386 0000145d 124 TestGlobalChildFunction
387 000014d9 57 TestGlobalParentFunction
388 // last one
389 00001b38 0 _fini
390
391 part of elf_test's symbols
392 vaddr(hex) size(dec) name
393 0000000000002000 0 _init
394 0000000000002020 0
395 00000000000022f0 47 _start
396 0000000000002478 15 main
397 00000000000023d9 110 TestGlobalChildFunction
398 0000000000002447 49 TestGlobalParentFunction
399 //last one
400 0000000000002aa8 0 _fini
401 */
402 #ifdef __arm__
403 ScopeDebugLevel tempLogLevel(LEVEL_MUCH, true);
404 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001320).GetName(), "_start");
405 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001359).GetName(), "_start");
406 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00001512).GetName(), "main");
407 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x0000152c).GetName(), "main");
408 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x0000145d).GetName(), "TestGlobalChildFunction");
409 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x000014d9).GetName(), "TestGlobalParentFunction");
410 #else
411 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x000022f0).GetName(), "_start");
412 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x0000231e).GetName(), "_start");
413 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002478).GetName(), "main");
414 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002486).GetName(), "main");
415 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x000023d9).GetName(), "TestGlobalChildFunction");
416 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(0x00002447).GetName(), "TestGlobalParentFunction");
417 #endif
418 if (HasFailure()) {
419 PrintSymbols(elfSymbols->GetSymbols());
420 }
421 }
422
423 /**
424 * @tc.name: GetSymbolWithVaddr
425 * @tc.desc:
426 * @tc.type: FUNC
427 */
428 HWTEST_F(SymbolsFileTest, GetSymbolWithVaddrFullMatch, TestSize.Level1)
429 {
430 auto elfSymbols = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
431 ASSERT_EQ(elfSymbols->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
432 if (elfSymbols->LoadSymbols(nullptr, TEST_SYMBOLS_FILE_ELF)) {
433 ASSERT_EQ(elfSymbols->GetSymbols().empty(), false);
434 /*
435 nm -C --defined-only symbols_file_test_elf64
436 addr = 1000 mangle name = _init
437 addr = 1040 mangle name = _start
438 addr = 1070 mangle name = deregister_tm_clones
439 addr = 10a0 mangle name = register_tm_clones
440 addr = 10e0 mangle name = __do_global_dtors_aux
441 addr = 1120 mangle name = frame_dummy
442 addr = 1129 mangle name = main
443 addr = 1140 mangle name = __libc_csu_init
444 addr = 11b0 mangle name = __libc_csu_fini
445
446 //last one
447 addr = 11b8 mangle name = _fini
448
449 nm -C --defined-only symbols_file_test_elf32
450 00001000 t _init
451 00001070 T _start
452 000010c0 t deregister_tm_clones
453 00001100 t register_tm_clones
454 00001150 t __do_global_dtors_aux
455 000011a0 t frame_dummy
456 000011ad T main
457 000011d0 T __libc_csu_init
458 00001240 T __libc_csu_fini
459
460 // last one
461 0000124c T _fini
462 */
463 #ifdef __arm__
464 enum SymbolAddr : uint64_t {
465 PLT = 0X1030U,
466 START = 0X1070U,
467 THUNK_AX = 0X10B0U,
468 DEREG = 0X10C0U,
469 REG = 0X1100U,
470 AUX = 0X1150U,
471 FRAME = 0X11A0U,
472 THUNK_DX = 0X11A9U,
473 MAIN = 0X11ADU,
474 THUNK_BX = 0X11C5U,
475 CSU_INIT = 0X11D0U,
476 CSU_FINI = 0X1240U,
477 THUNK_BP = 0X1245U,
478 };
479 #else
480 enum SymbolAddr : uint64_t {
481 PLT = 0X1020U,
482 START = 0X1040U,
483 DEREG = 0X1070U,
484 REG = 0X10A0U,
485 AUX = 0X10E0U,
486 FRAME = 0X1120U,
487 MAIN = 0X1129U,
488 CSU_INIT = 0X1140U,
489 CSU_FINI = 0X11B0U,
490 };
491 #endif
492 #ifdef __arm__
493 for (uint64_t addr = SymbolAddr::START; addr < SymbolAddr::THUNK_AX; ++addr) {
494 #else
495 for (uint64_t addr = SymbolAddr::START; addr < SymbolAddr::START; ++addr) {
496 #endif
497 if (elfSymbols->GetSymbolWithVaddr(addr).IsValid()) {
498 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(addr).demangle_, "_start");
499 }
500 }
501 for (uint64_t addr = SymbolAddr::DEREG; addr < SymbolAddr::REG; ++addr) {
502 if (elfSymbols->GetSymbolWithVaddr(addr).IsValid()) {
503 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(addr).demangle_, "deregister_tm_clones");
504 }
505 }
506 for (uint64_t addr = SymbolAddr::REG; addr < SymbolAddr::AUX; ++addr) {
507 if (elfSymbols->GetSymbolWithVaddr(addr).IsValid()) {
508 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(addr).demangle_, "register_tm_clones");
509 }
510 }
511 for (uint64_t addr = SymbolAddr::AUX; addr < SymbolAddr::FRAME; ++addr) {
512 if (elfSymbols->GetSymbolWithVaddr(addr).IsValid()) {
513 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(addr).demangle_, "__do_global_dtors_aux");
514 }
515 }
516 #ifdef __arm__
517 for (uint64_t addr = SymbolAddr::FRAME; addr < SymbolAddr::THUNK_DX; ++addr) {
518 #else
519 for (uint64_t addr = SymbolAddr::FRAME; addr < SymbolAddr::MAIN; ++addr) {
520 #endif
521 if (elfSymbols->GetSymbolWithVaddr(addr).IsValid()) {
522 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(addr).demangle_, "frame_dummy");
523 }
524 }
525 #ifdef __arm__
526 for (uint64_t addr = SymbolAddr::MAIN; addr < SymbolAddr::THUNK_BX; ++addr) {
527 #else
528 for (uint64_t addr = SymbolAddr::MAIN; addr < SymbolAddr::CSU_INIT; ++addr) {
529 #endif
530 if (elfSymbols->GetSymbolWithVaddr(addr).IsValid()) {
531 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(addr).demangle_, "main");
532 }
533 }
534 for (uint64_t addr = SymbolAddr::CSU_INIT; addr < SymbolAddr::CSU_FINI; ++addr) {
535 if (elfSymbols->GetSymbolWithVaddr(addr).IsValid()) {
536 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(addr).demangle_, "__libc_csu_init");
537 }
538 }
539 #ifdef __arm__
540 for (uint64_t addr = SymbolAddr::CSU_FINI; addr < SymbolAddr::THUNK_BP; ++addr) {
541 if (elfSymbols->GetSymbolWithVaddr(addr).IsValid()) {
542 EXPECT_EQ(elfSymbols->GetSymbolWithVaddr(addr).demangle_, "__libc_csu_fini");
543 }
544 }
545 #endif
546 if (HasFailure()) {
547 PrintSymbols(elfSymbols->GetSymbols());
548 }
549 }
550 }
551
552 /**
553 * @tc.name: GetVaddrInSymbols
554 * @tc.desc:
555 * @tc.type: FUNC
556 */
557 HWTEST_F(SymbolsFileTest, GetVaddrInSymbols, TestSize.Level1)
558 {
559 /*
560 00200000-002c5000 r--p 00000000 08:02 46400311
561 002c5000-00490000 r-xp 000c5000 08:02 4640031
562
563 [14] .text PROGBITS 00000000002c5000 000c5000
564
565 if ip is 0x46e6ab
566 1. find the map range is 002c5000-00490000
567 2. ip - map start(002c5000) = map section offset
568 3. map section offset + map page offset(000c5000) = elf file offset
569 4. elf file offset - exec file offset(000c5000)
570 = ip offset (ip always in exec file offset)
571 5. ip offset + exec begin vaddr(2c5000) = virtual ip in elf
572 */
573 auto elfSymbols = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
574 elfSymbols->textExecVaddrFileOffset_ = 0x000c5000;
575 elfSymbols->textExecVaddr_ = 0x002c5000;
576
577 // most easy case
578 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0x002c5123, 0x002c5000, 0x000c5000), 0x002c5123U);
579
580 // ip and map both change
581 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0xFF2c5123, 0xFF2c5000, 0x000c5000), 0x002c5123U);
582 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0x00000123, 0x00000000, 0x000c5000), 0x002c5123U);
583
584 // map page and offset change
585 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0x002ca123, 0x002c5000, 0x000c0000), 0x002c5123U);
586 EXPECT_EQ(elfSymbols->GetVaddrInSymbols(0x002c4123, 0x002c5000, 0x000c6000), 0x002c5123U);
587
588 // kernel dont care offset
589 auto kernelSymbols = SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE);
590 EXPECT_EQ(kernelSymbols->GetVaddrInSymbols(0x001234, 0x002c5000, 0x000c5000), 0x001234U);
591 }
592
593 /**
594 * @tc.name: FindSymbolFile
595 * @tc.desc:
596 * @tc.type: FUNC
597 */
598 HWTEST_F(SymbolsFileTest, FindSymbolFile, TestSize.Level1)
599 {
600 auto symbols = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
601
602 std::vector<std::string> symbolsFileSearchPaths;
603 std::string symboleFilePath;
604
605 symboleFilePath = TEST_FILE_VMLINUX;
606 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), true);
607
608 symbolsFileSearchPaths.emplace_back(PATH_RESOURCE_TEST_DATA);
609 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), false);
610
611 symbolsFileSearchPaths.clear();
612 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), true);
613
614 symboleFilePath = PATH_RESOURCE_TEST_DATA + TEST_FILE_VMLINUX;
615 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), false);
616
617 symbolsFileSearchPaths.emplace_back(PATH_RESOURCE_TEST_DATA);
618 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), false);
619
620 symboleFilePath = TEST_FILE_ELF;
621 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), false);
622
623 symbolsFileSearchPaths.clear();
624 EXPECT_EQ(symbols->FindSymbolFile(symbolsFileSearchPaths, symboleFilePath).empty(), true);
625 }
626
627 /**
628 * @tc.name: GetBuildId
629 * @tc.desc:
630 * @tc.type: FUNC
631 */
632 HWTEST_F(SymbolsFileTest, GetBuildId, TestSize.Level1)
633 {
634 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
635 // empty elf
636 EXPECT_EQ(symbolsFile->GetBuildId().empty(), true);
637 // set search path
638 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
639
640 symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
641 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
642 // kernel elf
643 EXPECT_EQ(symbolsFile->LoadSymbols(nullptr, TEST_FILE_VMLINUX), true);
644 EXPECT_EQ(symbolsFile->GetBuildId().empty(), false);
645
646 symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
647 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
648 // stripped elf
649 EXPECT_EQ(symbolsFile->LoadSymbols(nullptr, TEST_FILE_ELF), true);
650 EXPECT_EQ(symbolsFile->GetBuildId().empty(), false);
651
652 symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE);
653 ASSERT_EQ(symbolsFile->setSymbolsFilePath(PATH_RESOURCE_TEST_DATA), true);
654 // stripped elf
655 EXPECT_EQ(symbolsFile->LoadSymbols(nullptr, TEST_FILE_ELF_STRIPPED), true);
656 EXPECT_EQ(symbolsFile->GetBuildId().empty(), false);
657 }
658
659 struct sectionInfo {
660 const std::string name;
661 uint64_t addr;
662 uint64_t size;
663 uint64_t offset;
664 };
665
666 /**
667 * @tc.name: GetSectionInfo
668 * @tc.desc:
669 * @tc.type: FUNC
670 */
671 HWTEST_F(SymbolsFileTest, GetSectionInfo, TestSize.Level1)
672 {
673 std::unique_ptr<SymbolsFile> symbolsFile =
674 SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, TEST_FILE_ELF_FULL_PATH);
675 ASSERT_EQ(symbolsFile->LoadDebugInfo(), true);
676 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
677
678 /*
679 from readelf -e elf32_test
680 32bit
681 [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
682 [ 0] NULL 00000000 000000 000000 00 0 0 0
683 [ 1] .interp PROGBITS 000001b4 0001b4 000013 00 A 0 0 1
684 [ 2] .note.gnu.build-i NOTE 000001c8 0001c8 000024 00 A 0 0 4
685 [16] .text PROGBITS 00001320 001320 000818 00 AX 0 0 16
686 [19] .eh_frame_hdr PROGBITS 00002034 002034 0000dc 00 A 0 0 4
687 [20] .eh_frame PROGBITS 00002110 002110 0003a0 00 A 0 0 4
688 [29] .symtab SYMTAB 00000000 003034 000710 10 30 50 4
689 [30] .strtab STRTAB 00000000 003744 000c3d 00 0 0 1
690 [31] .shstrtab STRTAB 00000000 004381 00012a 00 0 0 1
691
692 from readelf -e elf_test
693 64bit
694 Section Headers:
695 [Nr] Name Type Address Offset
696 Size EntSize Flags Link Info Align
697 [ 0] NULL 0000000000000000 00000000
698 0000000000000000 0000000000000000 0 0 0
699 [ 1] .interp PROGBITS 0000000000000318 00000318
700 000000000000001c 0000000000000000 A 0 0 1
701 [ 2] .note.gnu.propert NOTE 0000000000000338 00000338
702 0000000000000020 0000000000000000 A 0 0 8
703 [16] .text PROGBITS 00000000000022f0 000022f0
704 00000000000007b5 0000000000000000 AX 0 0 16
705 [19] .eh_frame_hdr PROGBITS 0000000000003034 00003034
706 00000000000000bc 0000000000000000 A 0 0 4
707 [20] .eh_frame PROGBITS 00000000000030f0 000030f0
708 0000000000000320 0000000000000000 A 0 0 8
709 [29] .symtab SYMTAB 0000000000000000 00004040
710 00000000000009f0 0000000000000018 30 50 8
711 [30] .strtab STRTAB 0000000000000000 00004a30
712 0000000000000bbb 0000000000000000 0 0 1
713 [31] .shstrtab STRTAB 0000000000000000 000055eb
714 000000000000012c 0000000000000000 0 0 1
715 */
716 #ifdef __arm__
717 const std::vector<sectionInfo> sectionCheckList = {
718 {".note.gnu.build-id", 0x000001c8, 0x000024, 0x0001c8},
719 {".text", 0x00001320, 0x000818, 0x001320},
720 {".eh_frame_hdr", 0x00002034, 0x0000dc, 0x002034},
721 {".eh_frame", 0x00002110, 0x0003a0, 0x002110},
722 {".symtab", 0x00000000, 0x000710, 0x003034},
723 {".strtab", 0x00000000, 0x000c3d, 0x003744},
724 };
725 #else
726 const std::vector<sectionInfo> sectionCheckList = {
727 {".note.gnu.build-id", 0x0000000000000358, 0x0000000000000024, 0x00000358},
728 {".text", 0x00000000000022f0, 0x00000000000007b5, 0x000022f0},
729 {".eh_frame_hdr", 0x0000000000003034, 0x00000000000000bc, 0x00003034},
730 {".eh_frame", 0x00000000000030f0, 0x0000000000000320, 0x000030f0},
731 {".symtab", 0x00000000, 0x00000000000009f0, 0x00004040},
732 {".strtab", 0x00000000, 0x0000000000000bbb, 0x00004a30},
733 };
734 #endif
735 for (sectionInfo info : sectionCheckList) {
736 uint64_t addr;
737 uint64_t size;
738 uint64_t offset;
739 EXPECT_EQ(symbolsFile->GetSectionInfo(info.name, addr, size, offset), true);
740 EXPECT_EQ(addr, info.addr);
741 EXPECT_EQ(size, info.size);
742 EXPECT_EQ(offset, info.offset);
743 if (HasFailure()) {
744 printf("sectionInfo check failed at '%s', %" PRIx64 ",%" PRIx64 ",%" PRIx64 "\n",
745 info.name.c_str(), info.addr, info.size, info.offset);
746 }
747 }
748 }
749
750 #ifndef __arm__
751 /**
752 * @tc.name: GetHDRSectionInfo
753 * @tc.desc:
754 * @tc.type: FUNC
755 */
756 HWTEST_F(SymbolsFileTest, GetHDRSectionInfo, TestSize.Level1)
757 {
758 std::unique_ptr<SymbolsFile> symbolsFile =
759 SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, TEST_FILE_ELF_FULL_PATH);
760
761 ASSERT_EQ(symbolsFile->LoadSymbols(), true);
762 ASSERT_EQ(symbolsFile->LoadDebugInfo(), true);
763
764 uint64_t ehFrameHdrElfOffset;
765 uint64_t fdeTableElfOffset;
766 uint64_t fdeTableSize;
767
768 /*
769 readelf -e elf32_test | grep .eh_frame_hdr
770 [19] .eh_frame_hdr PROGBITS 00002034 002034 0000dc 00 A 0 0 4
771
772 readelf --debug-dump=frames elf32_test | grep FDE | wc -l
773 26
774
775 readelf -e elf_test | grep .eh_frame_hdr
776 [19] .eh_frame_hdr PROGBITS 0000000000003034 00003034
777
778 readelf --debug-dump=frames elf_test | grep FDE | wc -l
779 22
780 */
781 symbolsFile->GetHDRSectionInfo(ehFrameHdrElfOffset, fdeTableElfOffset, fdeTableSize);
782
783 EXPECT_EQ(ehFrameHdrElfOffset, 0x00003034u);
784 EXPECT_EQ(fdeTableSize, 22U);
785 }
786
787 /**
788 * @tc.name: GetHDRSectionInfo
789 * @tc.desc:
790 * @tc.type: FUNC
791 */
792 HWTEST_F(SymbolsFileTest, GetHDRSectionInfoStripped, TestSize.Level1)
793 {
794 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(
795 SYMBOL_ELF_FILE, PATH_RESOURCE_TEST_DATA + TEST_FILE_ELF_STRIPPED_NOEFHDR);
796
797 ASSERT_EQ(symbolsFile->LoadDebugInfo(), true);
798
799 uint64_t ehFrameHdrElfOffset;
800 uint64_t fdeTableElfOffset;
801 uint64_t fdeTableSize;
802
803 symbolsFile->GetHDRSectionInfo(ehFrameHdrElfOffset, fdeTableElfOffset, fdeTableSize);
804 uint64_t addr = 0;
805 uint64_t size = 0;
806 uint64_t offset = 0;
807 EXPECT_EQ(symbolsFile->GetSectionInfo(EH_FRAME_HR, addr, size, offset), false);
808 EXPECT_EQ(offset, 0U);
809 EXPECT_EQ(size, 0U);
810 EXPECT_EQ(addr, 0U);
811 }
812 #endif
813
814 /**
815 * @tc.name: CreateSymbolsFile
816 * @tc.desc:
817 * @tc.type: FUNC
818 */
819 HWTEST_F(SymbolsFileTest, CreateSymbolsFile, TestSize.Level1)
820 {
821 EXPECT_NE(SymbolsFile::CreateSymbolsFile(), nullptr);
822 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE), nullptr);
823 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_MODULE_FILE), nullptr);
824 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE), nullptr);
825 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_JAVA_FILE), nullptr);
826 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_JS_FILE), nullptr);
827 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE), nullptr);
828 EXPECT_NE(SymbolsFile::CreateSymbolsFile(SymbolsFileType(-1)), nullptr);
829 EXPECT_EQ(SymbolsFile::CreateSymbolsFile(SymbolsFileType(-2))->symbolFileType_,
830 SYMBOL_UNKNOW_FILE);
831
832 EXPECT_EQ(SymbolsFile::CreateSymbolsFile(KERNEL_MMAP_NAME)->symbolFileType_,
833 SYMBOL_KERNEL_FILE);
834 EXPECT_EQ(SymbolsFile::CreateSymbolsFile(TEST_FILE_ELF_FULL_PATH)->symbolFileType_,
835 SYMBOL_ELF_FILE);
836 }
837
838 /**
839 * @tc.name: LoadSymbolsFromSaved
840 * @tc.desc:
841 * @tc.type: FUNC
842 */
843 HWTEST_F(SymbolsFileTest, LoadSymbolsFromSaved, TestSize.Level1)
844 {
845 SymbolFileStruct sfs;
846 for (unsigned int type = 0; type < SYMBOL_UNKNOW_FILE; type++) {
847 sfs.filePath_ = std::to_string(rnd_());
848 sfs.symbolType_ = type;
849 sfs.textExecVaddrFileOffset_ = rnd_();
850 sfs.textExecVaddr_ = rnd_();
851 sfs.buildId_ = std::to_string(rnd_());
852 int nameIndex = 0;
853 // after LoadSymbolsFromSaved it will sort from low to high
854 // so we make a order item to test
855 constexpr int rndMax = 10000;
856 std::uniform_int_distribution<int> rndLimi(0, rndMax);
857 sfs.symbolStructs_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
858 std::to_string(nameIndex));
859 nameIndex++;
860 sfs.symbolStructs_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
861 std::to_string(nameIndex));
862 nameIndex++;
863 sfs.symbolStructs_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
864 std::to_string(nameIndex));
865 nameIndex++;
866
867 // setup the min vaddr
868
869 std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::LoadSymbolsFromSaved(sfs);
870
871 EXPECT_EQ(symbolsFile->filePath_, sfs.filePath_);
872 EXPECT_EQ(symbolsFile->symbolFileType_, sfs.symbolType_);
873 EXPECT_EQ(symbolsFile->textExecVaddr_, sfs.textExecVaddr_);
874 EXPECT_EQ(symbolsFile->textExecVaddrFileOffset_, sfs.textExecVaddrFileOffset_);
875 EXPECT_EQ(symbolsFile->GetBuildId(), sfs.buildId_);
876 EXPECT_EQ(symbolsFile->GetSymbols().size(), sfs.symbolStructs_.size());
877
878 for (DfxSymbol symbol : symbolsFile->GetSymbols()) {
879 SymbolStruct symbolStruct = sfs.symbolStructs_.front();
880 EXPECT_EQ(symbol.funcVaddr_, symbolStruct.vaddr_);
881 EXPECT_EQ(symbol.size_, symbolStruct.len_);
882 EXPECT_EQ(symbol.name_, symbolStruct.symbolName_);
883 sfs.symbolStructs_.erase(sfs.symbolStructs_.begin());
884 }
885 }
886 }
887
888 /**
889 * @tc.name: exportSymbolToFileFormatMatched
890 * @tc.desc:
891 * @tc.type: FUNC
892 */
893 HWTEST_F(SymbolsFileTest, exportSymbolToFileFormatMatched, TestSize.Level1)
894 {
895 for (int type = 0; type < SYMBOL_UNKNOW_FILE; type++) {
896 auto symbolsFile = SymbolsFile::CreateSymbolsFile();
897 symbolsFile->filePath_ = std::to_string(rnd_());
898 symbolsFile->symbolFileType_ = static_cast<SymbolsFileType>(type);
899 symbolsFile->textExecVaddrFileOffset_ = rnd_();
900 symbolsFile->buildId_ = std::to_string(rnd_());
901 int nameIndex = 0;
902 // after LoadSymbolsFromSaved it will sort from low to high
903 // so we make a order item to test
904 constexpr int rndMax = 10000;
905 std::uniform_int_distribution<int> rndLimi(0, rndMax);
906 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
907 std::to_string(nameIndex), symbolsFile->filePath_);
908 nameIndex++;
909 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
910 std::to_string(nameIndex), symbolsFile->filePath_);
911 nameIndex++;
912 symbolsFile->symbols_.emplace_back(rndLimi(rnd_) + nameIndex * rndMax, rnd_(),
913 std::to_string(nameIndex), symbolsFile->filePath_);
914 nameIndex++;
915
916 // setup the min vaddr
917 symbolsFile->textExecVaddr_ = std::numeric_limits<uint64_t>::max();
918
919 for (auto &symbol : symbolsFile->symbols_) {
920 symbolsFile->textExecVaddr_ = std::min(symbol.funcVaddr_, symbolsFile->textExecVaddr_);
921 }
922
923 // access last one to make it as matched.
924 uint64_t matchedVaddr = symbolsFile->symbols_.back().funcVaddr_;
925 auto symbol = symbolsFile->GetSymbolWithVaddr(matchedVaddr);
926 EXPECT_EQ(symbol.funcVaddr_, matchedVaddr);
927 if (HasFailure()) {
928 PrintSymbols(symbolsFile->GetSymbols());
929 }
930
931 SymbolFileStruct sfs {};
932 symbolsFile->ExportSymbolToFileFormat(sfs);
933
934 EXPECT_EQ(symbolsFile->symbolFileType_, sfs.symbolType_);
935 EXPECT_EQ(symbolsFile->textExecVaddrFileOffset_, sfs.textExecVaddrFileOffset_);
936 EXPECT_EQ(symbolsFile->GetBuildId(), sfs.buildId_);
937
938 // matched one should be remove
939 EXPECT_EQ(sfs.symbolStructs_.size(), 1u);
940 for (SymbolStruct symbolStruct : sfs.symbolStructs_) {
941 // nomore found for matched vaddr
942 EXPECT_EQ(symbolStruct.vaddr_, matchedVaddr);
943 }
944 }
945 }
946
947 /**
948 * @tc.name: UpdateBuildIdIfMatch
949 * @tc.desc:
950 * @tc.type: FUNC
951 */
952 HWTEST_F(SymbolsFileTest, UpdateBuildIdIfMatch, TestSize.Level1)
953 {
954 auto file = SymbolsFile::CreateSymbolsFile();
955 file->buildId_ = "123";
956 file->UpdateBuildIdIfMatch("456");
957 EXPECT_STREQ(file->buildId_.c_str(), "123");
958 EXPECT_STRNE(file->buildId_.c_str(), "456");
959 }
960 } // namespace HiPerf
961 } // namespace Developtools
962 } // namespace OHOS
963