1 /*
2 * Copyright (c) 2021-2023 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 #include "dfx_elf_parser.h"
17
18 #include <algorithm>
19 #include <cstdlib>
20 #include <iostream>
21 #include <securec.h>
22 #include <string>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <utility>
26
27 #include "dfx_define.h"
28 #include "dfx_log.h"
29 #include "dfx_util.h"
30
31 #ifndef PAGE_SIZE
32 #define PAGE_SIZE 4096
33 #endif
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace {
38 #undef LOG_DOMAIN
39 #undef LOG_TAG
40 #define LOG_DOMAIN 0xD002D11
41 #define LOG_TAG "DfxElfParser"
42 }
43
Read(uintptr_t pos,void * buf,size_t size)44 bool ElfParser::Read(uintptr_t pos, void *buf, size_t size)
45 {
46 if (mmap_->Read(pos, buf, size) == size) {
47 return true;
48 }
49 return false;
50 }
51
MmapSize()52 size_t ElfParser::MmapSize()
53 {
54 return mmap_->Size();
55 }
56
GetElfSize()57 uint64_t ElfParser::GetElfSize()
58 {
59 return elfSize_;
60 }
61
62 template <typename EhdrType, typename PhdrType, typename ShdrType>
ParseAllHeaders()63 bool ElfParser::ParseAllHeaders()
64 {
65 EhdrType ehdr;
66 if (!Read(0, &ehdr, sizeof(ehdr))) {
67 return false;
68 }
69
70 if (!ParseElfHeaders<EhdrType>(ehdr)) {
71 LOGW("%s", "ParseElfHeaders failed");
72 return false;
73 }
74
75 if (!ParseProgramHeaders<EhdrType, PhdrType>(ehdr)) {
76 LOGW("%s", "ParseProgramHeaders failed");
77 return false;
78 }
79
80 if (!ParseSectionHeaders<EhdrType, ShdrType>(ehdr)) {
81 LOGW("%s", "ParseSectionHeaders failed");
82 return false;
83 }
84 return true;
85 }
86
87 template <typename EhdrType>
ParseElfHeaders(const EhdrType & ehdr)88 bool ElfParser::ParseElfHeaders(const EhdrType& ehdr)
89 {
90 if (ehdr.e_shnum == 0) {
91 return false;
92 }
93
94 auto machine = ehdr.e_machine;
95 if (machine == EM_ARM) {
96 archType_ = ARCH_ARM;
97 } else if (machine == EM_386) {
98 archType_ = ARCH_X86;
99 } else if (machine == EM_AARCH64) {
100 archType_ = ARCH_ARM64;
101 } else if (machine == EM_RISCV) {
102 archType_ = ARCH_RISCV64;
103 } else if (machine == EM_X86_64) {
104 archType_ = ARCH_X86_64;
105 } else {
106 LOGW("Failed the machine = %d", machine);
107 }
108 elfSize_ = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
109 return true;
110 }
111
112 template <typename EhdrType, typename PhdrType>
ParseProgramHeaders(const EhdrType & ehdr)113 bool ElfParser::ParseProgramHeaders(const EhdrType& ehdr)
114 {
115 uint64_t offset = ehdr.e_phoff;
116 bool firstLoadHeader = true;
117 for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
118 PhdrType phdr;
119 if (!Read((uintptr_t)offset, &phdr, sizeof(phdr))) {
120 return false;
121 }
122
123 switch (phdr.p_type) {
124 case PT_LOAD: {
125 ElfLoadInfo loadInfo;
126 loadInfo.offset = phdr.p_offset;
127 loadInfo.tableVaddr = phdr.p_vaddr;
128 loadInfo.tableSize = static_cast<size_t>(phdr.p_memsz);
129 loadInfo.align = phdr.p_align;
130 if (loadInfo.align == 0) {
131 continue;
132 }
133 uint64_t len = loadInfo.tableSize + (loadInfo.tableVaddr & (loadInfo.align - 1));
134 loadInfo.mmapLen = len - (len & (loadInfo.align - 1)) + loadInfo.align;
135 ptLoads_[phdr.p_offset] = loadInfo;
136 if ((phdr.p_flags & PF_X) == 0) {
137 continue;
138 }
139 // Only set the load bias from the first executable load header.
140 if (firstLoadHeader) {
141 loadBias_ = static_cast<int64_t>(static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset);
142 }
143 firstLoadHeader = false;
144
145 if (static_cast<uint64_t>(phdr.p_vaddr) < static_cast<uint64_t>(startVaddr_)) {
146 startVaddr_ = static_cast<uint64_t>(phdr.p_vaddr);
147 startOffset_ = static_cast<uint64_t>(phdr.p_offset);
148 }
149 if (static_cast<uint64_t>(phdr.p_vaddr + phdr.p_memsz) > static_cast<uint64_t>(endVaddr_)) {
150 endVaddr_ = static_cast<uint64_t>(phdr.p_vaddr + phdr.p_memsz);
151 }
152 LOGU("Elf startVaddr: %" PRIx64 ", endVaddr: %" PRIx64 "", startVaddr_, endVaddr_);
153 break;
154 }
155 case PT_DYNAMIC: {
156 dynamicOffset_ = phdr.p_offset;
157 break;
158 }
159 default:
160 break;
161 }
162 }
163 return true;
164 }
165
GetMiniDebugInfo()166 std::shared_ptr<MiniDebugInfo> ElfParser::GetMiniDebugInfo()
167 {
168 return minidebugInfo_;
169 }
170
171 template <typename EhdrType, typename ShdrType>
ParseSectionHeaders(const EhdrType & ehdr)172 bool ElfParser::ParseSectionHeaders(const EhdrType& ehdr)
173 {
174 uint64_t offset = ehdr.e_shoff;
175
176 ShdrType shdr;
177 //section header string table index. include section header table with section name string table.
178 if (ehdr.e_shstrndx < ehdr.e_shnum) {
179 uint64_t secOffset = 0;
180 uint64_t secSize = 0;
181 uint64_t shNdxOffset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
182 if (!Read((uintptr_t)shNdxOffset, &shdr, sizeof(shdr))) {
183 LOGE("%s", "Read section header string table failed");
184 return false;
185 }
186 secOffset = shdr.sh_offset;
187 secSize = shdr.sh_size;
188 if (!ParseStrTab(sectionNames_, secOffset, secSize)) {
189 return false;
190 }
191 } else {
192 LOGE("e_shstrndx(%u) cannot greater than or equal e_shnum(%u)", ehdr.e_shstrndx, ehdr.e_shnum);
193 return false;
194 }
195
196 offset += ehdr.e_shentsize;
197 for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
198 if (i == ehdr.e_shstrndx) {
199 continue;
200 }
201 if (!Read((uintptr_t)offset, &shdr, sizeof(shdr))) {
202 return false;
203 }
204
205 std::string secName;
206 if (!GetSectionNameByIndex(secName, shdr.sh_name)) {
207 LOGE("%s", "Failed to get section name");
208 continue;
209 }
210
211 if (shdr.sh_size != 0 && secName == GNU_DEBUGDATA) {
212 minidebugInfo_ = std::make_shared<MiniDebugInfo>();
213 minidebugInfo_->offset = static_cast<uint64_t>(shdr.sh_offset);
214 minidebugInfo_->size = static_cast<uintptr_t>(shdr.sh_size);
215 }
216
217 ShdrInfo shdrInfo;
218 shdrInfo.addr = static_cast<uint64_t>(shdr.sh_addr);
219 shdrInfo.entSize = static_cast<uint64_t>(shdr.sh_entsize);
220 shdrInfo.size = static_cast<uint64_t>(shdr.sh_size);
221 shdrInfo.offset = static_cast<uint64_t>(shdr.sh_offset);
222 shdrInfoPairs_.emplace(std::make_pair(i, secName), shdrInfo);
223
224 if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
225 if (shdr.sh_link >= ehdr.e_shnum) {
226 continue;
227 }
228 ElfShdr elfShdr;
229 elfShdr.name = static_cast<uint32_t>(shdr.sh_name);
230 elfShdr.type = static_cast<uint32_t>(shdr.sh_type);
231 elfShdr.flags = static_cast<uint64_t>(shdr.sh_flags);
232 elfShdr.addr = static_cast<uint64_t>(shdr.sh_addr);
233 elfShdr.offset = static_cast<uint64_t>(shdr.sh_offset);
234 elfShdr.size = static_cast<uint64_t>(shdr.sh_size);
235 elfShdr.link = static_cast<uint32_t>(shdr.sh_link);
236 elfShdr.info = static_cast<uint32_t>(shdr.sh_info);
237 elfShdr.addrAlign = static_cast<uint64_t>(shdr.sh_addralign);
238 elfShdr.entSize = static_cast<uint64_t>(shdr.sh_entsize);
239 symShdrs_.emplace_back(elfShdr);
240 }
241 }
242 return true;
243 }
244
245 template <typename DynType>
ParseElfDynamic()246 bool ElfParser::ParseElfDynamic()
247 {
248 if (dynamicOffset_ == 0 || mmap_->Get() == nullptr) {
249 return false;
250 }
251
252 DynType *dyn = (DynType *)(dynamicOffset_ + static_cast<char*>(mmap_->Get()));
253 if (dyn == nullptr) {
254 return false;
255 }
256 for (; dyn->d_tag != DT_NULL; ++dyn) {
257 if (dyn->d_tag == DT_PLTGOT) {
258 // Assume that _DYNAMIC is writable and GLIBC has relocated it (true for x86 at least).
259 dtPltGotAddr_ = dyn->d_un.d_ptr;
260 break;
261 } else if (dyn->d_tag == DT_STRTAB) {
262 dtStrtabAddr_ = dyn->d_un.d_ptr;
263 } else if (dyn->d_tag == DT_STRSZ) {
264 dtStrtabSize_ = dyn->d_un.d_val;
265 } else if (dyn->d_tag == DT_SONAME) {
266 dtSonameOffset_ = dyn->d_un.d_val;
267 }
268 }
269 return true;
270 }
271
272 template <typename DynType>
ParseElfName()273 bool ElfParser::ParseElfName()
274 {
275 if (!ParseElfDynamic<DynType>()) {
276 return false;
277 }
278 ShdrInfo shdrInfo;
279 if (!GetSectionInfo(shdrInfo, DYNSTR)) {
280 return false;
281 }
282 uintptr_t sonameOffset = shdrInfo.offset + dtSonameOffset_;
283 uint64_t sonameOffsetMax = shdrInfo.offset + dtStrtabSize_;
284 size_t maxStrSize = static_cast<size_t>(sonameOffsetMax - sonameOffset);
285 mmap_->ReadString(sonameOffset, &soname_, maxStrSize);
286 LOGU("parse current elf file soname is %s.", soname_.c_str());
287 return true;
288 }
289
290 template <typename SymType>
IsFunc(const SymType sym)291 bool ElfParser::IsFunc(const SymType sym)
292 {
293 return ((sym.st_shndx != SHN_UNDEF) &&
294 (ELF32_ST_TYPE(sym.st_info) == STT_FUNC || ELF32_ST_TYPE(sym.st_info) == STT_GNU_IFUNC));
295 }
296
297 template <typename SymType>
ParseElfSymbols(bool isFunc)298 bool ElfParser::ParseElfSymbols(bool isFunc)
299 {
300 if (symShdrs_.empty()) {
301 return false;
302 }
303
304 elfSymbols_.clear();
305 for (const auto &iter : symShdrs_) {
306 const auto &shdr = iter;
307 ParseElfSymbols<SymType>(shdr, isFunc);
308 }
309 return (elfSymbols_.size() > 0);
310 }
311
312 template <typename SymType>
ParseElfSymbols(ElfShdr shdr,bool isFunc)313 bool ElfParser::ParseElfSymbols(ElfShdr shdr, bool isFunc)
314 {
315 ShdrInfo linkShdrInfo;
316 if (!GetSectionInfo(linkShdrInfo, shdr.link)) {
317 return false;
318 }
319
320 uint32_t count = static_cast<uint32_t>((shdr.entSize != 0) ? (shdr.size / shdr.entSize) : 0);
321 for (uint32_t idx = 0; idx < count; ++idx) {
322 uintptr_t offset = static_cast<uintptr_t>(shdr.offset + idx * shdr.entSize);
323 SymType sym;
324 if (!Read(offset, &sym, sizeof(sym))) {
325 continue;
326 }
327 if (sym.st_value == 0 || sym.st_size == 0) {
328 continue;
329 }
330 ElfSymbol elfSymbol;
331 if (isFunc && (!ParseElfSymbolName(linkShdrInfo, sym, elfSymbol.nameStr))) {
332 continue;
333 }
334 elfSymbol.value = static_cast<uint64_t>(sym.st_value);
335 elfSymbol.size = static_cast<uint64_t>(sym.st_size);
336 elfSymbol.name = static_cast<uint32_t>(sym.st_name);
337 elfSymbols_.emplace_back(elfSymbol);
338 }
339 LOGU("elfSymbols.size: %" PRIuPTR "", elfSymbols_.size());
340 return true;
341 }
342
343 template <typename SymType>
ParseElfSymbolName(ShdrInfo linkShdr,SymType sym,std::string & nameStr)344 bool ElfParser::ParseElfSymbolName(ShdrInfo linkShdr, SymType sym, std::string& nameStr)
345 {
346 if (!IsFunc(sym) || (static_cast<uint64_t>(sym.st_name) >= linkShdr.size) || mmap_->Get() == nullptr) {
347 return false;
348 }
349 uintptr_t nameOffset = static_cast<uintptr_t>(linkShdr.offset + sym.st_name);
350 nameStr = std::string(static_cast<char*>(mmap_->Get()) + nameOffset);
351 return true;
352 }
353
354 template <typename SymType>
ParseElfSymbolByAddr(uint64_t addr,ElfSymbol & elfSymbol)355 bool ElfParser::ParseElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol)
356 {
357 if (symShdrs_.empty()) {
358 return false;
359 }
360
361 for (const auto &shdr : symShdrs_) {
362 ShdrInfo linkShdrInfo;
363 if (!GetSectionInfo(linkShdrInfo, shdr.link)) {
364 return false;
365 }
366
367 uint32_t count = static_cast<uint32_t>((shdr.entSize != 0) ? (shdr.size / shdr.entSize) : 0);
368 for (uint32_t idx = 0; idx < count; ++idx) {
369 uintptr_t offset = static_cast<uintptr_t>(shdr.offset + idx * shdr.entSize);
370 SymType sym;
371 if (!Read(offset, &sym, sizeof(sym))) { // todo inplace search
372 continue;
373 }
374 if (sym.st_value == 0 || sym.st_size == 0) {
375 continue;
376 }
377
378 if ((sym.st_value <= addr) && (addr < (sym.st_value + sym.st_size)) &&
379 ParseElfSymbolName(linkShdrInfo, sym, elfSymbol.nameStr)) {
380 elfSymbol.value = static_cast<uint64_t>(sym.st_value);
381 elfSymbol.size = static_cast<uint64_t>(sym.st_size);
382 elfSymbol.name = static_cast<uint32_t>(sym.st_name);
383 LOGU("Parse elf symbol nameStr: %s", elfSymbol.nameStr.c_str());
384 return true;
385 }
386 }
387 }
388 return false;
389 }
390
GetSectionNameByIndex(std::string & nameStr,const uint32_t name)391 bool ElfParser::GetSectionNameByIndex(std::string& nameStr, const uint32_t name)
392 {
393 if (sectionNames_.empty() || name >= sectionNames_.size()) {
394 LOGE("name index(%u) out of range, size: %" PRIuPTR "", name, sectionNames_.size());
395 return false;
396 }
397
398 size_t endIndex = sectionNames_.find('\0', name);
399 if (endIndex != std::string::npos) {
400 nameStr = sectionNames_.substr(name, endIndex - name);
401 return true;
402 }
403 return false;
404 }
405
ParseStrTab(std::string & nameStr,const uint64_t offset,const uint64_t size)406 bool ElfParser::ParseStrTab(std::string& nameStr, const uint64_t offset, const uint64_t size)
407 {
408 if (size > MmapSize()) {
409 LOGE("size(%" PRIu64 ") is too large.", size);
410 return false;
411 }
412 char *namesBuf = new char[size];
413 if (namesBuf == nullptr) {
414 LOGE("%s", "New failed");
415 return false;
416 }
417 (void)memset_s(namesBuf, size, '\0', size);
418 if (!Read((uintptr_t)offset, namesBuf, size)) {
419 LOGE("%s", "Read failed");
420 delete[] namesBuf;
421 namesBuf = nullptr;
422 return false;
423 }
424 nameStr = std::string(namesBuf, namesBuf + size);
425 delete[] namesBuf;
426 namesBuf = nullptr;
427 return true;
428 }
429
GetSectionInfo(ShdrInfo & shdr,const uint32_t idx)430 bool ElfParser::GetSectionInfo(ShdrInfo& shdr, const uint32_t idx)
431 {
432 for (const auto &iter: shdrInfoPairs_) {
433 auto tmpPair = iter.first;
434 if (tmpPair.first == idx) {
435 shdr = iter.second;
436 return true;
437 }
438 }
439 return false;
440 }
441
GetSectionInfo(ShdrInfo & shdr,const std::string & secName)442 bool ElfParser::GetSectionInfo(ShdrInfo& shdr, const std::string& secName)
443 {
444 for (const auto &iter: shdrInfoPairs_) {
445 auto tmpPair = iter.first;
446 if (tmpPair.second == secName) {
447 shdr = iter.second;
448 return true;
449 }
450 }
451 return false;
452 }
453
GetSectionData(unsigned char * buf,uint64_t size,std::string secName)454 bool ElfParser::GetSectionData(unsigned char *buf, uint64_t size, std::string secName)
455 {
456 ShdrInfo shdr;
457 if (GetSectionInfo(shdr, secName)) {
458 if (Read(shdr.offset, buf, size)) {
459 return true;
460 }
461 } else {
462 LOGE("Failed to get data from secName %s", secName.c_str());
463 }
464 return false;
465 }
466
InitHeaders()467 bool ElfParser32::InitHeaders()
468 {
469 return ParseAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
470 }
471
InitHeaders()472 bool ElfParser64::InitHeaders()
473 {
474 return ParseAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
475 }
476
GetElfName()477 std::string ElfParser32::GetElfName()
478 {
479 if (soname_ == "") {
480 ParseElfName<Elf32_Dyn>();
481 }
482 return soname_;
483 }
484
GetElfName()485 std::string ElfParser64::GetElfName()
486 {
487 if (soname_ == "") {
488 ParseElfName<Elf64_Dyn>();
489 }
490 return soname_;
491 }
492
GetGlobalPointer()493 uintptr_t ElfParser32::GetGlobalPointer()
494 {
495 if (dtPltGotAddr_ == 0) {
496 ParseElfDynamic<Elf32_Dyn>();
497 }
498 return dtPltGotAddr_;
499 }
500
GetGlobalPointer()501 uintptr_t ElfParser64::GetGlobalPointer()
502 {
503 if (dtPltGotAddr_ == 0) {
504 ParseElfDynamic<Elf64_Dyn>();
505 }
506 return dtPltGotAddr_;
507 }
508
GetElfSymbols(bool isFunc)509 const std::vector<ElfSymbol>& ElfParser32::GetElfSymbols(bool isFunc)
510 {
511 ParseElfSymbols<Elf32_Sym>(isFunc);
512 return elfSymbols_;
513 }
514
GetElfSymbols(bool isFunc)515 const std::vector<ElfSymbol>& ElfParser64::GetElfSymbols(bool isFunc)
516 {
517 ParseElfSymbols<Elf64_Sym>(isFunc);
518 return elfSymbols_;
519 }
520
GetElfSymbolByAddr(uint64_t addr,ElfSymbol & elfSymbol)521 bool ElfParser32::GetElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol)
522 {
523 return ParseElfSymbolByAddr<Elf32_Sym>(addr, elfSymbol);
524 }
525
GetElfSymbolByAddr(uint64_t addr,ElfSymbol & elfSymbol)526 bool ElfParser64::GetElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol)
527 {
528 return ParseElfSymbolByAddr<Elf64_Sym>(addr, elfSymbol);
529 }
530 } // namespace HiviewDFX
531 } // namespace OHOS
532