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