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 #ifndef ELF_PARSER_H_ 17 #define ELF_PARSER_H_ 18 #include <cassert> 19 #include <cstring> 20 #include <functional> 21 #include <unordered_map> 22 #if !is_ohos 23 // this is not good enough 24 #include <../musl/include/elf.h> 25 #else 26 #include <elf.h> 27 #endif 28 #include <fcntl.h> 29 #include <stdint.h> 30 #include <strings.h> 31 #include <sys/types.h> 32 #include <unistd.h> 33 #include "utilities.h" 34 35 #if !is_mingw 36 #include <sys/mman.h> 37 #include <sys/stat.h> 38 #endif 39 40 namespace OHOS { 41 namespace Developtools { 42 namespace HiPerf { 43 namespace ELF { 44 using namespace std::string_literals; 45 46 constexpr std::size_t ehdr32Size {52}; 47 constexpr std::size_t ehdr64Size {64}; 48 constexpr std::size_t shdr32Size {40}; 49 constexpr std::size_t shdr64Size {64}; 50 constexpr std::size_t phdr32Size {32}; 51 constexpr std::size_t phdr64Size {56}; 52 constexpr std::size_t symEnt32Size {16}; 53 constexpr std::size_t symEnt64Size {24}; 54 55 class ElfHeader { 56 public: 57 static std::unique_ptr<ElfHeader> MakeUnique(unsigned char * const ehdrBuf, 58 const std::size_t bufSize); 59 bool Init(unsigned char * const ehdrBuf, const std::size_t bufSize); 60 61 unsigned char ehdrIdent_[EI_NIDENT]; 62 uint16_t type_; 63 uint16_t machine_; 64 uint16_t ehdrSize_; 65 uint16_t phdrEntSize_; 66 uint16_t phdrNumEnts_; 67 uint16_t shdrEntSize_; 68 uint16_t shdrNumEnts_; 69 uint16_t shdrStrTabIdx_; 70 uint32_t elfVersion_; 71 uint32_t ehdrFlags_; 72 uint64_t prgEntryVaddr_; 73 uint64_t phdrOffset_; 74 uint64_t shdrOffset_; 75 76 private: 77 explicit ElfHeader() = default; 78 bool ParseElf32Header(unsigned char * const ehdrBuf, const std::size_t bufSize); 79 bool ParseElf64Header(unsigned char * const ehdrBuf, const std::size_t bufSize); DumpEhdrBuf(const char * const ehdrBuf,const std::size_t bufSize)80 static inline void DumpEhdrBuf(const char * const ehdrBuf, const std::size_t bufSize) 81 { 82 const std::string fileName {"ehdr_buffer_dump"}; 83 std::ofstream ofs {fileName, std::ios::binary}; 84 if (ofs.is_open()) { 85 ofs.write(ehdrBuf, bufSize); 86 } 87 } 88 }; 89 90 class ProgramHeader { 91 public: 92 static std::unique_ptr<ProgramHeader> MakeUnique(char * const phdrBuf, const size_t bufSize); Init(char * const phdrBuf,const size_t bufSize)93 inline bool Init(char * const phdrBuf, const size_t bufSize) 94 { 95 if (bufSize == phdr32Size and ParsePrgHeader32(phdrBuf)) { 96 return true; 97 } 98 if (bufSize == phdr64Size and ParsePrgHeader64(phdrBuf)) { 99 return true; 100 } 101 HLOGE("parse program header failed, program header buffer dumped"); 102 return false; 103 } 104 105 uint32_t type_; 106 uint32_t flags_; 107 uint64_t offset_; 108 uint64_t vaddr_; 109 uint64_t paddr_; 110 uint64_t fileSize_; 111 uint64_t memSize_; 112 uint64_t secAlign_; 113 114 private: 115 explicit ProgramHeader() = default; 116 bool ParsePrgHeader32(char * const phdrBuf); 117 bool ParsePrgHeader64(char * const phdrBuf); DumpPhdrBuf(const char * const phdrBuf,const std::size_t bufSize)118 static inline void DumpPhdrBuf(const char * const phdrBuf, const std::size_t bufSize) 119 { 120 const std::string fileName {"phdr_buffer_dump"}; 121 std::ofstream ofs {fileName, std::ios::binary}; 122 if (ofs.is_open()) { 123 ofs.write(phdrBuf, bufSize); 124 } 125 } 126 }; 127 128 class SectionHeader { 129 public: 130 static std::unique_ptr<SectionHeader> MakeUnique(char * const shdrBuf, const size_t bufSize, 131 const size_t index); 132 Init(char * const shdrBuf,const size_t bufSize,const size_t index)133 inline bool Init(char * const shdrBuf, const size_t bufSize, const size_t index) 134 { 135 secIndex_ = index; 136 if (bufSize == shdr32Size and ParseSecHeader32(shdrBuf)) { 137 return true; 138 } 139 if (bufSize == shdr64Size and ParseSecHeader64(shdrBuf)) { 140 return true; 141 } 142 HLOGE("parse section header failed, section header buffer dumped"); 143 return false; 144 } 145 146 uint32_t nameIndex_; 147 uint32_t link_; 148 uint32_t info_; 149 uint64_t secFlags_; 150 uint64_t secVaddr_; 151 uint64_t fileOffset_; 152 uint64_t secSize_; 153 uint64_t secAddrAlign_; 154 uint64_t secEntrySize_; 155 uint64_t secType_; 156 uint32_t secIndex_; 157 std::string secTypeName_; 158 159 private: 160 explicit SectionHeader() = default; 161 bool ParseSecHeader32(char * const shdrBuf); 162 bool ParseSecHeader64(char * const shdrBuf); DumpShdrBuf(const char * const shdrBuf,const std::size_t bufSize)163 static inline void DumpShdrBuf(const char * const shdrBuf, const std::size_t bufSize) 164 { 165 const std::string fileName {"shdr_buffer_dump"}; 166 std::ofstream ofs {fileName, std::ios::binary}; 167 if (ofs.is_open()) { 168 ofs.write(shdrBuf, bufSize); 169 } 170 } 171 }; 172 173 class ElfSymbol { 174 public: 175 static std::unique_ptr<ElfSymbol> MakeUnique(char * const symBuf, const std::size_t bufSize); Init(char * const symBuf,const std::size_t bufSize)176 inline bool Init(char * const symBuf, const std::size_t bufSize) 177 { 178 if (bufSize == symEnt32Size and ParseElf32Symbol(symBuf)) { 179 return true; 180 } 181 if (bufSize == symEnt64Size and ParseElf64Symbol(symBuf)) { 182 return true; 183 } 184 HLOGE("parse elf symbol failed, symbol buffer dumped"); 185 return false; 186 } 187 188 uint16_t secIndex_; 189 uint32_t nameIndex_; 190 uint64_t symValue_; 191 uint64_t symSize_; 192 unsigned char symInfo_; 193 unsigned char symOtherInfo_; 194 195 private: 196 explicit ElfSymbol() = default; 197 bool ParseElf32Symbol(char * const symBuf); 198 bool ParseElf64Symbol(char * const symBuf); DumpSymBuf(const char * const symBuf,const std::size_t bufSize)199 static inline void DumpSymBuf(const char * const symBuf, const std::size_t bufSize) 200 { 201 const std::string fileName {"shdr_buffer_dump"}; 202 std::ofstream ofs {fileName, std::ios::binary}; 203 if (ofs.is_open()) { 204 ofs.write(symBuf, bufSize); 205 } 206 } 207 }; 208 209 class SymbolTable { 210 public: 211 static std::unique_ptr<SymbolTable> MakeUnique(const std::string &symNamesStr, 212 const char * const secBuf, 213 const uint64_t secSize, 214 const uint64_t entrySize); 215 216 std::vector<std::unique_ptr<ElfSymbol>> symbols_; 217 218 private: SymbolTable(const std::string & symNamesStr)219 explicit SymbolTable(const std::string &symNamesStr) : symNamesStr_ {symNamesStr} {} 220 221 const std::string symNamesStr_ {}; 222 }; 223 224 class ElfFile : public Noncopyable { 225 public: 226 virtual ~ElfFile(); 227 static std::unique_ptr<ElfFile> MakeUnique(const std::string &filename); 228 bool ParseFile(); 229 bool ParseSymTable(const SectionHeader *shdr); 230 std::string GetSectionName(const uint32_t startIndex); 231 IsOpened()232 inline bool IsOpened() const 233 { 234 return fd_ != -1; 235 } 236 GetStrPtr(uint32_t sh_link,uint32_t st_name)237 inline const char *GetStrPtr(uint32_t sh_link, uint32_t st_name) 238 { 239 for (const auto &shdrsItem : shdrs_) { 240 if (shdrsItem.second->secIndex_ == sh_link) { 241 if (mmap_ != MMAP_FAILED) { 242 char *elfFileBegin = (char *)mmap_; 243 return elfFileBegin + shdrsItem.second->fileOffset_ + st_name; 244 } 245 } 246 } 247 HLOGE("string not found sh_link %u st_name %d", sh_link, st_name); 248 return nullptr; 249 } 250 GetSectionData(uint32_t shIndex)251 inline const unsigned char *GetSectionData(uint32_t shIndex) 252 { 253 for (const auto &shdrsItem : shdrs_) { 254 if (shdrsItem.second->secIndex_ == shIndex) { 255 if (mmap_ != MMAP_FAILED) { 256 const unsigned char *elfFileBegin = (const unsigned char *)mmap_; 257 return elfFileBegin + shdrsItem.second->fileOffset_; 258 } 259 } 260 } 261 HLOGE("string not found shIndex %u ", shIndex); 262 return nullptr; 263 } 264 265 using SecHeaderTableType = std::unordered_map<std::string, std::unique_ptr<SectionHeader>>; 266 using PrgHeaderTableType = std::vector<std::unique_ptr<ProgramHeader>>; 267 int fd_ {-1}; 268 std::unique_ptr<ElfHeader> ehdr_ {nullptr}; 269 SecHeaderTableType shdrs_ {}; 270 PrgHeaderTableType phdrs_ {}; 271 std::string secNamesStr_ {}; 272 std::string symNamesStr_ {}; 273 std::unique_ptr<SymbolTable> symTable_ {nullptr}; 274 std::unique_ptr<SymbolTable> dynSymTable_ {nullptr}; 275 276 protected: 277 // for fuzz test we make a virtual function ReadFile(void * buf,size_t count)278 virtual ssize_t ReadFile(void *buf, size_t count) 279 { 280 return read(fd_, buf, count); 281 }; 282 explicit ElfFile(const std::string &filename); 283 284 private: 285 bool ParseElfHeader(); 286 bool ParsePrgHeaders(); 287 bool ParseSecNamesStr(); 288 bool ParseSecHeaders(); 289 bool ParseSymNamesStr(); 290 bool ParseSymTable(const std::string = ".symtab"); 291 bool ParseDynSymTable(); 292 293 void *mmap_ = MMAP_FAILED; 294 uint64_t mmapSize_ = 0; 295 }; 296 } // namespace ELF 297 } // namespace HiPerf 298 } // namespace Developtools 299 } // namespace OHOS 300 #endif // ELF_PARSER_H_ 301