• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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.h"
19 
20 #include <algorithm>
21 #include <chrono>
22 #include <cxxabi.h>
23 #include <fcntl.h>
24 #include <fstream>
25 
26 #if 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 "elf_parser.h"
37 #include "dwarf_encoding.h"
38 #include "utilities.h"
39 
40 using namespace OHOS::Developtools::NativeDaemon::ELF;
41 using namespace std::chrono;
42 
43 namespace OHOS {
44 namespace Developtools {
45 namespace NativeDaemon {
GetBuildId() const46 const std::string SymbolsFile::GetBuildId() const
47 {
48     return buildId_;
49 }
50 
UpdateBuildIdIfMatch(std::string buildId)51 bool SymbolsFile::UpdateBuildIdIfMatch(std::string buildId)
52 {
53     /*
54         here we have two case
55         1 buildId_ is empty
56             a) always return match
57         2 buildId_ is not empty
58             a) really check if the same one
59     */
60 
61     if (buildId_.empty()) {
62         // we have new empty build
63         if (buildId.empty()) {
64             // both empty , no build id provided
65             HLOGD("build id is empty.");
66             return true;
67         } else {
68             buildId_ = buildId;
69             HLOGD("new buildId %s", buildId_.c_str());
70             return true;
71         }
72     } else {
73         // we already have a build id
74         // so this is not the first time load symbol
75         // we need check if it match
76         HLOGV("expected buildid: %s vs %s", buildId_.c_str(), buildId.c_str());
77 
78         if (buildId_ != buildId) {
79             HLOGW("id not match");
80             return false;
81         } else {
82             HLOGD("id match");
83             return true;
84         }
85     }
86 }
87 
SearchReadableFile(const std::vector<std::string> & searchPaths,const std::string & filePath) const88 std::string SymbolsFile::SearchReadableFile(const std::vector<std::string> &searchPaths,
89     const std::string &filePath) const
90 {
91     if (filePath.empty()) {
92         HLOGW("nothing to found");
93         return filePath;
94     }
95     if (CheckPathReadable(filePath)) {
96         // found direct folder
97         HLOGD("find %s in current work dir", filePath.c_str());
98         return filePath;
99     }
100     for (auto searchPath : searchPaths) {
101         if (searchPath.back() != PATH_SEPARATOR) {
102             searchPath += PATH_SEPARATOR;
103         }
104         std::string PossibleFilePath = searchPath + filePath;
105         if (CheckPathReadable(PossibleFilePath)) {
106             return PossibleFilePath;
107         }
108         HLOGW("have not found '%s' in search paths.", filePath.c_str());
109     }
110     return std::string();
111 }
112 
FindSymbolFile(const std::vector<std::string> & symbolsFileSearchPaths,std::string symboleFilePath) const113 const std::string SymbolsFile::FindSymbolFile(
114     const std::vector<std::string> &symbolsFileSearchPaths, std::string symboleFilePath) const
115 {
116     /*
117         this function do 2 things:
118         find by name:
119             1 find dso path
120             2 find search path
121                 a) search path + dso path
122                 b) search path + dso name
123 
124         show we should return filePath_ as default ?
125     */
126     if (symboleFilePath.empty()) {
127         symboleFilePath = filePath_;
128         HLOGD("use default filename: %s ", symboleFilePath.c_str());
129     }
130     symboleFilePath = PlatformPathConvert(symboleFilePath);
131     std::string foundPath = SearchReadableFile(symbolsFileSearchPaths, symboleFilePath);
132     if (foundPath.empty()) {
133         if (symboleFilePath.find(PATH_SEPARATOR) != std::string::npos) {
134             // found it again with base name , split it and get last name
135             foundPath = SearchReadableFile(symbolsFileSearchPaths,
136                 StringSplit(symboleFilePath, PATH_SEPARATOR_STR).back());
137         }
138     }
139     return foundPath;
140 }
141 
142 class ElfFileSymbols : public SymbolsFile {
143 public:
ElfFileSymbols(const std::string symbolFilePath,const SymbolsFileType symbolsFileType=SYMBOL_ELF_FILE)144     explicit ElfFileSymbols(const std::string symbolFilePath,
145         const SymbolsFileType symbolsFileType = SYMBOL_ELF_FILE)
146         : SymbolsFile(symbolsFileType, symbolFilePath)
147     {
148     }
149 
~ElfFileSymbols()150     virtual ~ElfFileSymbols()
151     {
152         if (mmap_ != MMAP_FAILED) {
153             if (munmap(mmap_, mmapSize_) != 0) {
154                 HLOGE("munmap failed with %p", munmap);
155             }
156         }
157     }
158 
LoadSymbols(const std::string & symbolFilePath)159     bool LoadSymbols(const std::string &symbolFilePath) override
160     {
161         loaded_ = true;
162         std::string findSymbolFilePath = FindSymbolFile(symbolsFileSearchPaths_, symbolFilePath);
163         if (findSymbolFilePath.empty()) {
164             HLOGW("elf found failed (belong to %s)", filePath_.c_str());
165             return false;
166         }
167         if (LoadElfSymbols(findSymbolFilePath)) {
168             return true;
169         } else {
170             HLOGW("elf open failed with '%s'", findSymbolFilePath.c_str());
171             return false;
172         }
173         return false;
174     }
175 
ReadRoMemory(uint64_t addr,uint8_t * data,size_t size) const176     size_t ReadRoMemory(uint64_t addr, uint8_t *data, size_t size) const override
177     {
178         size_t readSize = 0;
179 
180         if (mmap_ != MMAP_FAILED) {
181             if ((addr + size) <= mmapSize_) {
182                 std::copy_n(static_cast<uint8_t *>(mmap_) + addr, size, data);
183                 readSize = size;
184             } else {
185                 HLOGW("read out of range.");
186                 HLOGW("try read 0x%" PRIx64 "(elf offset)+%zu max is 0x%" PRIx64 "", addr, size,
187                     mmapSize_);
188             }
189         } else {
190             if (readFd_ != nullptr) {
191                 if (fseek(readFd_.get(), addr, SEEK_SET) != 0) {
192                     return 0;
193                 }
194                 if (fread(data, size, 1u, readFd_.get())) {
195                     readSize = size;
196                 } else {
197                     HLOGEP("read at %" PRIx64 " failed for %s", addr, filePath_.c_str());
198                 }
199             }
200             HLOGM("no mmap files loaded");
201         }
202 
203         HLOGM("read %zu/%zu bytes at %" PRIx64 "(elf offset)", readSize, size, addr);
204 
205         return readSize;
206     }
207 
208 protected:
CovertByteBufferToHexString(const unsigned char * buffer,size_t size) const209     std::string CovertByteBufferToHexString(const unsigned char *buffer, size_t size) const
210     {
211         std::string descString;
212         size_t i = 0;
213         while (i < size) {
214             descString.append(ToHex(buffer[i]));
215             i++; // move to next char
216         }
217         return descString;
218     }
219 
ElfGetBuildId(const unsigned char * buffer,size_t size) const220     std::string ElfGetBuildId(const unsigned char *buffer, size_t size) const
221     {
222         const unsigned char *end = buffer + size;
223         HLOGV("size:%zu", size);
224 
225         /*
226         Note Section
227         A vendor or system engineer might need to mark an object file with special
228         information that other programs can check for conformance or compatibility. Sections
229         of type SHT_NOTE and program header elements of type PT_NOTE can be used for this
230         purpose.
231 
232         The note information in sections and program header elements holds any number of
233         entries, as shown in the following figure. For 64–bit objects and 32–bit objects,
234         each entry is an array of 4-byte words in the format of the target processor. Labels
235         are shown in Figure 12-6 to help explain note information organization, but are not
236         part of the specification.
237 
238         Figure 12-5 Note Information
239 
240         image:ELF note section information.
241         namesz and name
242         The first namesz bytes in name contain a null-terminated character representation of
243         the entry's owner or originator. No formal mechanism exists for avoiding name
244         conflicts. By convention, vendors use their own name, such as “XYZ Computer
245         Company,” as the identifier. If no name is present, namesz contains the value zero.
246         Padding is present, if necessary, to ensure 4-byte alignment for the descriptor.
247         Such padding is not included in namesz.
248 
249         descsz and desc
250         The first descsz bytes in desc hold the note descriptor. If no descriptor is
251         present, descsz contains the value zero. Padding is present, if necessary, to ensure
252         4-byte alignment for the next note entry. Such padding is not included in descsz.
253 
254         type
255         Provides the interpretation of the descriptor. Each originator controls its own
256         types. Multiple interpretations of a single type value can exist. A program must
257         recognize both the name and the type to understand a descriptor. Types currently
258         must be nonnegative.
259 
260         The note segment that is shown in the following figure holds two entries.
261         */
262 
263         // namesz + descsz + type
264         static constexpr const int ELF_NOTE_SECTION_LENS = sizeof(uint32_t) * 3;
265 
266         while (end - buffer >= ELF_NOTE_SECTION_LENS) {
267             uint32_t namesz;
268             uint32_t descsz;
269             uint32_t type;
270             CopyFromBufferAndMove(buffer, namesz);
271             CopyFromBufferAndMove(buffer, descsz);
272             CopyFromBufferAndMove(buffer, type);
273 
274             // to ensure 4-byte alignment for the descriptor.
275             constexpr const int ELF_NOTE_SECTION_NAME_ALIGN = 4;
276 
277             namesz = RoundUp(namesz, ELF_NOTE_SECTION_NAME_ALIGN);
278             descsz = RoundUp(descsz, ELF_NOTE_SECTION_NAME_ALIGN);
279             HLOGM("namesz:%u descsz:%u type:%u", namesz, descsz, type);
280 
281             // size enough ?
282             if (buffer >= end) {
283                 return std::string();
284             }
285             if (type == NT_GNU_BUILD_ID) {
286                 char name[namesz + 1];
287                 CopyBytesFromBufferAndMove(buffer, &name[0], namesz);
288                 name[namesz] = 0;
289                 HLOGM("found buildid name:%s", name);
290                 if (strcmp(name, ELF_NOTE_GNU) == 0) {
291                     std::string descString = CovertByteBufferToHexString(buffer, descsz);
292                     HLOGD("found buildid:%s", descString.c_str());
293                     return descString;
294                 } else {
295                     // next
296                     buffer += descsz;
297                 }
298             } else {
299                 // next
300                 buffer += namesz + descsz;
301             }
302         }
303         return std::string(); // found nothing
304     }
305 
306 private:
307     bool EhFrameHDRValid_ {false};
308     uint64_t ehFrameHDRElfOffset_ {0};
309     uint64_t ehFrameHDRFdeCount_ {0};
310     uint64_t ehFrameHDRFdeTableItemSize_ {0};
311     uint64_t ehFrameHDRFdeTableElfOffset_ {0};
312     OHOS::UniqueFd fd_ {-1};
313     std::unique_ptr<FILE, decltype(&fclose)> readFd_ {nullptr, &fclose};
314     struct ShdrInfo {
315         uint64_t sectionVaddr_;
316         uint64_t sectionSize_;
317         uint64_t sectionFileOffset_;
ShdrInfoOHOS::Developtools::NativeDaemon::ElfFileSymbols::ShdrInfo318         ShdrInfo(uint64_t sectionVaddr, uint64_t sectionSize, uint64_t sectionFileOffset)
319             : sectionVaddr_(sectionVaddr),
320               sectionSize_(sectionSize),
321               sectionFileOffset_(sectionFileOffset)
322         {
323         }
324     };
325     std::map<const std::string, ShdrInfo> shdrMap_;
326     void *mmap_ {MMAP_FAILED};
327     uint64_t mmapSize_ = {0};
328 
GetReadableName(std::string name) const329     std::string GetReadableName(std::string name) const
330     {
331         int status = 0;
332         char *demanle = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
333         const std::string readableNameString((status == 0) ? demanle : name);
334         free(static_cast<void *>(demanle));
335         return readableNameString;
336     }
337 
ElfStTypeName(unsigned char stt) const338     const std::string ElfStTypeName(unsigned char stt) const
339     {
340         switch (stt) {
341             case STT_FUNC:
342                 return "function";
343             case STT_GNU_IFUNC:
344                 return "gun_func";
345             case STT_OBJECT:
346                 return "  object";
347             default:
348                 return "  unknow";
349         }
350     }
351 
GetSectionInfo(const std::string & name,uint64_t & sectionVaddr,uint64_t & sectionSize,uint64_t & sectionFileOffset) const352     bool GetSectionInfo(const std::string &name, uint64_t &sectionVaddr, uint64_t &sectionSize,
353         uint64_t &sectionFileOffset) const override
354     {
355         HLOGM("Section '%s' found in %zu", name.c_str(), shdrMap_.size());
356         if (shdrMap_.count(name) > 0) {
357             HLOGM("Section '%s' found", name.c_str());
358             const auto &shdrInfo = shdrMap_.at(name);
359             sectionVaddr = shdrInfo.sectionVaddr_;
360             sectionSize = shdrInfo.sectionSize_;
361             sectionFileOffset = shdrInfo.sectionFileOffset_;
362             HLOGM("Get Section '%s' %" PRIx64 " - %" PRIx64 "", name.c_str(), sectionVaddr,
363                 sectionSize);
364             return true;
365         } else {
366             HLOGW("Section '%s' not found", name.c_str());
367             return false;
368         }
369     }
370 
371 #ifndef __arm__
GetHDRSectionInfo(uint64_t & ehFrameHdrElfOffset,uint64_t & fdeTableElfOffset,uint64_t & fdeTableSize) const372     bool GetHDRSectionInfo(uint64_t &ehFrameHdrElfOffset, uint64_t &fdeTableElfOffset,
373         uint64_t &fdeTableSize) const override
374     {
375         if (EhFrameHDRValid_) {
376             ehFrameHdrElfOffset = ehFrameHDRElfOffset_;
377             fdeTableElfOffset = ehFrameHDRFdeTableElfOffset_;
378             fdeTableSize = ehFrameHDRFdeCount_ * ehFrameHDRFdeTableItemSize_;
379             return true;
380         } else {
381             HLOGW("!EhFrameHDRValid_");
382             return false;
383         }
384     }
385 #endif
386 
DumpEhFrameHDR() const387     void DumpEhFrameHDR() const
388     {
389         HLOGD("  ehFrameHDRElfOffset_:          0x%" PRIx64 "", ehFrameHDRElfOffset_);
390         HLOGD("  ehFrameHDRFdeCount_:           0x%" PRIx64 "", ehFrameHDRFdeCount_);
391         HLOGD("  ehFrameHDRFdeTableElfOffset_:  0x%" PRIx64 "", ehFrameHDRFdeTableElfOffset_);
392         HLOGD("  ehFrameHDRFdeTableItemSize_:   0x%" PRIx64 "", ehFrameHDRFdeTableItemSize_);
393     }
394 
LoadEhFrameHDR(const unsigned char * buffer,size_t bufferSize,uint64_t shdrOffset)395     bool LoadEhFrameHDR(const unsigned char *buffer, size_t bufferSize, uint64_t shdrOffset)
396     {
397         eh_frame_hdr *ehFrameHdr = (eh_frame_hdr *)buffer;
398         const uint8_t *dataPtr = ehFrameHdr->encode_data;
399         DwarfEncoding dwEhFramePtr(ehFrameHdr->eh_frame_ptr_enc, dataPtr);
400         DwarfEncoding dwFdeCount(ehFrameHdr->fde_count_enc, dataPtr);
401         DwarfEncoding dwTable(ehFrameHdr->table_enc, dataPtr);
402         DwarfEncoding dwTableValue(ehFrameHdr->table_enc, dataPtr);
403 
404         HLOGD("eh_frame_hdr:");
405         HexDump(ehFrameHdr, BITS_OF_FOUR_BYTE, bufferSize);
406         unsigned char version = ehFrameHdr->version;
407         HLOGD("  version:           %02x:%s", version, (version == 1) ? "valid" : "invalid");
408         HLOGD("  eh_frame_ptr_enc:  %s", dwEhFramePtr.ToString().c_str());
409         HLOGD("  fde_count_enc:     %s", dwFdeCount.ToString().c_str());
410         HLOGD("  table_enc:         %s", dwTable.ToString().c_str());
411         HLOGD("  table_enc:         %s", dwTable.ToString().c_str());
412         HLOGD("  table_value_enc:   %s", dwTableValue.ToString().c_str());
413         HLOGD("  table_offset_in_hdr:   %zu", dwTable.GetData() - buffer);
414 
415         if (version != 1) {
416             HLOGD("eh_frame_hdr version is invalid");
417             return false;
418         }
419         EhFrameHDRValid_ = true;
420         ehFrameHDRElfOffset_ = shdrOffset;
421         ehFrameHDRFdeTableElfOffset_ = dwTable.GetData() - buffer + shdrOffset;
422         DumpEhFrameHDR();
423         return true;
424     }
425 
LoadFileToMemory(const std::string & loadElfPath)426     void LoadFileToMemory(const std::string &loadElfPath)
427     {
428 #ifndef USE_MMAP
429         FILE* fp = fopen(loadElfPath.c_str(), "rb");
430         if (fp != nullptr) {
431             readFd_.reset(fp);
432         } else {
433             readFd_.reset();
434         }
435         return;
436 #else
437 #if is_mingw
438         fd_ = OHOS::UniqueFd(open(loadElfPath.c_str(), O_RDONLY | O_BINARY));
439 #else
440         fd_ = OHOS::UniqueFd(open(loadElfPath.c_str(), O_RDONLY));
441 #endif
442         if (fd_ != -1) {
443             struct stat sb = {};
444 
445             if (fstat(fd_, &sb) == -1) {
446                 HLOGE("unable to check the file size");
447             } else {
448                 HLOGV("file stat size %" PRIu64 "", sb.st_size);
449 
450                 // unmap it first
451                 if (mmap_ != MMAP_FAILED) {
452                     munmap(mmap_, mmapSize_);
453                 }
454 
455                 mmap_ = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd_, 0);
456                 if (mmap_ == MMAP_FAILED) {
457                     HLOGE("unable to map the file size %" PRIu64 " ", sb.st_size);
458                     mmapSize_ = 0;
459                 } else {
460                     mmapSize_ = sb.st_size;
461                     HLOGD("mmap build with size %" PRIu64 " ", mmapSize_);
462                 }
463             }
464         } else {
465             const int bufSize = 1024;
466             char buf[bufSize] = { 0 };
467             strerror_r(errno, buf, bufSize);
468             HLOGD("elf file open failed with %s by %s", loadElfPath.c_str(), buf);
469             return;
470         }
471 #endif
472     }
473 
ParseSymTab(const std::unique_ptr<ElfFile> & elfFile,const std::unique_ptr<ELF::SectionHeader> & shdr,std::vector<Symbol> & symbolsTable) const474     bool ParseSymTab(const std::unique_ptr<ElfFile> &elfFile,
475         const std::unique_ptr<ELF::SectionHeader> &shdr, std::vector<Symbol> &symbolsTable) const
476     {
477         HLOGV("ParseSymTable");
478         if (!elfFile->ParseSymTable(shdr.get())) {
479             return false;
480         }
481 
482         HLOGV("Symbol Table:%s", shdr->secTypeName_.c_str());
483         HLOGM("%*s|%16s|%4s|%s", MAX_SYMBOLS_TYPE_NAME_LEN, "type", "addr", "size", "name");
484 
485         for (const std::unique_ptr<ElfSymbol> &symbol : elfFile->symTable_->symbols_) {
486             if (ELF64_ST_TYPE(symbol->symInfo_) == STT_FUNC or
487                 ELF64_ST_TYPE(symbol->symInfo_) == STT_GNU_IFUNC) {
488                 /*
489                     name|            addr|size|name
490                 function|00000000c0102b8c|  56|__lookup_processor_type
491                 function|00000000c0102bd4|   0|__error_p
492                 function|00000000c0008224|  64|__vet_atags
493                 function|00000000c0008144| 128|__fixup_smp
494                 function|00000000c00081d0|  64|__fixup_pv_table
495                 function|00000000c000808c| 168|__create_page_tables
496                 function|00000000c0b002e0|  68|__mmap_switched
497                 function|00000000c0102acc|  20|__enable_mmu
498                 object|00000000c0102ac0|   0|__secondary_data
499                 function|00000000c0102ae0|  20|__do_fixup_smp_on_up
500                 */
501 
502                 std::string name = elfFile->GetStrPtr(shdr->link_, symbol->nameIndex_);
503                 uint64_t base = symbol->symValue_;
504                 uint64_t len = symbol->symSize_;
505                 std::string type = ElfStTypeName(ELF64_ST_TYPE(symbol->symInfo_));
506 
507                 HLOGM("%10s|%016" PRIx64 "|%4" PRIu64 "|%s", type.c_str(), base, len,
508                     GetReadableName(name).c_str());
509 
510                 if (base == 0) {
511                     continue; // we dont need 0 addr symbol
512                 }
513                 Symbol symbol(base, len, name, filePath_); // we use full name here
514                 symbol.demangle_ = GetReadableName(name);
515                 symbolsTable.emplace_back(symbol);
516             } else {
517                 continue;
518             }
519         } // for symbols
520         return true;
521     }
ParseShdr(const std::unique_ptr<ElfFile> elfFile,std::vector<Symbol> & symbolsTable,std::vector<Symbol> & dynamicSymbolsTable,std::string & buildIdFound)522     bool ParseShdr(const std::unique_ptr<ElfFile> elfFile, std::vector<Symbol> &symbolsTable,
523         std::vector<Symbol> &dynamicSymbolsTable, std::string &buildIdFound)
524     {
525         // walkthough
526         for (const auto &shdrPair : elfFile->shdrs_) {
527             const auto &shdr = shdrPair.second;
528             const char *sh_name =
529                 elfFile->GetStrPtr(elfFile->ehdr_->shdrStrTabIdx_, shdr->nameIndex_);
530             const unsigned char *data = elfFile->GetSectionData(shdr->secIndex_);
531 
532             if (sh_name == nullptr || data == nullptr) {
533                 HLOGE("name %p or data %p get failed.", sh_name, data);
534                 return false;
535             }
536 
537             HLOGVVV("shdr name '%s' vaddr 0x%" PRIx64 " offset 0x%" PRIx64 " size 0x%" PRIx64
538                     " type 0x%" PRIx64 "(%s) index %u link 0x%u entry 0x%" PRIx64 "",
539                 sh_name, shdr->secVaddr_, shdr->fileOffset_, shdr->secSize_, shdr->secType_,
540                 shdr->secTypeName_.c_str(), shdr->secIndex_, shdr->link_, shdr->secEntrySize_);
541 
542             shdrMap_.emplace(sh_name, ShdrInfo(shdr->secVaddr_, shdr->secSize_, shdr->fileOffset_));
543 
544             switch (shdr->secType_) {
545                 case SHT_SYMTAB:
546                     if (!ParseSymTab(elfFile, shdr, symbolsTable)) {
547                         return false;
548                     }
549                     break;
550                 case SHT_DYNSYM:
551                     if (!ParseSymTab(elfFile, shdr, dynamicSymbolsTable)) {
552                         return false;
553                     }
554                     break;
555                 case SHT_NOTE:
556                     // notes
557                     if (buildIdFound.empty()) {
558                         // we use our function, not from gelf_getnote
559                         HLOGM("found NOTE_GNU_BUILD_ID size:  %" PRIu64 "", shdr->secSize_);
560 
561                         // there will be a log of note sh , we just need the right one
562                         buildIdFound = ElfGetBuildId(data, shdr->secSize_);
563                     }
564                     break;
565 #ifndef __arm__
566                 case SHT_PROGBITS:
567                     if (EH_FRAME_HR == sh_name) {
568                         LoadEhFrameHDR(data, shdr->secSize_, shdr->fileOffset_);
569                     }
570                     break;
571 #endif
572                 default:
573                     HLOGM("skip shdr.sh_type %" PRIx64 "", shdr->secType_);
574                     break;
575             } // for shdr
576         }     // for each shdrs_
577         return true;
578     }
579 
LoadElfFile(std::string & elfPath)580     std::unique_ptr<ElfFile> LoadElfFile(std::string &elfPath)
581     {
582         HLOGD("try load elf %s", elfPath.c_str());
583         if (elfPath.empty()) {
584             elfPath = filePath_;
585             HLOGD("use default elf path %s\n", elfPath.c_str());
586         }
587         return ElfFile::MakeUnique(elfPath);
588     }
589 
UpdateSymbols(std::vector<Symbol> & symbolsTable,std::vector<Symbol> & dynamicSymbolsTable,const std::string & elfPath)590     void UpdateSymbols(std::vector<Symbol> &symbolsTable, std::vector<Symbol> &dynamicSymbolsTable,
591         const std::string &elfPath)
592     {
593         symbols_.clear();
594         HLOGD("%zu symbols loadded from symbolsTable.", symbolsTable.size());
595         HLOGD("%zu symbols loadded from dynamicSymbolsTable.", dynamicSymbolsTable.size());
596 
597         if (symbolsTable.size() > dynamicSymbolsTable.size()) {
598             symbols_ = symbolsTable;
599         } else {
600             symbols_ = dynamicSymbolsTable;
601         }
602         AdjustSymbols();
603         HLOGD("%zu symbols loadded from elf '%s'.", symbols_.size(), elfPath.c_str());
604         if (buildId_.empty()) {
605             HLOGD("buildId not found from elf '%s'.", elfPath.c_str());
606             // dont failed. some time the lib have not got the build id
607             // buildId not found from elf '/system/bin/ld-musl-arm.so.1'.
608         }
609     }
610 
LoadElfSymbols(std::string elfPath)611     bool LoadElfSymbols(std::string elfPath)
612     {
613 #ifdef HIPERF_DEBUG_TIME
614         const auto startTime = steady_clock::now();
615 #endif
616         std::unique_ptr<ElfFile> elfFile = LoadElfFile(elfPath);
617         if (elfFile == nullptr) {
618             HLOGD("elf load failed");
619             return false;
620         } else {
621             HLOGD("loaded elf %s", elfPath.c_str());
622         }
623         // we prepare two table here
624         // only one we will push in to symbols_
625         // or both drop if build id is not same
626         std::vector<Symbol> symbolsTable, dynamicSymbolsTable;
627         std::string buildIdFound;
628         for (auto &phdr : elfFile->phdrs_) {
629             if ((phdr->type_ == PT_LOAD) && (phdr->flags_ & PF_X)) {
630                 // find the min addr
631                 if (textExecVaddr_ != std::min(textExecVaddr_, phdr->vaddr_)) {
632                     textExecVaddr_ = std::min(textExecVaddr_, phdr->vaddr_);
633                     textExecVaddrFileOffset_ = phdr->offset_;
634                 }
635             }
636         }
637 
638         HLOGD("textExecVaddr_ 0x%016" PRIx64 " file offset 0x%016" PRIx64 "", textExecVaddr_,
639             textExecVaddrFileOffset_);
640 
641         if (!ParseShdr(std::move(elfFile), symbolsTable, dynamicSymbolsTable, buildIdFound)) {
642             return false;
643         }
644 
645         if (UpdateBuildIdIfMatch(buildIdFound)) {
646             UpdateSymbols(symbolsTable, dynamicSymbolsTable, elfPath);
647         } else {
648             HLOGW("symbols will not update for '%s' because buildId is not match.",
649                 elfPath.c_str());
650             // this mean failed . we dont goon for this.
651             return false;
652         }
653 
654         // mmap it for later use
655         LoadFileToMemory(elfPath);
656 #ifdef HIPERF_DEBUG_TIME
657         auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
658         if (usedTime.count() != 0) {
659             HLOGV("cost %0.3f ms to load symbols '%s'",
660                 usedTime.count() / static_cast<double>(milliseconds::duration::period::den),
661                 elfPath.c_str());
662         }
663 #endif
664         return true;
665     }
666 
GetVaddrInSymbols(uint64_t ip,uint64_t mapStart,uint64_t mapPageOffset) const667     uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart,
668         uint64_t mapPageOffset) const override
669     {
670         /*
671             00200000-002c5000 r--p 00000000 08:02 46400311
672             002c5000-00490000 r-xp 000c5000 08:02 4640031
673 
674             [14] .text             PROGBITS         00000000002c5000  000c5000
675 
676             if ip is 0x46e6ab
677             1. find the map range is 002c5000-00490000
678             2. ip - map start(002c5000) = map section offset
679             3. map section offset + map page offset(000c5000) = elf file offset
680             4. elf file offset - exec file offset(000c5000)
681                 = ip offset (ip always in exec file offset)
682             5. ip offset + exec begin vaddr(2c5000) = virtual ip in elf
683         */
684         uint64_t vaddr = ip - mapStart + mapPageOffset - textExecVaddrFileOffset_ + textExecVaddr_;
685         HLOGM(" ip :0x%016" PRIx64 " -> elf offset :0x%016" PRIx64 " -> vaddr :0x%016" PRIx64 " ",
686             ip, ip - mapStart + mapPageOffset, vaddr);
687         HLOGM("(minExecAddrFileOffset_ is 0x%" PRIx64 " textExecVaddr_ is 0x%" PRIx64 ")",
688             textExecVaddrFileOffset_, textExecVaddr_);
689         return vaddr;
690     }
691 };
692 
693 class KernelSymbols : public ElfFileSymbols {
694 public:
KernelSymbols(const std::string symbolFilePath)695     explicit KernelSymbols(const std::string symbolFilePath)
696         : ElfFileSymbols(symbolFilePath, SYMBOL_KERNEL_FILE)
697     {
698     }
699 
700     static constexpr const int KSYM_MIN_TOKENS = 3;
701 
ParseKallsymsLine()702     bool ParseKallsymsLine()
703     {
704 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
705         const auto startTime = steady_clock::now();
706         std::chrono::microseconds parseLineTime = std::chrono::microseconds::zero();
707         std::chrono::microseconds sscanfTime = std::chrono::microseconds::zero();
708         std::chrono::microseconds newTime = std::chrono::microseconds::zero();
709         std::chrono::microseconds readFileTime = std::chrono::microseconds::zero();
710 #endif
711         size_t lines = 0;
712 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
713         const auto eachFileStartTime = steady_clock::now();
714 #endif
715         std::string kallsym;
716         if (!ReadFileToString("/proc/kallsyms", kallsym)) {
717             HLOGW("/proc/kallsyms load failed.");
718             return false;
719         }
720 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
721         // any way we finish the line scan
722         readFileTime += duration_cast<milliseconds>(steady_clock::now() - eachFileStartTime);
723 #endif
724         char *lineBegin = kallsym.data();
725         char *dataEnd = lineBegin + kallsym.size();
726         while (lineBegin < dataEnd) {
727             char *lineEnd = strchr(lineBegin, '\n');
728             if (lineEnd != nullptr) {
729                 *lineEnd = '\0';
730             }
731             size_t lineSize = (lineEnd != nullptr) ? (lineEnd - lineBegin) : (dataEnd - lineBegin);
732 
733 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
734             const auto eachLineStartTime = steady_clock::now();
735 #endif
736             lines++;
737             uint64_t addr = 0;
738             char type = '\0';
739 
740             char nameRaw[lineSize];
741             char moduleRaw[lineSize];
742             int ret = sscanf_s(lineBegin, "%" PRIx64 " %c %s%s", &addr, &type, sizeof(type),
743                 nameRaw, sizeof(nameRaw), moduleRaw, sizeof(moduleRaw));
744 
745             lineBegin = lineEnd + 1;
746 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
747             // any way we finish the line scan
748             sscanfTime += duration_cast<milliseconds>(steady_clock::now() - eachLineStartTime);
749 #endif
750             if (ret >= KSYM_MIN_TOKENS) {
751                 if (ret == KSYM_MIN_TOKENS) {
752                     moduleRaw[0] = '\0';
753                 }
754                 HLOGM(" 0x%016" PRIx64 " %c '%s' '%s'", addr, type, nameRaw, moduleRaw);
755             } else {
756                 HLOGW("unknow line %d: '%s'", ret, lineBegin);
757                 continue;
758             }
759             std::string name = nameRaw;
760             std::string module = moduleRaw;
761 
762             /*
763             T
764             The symbol is in the text (code) section.
765 
766             W
767             The symbol is a weak symbol that has not been specifically
768             tagged as a weak object symbol. When a weak defined symbol is
769             linked with a normal defined symbol, the normal defined symbol
770             is used with no error. When a weak undefined symbol is linked
771             and the symbol is not defined, the value of the weak symbol
772             becomes zero with no error.
773             */
774             if (addr != 0 && strchr("TtWw", type)) {
775 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
776                 const auto eachNewSymbolTime = steady_clock::now();
777 #endif
778                 // we only need text symbols
779                 symbols_.emplace_back(addr, name, module.empty() ? filePath_ : module);
780 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
781                 newTime += duration_cast<milliseconds>(steady_clock::now() - eachNewSymbolTime);
782 #endif
783             }
784 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
785             parseLineTime += duration_cast<milliseconds>(steady_clock::now() - eachLineStartTime);
786 #endif
787         }
788 #ifdef HIPERF_DEBUG_SYMBOLS_TIME
789         std::chrono::microseconds usedTime =
790             duration_cast<milliseconds>(steady_clock::now() - startTime);
791         printf("parse kernel symbols use : %0.3f ms\n", usedTime.count() / MS_DUARTION);
792         printf("parse line use : %0.3f ms\n", parseLineTime.count() / MS_DUARTION);
793         printf("sscanf line use : %0.3f ms\n", sscanfTime.count() / MS_DUARTION);
794         printf("new symbols use : %0.3f ms\n", newTime.count() / MS_DUARTION);
795         printf("read file use : %0.3f ms\n", readFileTime.count() / MS_DUARTION);
796 #endif
797         HLOGD("%zu line processed(%zu symbols)", lines, symbols_.size());
798         return true;
799     }
800 
801     const std::string KPTR_RESTRICT = "/proc/sys/kernel/kptr_restrict";
802 
LoadKernelSyms()803     bool LoadKernelSyms()
804     {
805         HLOGD("try read /proc/kallsyms");
806         if (access("/proc/kallsyms", R_OK) != 0) {
807             printf("No vmlinux path is given, and kallsyms cannot be opened\n");
808             return false;
809         }
810 
811         if (ReadFileToString(KPTR_RESTRICT).front() != '0') {
812             printf("/proc/sys/kernel/kptr_restrict is NOT 0\n");
813             if (!WriteStringToFile(KPTR_RESTRICT, "0")) {
814                 printf("/proc/sys/kernel/kptr_restrict write failed and we cant not change it.\n");
815             }
816         }
817 
818         // getline end
819         if (!ParseKallsymsLine()) {
820             return false;
821         }
822 
823         if (symbols_.empty()) {
824             printf("The symbol table addresses in /proc/kallsyms are all 0.\n"
825                    "Please check the value of /proc/sys/kernel/kptr_restrict, it "
826                    "should be 0.\n"
827                    "Or provide a separate vmlinux path.\n");
828 
829             if (buildId_.size() != 0) {
830                 // but we got the buildid , so we make a dummpy symbols
831                 HLOGD("kallsyms not found. but we have the buildid");
832                 return true;
833             } else {
834                 // we got nothing
835                 return false;
836             }
837         } else {
838             AdjustSymbols();
839             printf("%zu symbols_ loadded from kallsyms.\n", symbols_.size());
840             return true;
841         }
842     }
LoadSymbols(const std::string & symbolFilePath)843     virtual bool LoadSymbols(const std::string &symbolFilePath) override
844     {
845         loaded_ = true;
846         HLOGV("KernelSymbols try read '%s' search paths size %zu", symbolFilePath.c_str(),
847             symbolsFileSearchPaths_.size());
848 
849         if (symbolsFileSearchPaths_.size() == 0) {
850             // try read
851             HLOGD("try read /sys/kernel/notes");
852             std::string notes = ReadFileToString("/sys/kernel/notes");
853             if (notes.empty()) {
854                 printf("notes cannot be opened, unable get buildid\n");
855                 return false;
856             } else {
857                 HLOGD("kernel notes size: %zu", notes.size());
858                 buildId_ = ElfGetBuildId((const unsigned char *)notes.data(), notes.size());
859             }
860 
861             const auto startTime = std::chrono::steady_clock::now();
862             if (!LoadKernelSyms()) {
863                 printf("parse kalsyms failed.\n");
864                 return false;
865             } else {
866                 const auto thisTime = std::chrono::steady_clock::now();
867                 const auto usedTimeMsTick =
868                     std::chrono::duration_cast<std::chrono::milliseconds>(thisTime - startTime);
869                 printf("Load kernel symbols (total %" PRId64 " ms)\n", (int64_t)usedTimeMsTick.count());
870                 // load complete
871                 return true;
872             }
873         } // no search path
874 
875         // try vmlinux
876         return ElfFileSymbols::LoadSymbols(KERNEL_ELF_NAME);
877     }
GetVaddrInSymbols(uint64_t ip,uint64_t mapStart,uint64_t) const878     virtual uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t) const override
879     {
880         // ip is vaddr in /proc/kallsyms
881         return ip;
882     }
~KernelSymbols()883     ~KernelSymbols() override {}
884 };
885 
886 class KernelModuleSymbols : public ElfFileSymbols {
887 public:
KernelModuleSymbols(const std::string symbolFilePath)888     explicit KernelModuleSymbols(const std::string symbolFilePath) : ElfFileSymbols(symbolFilePath)
889     {
890         HLOGV("create %s", symbolFilePath.c_str());
891         symbolFileType_ = SYMBOL_KERNEL_MODULE_FILE;
892         module_ = symbolFilePath;
893     }
LoadSymbols(const std::string & symbolFilePath)894     virtual bool LoadSymbols(const std::string &symbolFilePath) override
895     {
896         loaded_ = true;
897         if (module_ == filePath_) {
898             // file name sitll not convert to ko file path
899             // this is in record mode
900             HLOGV("find ko name %s", module_.c_str());
901             for (const std::string &path : kernelModulePaths) {
902                 if (access(path.c_str(), R_OK) == 0) {
903                     std::string koPath = path + module_ + KERNEL_MODULES_EXT_NAME;
904                     HLOGV("found ko in %s", koPath.c_str());
905                     if (access(koPath.c_str(), R_OK) == 0) {
906                         // create symbol
907                         filePath_ = koPath;
908                         break; // find next ko
909                     }
910                 }
911             }
912             LoadBuildId();
913         } else {
914             HLOGV("we have file path, load with %s", filePath_.c_str());
915             return ElfFileSymbols::LoadSymbols(filePath_);
916         }
917         return false;
918     }
GetVaddrInSymbols(uint64_t ip,uint64_t mapStart,uint64_t) const919     virtual uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t) const override
920     {
921         return ip - mapStart;
922     }
923 
924 private:
LoadBuildId()925     bool LoadBuildId()
926     {
927         std::string sysFile = "/sys/module/" + module_ + "/notes/.note.gnu.build-id";
928         std::string buildIdRaw = ReadFileToString(sysFile);
929         if (!buildIdRaw.empty()) {
930             buildId_ = ElfGetBuildId((const unsigned char *)buildIdRaw.data(), buildIdRaw.size());
931             HLOGD("kerne module %s(%s) build id %s", module_.c_str(), filePath_.c_str(),
932                 buildId_.c_str());
933             return buildId_.empty() ? false : true;
934         }
935         return false;
936     }
937 
938     const std::vector<std::string> kernelModulePaths = {"/vendor/modules/"};
939     std::string module_ = "";
940 };
941 
942 class JavaFileSymbols : public ElfFileSymbols {
943 public:
JavaFileSymbols(const std::string symbolFilePath)944     explicit JavaFileSymbols(const std::string symbolFilePath) : ElfFileSymbols(symbolFilePath)
945     {
946         symbolFileType_ = SYMBOL_KERNEL_FILE;
947     }
LoadSymbols(const std::string & symbolFilePath)948     virtual bool LoadSymbols(const std::string &symbolFilePath) override
949     {
950         loaded_ = true;
951         return false;
952     }
~JavaFileSymbols()953     ~JavaFileSymbols() override {}
954 
GetVaddrInSymbols(uint64_t ip,uint64_t mapStart,uint64_t mapPageOffset) const955     virtual uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart,
956         uint64_t mapPageOffset) const override
957     {
958         // this is different with elf
959         // elf use  ip - mapStart + mapPageOffset - minExecAddrFileOffset_ + textExecVaddr_
960         return ip - mapStart + mapPageOffset;
961     }
962 };
963 
964 class JSFileSymbols : public ElfFileSymbols {
965 public:
JSFileSymbols(const std::string symbolFilePath)966     explicit JSFileSymbols(const std::string symbolFilePath) : ElfFileSymbols(symbolFilePath)
967     {
968         symbolFileType_ = SYMBOL_KERNEL_FILE;
969     }
LoadSymbols(const std::string & symbolFilePath)970     virtual bool LoadSymbols(const std::string &symbolFilePath) override
971     {
972         loaded_ = true;
973         return false;
974     }
~JSFileSymbols()975     ~JSFileSymbols() override {}
976 };
977 
978 class UnknowFileSymbols : public SymbolsFile {
979 public:
UnknowFileSymbols(const std::string symbolFilePath)980     explicit UnknowFileSymbols(const std::string symbolFilePath)
981         : SymbolsFile(SYMBOL_UNKNOW_FILE, symbolFilePath)
982     {
983     }
LoadSymbols(const std::string & symbolFilePath)984     virtual bool LoadSymbols(const std::string &symbolFilePath) override
985     {
986         loaded_ = true;
987         return false;
988     }
~UnknowFileSymbols()989     ~UnknowFileSymbols() override {}
990 };
991 
~SymbolsFile()992 SymbolsFile::~SymbolsFile() {}
993 
CreateSymbolsFile(SymbolsFileType symbolType,const std::string symbolFilePath)994 std::unique_ptr<SymbolsFile> SymbolsFile::CreateSymbolsFile(SymbolsFileType symbolType,
995     const std::string symbolFilePath)
996 {
997     switch (symbolType) {
998         case SYMBOL_KERNEL_FILE:
999             return std::make_unique<KernelSymbols>(
1000                 symbolFilePath.empty() ? KERNEL_MMAP_NAME : symbolFilePath);
1001         case SYMBOL_KERNEL_MODULE_FILE:
1002             return std::make_unique<KernelModuleSymbols>(symbolFilePath);
1003         case SYMBOL_ELF_FILE:
1004             return std::make_unique<ElfFileSymbols>(symbolFilePath);
1005         case SYMBOL_JAVA_FILE:
1006             return std::make_unique<JavaFileSymbols>(symbolFilePath);
1007         case SYMBOL_JS_FILE:
1008             return std::make_unique<JSFileSymbols>(symbolFilePath);
1009         default:
1010             return std::make_unique<SymbolsFile>(SYMBOL_UNKNOW_FILE, symbolFilePath);
1011     }
1012 }
1013 
CreateSymbolsFile(const std::string & symbolFilePath)1014 std::unique_ptr<SymbolsFile> SymbolsFile::CreateSymbolsFile(const std::string &symbolFilePath)
1015 {
1016     // we need check file name here
1017     if (symbolFilePath == KERNEL_MMAP_NAME) {
1018         return SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_FILE, symbolFilePath);
1019     } else if (StringEndsWith(symbolFilePath, KERNEL_MODULES_EXT_NAME)) {
1020         return SymbolsFile::CreateSymbolsFile(SYMBOL_KERNEL_MODULE_FILE, symbolFilePath);
1021     } else {
1022         // default is elf
1023         return SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, symbolFilePath);
1024     }
1025 }
1026 
AdjustSymbols()1027 void SymbolsFile::AdjustSymbols()
1028 {
1029     if (symbols_.size() <= 1u) {
1030         return;
1031     }
1032 
1033     // order
1034     sort(symbols_.begin(), symbols_.end(), Symbol::CompareLT);
1035     HLOGV("sort completed");
1036 
1037     size_t fullSize = symbols_.size();
1038     size_t erased = 0;
1039     // Check for duplicate values
1040 
1041     auto last = std::unique(symbols_.begin(), symbols_.end());
1042     symbols_.erase(last, symbols_.end());
1043     erased = fullSize - symbols_.size();
1044     HLOGV("uniqued completed");
1045     auto it = symbols_.begin();
1046     while (it != symbols_.end()) {
1047         it->index_ = it - symbols_.begin();
1048         it++;
1049     }
1050     HLOGV("indexed completed");
1051 
1052     HLOG_ASSERT(symbols_.size() != 0);
1053 
1054     if (textExecVaddrRange_ == maxVaddr) {
1055         textExecVaddrRange_ = symbols_.back().ipVaddr_ - symbols_.front().ipVaddr_;
1056     }
1057 
1058     HLOGDDD("%zu symbols after adjust (%zu erased) 0x%016" PRIx64 " - 0x%016" PRIx64
1059             " @0x%016" PRIx64 " ",
1060         symbols_.size(), erased, symbols_.front().ipVaddr_, symbols_.back().ipVaddr_,
1061         textExecVaddrFileOffset_);
1062 }
1063 
GetSymbols()1064 const std::vector<Symbol> &SymbolsFile::GetSymbols()
1065 {
1066     return symbols_;
1067 }
1068 
GetSymbolWithVaddr(uint64_t vaddr) const1069 const Symbol SymbolsFile::GetSymbolWithVaddr(uint64_t vaddr) const
1070 {
1071 #ifdef HIPERF_DEBUG_TIME
1072     const auto startTime = steady_clock::now();
1073 #endif
1074     Symbol symbol;
1075     // it should be already order from small to large
1076     if (symbols_.size() > 0u) {
1077         auto found =
1078             std::upper_bound(symbols_.begin(), symbols_.end(), vaddr, Symbol::ValueLessThanElem);
1079         /*
1080         if data is { 1, 2, 4, 5, 5, 6 };
1081         upper_bound for each val :
1082             0 < 1 at index 0
1083             1 < 2 at index 1
1084             2 < 4 at index 2
1085             3 < 4 at index 2
1086             4 < 5 at index 3
1087             5 < 6 at index 5
1088             6 < not found
1089         */
1090         if (found != symbols_.begin()) {
1091             found = std::prev(found);
1092             if (found->contain(vaddr)) {
1093                 found->Matched();
1094                 symbol = *found;
1095                 HLOGV("found '%s' for vaddr 0x%016" PRIx64 "", found->ToString().c_str(), vaddr);
1096             }
1097         }
1098     }
1099 
1100     if (!symbol.isValid()) {
1101         HLOGV("NOT found vaddr 0x%" PRIx64 " in symbole file %s(%zu)", vaddr, filePath_.c_str(),
1102             symbols_.size());
1103     }
1104 
1105     symbol.setIpVAddress(vaddr); // update vaddr again for return new one
1106 #ifdef HIPERF_DEBUG_TIME
1107     auto usedTime = duration_cast<milliseconds>(steady_clock::now() - startTime);
1108     if (usedTime > 1ms) {
1109         HLOGW("cost %" PRId64 "ms to search ", usedTime.count());
1110     }
1111 #endif
1112     return symbol;
1113 }
1114 
CheckPathReadable(const std::string & path) const1115 bool SymbolsFile::CheckPathReadable(const std::string &path) const
1116 {
1117     if (access(path.c_str(), R_OK) == 0) {
1118         return true;
1119     } else {
1120         HLOGM("'%s' is unable read", path.c_str());
1121         return false;
1122     }
1123 }
1124 
setSymbolsFilePath(const std::vector<std::string> & symbolsSearchPaths)1125 bool SymbolsFile::setSymbolsFilePath(const std::vector<std::string> &symbolsSearchPaths)
1126 {
1127     symbolsFileSearchPaths_.clear();
1128     for (auto &symbolsSearchPath : symbolsSearchPaths) {
1129         if (CheckPathReadable(symbolsSearchPath)) {
1130             symbolsFileSearchPaths_.emplace_back(symbolsSearchPath);
1131             HLOGV("'%s' is add to symbolsSearchPath", symbolsSearchPath.c_str());
1132         }
1133     }
1134     return (symbolsFileSearchPaths_.size() > 0);
1135 }
1136 
LoadSymbolsFromSaved(const SymbolFileStruct & symbolFileStruct)1137 std::unique_ptr<SymbolsFile> SymbolsFile::LoadSymbolsFromSaved(
1138     const SymbolFileStruct &symbolFileStruct)
1139 {
1140     auto symbolsFile = CreateSymbolsFile(symbolFileStruct.filePath_);
1141     symbolsFile->filePath_ = symbolFileStruct.filePath_;
1142     symbolsFile->symbolFileType_ = (SymbolsFileType)symbolFileStruct.symbolType_;
1143     symbolsFile->textExecVaddr_ = symbolFileStruct.textExecVaddr_;
1144     symbolsFile->textExecVaddrFileOffset_ = symbolFileStruct.textExecVaddrFileOffset_;
1145     symbolsFile->buildId_ = symbolFileStruct.buildId_;
1146     for (auto &symbolStruct : symbolFileStruct.symbolStructs_) {
1147         symbolsFile->symbols_.emplace_back(symbolStruct.vaddr_, symbolStruct.len_,
1148             symbolStruct.symbolName_, symbolFileStruct.filePath_);
1149     }
1150     symbolsFile->AdjustSymbols(); // reorder
1151     HLOGV("load %zu symbol from SymbolFileStruct for file '%s'", symbolsFile->symbols_.size(),
1152         symbolsFile->filePath_.c_str());
1153     return symbolsFile;
1154 }
1155 
exportSymbolToFileFormat(bool onlyMatched)1156 const SymbolFileStruct SymbolsFile::exportSymbolToFileFormat(bool onlyMatched)
1157 {
1158     SymbolFileStruct symbolFileStruct;
1159 
1160     symbolFileStruct.filePath_ = filePath_;
1161     symbolFileStruct.symbolType_ = symbolFileType_;
1162     symbolFileStruct.textExecVaddr_ = textExecVaddr_;
1163     symbolFileStruct.textExecVaddrFileOffset_ = textExecVaddrFileOffset_;
1164     symbolFileStruct.buildId_ = buildId_;
1165 
1166     auto symbols = GetSymbols();
1167 
1168     for (auto &symbol : symbols) {
1169         if (onlyMatched && !symbol.matched_) {
1170             continue;
1171         }
1172         auto &symbolStruct = symbolFileStruct.symbolStructs_.emplace_back();
1173         symbolStruct.vaddr_ = symbol.vaddr_;
1174         symbolStruct.len_ = symbol.len_;
1175         symbolStruct.symbolName_ = symbol.GetName();
1176     }
1177     HLOGV("export %zu symbol to SymbolFileStruct from %s", symbolFileStruct.symbolStructs_.size(),
1178         filePath_.c_str());
1179     return symbolFileStruct;
1180 }
1181 
GetVaddrInSymbols(uint64_t ip,uint64_t,uint64_t) const1182 uint64_t SymbolsFile::GetVaddrInSymbols(uint64_t ip, uint64_t, uint64_t) const
1183 {
1184     // no convert
1185     return ip;
1186 }
1187 } // namespace NativeDaemon
1188 } // namespace Developtools
1189 } // namespace OHOS
1190