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 #define HILOG_TAG "Symbols"
17
18 #include "symbols_file.h"
19
20 #include <algorithm>
21 #include <chrono>
22 #include <cxxabi.h>
23 #include <cstdlib>
24 #include <fcntl.h>
25 #include <fstream>
26 #include <string_view>
27 #include <type_traits>
28
29 #if defined(is_mingw) && is_mingw
30 #include <memoryapi.h>
31 #else
32 #include <sys/mman.h>
33 #include <sys/stat.h>
34 #endif
35 #include <unistd.h>
36
37 #include "dfx_ark.h"
38 #include "dfx_extractor_utils.h"
39 #include "dfx_symbols.h"
40 #include "dwarf_encoding.h"
41 #include "hiperf_hilog.h"
42 #include "unwinder_config.h"
43 #include "utilities.h"
44
45 using namespace OHOS::HiviewDFX;
46 using namespace std::chrono;
47
48 namespace OHOS {
49 namespace Developtools {
50 namespace HiPerf {
51 bool SymbolsFile::onRecording_ = true;
52 bool SymbolsFile::needParseJsFunc_ = false;
53
GetBuildId() const54 const std::string SymbolsFile::GetBuildId() const
55 {
56 return buildId_;
57 }
58
UpdateBuildIdIfMatch(std::string buildId)59 bool SymbolsFile::UpdateBuildIdIfMatch(std::string buildId)
60 {
61 /*
62 here we have two case
63 1 buildId_ is empty
64 a) always return match
65 2 buildId_ is not empty
66 a) really check if the same one
67 */
68
69 if (buildId_.empty()) {
70 // we have new empty build
71 if (buildId.empty()) {
72 // both empty , no build id provided
73 HLOGD("build id is empty.");
74 return true;
75 } else {
76 buildId_ = buildId;
77 HLOGD("new buildId %s", buildId_.c_str());
78 return true;
79 }
80 } else {
81 // we already have a build id
82 // so this is not the first time load symbol
83 // we need check if it match
84 HLOGV("expected buildid: %s vs %s", buildId_.c_str(), buildId.c_str());
85
86 if (buildId_ != buildId) {
87 HLOGW("id not match");
88 return false;
89 } else {
90 HLOGD("id match");
91 return true;
92 }
93 }
94 }
95
SearchReadableFile(const std::vector<std::string> &searchPaths, const std::string &filePath) const96 std::string SymbolsFile::SearchReadableFile(const std::vector<std::string> &searchPaths,
97 const std::string &filePath) const
98 {
99 if (filePath.empty()) {
100 HLOGW("nothing to found");
101 return filePath;
102 }
103 for (auto searchPath : searchPaths) {
104 if (searchPath.back() != PATH_SEPARATOR) {
105 searchPath += PATH_SEPARATOR;
106 }
107 std::string PossibleFilePath = searchPath + filePath;
108 if (CheckPathReadable(PossibleFilePath)) {
109 return PossibleFilePath;
110 }
111 HLOGW("have not found '%s' in search paths %s", filePath.c_str(), searchPath.c_str());
112 }
113 return EMPTY_STRING;
114 }
115
FindSymbolFile( const std::vector<std::string> &symbolsFileSearchPaths, std::string symboleFilePath) const116 const std::string SymbolsFile::FindSymbolFile(
117 const std::vector<std::string> &symbolsFileSearchPaths, std::string symboleFilePath) const
118 {
119 /*
120 this function do 2 things:
121 find by name:
122 1 find dso path
123 2 find search path
124 a) search path + dso path
125 b) search path + dso name
126
127 show we should return filePath_ as default ?
128 */
129 if (symboleFilePath.empty()) {
130 symboleFilePath = filePath_;
131 HLOGD("use default filename: %s ", symboleFilePath.c_str());
132 }
133 symboleFilePath = PlatformPathConvert(symboleFilePath);
134 std::string foundPath;
135 // search first if we have path
136 if (symbolsFileSearchPaths.size() != 0) {
137 foundPath = SearchReadableFile(symbolsFileSearchPaths, symboleFilePath);
138 if (foundPath.empty()) {
139 HLOGV("try base name for: %s split with %s", symboleFilePath.c_str(),
140 PATH_SEPARATOR_STR.c_str());
141 auto pathSplit = StringSplit(symboleFilePath, PATH_SEPARATOR_STR);
142 if (pathSplit.size() > 1) {
143 HLOGV("base name is: %s ", pathSplit.back().c_str());
144 // found it again with base name , split it and get last name
145 foundPath = SearchReadableFile(symbolsFileSearchPaths, pathSplit.back());
146 }
147 }
148 }
149
150 // only access the patch in onRecording_
151 // in report mode we don't load any thing in runtime path
152 if (foundPath.empty() and onRecording_) {
153 // try access direct at last
154 if (CheckPathReadable(symboleFilePath)) {
155 // found direct folder
156 HLOGD("find %s in current work dir", symboleFilePath.c_str());
157 return symboleFilePath;
158 }
159 }
160 return foundPath;
161 }
162
163 class ElfFileSymbols : public SymbolsFile {
164 public:
ElfFileSymbols(const std::string &symbolFilePath, const SymbolsFileType symbolsFileType = SYMBOL_ELF_FILE)165 explicit ElfFileSymbols(const std::string &symbolFilePath,
166 const SymbolsFileType symbolsFileType = SYMBOL_ELF_FILE)
167 : SymbolsFile(symbolsFileType, symbolFilePath)
168 {
169 }
170
~ElfFileSymbols()171 virtual ~ElfFileSymbols()
172 {
173 }
174
175 DfxSymbol GetSymbolWithPcAndMap(uint64_t pc, std::shared_ptr<DfxMap> map) override
176 {
177 const DfxSymbol symbol;
178 return symbol;
179 }
180
181 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
182 {
183 symbolsLoaded_ = true;
184 std::string findPath = FindSymbolFile(symbolsFileSearchPaths_, symbolFilePath);
185 if (findPath.empty() && elfFile_ == nullptr) { // elf not compressed in hap has been initialized before
186 HLOGW("elf found failed (belong to %s)", filePath_.c_str());
187 return false;
188 }
189 if (LoadElfSymbols(map, findPath)) {
190 return true;
191 } else {
192 HLOGW("elf open failed with '%s'", findPath.c_str());
193 return false;
194 }
195 return false;
196 }
197
198 void EnableMiniDebugInfo() override
199 {
200 UnwinderConfig::SetEnableMiniDebugInfo(true);
201 }
202
203 std::shared_ptr<DfxElf> GetElfFile() override
204 {
205 return elfFile_;
206 }
207
208 const std::unordered_map<uint64_t, ElfLoadInfo> GetPtLoads() override
209 {
210 CHECK_TRUE(elfFile_ == nullptr, info_, 0, "");
211 return elfFile_->GetPtLoads();
212 }
213
214 protected:
215 bool LoadDebugInfo(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
216 {
217 std::lock_guard<std::mutex> lock(mutex_);
218 if (debugInfoLoadResult_) {
219 return true; // it must have been loaded
220 } else if (debugInfoLoaded_) {
221 return debugInfoLoadResult_; // return the result of loaded
222 } else {
223 debugInfoLoaded_ = true;
224 }
225 std::string elfPath = FindSymbolFile(symbolsFileSearchPaths_, symbolFilePath);
226 if (elfPath.empty()) {
227 HLOGW("elf found failed (belong to %s)", filePath_.c_str());
228 return false;
229 }
230
231 if (elfFile_ == nullptr) {
232 if (StringEndsWith(elfPath, ".hap")) {
233 CHECK_TRUE(map == nullptr, false, 1, "map should not be nullptr.");
234 elfFile_ = DfxElf::CreateFromHap(elfPath, map->prevMap, map->offset);
235 HLOGD("try create elf from hap");
236 } else {
237 elfFile_ = std::make_shared<DfxElf>(elfPath);
238 }
239 }
240
241 CHECK_TRUE(elfFile_ == nullptr, false, 1, "Failed to create elf file for %s.", elfPath.c_str());
242
243 CHECK_TRUE(!elfFile_->IsValid(), false, 1, "parser elf file failed.");
244
245 HLOGD("loaded elf %s", elfPath.c_str());
246 // update path for so in hap
247 if (StringEndsWith(elfPath, ".hap")) {
248 filePath_ = elfPath + "!" + elfFile_->GetElfName();
249 HLOGD("update path for so in hap %s.", filePath_.c_str());
250 if (map == nullptr) {
251 HLOGW("map should not be nullptr.");
252 return false;
253 }
254 map->name = filePath_;
255 map->elf = elfFile_;
256 map->prevMap->name = filePath_;
257 map->prevMap->elf = elfFile_;
258 }
259
260 textExecVaddr_ = elfFile_->GetStartVaddr();
261 textExecVaddrFileOffset_ = elfFile_->GetStartOffset();
262
263 HLOGD("textExecVaddr_ 0x%016" PRIx64 " file offset 0x%016" PRIx64 "", textExecVaddr_,
264 textExecVaddrFileOffset_);
265
266 #ifndef __arm__
267 ShdrInfo shinfo;
268 if (elfFile_->GetSectionInfo(shinfo, ".eh_frame_hdr")) {
269 auto mmapPtr = elfFile_->GetMmapPtr();
270 CHECK_TRUE(mmapPtr == nullptr, false, 1, "mmapPtr should not be nullptr.");
271 LoadEhFrameHDR(mmapPtr + shinfo.offset, shinfo.size, shinfo.offset);
272 }
273 #endif
274
275 HLOGD("LoadDebugInfo success!");
276 debugInfoLoadResult_ = true;
277 return true;
278 }
279
280 private:
281 bool EhFrameHDRValid_ {false};
282 uint64_t ehFrameHDRElfOffset_ {0};
283 uint64_t ehFrameHDRFdeCount_ {0};
284 uint64_t ehFrameHDRFdeTableItemSize_ {0};
285 uint64_t ehFrameHDRFdeTableElfOffset_ {0};
286 std::shared_ptr<DfxElf> elfFile_;
287 std::unordered_map<uint64_t, ElfLoadInfo> info_;
288
289 bool GetSectionInfo(const std::string &name, uint64_t §ionVaddr, uint64_t §ionSize,
290 uint64_t §ionFileOffset) const override
291 {
292 struct ShdrInfo shdrInfo;
293 if (elfFile_->GetSectionInfo(shdrInfo, name)) {
294 sectionVaddr = shdrInfo.addr;
295 sectionSize = shdrInfo.size;
296 sectionFileOffset = shdrInfo.offset;
297 HLOGM("Get Section '%s' %" PRIx64 " - %" PRIx64 "", name.c_str(), sectionVaddr, sectionSize);
298 return true;
299 } else {
300 HLOGW("Section '%s' not found", name.c_str());
301 return false;
302 }
303 }
304
305 #ifndef __arm__
306 bool GetHDRSectionInfo(uint64_t &ehFrameHdrElfOffset, uint64_t &fdeTableElfOffset,
307 uint64_t &fdeTableSize) override
308 {
309 CHECK_TRUE(elfFile_ == nullptr, false, 0, "");
310 ShdrInfo shinfo;
311 if (!elfFile_->GetSectionInfo(shinfo, ".eh_frame_hdr")) {
312 return false;
313 }
314
315 ehFrameHDRElfOffset_ = shinfo.offset;
316 if (EhFrameHDRValid_) {
317 ehFrameHdrElfOffset = ehFrameHDRElfOffset_;
318 fdeTableElfOffset = ehFrameHDRFdeTableElfOffset_;
319 fdeTableSize = ehFrameHDRFdeCount_;
320 return true;
321 }
322 auto mmapPtr = elfFile_->GetMmapPtr();
323 if (mmapPtr == nullptr) {
324 HLOGE("mmapPtr should not be nullptr.");
325 return false;
326 }
327 if (!LoadEhFrameHDR(mmapPtr + shinfo.offset, elfFile_->GetMmapSize(), shinfo.offset)) {
328 HLOGW("Failed to load eh_frame_hdr");
329 return false;
330 }
331
332 ehFrameHdrElfOffset = ehFrameHDRElfOffset_;
333 fdeTableElfOffset = ehFrameHDRFdeTableElfOffset_;
334 fdeTableSize = ehFrameHDRFdeCount_;
335 return true;
336 }
337 #endif
338
DumpEhFrameHDR()339 void DumpEhFrameHDR()
340 {
341 HLOGD(" ehFrameHDRElfOffset_: 0x%" PRIx64 "", ehFrameHDRElfOffset_);
342 HLOGD(" ehFrameHDRFdeCount_: 0x%" PRIx64 "", ehFrameHDRFdeCount_);
343 HLOGD(" ehFrameHDRFdeTableElfOffset_: 0x%" PRIx64 "", ehFrameHDRFdeTableElfOffset_);
344 HLOGD(" ehFrameHDRFdeTableItemSize_: 0x%" PRIx64 "", ehFrameHDRFdeTableItemSize_);
345 }
346
LoadEhFrameHDR(const unsigned char *buffer, size_t bufferSize, uint64_t shdrOffset)347 bool LoadEhFrameHDR(const unsigned char *buffer, size_t bufferSize, uint64_t shdrOffset)
348 {
349 const eh_frame_hdr *ehFrameHdr = reinterpret_cast<const eh_frame_hdr *>(buffer);
350 CHECK_TRUE(ehFrameHdr == nullptr, false, 0, "");
351 const uint8_t *dataPtr = ehFrameHdr->encode_data;
352 DwarfEncoding dwEhFramePtr(ehFrameHdr->eh_frame_ptr_enc, dataPtr);
353 DwarfEncoding dwFdeCount(ehFrameHdr->fde_count_enc, dataPtr);
354 DwarfEncoding dwTable(ehFrameHdr->table_enc, dataPtr);
355 DwarfEncoding dwTableValue(ehFrameHdr->table_enc, dataPtr);
356
357 HLOGD("eh_frame_hdr:");
358 HexDump(ehFrameHdr, BITS_OF_FOUR_BYTE, bufferSize);
359 unsigned char version = ehFrameHdr->version;
360 HLOGD(" version: %02x:%s", version, (version == 1) ? "valid" : "invalid");
361 HLOGD(" eh_frame_ptr_enc: %s", dwEhFramePtr.ToString().c_str());
362 HLOGD(" fde_count_enc: %s", dwFdeCount.ToString().c_str());
363 HLOGD(" table_enc: %s", dwTable.ToString().c_str());
364 HLOGD(" table_value_enc: %s", dwTableValue.ToString().c_str());
365 HLOGD(" table_item_size: %zd", dwTable.GetSize() + dwTableValue.GetSize());
366 HLOGD(" table_offset_in_hdr: %zu", dwTable.GetData() - buffer);
367
368 CHECK_TRUE(version != 1, false, 1, "eh_frame_hdr version is invalid");
369 EhFrameHDRValid_ = true;
370 ehFrameHDRElfOffset_ = shdrOffset;
371 ehFrameHDRFdeCount_ = dwFdeCount.GetAppliedValue();
372 ehFrameHDRFdeTableElfOffset_ = dwTable.GetData() - buffer + shdrOffset;
373 ehFrameHDRFdeTableItemSize_ = dwTable.GetSize() + dwTableValue.GetSize();
374 DumpEhFrameHDR();
375
376 if (!dwFdeCount.IsOmit() && dwFdeCount.GetValue() > 0) {
377 return true;
378 } else {
379 HLOGW("fde table not found.\n");
380 }
381 return false;
382 }
383
UpdateSymbols(std::vector<DfxSymbol> &symbolsTable, const std::string &elfPath)384 void UpdateSymbols(std::vector<DfxSymbol> &symbolsTable, const std::string &elfPath)
385 {
386 symbols_.clear();
387 HLOGD("%zu symbols loadded from symbolsTable.", symbolsTable.size());
388
389 symbols_.swap(symbolsTable);
390
391 AdjustSymbols();
392 HLOGD("%zu symbols loadded from elf '%s'.", symbols_.size(), elfPath.c_str());
393 for (auto& symbol: symbols_) {
394 HLOGD("symbol %s", symbol.ToDebugString().c_str());
395 }
396 if (buildId_.empty()) {
397 HLOGD("buildId not found from elf '%s'.", elfPath.c_str());
398 // don't failed. some time the lib have not got the build id
399 // buildId not found from elf '/system/bin/ld-musl-arm.so.1'.
400 }
401 }
402
AddSymbols(std::vector<DfxSymbol>& symbolsTable, std::shared_ptr<DfxElf> elf, const std::string& filePath)403 void AddSymbols(std::vector<DfxSymbol>& symbolsTable, std::shared_ptr<DfxElf> elf, const std::string& filePath)
404 {
405 // use elfFile_ to get symbolsTable
406 DfxSymbols::ParseSymbols(symbolsTable, elf, filePath);
407 DfxSymbols::AddSymbolsByPlt(symbolsTable, elf, filePath);
408 }
409
LoadElfSymbols(std::shared_ptr<DfxMap> map, std::string elfPath)410 bool LoadElfSymbols(std::shared_ptr<DfxMap> map, std::string elfPath)
411 {
412 #ifdef HIPERF_DEBUG_TIME
413 const auto startTime = steady_clock::now();
414 #endif
415 if (elfFile_ == nullptr) {
416 if (StringEndsWith(elfPath, ".hap") && map != nullptr) {
417 elfFile_ = DfxElf::CreateFromHap(elfPath, map->prevMap, map->offset);
418 map->elf = elfFile_;
419 } else {
420 elfFile_ = std::make_shared<DfxElf>(elfPath);
421 }
422 }
423 CHECK_TRUE(elfFile_ == nullptr, false, 1, "Failed to create elf file for %s.", elfPath.c_str());
424 HLOGD("loaded elf %s", elfPath.c_str());
425 if (!elfFile_->IsValid()) {
426 HLOGD("parser elf file failed.");
427 return false;
428 }
429
430 textExecVaddr_ = elfFile_->GetStartVaddr();
431 textExecVaddrFileOffset_ = elfFile_->GetStartOffset();
432 HLOGD("textExecVaddr_ 0x%016" PRIx64 " file offset 0x%016" PRIx64 "", textExecVaddr_,
433 textExecVaddrFileOffset_);
434
435 // we prepare two table here
436 // only one we will push in to symbols_
437 // or both drop if build id is not same
438 std::string buildIdFound = elfFile_->GetBuildId();
439 std::vector<DfxSymbol> symbolsTable;
440 AddSymbols(symbolsTable, elfFile_, filePath_);
441 if (UpdateBuildIdIfMatch(buildIdFound)) {
442 UpdateSymbols(symbolsTable, elfPath);
443 } else {
444 HLOGW("symbols will not update for '%s' because buildId is not match.",
445 elfPath.c_str());
446 // this mean failed . we don't goon for this.
447 return false;
448 }
449
450 #ifdef HIPERF_DEBUG_TIME
451 auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
452 if (usedTime.count() != 0) {
453 HLOGV("cost %0.3f ms to load symbols '%s'",
454 usedTime.count() / static_cast<double>(milliseconds::duration::period::den),
455 elfPath.c_str());
456 }
457 #endif
458 return true;
459 }
460
461 uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart,
462 uint64_t mapPageOffset) const override
463 {
464 /*
465 00200000-002c5000 r--p 00000000 08:02 46400311
466 002c5000-00490000 r-xp 000c5000 08:02 4640031
467
468 [14] .text PROGBITS 00000000002c5000 000c5000
469
470 if ip is 0x46e6ab
471 1. find the map range is 002c5000-00490000
472 2. ip - map start(002c5000) = map section offset
473 3. map section offset + map page offset(000c5000) = elf file offset
474 4. elf file offset - exec file offset(000c5000)
475 = ip offset (ip always in exec file offset)
476 5. ip offset + exec begin vaddr(2c5000) = virtual ip in elf
477 */
478 uint64_t vaddr = ip - mapStart + mapPageOffset - textExecVaddrFileOffset_ + textExecVaddr_;
479 HLOGM(" ip :0x%016" PRIx64 " -> elf offset :0x%016" PRIx64 " -> vaddr :0x%016" PRIx64 " ",
480 ip, ip - mapStart + mapPageOffset, vaddr);
481 HLOGM("(minExecAddrFileOffset_ is 0x%" PRIx64 " textExecVaddr_ is 0x%" PRIx64 ")",
482 textExecVaddrFileOffset_, textExecVaddr_);
483 return vaddr;
484 }
485 };
486
487 class KernelSymbols : public ElfFileSymbols {
488 public:
KernelSymbols(const std::string &symbolFilePath)489 explicit KernelSymbols(const std::string &symbolFilePath)
490 : ElfFileSymbols(symbolFilePath, SYMBOL_KERNEL_FILE)
491 {
492 }
493
KernelSymbols(const std::string &symbolFilePath, const SymbolsFileType symbolsFileType)494 KernelSymbols(const std::string &symbolFilePath,
495 const SymbolsFileType symbolsFileType)
496 : ElfFileSymbols(symbolFilePath, symbolsFileType)
497 {
498 }
499
500 static constexpr const int KSYM_MIN_TOKENS = 3;
501 static constexpr const int KSYM_DEFAULT_LINE = 35000;
502 static constexpr const int KSYM_DEFAULT_SIZE = 1024 * 1024 * 1; // 1MB
503
ParseKallsymsLine(const std::string &kallsymsPath)504 bool ParseKallsymsLine(const std::string &kallsymsPath)
505 {
506 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
507 const auto startTime = steady_clock::now();
508 std::chrono::microseconds parseLineTime = std::chrono::microseconds::zero();
509 std::chrono::microseconds sscanfTime = std::chrono::microseconds::zero();
510 std::chrono::microseconds newTime = std::chrono::microseconds::zero();
511 std::chrono::microseconds readFileTime = std::chrono::microseconds::zero();
512 #endif
513 size_t lines = 0;
514 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
515 const auto eachFileStartTime = steady_clock::now();
516 #endif
517 std::string kallsym;
518 CHECK_TRUE(!ReadFileToString(kallsymsPath, kallsym, KSYM_DEFAULT_SIZE) || kallsym.empty(), false, 1,
519 "%s load failed.", kallsymsPath.c_str());
520 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
521 // any way we finish the line scan
522 readFileTime += duration_cast<milliseconds>(steady_clock::now() - eachFileStartTime);
523 #endif
524 // reduce the mem alloc
525 symbols_.reserve(KSYM_DEFAULT_LINE);
526
527 char *lineBegin = kallsym.data();
528 char *dataEnd = lineBegin + kallsym.size();
529 while (lineBegin < dataEnd) {
530 char *lineEnd = strchr(lineBegin, '\n');
531 if (lineEnd != nullptr) {
532 *lineEnd = '\0';
533 } else {
534 lineEnd = dataEnd;
535 }
536 size_t lineSize = (lineEnd != nullptr) ? (lineEnd - lineBegin) : (dataEnd - lineBegin);
537
538 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
539 const auto eachLineStartTime = steady_clock::now();
540 #endif
541 lines++;
542 uint64_t addr = 0;
543 char type = '\0';
544
545 char nameRaw[lineSize];
546 char moduleRaw[lineSize];
547 int ret = sscanf_s(lineBegin, "%" PRIx64 " %c %s%s", &addr, &type, sizeof(type),
548 nameRaw, sizeof(nameRaw), moduleRaw, sizeof(moduleRaw));
549
550 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
551 // any way we finish the line scan
552 sscanfTime += duration_cast<milliseconds>(steady_clock::now() - eachLineStartTime);
553 #endif
554 if (ret >= KSYM_MIN_TOKENS) {
555 if (ret == KSYM_MIN_TOKENS) {
556 moduleRaw[0] = '\0';
557 }
558 HLOGM(" 0x%016" PRIx64 " %c '%s' '%s'", addr, type, nameRaw, moduleRaw);
559 } else {
560 HLOGW("unknown line %d: '%s'", ret, lineBegin);
561 lineBegin = lineEnd + 1;
562 continue;
563 }
564 lineBegin = lineEnd + 1;
565 std::string name = nameRaw;
566 std::string module = moduleRaw;
567
568 /*
569 T
570 The symbol is in the text (code) section.
571
572 W
573 The symbol is a weak symbol that has not been specifically
574 tagged as a weak object symbol. When a weak defined symbol is
575 linked with a normal defined symbol, the normal defined symbol
576 is used with no error. When a weak undefined symbol is linked
577 and the symbol is not defined, the value of the weak symbol
578 becomes zero with no error.
579 */
580 if (addr != 0 && strchr("TtWw", type)) {
581 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
582 const auto eachNewSymbolTime = steady_clock::now();
583 #endif
584 // we only need text symbols
585 symbols_.emplace_back(addr, name, module.empty() ? filePath_ : module);
586 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
587 newTime += duration_cast<milliseconds>(steady_clock::now() - eachNewSymbolTime);
588 #endif
589 }
590 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
591 parseLineTime += duration_cast<milliseconds>(steady_clock::now() - eachLineStartTime);
592 #endif
593 }
594 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
595 std::chrono::microseconds usedTime =
596 duration_cast<milliseconds>(steady_clock::now() - startTime);
597 printf("parse kernel symbols use : %0.3f ms\n", usedTime.count() / MS_DURATION);
598 printf("parse line use : %0.3f ms\n", parseLineTime.count() / MS_DURATION);
599 printf("sscanf line use : %0.3f ms\n", sscanfTime.count() / MS_DURATION);
600 printf("new symbols use : %0.3f ms\n", newTime.count() / MS_DURATION);
601 printf("read file use : %0.3f ms\n", readFileTime.count() / MS_DURATION);
602 #endif
603 HLOGD("load %s: %zu line processed(%zu symbols)", kallsymsPath.c_str(), lines, symbols_.size());
604 return true;
605 }
606
607 const std::string KPTR_RESTRICT = "/proc/sys/kernel/kptr_restrict";
608
LoadKernelSyms()609 bool LoadKernelSyms()
610 {
611 if (!IsRoot()) {
612 return false;
613 }
614 HLOGD("try read /proc/kallsyms");
615 if (access("/proc/kallsyms", R_OK) != 0) {
616 printf("No vmlinux path is given, and kallsyms cannot be opened\n");
617 return false;
618 }
619 bool hasChangeKptr = false;
620 std::string oldKptrRestrict = ReadFileToString(KPTR_RESTRICT);
621 if (oldKptrRestrict.front() != '0') {
622 printf("/proc/sys/kernel/kptr_restrict is NOT 0, will try set it to 0.\n");
623 hasChangeKptr = WriteStringToFile(KPTR_RESTRICT, "0");
624 if (!hasChangeKptr) {
625 printf("/proc/sys/kernel/kptr_restrict write failed and we can't not change it.\n");
626 }
627 }
628
629 // getline end
630 CHECK_TRUE(!ParseKallsymsLine("/proc/kallsyms"), false, 0, "");
631
632 if (hasChangeKptr) {
633 if (!WriteStringToFile(KPTR_RESTRICT, oldKptrRestrict)) {
634 printf("recover /proc/sys/kernel/kptr_restrict fail.\n");
635 }
636 }
637
638 if (symbols_.empty()) {
639 printf("The symbol table addresses in /proc/kallsyms are all 0.\n"
640 "Please check the value of /proc/sys/kernel/kptr_restrict, it "
641 "should be 0.\n"
642 "Or provide a separate vmlinux path.\n");
643
644 if (buildId_.size() != 0) {
645 // but we got the buildid , so we make a dummpy symbols
646 HLOGD("kallsyms not found. but we have the buildid");
647 return true;
648 } else {
649 // we got nothing
650 return false;
651 }
652 } else {
653 AdjustSymbols();
654 HLOGV("%zu symbols_ loadded from kallsyms.\n", symbols_.size());
655 return true;
656 }
657 }
658 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
659 {
660 symbolsLoaded_ = true;
661 HLOGV("KernelSymbols try read '%s' search paths size %zu, inDeviceRecord %d",
662 symbolFilePath.c_str(), symbolsFileSearchPaths_.size(), onRecording_);
663
664 if (onRecording_) {
665 const auto startTime = std::chrono::steady_clock::now();
666 if (!LoadKernelSyms()) {
667 if (IsRoot()) {
668 printf("parse kalsyms failed.\n");
669 }
670 return false;
671 } else {
672 const auto thisTime = std::chrono::steady_clock::now();
673 const auto usedTimeMsTick =
674 std::chrono::duration_cast<std::chrono::milliseconds>(thisTime - startTime);
675 HLOGV("Load kernel symbols (total %" PRId64 " ms)\n", (int64_t)usedTimeMsTick.count());
676 // load complete
677 return true;
678 }
679
680 // try read
681 HLOGD("try read /sys/kernel/notes");
682 std::string notes = ReadFileToString("/sys/kernel/notes");
683 if (notes.empty()) {
684 printf("notes cannot be opened, unable get buildid\n");
685 return false;
686 } else {
687 HLOGD("kernel notes size: %zu", notes.size());
688 buildId_ = DfxElf::GetBuildId((uint64_t)notes.data(), (uint64_t)notes.size());
689 }
690 } // no search path
691
692 // try vmlinux
693 return ElfFileSymbols::LoadSymbols(nullptr, KERNEL_ELF_NAME);
694 }
695 uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t) const override
696 {
697 // ip is vaddr in /proc/kallsyms
698 return ip;
699 }
700 ~KernelSymbols() override {}
701 };
702
703 class KernelThreadSymbols : public KernelSymbols {
704 public:
KernelThreadSymbols(const std::string &symbolFilePath)705 explicit KernelThreadSymbols(const std::string &symbolFilePath)
706 : KernelSymbols(symbolFilePath, SYMBOL_KERNEL_THREAD_FILE)
707 {
708 }
709
LoadKernelSyms()710 bool LoadKernelSyms()
711 {
712 if (!IsRoot()) {
713 return false;
714 }
715 // find real proc path by filePath_
716 std::string procPath;
717 if (filePath_ == SYSMGR_FILE_NAME) {
718 procPath = StringPrintf("/proc/%u/uallsyms", SYSMGR_PID);
719 } else if (filePath_ == DEVHOST_FILE_NAME) {
720 procPath = "/proc/devhost/root/kallsyms";
721 }
722 HLOGD("try read kernel thread symbol file %s in %s", filePath_.c_str(), procPath.c_str());
723 CHECK_TRUE(access(procPath.c_str(), R_OK) != 0, false, LOG_TYPE_PRINTF,
724 "kernel thread symbol file %s cannot be opened\n", filePath_.c_str());
725 bool hasChangeKptr = false;
726 std::string oldKptrRestrict = ReadFileToString(KPTR_RESTRICT);
727 if (oldKptrRestrict.front() != '0') {
728 printf("/proc/sys/kernel/kptr_restrict is NOT 0, will try set it to 0.\n");
729 hasChangeKptr = WriteStringToFile(KPTR_RESTRICT, "0");
730 if (!hasChangeKptr) {
731 printf("/proc/sys/kernel/kptr_restrict write failed and we can't not change it.\n");
732 }
733 }
734
735 // getline end
736 CHECK_TRUE(!ParseKallsymsLine(procPath), false, 0, "");
737
738 if (hasChangeKptr) {
739 if (!WriteStringToFile(KPTR_RESTRICT, oldKptrRestrict)) {
740 printf("recover /proc/sys/kernel/kptr_restrict fail.\n");
741 }
742 }
743
744 if (symbols_.empty()) {
745 printf("The symbol table addresses in %s are all 0.\n"
746 "Please check the value of /proc/sys/kernel/kptr_restrict, it "
747 "should be 0.\n", filePath_.c_str());
748 return false;
749 } else {
750 AdjustSymbols();
751 HLOGV("%zu symbols_ loadded from %s.\n", symbols_.size(), procPath.c_str());
752 return true;
753 }
754 }
755
756 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
757 {
758 symbolsLoaded_ = true;
759 HLOGV("KernelThreadSymbols try read '%s', inDeviceRecord %d",
760 filePath_.c_str(), onRecording_);
761
762 if (onRecording_) {
763 const auto startTime = std::chrono::steady_clock::now();
764 if (!LoadKernelSyms()) {
765 if (IsRoot()) {
766 printf("parse %s failed.\n", filePath_.c_str());
767 }
768 } else {
769 const auto thisTime = std::chrono::steady_clock::now();
770 const auto usedTimeMsTick =
771 std::chrono::duration_cast<std::chrono::milliseconds>(thisTime - startTime);
772 HLOGV("Load kernel thread symbols (total %" PRId64 " ms)\n", (int64_t)usedTimeMsTick.count());
773 // load complete
774 return true;
775 }
776 } // no search path
777
778 // try elf
779 return ElfFileSymbols::LoadSymbols(nullptr, filePath_);
780 }
781 ~KernelThreadSymbols() override {}
782 };
783
784 class KernelModuleSymbols : public ElfFileSymbols {
785 public:
KernelModuleSymbols(const std::string &symbolFilePath)786 explicit KernelModuleSymbols(const std::string &symbolFilePath) : ElfFileSymbols(symbolFilePath)
787 {
788 HLOGV("create %s", symbolFilePath.c_str());
789 symbolFileType_ = SYMBOL_KERNEL_MODULE_FILE;
790 module_ = symbolFilePath;
791 }
792 ~KernelModuleSymbols() override {};
793
794 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
795 {
796 symbolsLoaded_ = true;
797 if (module_ == filePath_ and onRecording_) {
798 // file name still not convert to ko file path
799 // this is in record mode
800 HLOGV("find ko name %s", module_.c_str());
801 for (const std::string &path : kernelModulePaths) {
802 if (access(path.c_str(), R_OK) == 0) {
803 std::string koPath = path + module_ + KERNEL_MODULES_EXT_NAME;
804 HLOGV("found ko in %s", koPath.c_str());
805 if (access(koPath.c_str(), R_OK) == 0) {
806 // create symbol
807 filePath_ = koPath;
808 break; // find next ko
809 }
810 }
811 }
812 LoadBuildId();
813 } else {
814 HLOGV("we have file path, load with %s", filePath_.c_str());
815 return ElfFileSymbols::LoadSymbols(nullptr, filePath_);
816 }
817 return false;
818 }
819 uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t) const override
820 {
821 return ip - mapStart;
822 }
823
824 private:
LoadBuildId()825 bool LoadBuildId()
826 {
827 std::string sysFile = "/sys/module/" + module_ + "/notes/.note.gnu.build-id";
828 std::string buildIdRaw = ReadFileToString(sysFile);
829 if (!buildIdRaw.empty()) {
830 buildId_ = DfxElf::GetBuildId((uint64_t)buildIdRaw.data(), (uint64_t)buildIdRaw.size());
831 HLOGD("kerne module %s(%s) build id %s", module_.c_str(), filePath_.c_str(),
832 buildId_.c_str());
833 return buildId_.empty() ? false : true;
834 }
835 return false;
836 }
837
838 const std::vector<std::string> kernelModulePaths = {"/vendor/modules/"};
839 std::string module_ = "";
840 };
841
842 class JavaFileSymbols : public ElfFileSymbols {
843 public:
JavaFileSymbols(const std::string &symbolFilePath)844 explicit JavaFileSymbols(const std::string &symbolFilePath) : ElfFileSymbols(symbolFilePath)
845 {
846 symbolFileType_ = SYMBOL_KERNEL_FILE;
847 }
848 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
849 {
850 symbolsLoaded_ = true;
851 return false;
852 }
853 ~JavaFileSymbols() override {}
854
855 uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart,
856 uint64_t mapPageOffset) const override
857 {
858 // this is different with elf
859 // elf use ip - mapStart + mapPageOffset - minExecAddrFileOffset_ + textExecVaddr_
860 return ip - mapStart + mapPageOffset;
861 }
862 };
863
864 class JSFileSymbols : public ElfFileSymbols {
865 public:
JSFileSymbols(const std::string &symbolFilePath)866 explicit JSFileSymbols(const std::string &symbolFilePath) : ElfFileSymbols(symbolFilePath)
867 {
868 symbolFileType_ = SYMBOL_KERNEL_FILE;
869 }
870 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
871 {
872 symbolsLoaded_ = true;
873 return false;
874 }
875 ~JSFileSymbols() override {}
876 };
877
878 class HapFileSymbols : public ElfFileSymbols {
879 private:
880 #if defined(is_ohos) && is_ohos
881 std::unique_ptr<DfxExtractor> dfxExtractor_;
882 bool hapExtracted_ = false;
883 #endif
884 std::unique_ptr<uint8_t[]> abcDataPtr_ = nullptr;
885 [[maybe_unused]] uintptr_t loadOffSet_ = 0;
886 [[maybe_unused]] size_t abcDataSize_ = 0;
887 [[maybe_unused]] uintptr_t arkExtractorptr_ = 0;
888 bool isHapAbc_ = false;
889 pid_t pid_ = 0;
890 public:
HapFileSymbols(const std::string &symbolFilePath, pid_t pid)891 explicit HapFileSymbols(const std::string &symbolFilePath, pid_t pid)
892 : ElfFileSymbols(symbolFilePath, SYMBOL_HAP_FILE)
893 {
894 pid_ = pid;
895 }
896
IsHapAbc()897 bool IsHapAbc()
898 {
899 #if defined(is_ohos) && is_ohos
900 if (hapExtracted_) {
901 return isHapAbc_;
902 }
903 hapExtracted_ = true;
904 HLOGD("the symbol file is %s, pid is %d.", filePath_.c_str(), pid_);
905 if (IsRoot()) {
906 if (IsApplicationEncryped(pid_)) {
907 HLOGD("no need to parse js symbols");
908 return false;
909 }
910 }
911
912 CHECK_TRUE(StringEndsWith(filePath_, ".hap") && map_->IsMapExec(), false, 1,
913 "map is exec not abc file , the symbol file is:%s", map_->name.c_str());
914
915 if (StringEndsWith(filePath_, ".hap") || StringEndsWith(filePath_, ".hsp") ||
916 StringEndsWith(filePath_, ".hqf")) {
917 dfxExtractor_ = std::make_unique<DfxExtractor>(filePath_);
918 CHECK_TRUE(!dfxExtractor_->GetHapAbcInfo(loadOffSet_, abcDataPtr_, abcDataSize_), false, 1,
919 "failed to call GetHapAbcInfo, the symbol file is:%s", filePath_.c_str());
920 HLOGD("loadOffSet %u", (uint32_t)loadOffSet_);
921 if (abcDataPtr_ != nullptr) {
922 isHapAbc_ = true;
923 HLOGD("symbol file : %s, isAbc: %d", filePath_.c_str(), isHapAbc_);
924 }
925 } else {
926 loadOffSet_ = map_->offset;
927 abcDataSize_ = map_->end - map_->begin;
928 abcDataPtr_ = std::make_unique<uint8_t[]>(abcDataSize_);
929 auto size = DfxMemory::ReadProcMemByPid(pid_, map_->begin, abcDataPtr_.get(), map_->end - map_->begin);
930 if (size != abcDataSize_) {
931 HLOGD("return size is small abcDataPtr : %s, isAbc: %d", abcDataPtr_.get(), isHapAbc_);
932 return false;
933 }
934 isHapAbc_ = true;
935 HLOGD("symbol file name %s loadOffSet %u abcDataSize_ %u",
936 filePath_.c_str(), (uint32_t)loadOffSet_, (uint32_t)abcDataSize_);
937 }
938 auto ret = DfxArk::ArkCreateJsSymbolExtractor(&arkExtractorptr_);
939 if (ret < 0) {
940 arkExtractorptr_ = 0;
941 HLOGE("failed to call ArkCreateJsSymbolExtractor, the symbol file is:%s", filePath_.c_str());
942 }
943 #endif
944 return isHapAbc_;
945 }
946
947 bool IsAbc() override
948 {
949 return isHapAbc_ == true;
950 }
951
952 void SetBoolValue(bool value) override
953 {
954 isHapAbc_ = value;
955 }
956
957 bool LoadDebugInfo(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
958 {
959 HLOGD("map ptr:%p, map name:%s", map.get(), map->name.c_str());
960 if (debugInfoLoaded_) {
961 return true;
962 }
963 CHECK_TRUE(!onRecording_, true, 0, "");
964
965 if (!IsHapAbc()) {
966 ElfFileSymbols::LoadDebugInfo(map, "");
967 }
968 debugInfoLoaded_ = true;
969 debugInfoLoadResult_ = true;
970 return true;
971 }
972
973 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
974 {
975 HLOGD("map ptr:%p, map name:%s", map.get(), map->name.c_str());
976 CHECK_TRUE(symbolsLoaded_ || !onRecording_, true, 0, "");
977 symbolsLoaded_ = true;
978 if (!IsHapAbc()) {
979 ElfFileSymbols::LoadSymbols(map, "");
980 }
981 return true;
982 }
983
984 DfxSymbol GetSymbolWithPcAndMap(uint64_t ip, std::shared_ptr<DfxMap> map) override
985 {
986 // get cache
987 auto iter = symbolsMap_.find(ip);
988 if (iter != symbolsMap_.end()) {
989 return iter->second;
990 }
991 if (map == nullptr) {
992 return DfxSymbol(ip, "");
993 }
994 HLOGD("map ptr:%p, map name:%s", map.get(), map->name.c_str());
995
996 #if defined(is_ohos) && is_ohos
997 if (IsAbc() && needParseJsFunc_) {
998 JsFunction jsFunc;
999 std::string module = map->name;
1000 HLOGD("map->name module:%s", module.c_str());
1001 auto ret = DfxArk::ParseArkFrameInfo(static_cast<uintptr_t>(ip), static_cast<uintptr_t>(map->begin),
1002 loadOffSet_, abcDataPtr_.get(), abcDataSize_,
1003 arkExtractorptr_, &jsFunc);
1004 if (ret == -1) {
1005 HLOGD("failed to call ParseArkFrameInfo, the symbol file is : %s", map->name.c_str());
1006 return DfxSymbol(ip, "");
1007 }
1008 this->symbolsMap_.insert(std::make_pair(ip,
1009 DfxSymbol(ip,
1010 jsFunc.codeBegin,
1011 jsFunc.functionName,
1012 jsFunc.ToString(),
1013 map->name)));
1014
1015 DfxSymbol &foundSymbol = symbolsMap_[ip];
1016 if (!foundSymbol.matched_) {
1017 foundSymbol.matched_ = true;
1018 foundSymbol.symbolFileIndex_ = id_;
1019 matchedSymbols_.push_back(&(symbolsMap_[ip]));
1020 }
1021
1022 HLOGD("ip : 0x%" PRIx64 " the symbol file is : %s, function is %s demangle_ : %s", ip,
1023 symbolsMap_[ip].module_.data(), jsFunc.functionName, matchedSymbols_.back()->demangle_.data());
1024 return symbolsMap_[ip];
1025 }
1026 #endif
1027 DfxSymbol symbol(ip, "");
1028 return symbol;
1029 }
1030 };
1031
1032 class UnknowFileSymbols : public SymbolsFile {
1033 public:
UnknowFileSymbols(const std::string &symbolFilePath)1034 explicit UnknowFileSymbols(const std::string &symbolFilePath)
1035 : SymbolsFile(SYMBOL_UNKNOW_FILE, symbolFilePath)
1036 {
1037 }
1038 bool LoadSymbols(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
1039 {
1040 symbolsLoaded_ = true;
1041 return false;
1042 }
1043 ~UnknowFileSymbols() override {}
1044 };
1045
~SymbolsFile()1046 SymbolsFile::~SymbolsFile() {}
1047
CreateSymbolsFile(SymbolsFileType symbolType, const std::string symbolFilePath, pid_t pid)1048 std::unique_ptr<SymbolsFile> SymbolsFile::CreateSymbolsFile(SymbolsFileType symbolType,
1049 const std::string symbolFilePath, pid_t pid)
1050 {
1051 switch (symbolType) {
1052 case SYMBOL_KERNEL_FILE:
1053 return std::make_unique<KernelSymbols>(symbolFilePath.empty() ? KERNEL_MMAP_NAME
1054 : symbolFilePath);
1055 case SYMBOL_KERNEL_MODULE_FILE:
1056 return std::make_unique<KernelModuleSymbols>(symbolFilePath);
1057 case SYMBOL_KERNEL_THREAD_FILE:
1058 return std::make_unique<KernelThreadSymbols>(symbolFilePath);
1059 case SYMBOL_ELF_FILE:
1060 return std::make_unique<ElfFileSymbols>(symbolFilePath);
1061 case SYMBOL_JAVA_FILE:
1062 return std::make_unique<JavaFileSymbols>(symbolFilePath);
1063 case SYMBOL_JS_FILE:
1064 return std::make_unique<JSFileSymbols>(symbolFilePath);
1065 case SYMBOL_HAP_FILE:
1066 return std::make_unique<HapFileSymbols>(symbolFilePath, pid);
1067 default:
1068 return std::make_unique<SymbolsFile>(SYMBOL_UNKNOW_FILE, symbolFilePath);
1069 }
1070 }
1071
CreateSymbolsFile(const std::string &symbolFilePath, pid_t pid)1072 std::unique_ptr<SymbolsFile> SymbolsFile::CreateSymbolsFile(const std::string &symbolFilePath, pid_t pid)
1073 {
1074 // we need check file name here
1075 if (symbolFilePath == KERNEL_MMAP_NAME) {
1076 return SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE, symbolFilePath);
1077 } else if (symbolFilePath == SYSMGR_FILE_NAME ||
1078 symbolFilePath == DEVHOST_LINUX_FILE_NAME ||
1079 StringStartsWith(symbolFilePath, DEVHOST_LINUX_PREFIX)) {
1080 return SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_THREAD_FILE, symbolFilePath);
1081 } else if (StringEndsWith(symbolFilePath, KERNEL_MODULES_EXT_NAME)) {
1082 return SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_MODULE_FILE, symbolFilePath);
1083 } else if (IsArkJsFile(symbolFilePath)) {
1084 return SymbolsFile::CreateSymbolsFile(SYMBOL_HAP_FILE, symbolFilePath, pid);
1085 } else {
1086 // default is elf, this may be problematic in the future.
1087 return SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, symbolFilePath);
1088 }
1089 }
1090
AdjustSymbols()1091 void SymbolsFile::AdjustSymbols()
1092 {
1093 if (symbols_.size() <= 0) {
1094 return;
1095 }
1096
1097 // order
1098 sort(symbols_.begin(), symbols_.end(), [](const DfxSymbol& a, const DfxSymbol& b) {
1099 return a.funcVaddr_ < b.funcVaddr_;
1100 });
1101 HLOGV("sort completed");
1102
1103 size_t fullSize = symbols_.size();
1104 size_t erased = 0;
1105
1106 // Check for duplicate vaddr
1107 auto last = std::unique(symbols_.begin(), symbols_.end(), [](const DfxSymbol &a, const DfxSymbol &b) {
1108 return (a.funcVaddr_ == b.funcVaddr_);
1109 });
1110 symbols_.erase(last, symbols_.end());
1111 erased = fullSize - symbols_.size();
1112 HLOGV("uniqued completed");
1113 auto it = symbols_.begin();
1114 while (it != symbols_.end()) {
1115 it->index_ = it - symbols_.begin();
1116 it++;
1117 }
1118 HLOGV("indexed completed");
1119
1120 HLOG_ASSERT(symbols_.size() != 0);
1121
1122 if (textExecVaddrRange_ == maxVaddr) {
1123 textExecVaddrRange_ = symbols_.back().funcVaddr_ - symbols_.front().funcVaddr_;
1124 }
1125
1126 HLOGDDD("%zu symbols after adjust (%zu erased) 0x%016" PRIx64 " - 0x%016" PRIx64
1127 " @0x%016" PRIx64 " ",
1128 symbols_.size(), erased, symbols_.front().funcVaddr_, symbols_.back().funcVaddr_,
1129 textExecVaddrFileOffset_);
1130 }
1131
SortMatchedSymbols()1132 void SymbolsFile::SortMatchedSymbols()
1133 {
1134 if (matchedSymbols_.size() <= 1u) {
1135 return;
1136 }
1137 sort(matchedSymbols_.begin(), matchedSymbols_.end(), [](const DfxSymbol* a, const DfxSymbol* b) {
1138 if (a == nullptr || b == nullptr) {
1139 return true;
1140 }
1141 return a->funcVaddr_ < b->funcVaddr_;
1142 });
1143 }
1144
GetSymbols()1145 const std::vector<DfxSymbol> &SymbolsFile::GetSymbols()
1146 {
1147 return symbols_;
1148 }
1149
GetMatchedSymbols()1150 const std::vector<DfxSymbol *> &SymbolsFile::GetMatchedSymbols()
1151 {
1152 return matchedSymbols_;
1153 }
1154
GetSymbolWithVaddr(uint64_t vaddrInFile)1155 const DfxSymbol SymbolsFile::GetSymbolWithVaddr(uint64_t vaddrInFile)
1156 {
1157 #ifdef HIPERF_DEBUG_TIME
1158 const auto startTime = steady_clock::now();
1159 #endif
1160 DfxSymbol symbol;
1161 // it should be already order from small to large
1162 auto found =
1163 std::upper_bound(symbols_.begin(), symbols_.end(), vaddrInFile, DfxSymbol::ValueLessThen);
1164 /*
1165 if data is { 1, 2, 4, 5, 5, 6 };
1166 upper_bound for each val :
1167 0 < 1 at index 0
1168 1 < 2 at index 1
1169 2 < 4 at index 2
1170 3 < 4 at index 2
1171 4 < 5 at index 3
1172 5 < 6 at index 5
1173 6 < not found
1174 if key symbol vaddr is { 1, 2, 4, 5, 5, 6 };
1175 check ip vaddr for each val :
1176 ip sym
1177 0 not found
1178 1 1
1179 1 1
1180 2 2
1181 3 3
1182 4 4
1183 5 5
1184 6 6
1185 7 7
1186 */
1187 if (found != symbols_.begin()) {
1188 found = std::prev(found);
1189 if (found != symbols_.end()) {
1190 if (found->Contain(vaddrInFile)) {
1191 found->offsetToVaddr_ = vaddrInFile - found->funcVaddr_;
1192 if (!found->matched_) {
1193 found->matched_ = true;
1194 matchedSymbols_.push_back(&(*found));
1195 }
1196 symbol = *found; // copy
1197 HLOGV("found '%s' for vaddr 0x%016" PRIx64 "", symbol.ToString().c_str(), vaddrInFile);
1198 }
1199 }
1200 }
1201
1202 if (!symbol.IsValid()) {
1203 HLOGV("NOT found vaddr 0x%" PRIx64 " in symbole file %s(%zu)", vaddrInFile,
1204 filePath_.c_str(), symbols_.size());
1205 }
1206 symbol.fileVaddr_ = vaddrInFile;
1207 symbol.symbolFileIndex_ = id_;
1208
1209 #ifdef HIPERF_DEBUG_TIME
1210 auto usedTime = duration_cast<milliseconds>(steady_clock::now() - startTime);
1211 if (usedTime > 1ms) {
1212 HLOGW("cost %" PRId64 "ms to search ", usedTime.count());
1213 }
1214 #endif
1215 return symbol;
1216 }
1217
CheckPathReadable(const std::string &path) const1218 bool SymbolsFile::CheckPathReadable(const std::string &path) const
1219 {
1220 if (access(path.c_str(), R_OK) == 0) {
1221 return true;
1222 } else {
1223 HLOGM("'%s' is unable read", path.c_str());
1224 return false;
1225 }
1226 }
1227
setSymbolsFilePath(const std::vector<std::string> &symbolsSearchPaths)1228 bool SymbolsFile::setSymbolsFilePath(const std::vector<std::string> &symbolsSearchPaths)
1229 {
1230 symbolsFileSearchPaths_.clear();
1231 for (auto &symbolsSearchPath : symbolsSearchPaths) {
1232 if (CheckPathReadable(symbolsSearchPath)) {
1233 symbolsFileSearchPaths_.emplace_back(symbolsSearchPath);
1234 HLOGV("'%s' is add to symbolsSearchPath", symbolsSearchPath.c_str());
1235 }
1236 }
1237 return (symbolsFileSearchPaths_.size() > 0);
1238 }
1239
LoadSymbolsFromSaved( const SymbolFileStruct &symbolFileStruct)1240 std::unique_ptr<SymbolsFile> SymbolsFile::LoadSymbolsFromSaved(
1241 const SymbolFileStruct &symbolFileStruct)
1242 {
1243 bool isHapSymbolFile = static_cast<SymbolsFileType>(symbolFileStruct.symbolType_) == SYMBOL_HAP_FILE;
1244 HLOGD("isHapSymbolFile : %d", isHapSymbolFile);
1245 auto symbolsFile = CreateSymbolsFile(symbolFileStruct.filePath_);
1246
1247 // default create elf file. but hap file need special operation.
1248 symbolsFile->filePath_ = symbolFileStruct.filePath_;
1249 symbolsFile->symbolFileType_ = static_cast<SymbolsFileType>(symbolFileStruct.symbolType_);
1250 symbolsFile->textExecVaddr_ = symbolFileStruct.textExecVaddr_;
1251 symbolsFile->textExecVaddrFileOffset_ = symbolFileStruct.textExecVaddrFileOffset_;
1252 symbolsFile->buildId_ = symbolFileStruct.buildId_;
1253 for (auto &symbolStruct : symbolFileStruct.symbolStructs_) {
1254 symbolsFile->symbols_.emplace_back(symbolStruct.vaddr_, symbolStruct.len_,
1255 symbolStruct.symbolName_, symbolFileStruct.filePath_);
1256 }
1257 symbolsFile->AdjustSymbols(); // reorder
1258 if (isHapSymbolFile) {
1259 for (const auto& symbol : symbolsFile->symbols_) {
1260 symbolsFile->symbolsMap_.emplace(symbol.funcVaddr_, symbol);
1261 }
1262 symbolsFile->SetBoolValue(true);
1263 }
1264 symbolsFile->debugInfoLoadResult_ = true;
1265 symbolsFile->symbolsLoaded_ = true; // all ready LoadFrom perf.data
1266 HLOGV("load %zu symbol from SymbolFileStruct for file '%s'", symbolsFile->symbols_.size(),
1267 symbolsFile->filePath_.c_str());
1268 return symbolsFile;
1269 }
1270
SetBoolValue(bool value)1271 void SymbolsFile::SetBoolValue(bool value)
1272 {
1273 }
1274
ExportSymbolToFileFormat(SymbolFileStruct &symbolFileStruct)1275 void SymbolsFile::ExportSymbolToFileFormat(SymbolFileStruct &symbolFileStruct)
1276 {
1277 symbolFileStruct.filePath_ = filePath_;
1278 symbolFileStruct.symbolType_ = symbolFileType_;
1279 symbolFileStruct.textExecVaddr_ = textExecVaddr_;
1280 symbolFileStruct.textExecVaddrFileOffset_ = textExecVaddrFileOffset_;
1281 symbolFileStruct.buildId_ = buildId_;
1282
1283 SortMatchedSymbols();
1284 auto symbols = GetMatchedSymbols();
1285 symbolFileStruct.symbolStructs_.reserve(symbols.size());
1286 for (const auto symbol : symbols) {
1287 auto &symbolStruct = symbolFileStruct.symbolStructs_.emplace_back();
1288 symbolStruct.vaddr_ = symbol->funcVaddr_;
1289 symbolStruct.len_ = symbol->size_;
1290 symbolStruct.symbolName_ = symbol->GetName();
1291 }
1292
1293 HLOGV("export %zu symbol to SymbolFileStruct from %s", symbolFileStruct.symbolStructs_.size(),
1294 filePath_.c_str());
1295 }
1296
GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t mapOffset) const1297 uint64_t SymbolsFile::GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t mapOffset) const
1298 {
1299 // no convert
1300 return ip;
1301 }
1302
AddSymbol(DfxSymbol symbol)1303 void SymbolsFile::AddSymbol(DfxSymbol symbol)
1304 {
1305 symbolsLoaded_ = true;
1306 symbols_.emplace_back(symbol);
1307 }
1308 } // namespace HiPerf
1309 } // namespace Developtools
1310 } // namespace OHOS
1311