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 §ionVaddr, uint64_t §ionSize,
284 uint64_t §ionFileOffset) 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