1 /*
2 * Copyright (c) 2025 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_factory.h"
17
18 #include <string>
19 #include <algorithm>
20 #include <cstdlib>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <utility>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26
27 #include "dfx_define.h"
28 #include "dfx_log.h"
29 #include "dfx_maps.h"
30 #include "dfx_trace_dlsym.h"
31 #include "dfx_util.h"
32 #include "smart_fd.h"
33 #if defined(ENABLE_MINIDEBUGINFO)
34 #include "7zCrc.h"
35 #include "unwinder_config.h"
36 #include "Xz.h"
37 #include "XzCrc64.h"
38 #endif
39
40 namespace OHOS {
41 namespace HiviewDFX {
42 namespace {
43 #undef LOG_DOMAIN
44 #undef LOG_TAG
45 #define LOG_DOMAIN 0xD002D11
46 #define LOG_TAG "ElfFactory"
47 }
48 #if defined(ENABLE_MINIDEBUGINFO)
Create()49 std::shared_ptr<DfxElf> MiniDebugInfoFactory::Create()
50 {
51 DFX_TRACE_SCOPED_DLSYM("CreateMiniDebugInfo");
52 if (!UnwinderConfig::GetEnableMiniDebugInfo()) {
53 return nullptr;
54 }
55
56 std::vector<uint8_t> miniDebugInfoData;
57 if (!XzDecompress(reinterpret_cast<uint8_t *>(gnuDebugDataHdr_.address),
58 gnuDebugDataHdr_.size, miniDebugInfoData)) {
59 DFXLOGU("Failed to decompressed .gnu_debugdata seciton.");
60 return nullptr;
61 }
62 // miniDebugInfoData store the decompressed bytes.
63 // use these bytes to construct an elf.
64 auto mMap = std::make_shared<DfxMmap>();
65 if (!mMap->Init(std::move(miniDebugInfoData))) {
66 DFXLOGE("Failed to init mmap_!");
67 return nullptr;
68 }
69 auto miniDebugInfo = std::make_shared<DfxElf>(mMap);
70 if (!miniDebugInfo->IsValid()) {
71 DFXLOGE("Failed to parse mini debuginfo Elf.");
72 return nullptr;
73 }
74 return miniDebugInfo;
75 }
76
XzAlloc(ISzAllocPtr,size_t size)77 static void* XzAlloc(ISzAllocPtr, size_t size)
78 {
79 return malloc(size);
80 }
81
XzFree(ISzAllocPtr,void * address)82 static void XzFree(ISzAllocPtr, void *address)
83 {
84 free(address);
85 }
86
XzDecompress(const uint8_t * src,size_t srcLen,std::vector<uint8_t> & out)87 bool MiniDebugInfoFactory::XzDecompress(const uint8_t *src, size_t srcLen, std::vector<uint8_t>& out)
88 {
89 DFX_TRACE_SCOPED_DLSYM("XzDecompress");
90 ISzAlloc alloc;
91 CXzUnpacker state;
92 alloc.Alloc = XzAlloc;
93 alloc.Free = XzFree;
94 XzUnpacker_Construct(&state, &alloc);
95 CrcGenerateTable();
96 Crc64GenerateTable();
97 size_t srcOff = 0;
98 size_t dstOff = 0;
99 out.resize(srcLen);
100 ECoderStatus status = CODER_STATUS_NOT_FINISHED;
101 constexpr uint16_t expandFactor = 2;
102 while (status == CODER_STATUS_NOT_FINISHED) {
103 out.resize(out.size() * expandFactor);
104 size_t srcRemain = srcLen - srcOff;
105 size_t dstRemain = out.size() - dstOff;
106 int res = XzUnpacker_Code(&state,
107 reinterpret_cast<Byte*>(&out[dstOff]), &dstRemain,
108 reinterpret_cast<const Byte*>(&src[srcOff]), &srcRemain,
109 true, CODER_FINISH_ANY, &status);
110 if (res != SZ_OK) {
111 XzUnpacker_Free(&state);
112 return false;
113 }
114 srcOff += srcRemain;
115 dstOff += dstRemain;
116 }
117 XzUnpacker_Free(&state);
118 if (!XzUnpacker_IsStreamWasFinished(&state)) {
119 return false;
120 }
121 out.resize(dstOff);
122 return true;
123 }
124 #endif
125
Create()126 std::shared_ptr<DfxElf> RegularElfFactory::Create()
127 {
128 std::shared_ptr<DfxElf> regularElf = std::make_shared<DfxElf>();
129 if (filePath_.empty()) {
130 DFXLOGE("file path is empty!");
131 return regularElf;
132 }
133 DFXLOGU("file: %{public}s", filePath_.c_str());
134 #if defined(is_ohos) && is_ohos
135 if (!DfxMaps::IsLegalMapItem(filePath_)) {
136 DFXLOGD("Illegal map file, please check file: %{public}s", filePath_.c_str());
137 return regularElf;
138 }
139 #endif
140
141 #if defined(is_mingw) && is_mingw
142 int fd = OHOS_TEMP_FAILURE_RETRY(open(filePath_.c_str(), O_RDONLY | O_BINARY));
143 #else
144 int fd = OHOS_TEMP_FAILURE_RETRY(open(filePath_.c_str(), O_RDONLY));
145 #endif
146 SmartFd smartFd(fd);
147 if (!smartFd) {
148 DFXLOGE("Failed to open file: %{public}s, errno(%{public}d)", filePath_.c_str(), errno);
149 return regularElf;
150 }
151 auto mMap = std::make_shared<DfxMmap>();
152 if (!mMap->Init(smartFd.GetFd(), static_cast<size_t>(GetFileSize(smartFd.GetFd())), 0)) {
153 DFXLOGE("Failed to mmap init.");
154 return regularElf;
155 }
156 regularElf->SetMmap(mMap);
157 return regularElf;
158 }
159
Create()160 std::shared_ptr<DfxElf> VdsoElfFactory::Create()
161 {
162 #if is_ohos && !is_mingw
163 std::vector<uint8_t> shmmData(size_);
164 size_t byte = ReadProcMemByPid(pid_, begin_, shmmData.data(), size_);
165 if (byte != size_) {
166 DFXLOGE("Failed to read shmm data");
167 return nullptr;
168 }
169
170 auto mMap = std::make_shared<DfxMmap>();
171 if (!mMap->Init(std::move(shmmData))) {
172 DFXLOGE("Failed to init mmap_!");
173 return nullptr;
174 }
175 auto vdsoElf = std::make_shared<DfxElf>(mMap);
176 if (!vdsoElf->IsValid()) {
177 DFXLOGE("Failed to parse Embedded Elf.");
178 return nullptr;
179 }
180 return vdsoElf;
181 #endif
182 return nullptr;
183 }
184
185
Create()186 std::shared_ptr<DfxElf> CompressHapElfFactory::Create()
187 {
188 /*
189 elf header is in the first mmap area
190 c3840000-c38a6000 r--p 00174000 /data/storage/el1/bundle/entry.hap <- program header
191 c38a6000-c3945000 r-xp 001d9000 /data/storage/el1/bundle/entry.hap <- pc is in this region
192 c3945000-c394b000 r--p 00277000 /data/storage/el1/bundle/entry.hap
193 c394b000-c394c000 rw-p 0027c000 /data/storage/el1/bundle/entry.hap
194 */
195 if (prevMap_ == nullptr) {
196 DFXLOGE("current hap map item or prev map item , maybe pc is wrong?");
197 return nullptr;
198 }
199 // Do not use the Realpath function, the sandbox path Realpath function will return failure
200 if (!StartsWith(filePath_, "/proc") || !EndsWith(filePath_, ".hap")) {
201 DFXLOGD("Illegal file path, please check file: %{public}s", filePath_.c_str());
202 return nullptr;
203 }
204 SmartFd smartFd(static_cast<int>(OHOS_TEMP_FAILURE_RETRY(open(filePath_.c_str(), O_RDONLY))));
205 if (!smartFd) {
206 DFXLOGE("Failed to open hap file, errno(%{public}d)", errno);
207 return nullptr;
208 }
209
210 size_t elfSize = 0;
211 if (!VerifyElf(smartFd.GetFd(), elfSize)) {
212 return {};
213 }
214 DFXLOGU("elfSize: %{public}zu", elfSize);
215 auto mMap = std::make_shared<DfxMmap>();
216 if (!mMap->Init(smartFd.GetFd(), elfSize, prevMap_->offset)) {
217 DFXLOGE("Failed to init mmap_!");
218 return {};
219 }
220 std::shared_ptr<DfxElf> compressHapElf = std::make_shared<DfxElf>(mMap);
221 compressHapElf->SetBaseOffset(prevMap_->offset);
222 if (!compressHapElf->IsValid()) {
223 DFXLOGE("Failed to parse compress hap Elf.");
224 return {};
225 }
226 return compressHapElf;
227 }
228
VerifyElf(int fd,size_t & elfSize)229 bool CompressHapElfFactory::VerifyElf(int fd, size_t& elfSize)
230 {
231 size_t size = prevMap_->end - prevMap_->begin;
232 auto mmap = std::make_shared<DfxMmap>();
233 if (!mmap->Init(fd, size, static_cast<off_t>(prevMap_->offset))) {
234 DFXLOGE("Failed to mmap program header in hap.");
235 return false;
236 }
237 const uint8_t* data = static_cast<const uint8_t*>(mmap->Get());
238 if (data == nullptr || memcmp(data, ELFMAG, SELFMAG) != 0) {
239 DFXLOGE("Invalid elf hdr?");
240 return false;
241 }
242 uint8_t classType = data[EI_CLASS];
243 elfSize = 0;
244 if (classType == ELFCLASS32) {
245 const Elf32_Ehdr* ehdr = reinterpret_cast<const Elf32_Ehdr *>(data);
246 elfSize = static_cast<size_t>(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum));
247 } else if (classType == ELFCLASS64) {
248 const Elf64_Ehdr* ehdr = reinterpret_cast<const Elf64_Ehdr *>(data);
249 elfSize = static_cast<size_t>(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum));
250 }
251 if (elfSize == 0) {
252 DFXLOGE("elf size equal zero, invalid elf!");
253 return false;
254 }
255 auto fileSize = GetFileSize(fd);
256 if (fileSize <= 0) {
257 DFXLOGE("file size can not less or equal zero!");
258 return false;
259 }
260 if (elfSize + prevMap_->offset > static_cast<size_t>(fileSize)) {
261 DFXLOGE("Invalid elf size? elf size: %{public}zu, hap size: %{public}zu", elfSize,
262 static_cast<size_t>(fileSize));
263 return false;
264 }
265 return true;
266 }
267 } // namespace HiviewDFX
268 } // namespace OHOS
269