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 /* This files contains process dump elf module. */
17
18 #include "dfx_elf.h"
19
20 #include <cstdlib>
21 #include <fcntl.h>
22 #include <new>
23 #include <string>
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <vector>
29 #include "bits/fcntl.h"
30 #include "dfx_log.h"
31 #include "elf.h"
32 #include "link.h"
33
34 #ifndef PAGE_SIZE
35 #define PAGE_SIZE 4096
36 #endif
37
38 namespace OHOS {
39 namespace HiviewDFX {
40 static const int MAX_MAP_SIZE = 65536;
41
Create(const std::string path)42 std::shared_ptr<DfxElf> DfxElf::Create(const std::string path)
43 {
44 char realPaths[PATH_MAX] = {0};
45 if (!realpath(path.c_str(), realPaths)) {
46 DfxLogWarn("Fail to do realpath(%s).", path.c_str());
47 return nullptr;
48 }
49
50 auto dfxElf = std::make_shared<DfxElf>();
51
52 dfxElf->SetFd(open(realPaths, O_RDONLY | O_CLOEXEC));
53
54 if (dfxElf->fd_ < 0) {
55 DfxLogWarn("Fail to open elf file(%s).", realPaths);
56 return nullptr;
57 }
58
59 struct stat elfStat;
60 if (fstat(dfxElf->fd_, &elfStat) != 0) {
61 DfxLogWarn("Fail to get elf size.");
62 close(dfxElf->fd_);
63 dfxElf->SetFd(-1);
64 return nullptr;
65 }
66
67 dfxElf->SetSize((uint64_t)elfStat.st_size);
68 if (!dfxElf->ParseElfHeader()) {
69 DfxLogWarn("Fail to parse elf header.");
70 close(dfxElf->fd_);
71 dfxElf->SetFd(-1);
72 return nullptr;
73 }
74
75 if (!dfxElf->ParseElfProgramHeader()) {
76 DfxLogWarn("Fail to parse elf program header.");
77 close(dfxElf->GetFd());
78 dfxElf->SetFd(-1);
79 return nullptr;
80 }
81
82 close(dfxElf->GetFd());
83 dfxElf->SetFd(-1);
84 return dfxElf;
85 }
86
ParseElfHeader()87 bool DfxElf::ParseElfHeader()
88 {
89 ssize_t nread = read(fd_, &(header_), sizeof(header_));
90 if (nread < 0 || nread != static_cast<long>(sizeof(header_))) {
91 DfxLogWarn("Failed to read elf header.");
92 return false;
93 }
94 return true;
95 }
96
ParseElfProgramHeader()97 bool DfxElf::ParseElfProgramHeader()
98 {
99 size_t size = header_.e_phnum * sizeof(ElfW(Phdr));
100 if (size > MAX_MAP_SIZE) {
101 DfxLogWarn("Exceed max mmap size.");
102 return false;
103 }
104
105 size_t offset = header_.e_phoff;
106 size_t startOffset = offset & static_cast<size_t>(getpagesize() - 1);
107 size_t alignedOffset = offset & (~(static_cast<size_t>(getpagesize() - 1)));
108 uint64_t endOffset;
109 if (__builtin_add_overflow(static_cast<uint64_t>(size), static_cast<uint64_t>(offset), &endOffset) ||
110 __builtin_add_overflow(static_cast<uint64_t>(endOffset), static_cast<uint64_t>(startOffset), &endOffset)) {
111 DfxLogWarn("Offset calculate error.");
112 return false;
113 }
114
115 size_t mapSize = static_cast<size_t>(endOffset - offset);
116 if (mapSize > MAX_MAP_SIZE) {
117 DfxLogWarn("Exceed max mmap size.");
118 return false;
119 }
120
121 void *map = mmap(nullptr, mapSize, PROT_READ, MAP_PRIVATE, fd_, static_cast<off_t>(alignedOffset));
122 if (map == static_cast<void *>MAP_FAILED) {
123 DfxLogWarn("Failed to mmap elf.");
124 return false;
125 }
126
127 ElfW(Phdr) *phdrTable = (ElfW(Phdr) *)(static_cast<uint8_t*>(map) + startOffset);
128 for (size_t i = 0; i < header_.e_phnum; i++) {
129 ElfW(Phdr) * phdr = &(phdrTable[i]);
130 if (phdr->p_type != PT_LOAD) {
131 continue;
132 }
133 CreateLoadInfo(phdr->p_vaddr, phdr->p_offset);
134 }
135 munmap(map, mapSize);
136 return true;
137 }
138
FindRealLoadOffset(uint64_t offset) const139 uint64_t DfxElf::FindRealLoadOffset(uint64_t offset) const
140 {
141 for (auto iter = infos_.begin(); iter != infos_.end(); iter++) {
142 if ((iter->offset & -PAGE_SIZE) == offset) {
143 return offset + (iter->vaddr - iter->offset);
144 }
145 }
146 return offset;
147 }
148
CreateLoadInfo(uint64_t vaddr,uint64_t offset)149 void DfxElf::CreateLoadInfo(uint64_t vaddr, uint64_t offset)
150 {
151 std::unique_ptr<ElfLoadInfo> info(new ElfLoadInfo());
152 if (info == nullptr) {
153 return;
154 }
155 info->vaddr = vaddr;
156 info->offset = offset;
157
158 infos_.push_back(*info);
159 }
160
GetName() const161 std::string DfxElf::GetName() const
162 {
163 return name_;
164 }
165
SetName(const std::string & name)166 void DfxElf::SetName(const std::string &name)
167 {
168 name_ = name;
169 }
170
GetPath() const171 std::string DfxElf::GetPath() const
172 {
173 return path_;
174 }
175
SetPath(const std::string & path)176 void DfxElf::SetPath(const std::string &path)
177 {
178 path_ = path;
179 }
180
ElfW(Ehdr)181 ElfW(Ehdr) DfxElf::GetHeader() const
182 {
183 return header_;
184 }
185
SetHeader(ElfW (Ehdr)header)186 void DfxElf::SetHeader(ElfW(Ehdr) header)
187 {
188 header_ = header;
189 }
190
GetInfos() const191 std::vector<ElfLoadInfo> DfxElf::GetInfos() const
192 {
193 return infos_;
194 }
SetInfos(const std::vector<ElfLoadInfo> & infos)195 void DfxElf::SetInfos(const std::vector<ElfLoadInfo> &infos)
196 {
197 infos_ = infos;
198 }
199
GetFd() const200 int32_t DfxElf::GetFd() const
201 {
202 return fd_;
203 }
204
SetFd(int32_t fdValue)205 void DfxElf::SetFd(int32_t fdValue)
206 {
207 fd_ = fdValue;
208 }
209
GetLoadBias() const210 size_t DfxElf::GetLoadBias() const
211 {
212 return loadBias_;
213 }
214
SetLoadBias(size_t loadBias)215 void DfxElf::SetLoadBias(size_t loadBias)
216 {
217 loadBias_ = loadBias;
218 }
219
GetSize() const220 uint64_t DfxElf::GetSize() const
221 {
222 return size_;
223 }
224
SetSize(uint64_t size)225 void DfxElf::SetSize(uint64_t size)
226 {
227 size_ = size;
228 }
229 } // namespace HiviewDFX
230 } // namespace OHOS
231