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