1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
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 #include <elf_file.h>
16
17 #include <cinttypes>
18
19 namespace OHOS {
20 namespace Developtools {
21 namespace Hiebpf {
ElfFile(const std::string & filename)22 ElfFile::ElfFile(const std::string &filename)
23 {
24 fd_ = open(filename.c_str(), O_RDONLY);
25 if (fd_ != -1) {
26 struct stat sb;
27 if (fstat(fd_, &sb) == -1) {
28 HHLOGE(true, "unable to check the file size");
29 } else {
30 HHLOGD(true, "file stat size %" PRIu64 " ", sb.st_size);
31 mmap_ = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd_, 0);
32 if (mmap_ == MMAP_FAILED) {
33 HHLOGE(true, "unable to map the file size %" PRIu64 " ", sb.st_size);
34 mmapSize_ = 0;
35 } else {
36 mmapSize_ = sb.st_size;
37 HHLOGD(true, "mmap build with size %" PRIu64 " ", mmapSize_);
38 }
39 }
40 }
41 }
42
~ElfFile()43 ElfFile::~ElfFile()
44 {
45 if (mmap_ != MMAP_FAILED) {
46 munmap(mmap_, mmapSize_);
47 }
48
49 if (fd_ != -1) {
50 close(fd_);
51 fd_ = -1;
52 }
53 }
54
MakeUnique(const std::string & filename)55 std::unique_ptr<ElfFile> ElfFile::MakeUnique(const std::string &filename)
56 {
57 std::unique_ptr<ElfFile> file {new (std::nothrow) ElfFile(filename)};
58 CHECK_NOTNULL(file, nullptr, "Error in ElfFile::MakeUnique(): ElfFile::ElfFile() failed");
59 CHECK_TRUE(file->IsOpened(), nullptr, "Error in ElfFile::MakeUnique(): elf file not opended");
60 CHECK_TRUE(file->ParseFile(), nullptr, "parse elf file failed");
61 return file;
62 }
63
ParseFile()64 bool ElfFile::ParseFile()
65 {
66 CHECK_TRUE(ParseElfHeader(), false, "Error in ElfFile::MakeUnique(): ElfFile::ParseElfHeader() failed");
67 CHECK_TRUE(ParsePrgHeaders(), false, "Error in ElfFile::MakeUnique(): ElfFile::ParsePrgHeaders() failed");
68 CHECK_TRUE(ParseSecNamesStr(), false, "Error in ElfFile::MakeUnique(): ElfFile::ParseSecNamesStr() failed");
69 CHECK_TRUE(ParseSecHeaders(), false, "Error in ElfFile::MakeUnique(): ElfFile::ParseSecHeaders() failed");
70 return true;
71 }
72
ParseElfHeader()73 bool ElfFile::ParseElfHeader()
74 {
75 ssize_t ret = lseek(fd_, 0, SEEK_SET);
76 CHECK_TRUE(ret == 0, false, "lseek ret %zu", ret);
77
78 unsigned char ehdrBuf[ehdr64Size] {0};
79 size_t readsize = ReadFile(ehdrBuf, ehdr64Size);
80 CHECK_TRUE(readsize >= ehdr64Size, false,
81 "file size not enough, try read %zu, only have %zu", ehdr64Size, readsize);
82 ehdr_ = ElfHeader::MakeUnique(ehdrBuf, readsize);
83 return !(ehdr_ == nullptr);
84 }
85
ParsePrgHeaders()86 bool ElfFile::ParsePrgHeaders()
87 {
88 size_t phdrSize = ehdr_->phdrEntSize_;
89 size_t numPhdrs = ehdr_->phdrNumEnts_;
90 uint64_t phdrOffset = ehdr_->phdrOffset_;
91 int64_t ret = lseek(fd_, phdrOffset, SEEK_SET);
92 if (ret != static_cast<int64_t>(phdrOffset)) {
93 return false;
94 }
95 char *phdrsBuf = new (std::nothrow) char[phdrSize * numPhdrs];
96 CHECK_NOTNULL(phdrsBuf, false, "Error in ELF::ElfFile::ParsePrgHeaders(): new failed");
97
98 ret = ReadFile(phdrsBuf, phdrSize * numPhdrs);
99 if (ret != static_cast<int64_t>(phdrSize * numPhdrs)) {
100 delete[] phdrsBuf;
101 phdrsBuf = nullptr;
102 return false;
103 }
104 char *phdrBuf = phdrsBuf;
105 for (size_t count = 0; count < numPhdrs; ++count) {
106 std::unique_ptr<ProgramHeader> phdr = ProgramHeader::MakeUnique(phdrBuf, phdrSize);
107 if (phdr == nullptr) {
108 delete[] phdrsBuf;
109 phdrsBuf = nullptr;
110 HHLOGE(true, "Error in Elf::ParsePrgHeaders(): ProgramHeader::MakeUnique() failed");
111 return false;
112 }
113 phdrs_.push_back(std::move(phdr));
114 phdrBuf += phdrSize;
115 }
116 delete[] phdrsBuf;
117 phdrsBuf = nullptr;
118 return true;
119 }
120
ParseSecNamesStr()121 bool ElfFile::ParseSecNamesStr()
122 {
123 // get string table section header
124 size_t shdrSize = ehdr_->shdrEntSize_;
125 size_t shdrIndex = ehdr_->shdrStrTabIdx_;
126 uint64_t shdrOffset = ehdr_->shdrOffset_ + ((uint64_t)shdrIndex) * shdrSize;
127 int64_t ret = lseek(fd_, shdrOffset, SEEK_SET);
128 if (ret != static_cast<int64_t>(shdrOffset)) {
129 return false;
130 }
131
132 char *shdrBuf = new (std::nothrow) char[shdrSize];
133 CHECK_NOTNULL(shdrBuf, false, "Error in ElfFile::ParseSecNamesStr(): new failed");
134
135 ret = ReadFile(shdrBuf, shdrSize);
136 if (ret != static_cast<int64_t>(shdrSize)) {
137 delete[] shdrBuf;
138 shdrBuf = nullptr;
139 return false;
140 }
141 const std::string secName {".shstrtab"};
142 shdrs_[secName] = SectionHeader::MakeUnique(shdrBuf, shdrSize, shdrIndex);
143 if (shdrs_[secName] == nullptr) {
144 HHLOGE(true, "Error in ElfFile::ParseSecNamesStr(): SectionHeader::MakeUnique() failed");
145 delete[] shdrBuf;
146 shdrBuf = nullptr;
147 return false;
148 }
149 delete[] shdrBuf;
150 shdrBuf = nullptr;
151
152 // get content of string section table
153 uint64_t secOffset = shdrs_[secName]->fileOffset_;
154 size_t secSize = shdrs_[secName]->secSize_;
155 ret = lseek(fd_, secOffset, SEEK_SET);
156 if (ret != static_cast<int64_t>(secOffset)) {
157 return false;
158 }
159 char *secNamesBuf = new (std::nothrow) char[secSize];
160 CHECK_NOTNULL(secNamesBuf, false, "Error in ElfFile::ParseSecNamesStr(): new secNamesBuf failed");
161 ret = ReadFile(secNamesBuf, secSize);
162 if (ret != static_cast<int64_t>(secSize)) {
163 delete[] secNamesBuf;
164 secNamesBuf = nullptr;
165 return false;
166 }
167 secNamesStr_ = std::string(secNamesBuf, secNamesBuf + secSize);
168 delete[] secNamesBuf;
169 secNamesBuf = nullptr;
170 return true;
171 }
172
ParseSecHeaders()173 bool ElfFile::ParseSecHeaders()
174 {
175 size_t shdrSize = ehdr_->shdrEntSize_;
176 size_t numShdrs = ehdr_->shdrNumEnts_;
177 uint64_t shdrOffset = ehdr_->shdrOffset_;
178 int64_t ret = lseek(fd_, shdrOffset, SEEK_SET);
179 if (ret != static_cast<int64_t>(shdrOffset)) {
180 return false;
181 }
182 char *shdrsBuf = new (std::nothrow) char[shdrSize * numShdrs];
183 CHECK_NOTNULL(shdrsBuf, false, "Error in ELF::ElfFile::ParseSecHeaders(): new failed");
184
185 ret = ReadFile(shdrsBuf, shdrSize * numShdrs);
186 if (ret != static_cast<int64_t>(shdrSize * numShdrs)) {
187 delete[] shdrsBuf;
188 shdrsBuf = nullptr;
189 return false;
190 }
191
192 char *shdrBuf = shdrsBuf;
193 for (size_t count = 0; count < numShdrs; ++count) {
194 if (count == ehdr_->shdrStrTabIdx_) {
195 shdrBuf += shdrSize;
196 continue;
197 }
198 std::unique_ptr<SectionHeader> shdr = SectionHeader::MakeUnique(shdrBuf, shdrSize, count);
199 if (shdr == nullptr) {
200 delete[] shdrsBuf;
201 shdrsBuf = nullptr;
202 return false;
203 }
204 std::string secName = GetSectionName(shdr->nameIndex_);
205 shdrs_[secName] = std::move(shdr);
206 shdr.reset(nullptr);
207 shdrBuf += shdrSize;
208 }
209 delete[] shdrsBuf;
210 shdrsBuf = nullptr;
211 return true;
212 }
213
GetSectionName(const uint32_t startIndex)214 std::string ElfFile::GetSectionName(const uint32_t startIndex)
215 {
216 if (startIndex >= secNamesStr_.size()) {
217 HHLOGF(true, "out_of_range %s ,endIndex %d ", secNamesStr_.c_str(), startIndex);
218 return "";
219 }
220 size_t endIndex {startIndex};
221 for (; endIndex < secNamesStr_.size(); ++endIndex) {
222 if (secNamesStr_[endIndex] == '\0') {
223 break;
224 }
225 }
226 return secNamesStr_.substr(startIndex, endIndex - startIndex);
227 }
228
229 // ElfHeader
MakeUnique(unsigned char * const ehdrBuf,const std::size_t bufSize)230 std::unique_ptr<ElfHeader> ElfHeader::MakeUnique(unsigned char * const ehdrBuf,
231 const std::size_t bufSize)
232 {
233 std::unique_ptr<ElfHeader> ehdr {new (std::nothrow) ElfHeader()};
234 CHECK_NOTNULL(ehdr, nullptr, "ElfHeader() failed");
235 CHECK_TRUE(ehdr->Init(ehdrBuf, bufSize), nullptr, "ElfHeader::Init(ehdrBuf, bufSize) failed\n");
236 return ehdr;
237 }
238
Init(unsigned char * const ehdrBuf,const std::size_t bufSize)239 bool ElfHeader::Init(unsigned char * const ehdrBuf, const std::size_t bufSize)
240 {
241 std::string magicStr {ehdrBuf, ehdrBuf + SELFMAG};
242 std::string elfMagic {ELFMAG};
243 CHECK_TRUE(magicStr.compare(elfMagic) == 0, false, "elf magic not found");
244 std::copy(ehdrBuf, ehdrBuf + EI_NIDENT, ehdrIdent_);
245
246 if (ehdrBuf[EI_CLASS] == ELFCLASS32 and ParseElf32Header(ehdrBuf, bufSize)) {
247 return true;
248 }
249 if (ehdrBuf[EI_CLASS] == ELFCLASS64 and ParseElf64Header(ehdrBuf, bufSize)) {
250 return true;
251 }
252 HHLOGE(true, "init elf header failed, elf header buffer dumped");
253 return false;
254 }
255
ParseElf32Header(unsigned char * const ehdrBuf,const std::size_t bufSize)256 bool ElfHeader::ParseElf32Header(unsigned char * const ehdrBuf, const std::size_t bufSize)
257 {
258 if (bufSize < ehdr32Size) {
259 HHLOGE(true, "bad elf32 header buffer");
260 return false;
261 }
262 size_t curIndex {EI_NIDENT};
263 uint16_t *u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
264 type_ = u2Buf[0];
265 curIndex += sizeof(uint16_t);
266
267 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
268 machine_ = u2Buf[0];
269 curIndex += sizeof(uint16_t);
270
271 uint32_t *u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
272 elfVersion_ = u4Buf[0];
273 curIndex += sizeof(uint32_t);
274
275 u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
276 prgEntryVaddr_ = u4Buf[0];
277 curIndex += sizeof(uint32_t);
278
279 u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
280 phdrOffset_ = u4Buf[0];
281 curIndex += sizeof(uint32_t);
282
283 u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
284 shdrOffset_ = u4Buf[0];
285 curIndex += sizeof(uint32_t);
286
287 u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
288 ehdrFlags_ = u4Buf[0];
289 curIndex += sizeof(uint32_t);
290
291 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
292 ehdrSize_ = u2Buf[0];
293 curIndex += sizeof(uint16_t);
294
295 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
296 phdrEntSize_ = u2Buf[0];
297 curIndex += sizeof(uint16_t);
298
299 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
300 phdrNumEnts_ = u2Buf[0];
301 curIndex += sizeof(uint16_t);
302
303 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
304 shdrEntSize_ = u2Buf[0];
305 curIndex += sizeof(uint16_t);
306
307 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
308 shdrNumEnts_ = u2Buf[0];
309 curIndex += sizeof(uint16_t);
310
311 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
312 shdrStrTabIdx_ = u2Buf[0];
313
314 return true;
315 }
316
ParseElf64Header(unsigned char * const ehdrBuf,const std::size_t bufSize)317 bool ElfHeader::ParseElf64Header(unsigned char * const ehdrBuf, const std::size_t bufSize)
318 {
319 CHECK_TRUE(bufSize >= ehdr64Size, false, "bad elf64 header buffer");
320 size_t curIndex {EI_NIDENT};
321 uint16_t *u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
322 type_ = u2Buf[0];
323 curIndex += sizeof(uint16_t);
324
325 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
326 machine_ = u2Buf[0];
327 curIndex += sizeof(uint16_t);
328
329 uint32_t *u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
330 elfVersion_ = u4Buf[0];
331 curIndex += sizeof(uint32_t);
332
333 uint64_t *u8Buf = reinterpret_cast<uint64_t *>(ehdrBuf + curIndex);
334 prgEntryVaddr_ = u8Buf[0];
335 curIndex += sizeof(uint64_t);
336
337 u8Buf = reinterpret_cast<uint64_t *>(ehdrBuf + curIndex);
338 phdrOffset_ = u8Buf[0];
339 curIndex += sizeof(uint64_t);
340
341 u8Buf = reinterpret_cast<uint64_t *>(ehdrBuf + curIndex);
342 shdrOffset_ = u8Buf[0];
343 curIndex += sizeof(uint64_t);
344
345 u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
346 ehdrFlags_ = u4Buf[0];
347 curIndex += sizeof(uint32_t);
348
349 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
350 ehdrSize_ = u2Buf[0];
351 curIndex += sizeof(uint16_t);
352
353 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
354 phdrEntSize_ = u2Buf[0];
355 curIndex += sizeof(uint16_t);
356
357 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
358 phdrNumEnts_ = u2Buf[0];
359 curIndex += sizeof(uint16_t);
360
361 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
362 shdrEntSize_ = u2Buf[0];
363 curIndex += sizeof(uint16_t);
364
365 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
366 shdrNumEnts_ = static_cast<long long>(*u2Buf);
367 curIndex += sizeof(uint16_t);
368
369 u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
370 shdrStrTabIdx_ = u2Buf[0];
371
372 return true;
373 }
374
375 // SectionHeader
376 enum class NUMBER : int {
377 ZERO = 0,
378 ONE = 1,
379 TWO = 2,
380 THREE = 3,
381 FOUR = 4,
382 FIVE = 5,
383 SIX = 6,
384 SEVEN = 7,
385 EIGHT = 8,
386 NINE = 9,
387 TEN = 10,
388 ELEVEN = 11,
389 TWELVE = 12,
390 };
391
MakeUnique(char * const shdrBuf,const size_t bufSize,const size_t index)392 std::unique_ptr<SectionHeader> SectionHeader::MakeUnique(char * const shdrBuf, const size_t bufSize,
393 const size_t index)
394 {
395 std::unique_ptr<SectionHeader> shdr {new (std::nothrow) SectionHeader()};
396 if (shdr == nullptr) {
397 return nullptr;
398 }
399 CHECK_TRUE(shdr->Init(shdrBuf, bufSize, index), nullptr, "SectionHeader::Init(shdrBuf, bufSize, index) failed");
400 return shdr;
401 }
402
ParseSecHeader32(char * const shdrBuf)403 bool SectionHeader::ParseSecHeader32(char * const shdrBuf)
404 {
405 uint32_t *u4Buf = reinterpret_cast<uint32_t *>(shdrBuf);
406 int index {0};
407 nameIndex_ = u4Buf[index];
408 index = static_cast<int>(NUMBER::ONE);
409 secType_ = u4Buf[index];
410 index = static_cast<int>(NUMBER::TWO);
411 secFlags_ = u4Buf[index];
412 index = static_cast<int>(NUMBER::SIX);
413 link_ = u4Buf[index];
414 index = static_cast<int>(NUMBER::SEVEN);
415 info_ = u4Buf[index];
416 index = static_cast<int>(NUMBER::THREE);
417 secVaddr_ = u4Buf[index];
418 index = static_cast<int>(NUMBER::FOUR);
419 fileOffset_ = u4Buf[index];
420 index = static_cast<int>(NUMBER::FIVE);
421 secSize_ = u4Buf[index];
422 index = static_cast<int>(NUMBER::EIGHT);
423 secAddrAlign_ = u4Buf[index];
424 index = static_cast<int>(NUMBER::NINE);
425 secEntrySize_ = u4Buf[index];
426 return true;
427 }
428
ParseSecHeader64(char * const shdrBuf)429 bool SectionHeader::ParseSecHeader64(char * const shdrBuf)
430 {
431 uint64_t *u8Buf = reinterpret_cast<uint64_t *>(shdrBuf);
432 uint32_t *u4Buf = reinterpret_cast<uint32_t *>(shdrBuf);
433 size_t index {0};
434 nameIndex_ = u4Buf[index];
435 index = static_cast<size_t>(NUMBER::ONE);
436 secType_ = u4Buf[index];
437 secFlags_ = u8Buf[index];
438 index = static_cast<size_t>(NUMBER::TEN);
439 link_ = u4Buf[index];
440 index = static_cast<size_t>(NUMBER::ELEVEN);
441 info_ = u4Buf[index];
442 index = static_cast<size_t>(NUMBER::TWO);
443 secVaddr_ = u8Buf[index];
444 index = static_cast<size_t>(NUMBER::THREE);
445 fileOffset_ = u8Buf[index];
446 index = static_cast<size_t>(NUMBER::FOUR);
447 secSize_ = u8Buf[index];
448 index = static_cast<size_t>(NUMBER::SIX);
449 secAddrAlign_ = u8Buf[index];
450 index = static_cast<size_t>(NUMBER::SEVEN);
451 secEntrySize_ = u8Buf[index];
452 return true;
453 }
454
455 // ProgramHeader
MakeUnique(char * const phdrBuf,const size_t bufSize)456 std::unique_ptr<ProgramHeader> ProgramHeader::MakeUnique(char * const phdrBuf, const size_t bufSize)
457 {
458 std::unique_ptr<ProgramHeader> phdr {new (std::nothrow) ProgramHeader()};
459 CHECK_NOTNULL(phdr, nullptr, "ProgramHeader() failed");
460 CHECK_TRUE(phdr->Init(phdrBuf, bufSize), nullptr, "ProgramHeader::Init(phdrBuf, bufSize) failed");
461 return phdr;
462 }
463
ParsePrgHeader32(char * const phdrBuf)464 bool ProgramHeader::ParsePrgHeader32(char * const phdrBuf)
465 {
466 uint32_t *u4Buf = reinterpret_cast<uint32_t *>(phdrBuf);
467 size_t index {0};
468 type_ = u4Buf[index];
469 ++index;
470 offset_ = u4Buf[index];
471 ++index;
472 vaddr_ = u4Buf[index];
473 ++index;
474 paddr_ = u4Buf[index];
475 ++index;
476 fileSize_ = u4Buf[index];
477 ++index;
478 memSize_ = u4Buf[index];
479 ++index;
480 flags_ = u4Buf[index];
481 ++index;
482 secAlign_ = u4Buf[index];
483 return true;
484 }
485
ParsePrgHeader64(char * const phdrBuf)486 bool ProgramHeader::ParsePrgHeader64(char * const phdrBuf)
487 {
488 uint32_t *u4Buf = reinterpret_cast<uint32_t *>(phdrBuf);
489 size_t index {0};
490 type_ = u4Buf[index];
491 ++index;
492 flags_ = u4Buf[index];
493
494 uint64_t *u8Buf = reinterpret_cast<uint64_t *>(phdrBuf);
495 offset_ = u8Buf[index];
496 ++index;
497 vaddr_ = u8Buf[index];
498 ++index;
499 paddr_ = u8Buf[index];
500 ++index;
501 fileSize_ = u8Buf[index];
502 ++index;
503 memSize_ = u8Buf[index];
504 ++index;
505 secAlign_ = u8Buf[index];
506 return true;
507 }
508 } // namespace Hiebpf
509 } // namespace Developtools
510 } // namespace OHOS
511