• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "dfx_accessors.h"
17 
18 #include <algorithm>
19 #include <elf.h>
20 #include <fcntl.h>
21 #include <securec.h>
22 #include <sys/ptrace.h>
23 #include <sys/syscall.h>
24 #include <sys/uio.h>
25 #include "dfx_define.h"
26 #include "dfx_errors.h"
27 #include "dfx_log.h"
28 #include "dfx_regs.h"
29 #include "dfx_trace_dlsym.h"
30 #include "dfx_elf.h"
31 #include "dfx_maps.h"
32 
33 namespace OHOS {
34 namespace HiviewDFX {
35 namespace {
36 #undef LOG_DOMAIN
37 #undef LOG_TAG
38 #define LOG_DOMAIN 0xD002D11
39 #define LOG_TAG "DfxAccessors"
40 
41 static const int FOUR_BYTES = 4;
42 static const int EIGHT_BYTES = 8;
43 static const int THIRTY_TWO_BITS = 32;
44 }
45 
GetMapByPcAndCtx(uintptr_t pc,std::shared_ptr<DfxMap> & map,void * arg)46 bool DfxAccessors::GetMapByPcAndCtx(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg)
47 {
48     if (arg == nullptr) {
49         return false;
50     }
51     UnwindContext* ctx = reinterpret_cast<UnwindContext *>(arg);
52     if (ctx->map != nullptr && ctx->map->Contain(static_cast<uint64_t>(pc))) {
53         map = ctx->map;
54         DFXLOGU("map had matched by ctx, map name: %{public}s", map->name.c_str());
55         return true;
56     }
57 
58     if (ctx->maps == nullptr || !ctx->maps->FindMapByAddr(pc, map) || (map == nullptr)) {
59         ctx->map = nullptr;
60         return false;
61     }
62     ctx->map = map;
63     return true;
64 }
65 
CreatePipe()66 bool DfxAccessorsLocal::CreatePipe()
67 {
68     if (initPipe_) {
69         return true;
70     }
71 
72     std::lock_guard<std::mutex> lock(mutex_);
73     if (!initPipe_ && syscall(SYS_pipe2, pfd_, O_CLOEXEC | O_NONBLOCK) == 0) {
74         initPipe_ = true;
75     }
76     return initPipe_;
77 }
78 
~DfxAccessorsLocal(void)79 DfxAccessorsLocal::~DfxAccessorsLocal(void)
80 {
81     if (initPipe_) {
82         syscall(SYS_close, pfd_[PIPE_WRITE]);
83         syscall(SYS_close, pfd_[PIPE_READ]);
84         initPipe_ = false;
85     }
86 }
87 
AccessMem(uintptr_t addr,uintptr_t * val,void * arg)88 NO_SANITIZE int DfxAccessorsLocal::AccessMem(uintptr_t addr, uintptr_t *val, void *arg)
89 {
90     if (val == nullptr) {
91         return UNW_ERROR_INVALID_MEMORY;
92     }
93     UnwindContext* ctx = reinterpret_cast<UnwindContext *>(arg);
94     if (ctx == nullptr || ctx->stackCheck == false) {
95         *val = *reinterpret_cast<uintptr_t *>(addr);
96         return UNW_ERROR_NONE;
97     }
98     if (UNLIKELY(ctx->stackTop < ctx->stackBottom)) {
99         DFXLOGU("Failed to access addr, the stackTop smaller than stackBottom");
100         return UNW_ERROR_INVALID_MEMORY;
101     }
102     if ((addr >= ctx->stackBottom) && (addr + sizeof(uintptr_t) < ctx->stackTop)) {
103         *val = *reinterpret_cast<uintptr_t *>(addr);
104         return UNW_ERROR_NONE;
105     }
106     if (!CreatePipe()) {
107         DFXLOGU("Failed to access addr, the pipe create fail, errno:%{public}d", errno);
108         return UNW_ERROR_INVALID_MEMORY;
109     }
110     if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_write, pfd_[PIPE_WRITE], addr, sizeof(uintptr_t))) == -1) {
111         DFXLOGU("Failed to access addr, the pipe write fail, errno:%{public}d", errno);
112         return UNW_ERROR_INVALID_MEMORY;
113     }
114     if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_read, pfd_[PIPE_READ], val, sizeof(uintptr_t))) == -1) {
115         DFXLOGU("Failed to access addr, the pipe read fail, errno:%{public}d", errno);
116         return UNW_ERROR_INVALID_MEMORY;
117     }
118     return UNW_ERROR_NONE;
119 }
120 
AccessReg(int reg,uintptr_t * val,void * arg)121 int DfxAccessorsLocal::AccessReg(int reg, uintptr_t *val, void *arg)
122 {
123     UnwindContext* ctx = reinterpret_cast<UnwindContext *>(arg);
124     if (ctx == nullptr) {
125         return UNW_ERROR_INVALID_CONTEXT;
126     }
127     if (ctx->regs == nullptr || reg < 0 || reg >= (int)ctx->regs->RegsSize()) {
128         return UNW_ERROR_INVALID_REGS;
129     }
130 
131     *val = static_cast<uintptr_t>((*(ctx->regs))[reg]);
132     return UNW_ERROR_NONE;
133 }
134 
FindUnwindTable(uintptr_t pc,UnwindTableInfo & uti,void * arg)135 int DfxAccessorsLocal::FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti, void *arg)
136 {
137     UnwindContext *ctx = reinterpret_cast<UnwindContext *>(arg);
138     if (ctx == nullptr) {
139         return UNW_ERROR_INVALID_CONTEXT;
140     }
141 
142     int ret = UNW_ERROR_INVALID_ELF;
143     if (ctx->map != nullptr && ctx->map->IsVdsoMap()) {
144         auto elf = ctx->map->GetElf(getpid());
145         if (elf == nullptr) {
146             DFXLOGU("FindUnwindTable elf is null");
147             return ret;
148         }
149         ret = elf->FindUnwindTableInfo(pc, ctx->map, uti);
150     } else {
151         ret = DfxElf::FindUnwindTableLocal(pc, uti);
152     }
153     if (ret == UNW_ERROR_NONE) {
154         ctx->di = uti;
155     }
156     return ret;
157 }
158 
GetMapByPc(uintptr_t pc,std::shared_ptr<DfxMap> & map,void * arg)159 int DfxAccessorsLocal::GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg)
160 {
161     if (!DfxAccessors::GetMapByPcAndCtx(pc, map, arg)) {
162         return UNW_ERROR_INVALID_MAP;
163     }
164     return UNW_ERROR_NONE;
165 }
166 
AccessMem(uintptr_t addr,uintptr_t * val,void * arg)167 int DfxAccessorsRemote::AccessMem(uintptr_t addr, uintptr_t *val, void *arg)
168 {
169 #if !defined(__LP64__)
170     // Cannot read an address greater than 32 bits in a 32 bit context.
171     if (addr > UINT32_MAX) {
172         return UNW_ERROR_ILLEGAL_VALUE;
173     }
174 #endif
175     UnwindContext *ctx = reinterpret_cast<UnwindContext *>(arg);
176     if ((ctx == nullptr) || (ctx->pid <= 0)) {
177         return UNW_ERROR_INVALID_CONTEXT;
178     }
179 
180     if (ctx->map != nullptr && ctx->map->elf != nullptr) {
181         uintptr_t pos = ctx->map->GetRelPc(addr);
182         if (ctx->map->elf->Read(pos, val, sizeof(uintptr_t))) {
183             DFXLOGU("Read elf mmap pos: %{public}p", (void *)pos);
184             return UNW_ERROR_NONE;
185         }
186     }
187 
188     int i, end;
189     if (sizeof(long) == FOUR_BYTES && sizeof(uintptr_t) == EIGHT_BYTES) {
190         end = 2; // 2 : read two times
191     } else {
192         end = 1;
193     }
194 
195     uintptr_t tmpVal;
196     for (i = 0; i < end; i++) {
197         uintptr_t tmpAddr = ((i == 0) ? addr : addr + FOUR_BYTES);
198         errno = 0;
199 
200         tmpVal = (unsigned long) ptrace(PTRACE_PEEKDATA, ctx->pid, tmpAddr, nullptr);
201         if (i == 0) {
202             *val = 0;
203         }
204 
205 #if __BYTE_ORDER == __LITTLE_ENDIAN
206         *val |= tmpVal << (i * THIRTY_TWO_BITS);
207 #else
208         *val |= (i == 0 && end == 2 ? tmpVal << THIRTY_TWO_BITS : tmpVal); // 2 : read two times
209 #endif
210         if (errno) {
211             DFXLOGU("errno: %{public}d", errno);
212             return UNW_ERROR_ILLEGAL_VALUE;
213         }
214     }
215     return UNW_ERROR_NONE;
216 }
217 
AccessReg(int reg,uintptr_t * val,void * arg)218 int DfxAccessorsRemote::AccessReg(int reg, uintptr_t *val, void *arg)
219 {
220     UnwindContext *ctx = reinterpret_cast<UnwindContext *>(arg);
221     if (ctx == nullptr) {
222         return UNW_ERROR_INVALID_CONTEXT;
223     }
224     if (ctx->regs == nullptr || reg < 0 || reg >= (int)ctx->regs->RegsSize()) {
225         return UNW_ERROR_INVALID_REGS;
226     }
227 
228     *val = static_cast<uintptr_t>((*(ctx->regs))[reg]);
229     return UNW_ERROR_NONE;
230 }
231 
FindUnwindTable(uintptr_t pc,UnwindTableInfo & uti,void * arg)232 int DfxAccessorsRemote::FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti, void *arg)
233 {
234     DFX_TRACE_SCOPED_DLSYM("FindUnwindTable");
235     UnwindContext *ctx = reinterpret_cast<UnwindContext *>(arg);
236     if (ctx == nullptr || ctx->map == nullptr) {
237         return UNW_ERROR_INVALID_CONTEXT;
238     }
239     if (pc >= ctx->di.startPc && pc < ctx->di.endPc) {
240         DFXLOGU("FindUnwindTable had pc matched");
241         uti = ctx->di;
242         return UNW_ERROR_NONE;
243     }
244 
245     auto elf = ctx->map->GetElf(ctx->pid);
246     if (elf == nullptr) {
247         DFXLOGU("FindUnwindTable elf is null");
248         return UNW_ERROR_INVALID_ELF;
249     }
250     int ret = elf->FindUnwindTableInfo(pc, ctx->map, uti);
251     if (ret == UNW_ERROR_NONE) {
252         ctx->di = uti;
253     }
254     return ret;
255 }
256 
GetMapByPc(uintptr_t pc,std::shared_ptr<DfxMap> & map,void * arg)257 int DfxAccessorsRemote::GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg)
258 {
259     if (!DfxAccessors::GetMapByPcAndCtx(pc, map, arg)) {
260         return UNW_ERROR_INVALID_MAP;
261     }
262     return UNW_ERROR_NONE;
263 }
264 
AccessMem(uintptr_t addr,uintptr_t * val,void * arg)265 int DfxAccessorsCustomize::AccessMem(uintptr_t addr, uintptr_t *val, void *arg)
266 {
267     if (accessors_ == nullptr || accessors_->AccessMem == nullptr) {
268         return -1;
269     }
270     return accessors_->AccessMem(addr, val, arg);
271 }
272 
AccessReg(int reg,uintptr_t * val,void * arg)273 int DfxAccessorsCustomize::AccessReg(int reg, uintptr_t *val, void *arg)
274 {
275     if (accessors_ == nullptr || accessors_->AccessReg == nullptr) {
276         return -1;
277     }
278     return accessors_->AccessReg(reg, val, arg);
279 }
280 
FindUnwindTable(uintptr_t pc,UnwindTableInfo & uti,void * arg)281 int DfxAccessorsCustomize::FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti, void *arg)
282 {
283     if (accessors_ == nullptr || accessors_->FindUnwindTable == nullptr) {
284         return -1;
285     }
286     return accessors_->FindUnwindTable(pc, uti, arg);
287 }
288 
GetMapByPc(uintptr_t pc,std::shared_ptr<DfxMap> & map,void * arg)289 int DfxAccessorsCustomize::GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg)
290 {
291     if (accessors_ == nullptr || accessors_->GetMapByPc == nullptr) {
292         return -1;
293     }
294     return accessors_->GetMapByPc(pc, map, arg);
295 }
296 } // namespace HiviewDFX
297 } // namespace OHOS
298