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 #include <elf_parser.h>
17
18 using namespace OHOS::Developtools::NativeDaemon::ELF;
19 namespace OHOS {
20 namespace Developtools {
21 namespace NativeDaemon {
ElfFile(const std::string & filename)22 ElfFile::ElfFile(const std::string &filename)
23 {
24 #if is_mingw
25 fd_ = open(filename.c_str(), O_RDONLY | O_BINARY);
26 #else
27 fd_ = open(filename.c_str(), O_RDONLY);
28 #endif
29 if (fd_ != -1) {
30 struct stat sb;
31 if (fstat(fd_, &sb) == -1) {
32 HLOGE("unable to check the file size");
33 } else {
34 HLOGD("file stat size %" PRIu64 "", sb.st_size);
35
36 mmap_ = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd_, 0);
37 if (mmap_ == MMAP_FAILED) {
38 HLOGE("unable to map the file size %" PRIu64 " ", sb.st_size);
39 mmapSize_ = 0;
40 } else {
41 mmapSize_ = sb.st_size;
42 HLOGD("mmap build with size %" PRIu64 " ", mmapSize_);
43 }
44 }
45 }
46 }
47
~ElfFile()48 ElfFile::~ElfFile()
49 {
50 if (mmap_ != MMAP_FAILED) {
51 munmap(mmap_, mmapSize_);
52 }
53
54 if (fd_ != -1) {
55 close(fd_);
56 fd_ = -1;
57 }
58 }
59
MakeUnique(const std::string & filename)60 std::unique_ptr<ElfFile> ElfFile::MakeUnique(const std::string &filename)
61 {
62 std::unique_ptr<ElfFile> file {new (std::nothrow) ElfFile(filename)};
63 if (file == nullptr) {
64 HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ElfFile() failed");
65 return nullptr;
66 }
67 if (!file->IsOpened()) {
68 HLOGE("Error in ElfFile::MakeUnique(): elf file not opended");
69 return nullptr;
70 }
71 if (!file->ParseFile()) {
72 HLOGE("parse elf file failed");
73 return nullptr;
74 }
75 return file;
76 }
77
ParseFile()78 bool ElfFile::ParseFile()
79 {
80 if (!ParseElfHeader()) {
81 HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseElfHeader() failed");
82 return false;
83 }
84 if (!ParsePrgHeaders()) {
85 HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParsePrgHeaders() failed");
86 return false;
87 }
88 if (!ParseSecNamesStr()) {
89 HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseSecNamesStr() failed");
90 return false;
91 }
92 if (!ParseSecHeaders()) {
93 HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseSecHeaders() failed");
94 return false;
95 }
96 return true;
97 }
98
ParseElfHeader()99 bool ElfFile::ParseElfHeader()
100 {
101 size_t ret = lseek(fd_, 0, SEEK_SET);
102 if (ret != 0) {
103 HLOGW("lseek ret %zu", ret);
104 return false;
105 }
106 HLOG_ASSERT(ret == 0);
107 unsigned char ehdrBuf[ehdr64Size] {0};
108 ret = ReadFile(ehdrBuf, ehdr64Size);
109 if (ret < ehdr64Size) {
110 HLOGW("file size not enough, try read %zu, only have %zu", ehdr64Size, ret);
111 }
112 HLOG_ASSERT(ret > 0);
113 ehdr_ = ElfHeader::MakeUnique(ehdrBuf, ret);
114 return !(ehdr_ == nullptr);
115 }
116
ParsePrgHeaders()117 bool ElfFile::ParsePrgHeaders()
118 {
119 size_t phdrSize = ehdr_->phdrEntSize_;
120 size_t numPhdrs = ehdr_->phdrNumEnts_;
121 uint64_t phdrOffset = ehdr_->phdrOffset_;
122 int64_t ret = lseek(fd_, phdrOffset, SEEK_SET);
123 HLOG_ASSERT(ret == static_cast<int64_t>(phdrOffset));
124 char *phdrsBuf = new (std::nothrow) char[phdrSize * numPhdrs];
125 if (phdrsBuf == nullptr) {
126 HLOGE("Error in ELF::ElfFile::ParsePrgHeaders(): new failed");
127 return false;
128 }
129 if (memset_s(phdrsBuf, phdrSize * numPhdrs, 0, phdrSize * numPhdrs) != EOK) {
130 HLOGE("memset_s failed");
131 }
132 ret = ReadFile(phdrsBuf, phdrSize * numPhdrs);
133 if (ret != static_cast<int64_t>(phdrSize * numPhdrs)) {
134 delete[] phdrsBuf;
135 phdrsBuf = nullptr;
136 return false;
137 }
138 char *phdrBuf = phdrsBuf;
139 for (size_t count = 0; count < numPhdrs; ++count) {
140 std::unique_ptr<ProgramHeader> phdr = ProgramHeader::MakeUnique(phdrBuf, phdrSize);
141 if (phdr == nullptr) {
142 delete[] phdrsBuf;
143 phdrsBuf = nullptr;
144 HLOGE("Error in Elf::ParsePrgHeaders(): ProgramHeader::MakeUnique() failed");
145 return false;
146 }
147 phdrs_.push_back(std::move(phdr));
148 phdrBuf += phdrSize;
149 }
150 delete[] phdrsBuf;
151 phdrsBuf = nullptr;
152 return true;
153 }
154
ParseSecNamesStr()155 bool ElfFile::ParseSecNamesStr()
156 {
157 // get string table section header
158 size_t shdrSize = ehdr_->shdrEntSize_;
159 size_t shdrIndex = ehdr_->shdrStrTabIdx_;
160 uint64_t shdrOffset = ehdr_->shdrOffset_ + shdrIndex * shdrSize;
161 int64_t ret = lseek(fd_, shdrOffset, SEEK_SET);
162 HLOG_ASSERT(ret == static_cast<int64_t>(shdrOffset));
163 char *shdrBuf = new (std::nothrow) char[shdrSize];
164 if (shdrBuf == nullptr) {
165 HLOGE("Error in ElfFile::ParseSecNamesStr(): new failed");
166 return false;
167 }
168 if (memset_s(shdrBuf, shdrSize, 0, shdrSize) != EOK) {
169 HLOGE("memset_s failed");
170 }
171 ret = ReadFile(shdrBuf, shdrSize);
172 HLOG_ASSERT(ret == static_cast<int64_t>(shdrSize));
173 const std::string secName {".shstrtab"};
174 shdrs_[secName] = SectionHeader::MakeUnique(shdrBuf, shdrSize, shdrIndex);
175 if (shdrs_[secName] == nullptr) {
176 HLOGE("Error in ElfFile::ParseSecNamesStr(): SectionHeader::MakeUnique() failed");
177 delete[] shdrBuf;
178 shdrBuf = nullptr;
179 return false;
180 }
181 delete[] shdrBuf;
182 shdrBuf = nullptr;
183
184 // get content of string section table
185 uint64_t secOffset = shdrs_[secName]->fileOffset_;
186 size_t secSize = shdrs_[secName]->secSize_;
187 ret = lseek(fd_, secOffset, SEEK_SET);
188 HLOG_ASSERT(ret == static_cast<int64_t>(secOffset));
189 char *secNamesBuf = new (std::nothrow) char[secSize];
190 if (secNamesBuf == nullptr) {
191 return false;
192 }
193 if (memset_s(secNamesBuf, secSize, '\0', secSize) != EOK) {
194 delete[] secNamesBuf;
195 secNamesBuf = nullptr;
196 HLOGE("memset_s failed");
197 return false;
198 }
199 ret = ReadFile(secNamesBuf, secSize);
200 if (ret != static_cast<int64_t>(secSize)) {
201 delete[] secNamesBuf;
202 secNamesBuf = nullptr;
203 return false;
204 }
205 secNamesStr_ = std::string(secNamesBuf, secNamesBuf + secSize);
206 delete[] secNamesBuf;
207 secNamesBuf = nullptr;
208 return true;
209 }
210
ParseSecHeaders()211 bool ElfFile::ParseSecHeaders()
212 {
213 size_t shdrSize = ehdr_->shdrEntSize_;
214 size_t numShdrs = ehdr_->shdrNumEnts_;
215 uint64_t shdrOffset = ehdr_->shdrOffset_;
216 int64_t ret = lseek(fd_, shdrOffset, SEEK_SET);
217 HLOG_ASSERT(ret == static_cast<int64_t>(shdrOffset));
218 char *shdrsBuf = new (std::nothrow) char[shdrSize * numShdrs];
219 if (shdrsBuf == nullptr) {
220 HLOGE("Error in ELF::ElfFile::ParseSecHeaders(): new failed");
221 return false;
222 }
223 if (memset_s(shdrsBuf, shdrSize * numShdrs, '\0', shdrSize * numShdrs) != EOK) {
224 HLOGE("memset_s failed");
225 }
226 ret = ReadFile(shdrsBuf, shdrSize * numShdrs);
227 HLOG_ASSERT(ret == static_cast<int64_t>(shdrSize * numShdrs));
228 char *shdrBuf = shdrsBuf;
229 for (size_t count = 0; count < numShdrs; ++count) {
230 if (count == ehdr_->shdrStrTabIdx_) {
231 shdrBuf += shdrSize;
232 continue;
233 }
234 std::unique_ptr<SectionHeader> shdr = SectionHeader::MakeUnique(shdrBuf, shdrSize, count);
235 if (shdr == nullptr) {
236 delete[] shdrsBuf;
237 shdrsBuf = nullptr;
238 return false;
239 }
240 std::string secName = GetSectionName(shdr->nameIndex_);
241 shdrs_[secName] = std::move(shdr);
242 shdr.reset(nullptr);
243 shdrBuf += shdrSize;
244 }
245 delete[] shdrsBuf;
246 shdrsBuf = nullptr;
247 return true;
248 }
249
ParseSymTable(const std::string secName)250 bool ElfFile::ParseSymTable(const std::string secName)
251 {
252 if (shdrs_.find(secName) == shdrs_.end()) {
253 HLOGE("Error in ELF::ElfFile::ParseSymTable(): section %s does not exist", secName.c_str());
254 return false;
255 } else {
256 return ParseSymTable(shdrs_[secName].get());
257 }
258 }
259
ParseSymTable(const SectionHeader * shdr)260 bool ElfFile::ParseSymTable(const SectionHeader *shdr)
261 {
262 if (shdr == nullptr) {
263 return false;
264 }
265 uint64_t secOffset = shdr->fileOffset_;
266 int64_t ret = lseek(fd_, secOffset, SEEK_SET);
267 HLOG_ASSERT(ret == static_cast<int64_t>(secOffset));
268 uint64_t secSize = shdr->secSize_;
269 uint64_t entrySize = shdr->secEntrySize_;
270 char *secBuf = new (std::nothrow) char[secSize];
271 if (secBuf == nullptr) {
272 HLOGE("Error in EFL::ElfFile::ParseSymTable(): new failed");
273 return false;
274 }
275 ret = ReadFile(secBuf, secSize);
276 HLOG_ASSERT(ret == static_cast<int64_t>(secSize));
277 symTable_ = SymbolTable::MakeUnique(symNamesStr_, secBuf, secSize, entrySize);
278 if (symTable_ == nullptr) {
279 delete[] secBuf;
280 secBuf = nullptr;
281 return false;
282 }
283 delete[] secBuf;
284 secBuf = nullptr;
285 return true;
286 }
287
ParseSymNamesStr()288 bool ElfFile::ParseSymNamesStr()
289 {
290 const std::string secName {".strtab"};
291 if (shdrs_.find(secName) == shdrs_.end()) {
292 HLOGE("Error in ElfFile::ParseSymNamesStr(): section %s does not exist", secName.c_str());
293 return false;
294 }
295 const auto &shdr = shdrs_[secName];
296 uint64_t secOffset = shdr->fileOffset_;
297 uint64_t secSize = shdr->secSize_;
298 int64_t ret = lseek(fd_, secOffset, SEEK_SET);
299 char *secBuf = new (std::nothrow) char[secSize];
300 if (secBuf == nullptr) {
301 HLOGE("Error in ElfFile::ParsesymNamesStr(): new failed");
302 return false;
303 }
304 if (memset_s(secBuf, secSize, '\0', secSize) != EOK) {
305 HLOGE("memset failed");
306 }
307 ret = ReadFile(secBuf, secSize);
308 HLOG_ASSERT(ret == static_cast<int64_t>(secSize));
309 symNamesStr_ = std::string(secBuf, secSize);
310 if (symNamesStr_ == "") {
311 delete[] secBuf;
312 secBuf = nullptr;
313 return false;
314 }
315 delete[] secBuf;
316 secBuf = nullptr;
317 return true;
318 }
319
ParseDynSymTable()320 bool ElfFile::ParseDynSymTable()
321 {
322 const std::string secName {".dynsym"};
323 if (shdrs_.find(secName) == shdrs_.end()) {
324 HLOGE("Error in ELF::ElfFile::ParseSymTable(): section %s does not exist", secName.c_str());
325 return false;
326 }
327 const auto &shdr = shdrs_[secName];
328 uint64_t secOffset = shdr->fileOffset_;
329 int64_t ret = lseek(fd_, secOffset, SEEK_SET);
330 HLOG_ASSERT(ret == static_cast<int64_t>(secOffset));
331 uint64_t secSize = shdr->secSize_;
332 uint64_t entrySize = shdr->secEntrySize_;
333 char *secBuf = new (std::nothrow) char[secSize];
334 if (secBuf == nullptr) {
335 HLOGE("Error in EFL::ElfFile::ParseDynSymTable(): new failed");
336 return false;
337 }
338 ret = ReadFile(secBuf, secSize);
339 HLOG_ASSERT(ret == static_cast<int64_t>(secSize));
340 dynSymTable_ = SymbolTable::MakeUnique(symNamesStr_, secBuf, secSize, entrySize);
341 if (dynSymTable_ == nullptr) {
342 delete[] secBuf;
343 secBuf = nullptr;
344 return false;
345 }
346 delete[] secBuf;
347 secBuf = nullptr;
348 return true;
349 }
350
GetSectionName(const uint32_t startIndex)351 std::string ElfFile::GetSectionName(const uint32_t startIndex)
352 {
353 if (startIndex >= secNamesStr_.size()) {
354 HLOGF("out_of_range %s ,endIndex %d ", secNamesStr_.c_str(), startIndex);
355 return "";
356 }
357 size_t endIndex {startIndex};
358 for (; endIndex < secNamesStr_.size(); ++endIndex) {
359 if (secNamesStr_[endIndex] == '\0') {
360 break;
361 }
362 }
363 return secNamesStr_.substr(startIndex, endIndex - startIndex);
364 }
365 } // namespace NativeDaemon
366 } // namespace Developtools
367 } // namespace OHOS