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