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