• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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