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