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