• 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 <securec.h>
21 #include <sys/ptrace.h>
22 #include <sys/uio.h>
23 #include "dfx_define.h"
24 #include "dfx_log.h"
25 #include "dfx_regs.h"
26 #include "dfx_elf.h"
27 #include "dfx_maps.h"
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace {
32 #undef LOG_DOMAIN
33 #undef LOG_TAG
34 #define LOG_DOMAIN 0xD002D11
35 #define LOG_TAG "DfxAccessors"
36 
37 static const int FOUR_BYTES = 4;
38 static const int EIGHT_BYTES = 8;
39 static const int THIRTY_TWO_BITS = 32;
40 }
41 
IsValidFrame(uintptr_t addr,uintptr_t stackBottom,uintptr_t stackTop)42 bool DfxAccessorsLocal::IsValidFrame(uintptr_t addr, uintptr_t stackBottom, uintptr_t stackTop)
43 {
44     if (UNLIKELY(stackTop < stackBottom)) {
45         return false;
46     }
47     return ((addr >= stackBottom) && (addr < stackTop - sizeof(uintptr_t)));
48 }
49 
AccessMem(uintptr_t addr,uintptr_t * val,void * arg)50 int DfxAccessorsLocal::AccessMem(uintptr_t addr, uintptr_t *val, void *arg)
51 {
52     if (val == nullptr) {
53         return UNW_ERROR_INVALID_MEMORY;
54     }
55     UnwindContext* ctx = reinterpret_cast<UnwindContext *>(arg);
56     if ((ctx != nullptr) && (ctx->stackCheck == true) && (!IsValidFrame(addr, ctx->stackBottom, ctx->stackTop))) {
57         LOGE("Failed to access addr");
58         return UNW_ERROR_INVALID_MEMORY;
59     }
60     *val = *(uintptr_t *) addr;
61     return UNW_ERROR_NONE;
62 }
63 
AccessReg(int reg,uintptr_t * val,void * arg)64 int DfxAccessorsLocal::AccessReg(int reg, uintptr_t *val, void *arg)
65 {
66     UnwindContext* ctx = reinterpret_cast<UnwindContext *>(arg);
67     if (ctx == nullptr) {
68         return UNW_ERROR_INVALID_CONTEXT;
69     }
70     if (ctx->regs == nullptr || reg < 0 || reg >= (int)ctx->regs->RegsSize()) {
71         return UNW_ERROR_INVALID_REGS;
72     }
73 
74     *val = static_cast<uintptr_t>((*(ctx->regs))[reg]);
75     return UNW_ERROR_NONE;
76 }
77 
FindUnwindTable(uintptr_t pc,UnwindTableInfo & uti,void * arg)78 int DfxAccessorsLocal::FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti, void *arg)
79 {
80     UnwindContext *ctx = reinterpret_cast<UnwindContext *>(arg);
81     if (ctx == nullptr) {
82         LOGE("ctx is null");
83         return UNW_ERROR_INVALID_CONTEXT;
84     }
85 
86     int ret = DfxElf::FindUnwindTableLocal(pc, uti);
87     if (ret == UNW_ERROR_NONE) {
88         ctx->di = uti;
89     }
90     return ret;
91 }
92 
AccessMem(uintptr_t addr,uintptr_t * val,void * arg)93 int DfxAccessorsRemote::AccessMem(uintptr_t addr, uintptr_t *val, void *arg)
94 {
95 #if !defined(__LP64__)
96     // Cannot read an address greater than 32 bits in a 32 bit context.
97     if (addr > UINT32_MAX) {
98         return UNW_ERROR_ILLEGAL_VALUE;
99     }
100 #endif
101     UnwindContext *ctx = reinterpret_cast<UnwindContext *>(arg);
102     if ((ctx == nullptr) || (ctx->pid <= 0)) {
103         return UNW_ERROR_INVALID_CONTEXT;
104     }
105     int i, end;
106     if (sizeof(long) == FOUR_BYTES && sizeof(uintptr_t) == EIGHT_BYTES) {
107         end = 2; // 2 : read two times
108     } else {
109         end = 1;
110     }
111 
112     uintptr_t tmpVal;
113     for (i = 0; i < end; i++) {
114         uintptr_t tmpAddr = ((i == 0) ? addr : addr + FOUR_BYTES);
115         errno = 0;
116 
117         tmpVal = (unsigned long) ptrace(PTRACE_PEEKDATA, ctx->pid, tmpAddr, nullptr);
118         if (i == 0) {
119             *val = 0;
120         }
121 
122 #if __BYTE_ORDER == __LITTLE_ENDIAN
123         *val |= tmpVal << (i * THIRTY_TWO_BITS);
124 #else
125         *val |= (i == 0 && end == 2 ? tmpVal << THIRTY_TWO_BITS : tmpVal); // 2 : read two times
126 #endif
127         if (errno) {
128             LOGE("errno: %d", errno);
129             return UNW_ERROR_ILLEGAL_VALUE;
130         }
131     }
132     return UNW_ERROR_NONE;
133 }
134 
AccessReg(int reg,uintptr_t * val,void * arg)135 int DfxAccessorsRemote::AccessReg(int reg, uintptr_t *val, void *arg)
136 {
137     UnwindContext *ctx = reinterpret_cast<UnwindContext *>(arg);
138     if (ctx == nullptr) {
139         return UNW_ERROR_INVALID_CONTEXT;
140     }
141     if (ctx->regs == nullptr || reg < 0 || reg >= (int)ctx->regs->RegsSize()) {
142         return UNW_ERROR_INVALID_REGS;
143     }
144 
145     *val = static_cast<uintptr_t>((*(ctx->regs))[reg]);
146     return UNW_ERROR_NONE;
147 }
148 
FindUnwindTable(uintptr_t pc,UnwindTableInfo & uti,void * arg)149 int DfxAccessorsRemote::FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti, void *arg)
150 {
151     UnwindContext *ctx = reinterpret_cast<UnwindContext *>(arg);
152     if (ctx == nullptr || ctx->map == nullptr) {
153         return UNW_ERROR_INVALID_CONTEXT;
154     }
155     if (pc >= ctx->di.startPc && pc < ctx->di.endPc) {
156         LOGU("FindUnwindTable had pc matched");
157         uti = ctx->di;
158         return UNW_ERROR_NONE;
159     }
160 
161     auto elf = ctx->map->GetElf();
162     if (elf == nullptr) {
163         LOGU("FindUnwindTable elf is null");
164         return UNW_ERROR_INVALID_ELF;
165     }
166     int ret = elf->FindUnwindTableInfo(pc, ctx->map, uti);
167     if (ret == UNW_ERROR_NONE) {
168         ctx->di = uti;
169     }
170     return ret;
171 }
172 
AccessMem(uintptr_t addr,uintptr_t * val,void * arg)173 int DfxAccessorsCustomize::AccessMem(uintptr_t addr, uintptr_t *val, void *arg)
174 {
175     if (accessors_ == nullptr) {
176         return -1;
177     }
178     return accessors_->AccessMem(addr, val, arg);
179 }
180 
AccessReg(int reg,uintptr_t * val,void * arg)181 int DfxAccessorsCustomize::AccessReg(int reg, uintptr_t *val, void *arg)
182 {
183     if (accessors_ == nullptr) {
184         return -1;
185     }
186     return accessors_->AccessReg(reg, val, arg);
187 }
188 
FindUnwindTable(uintptr_t pc,UnwindTableInfo & uti,void * arg)189 int DfxAccessorsCustomize::FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti, void *arg)
190 {
191     if (accessors_ == nullptr) {
192         return -1;
193     }
194     return accessors_->FindUnwindTable(pc, uti, arg);
195 }
196 } // namespace HiviewDFX
197 } // namespace OHOS
198