1 /*
2 * Copyright (c) 2022-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_fault_stack.h"
17
18 #include <algorithm>
19 #include <csignal>
20 #include <sys/ptrace.h>
21 #include "dfx_config.h"
22 #include "dfx_logger.h"
23 #include "dfx_ring_buffer_wrapper.h"
24
25 namespace OHOS {
26 namespace HiviewDFX {
27 namespace {
28 #if defined(__arm__)
29 constexpr uint64_t STEP = 4;
30 #define PRINT_FORMAT "%08x"
31 #elif defined(__aarch64__)
32 constexpr uint64_t STEP = 8;
33 #define PRINT_FORMAT "%016llx"
34 #else
35 constexpr uint64_t STEP = 8;
36 #define PRINT_FORMAT "%016llx"
37 #endif
38 }
ReadTargetMemory(uintptr_t addr,uintptr_t & value) const39 bool FaultStack::ReadTargetMemory(uintptr_t addr, uintptr_t &value) const
40 {
41 uintptr_t targetAddr = addr;
42 auto retAddr = reinterpret_cast<long*>(&value);
43 for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
44 *retAddr = ptrace(PTRACE_PEEKTEXT, tid_, reinterpret_cast<void*>(targetAddr), nullptr);
45 if (*retAddr == -1) {
46 return false;
47 }
48 targetAddr += sizeof(long);
49 retAddr += 1;
50 }
51
52 return true;
53 }
54
AdjustAndCreateMemoryBlock(size_t index,uintptr_t prevSp,uintptr_t prevEndAddr,uintptr_t size)55 uintptr_t FaultStack::AdjustAndCreateMemoryBlock(size_t index, uintptr_t prevSp, uintptr_t prevEndAddr, uintptr_t size)
56 {
57 uintptr_t lowAddrLength = DfxConfig::GetConfig().lowAddressStep;
58 uintptr_t startAddr = prevSp - lowAddrLength * STEP;
59 if (prevEndAddr != 0 && startAddr <= prevEndAddr) {
60 startAddr = prevEndAddr;
61 } else {
62 size += lowAddrLength;
63 }
64
65 if (size == 0) {
66 return prevEndAddr;
67 }
68
69 std::string name = "sp" + std::to_string(index - 1);
70 auto block = CreateMemoryBlock(startAddr, prevSp, size, name);
71 blocks_.push_back(block);
72 return startAddr + size * STEP;
73 }
74
CollectStackInfo(const std::vector<std::shared_ptr<DfxFrame>> & frames)75 bool FaultStack::CollectStackInfo(const std::vector<std::shared_ptr<DfxFrame>> &frames)
76 {
77 if (frames.empty()) {
78 DFXLOG_WARN("null frames.");
79 return false;
80 }
81
82 size_t index = 1;
83 uintptr_t minAddr = 4096;
84 uintptr_t size = 0;
85 uintptr_t prevSp = 0;
86 uintptr_t curSp = 0;
87 uintptr_t prevEndAddr = 0;
88 uintptr_t highAddrLength = DfxConfig::GetConfig().highAddressStep;
89 auto firstFrame = frames.at(0);
90 if (firstFrame != nullptr) {
91 prevSp = static_cast<uintptr_t>(firstFrame->sp);
92 }
93 constexpr size_t MAX_FAULT_STACK_SZ = 4;
94 for (index = 1; index < frames.size(); index++) {
95 if (index > MAX_FAULT_STACK_SZ) {
96 break;
97 }
98
99 auto frame = frames.at(index);
100 if (frame != nullptr) {
101 curSp = static_cast<uintptr_t>(frame->sp);
102 }
103
104 size = 0;
105 if (curSp > prevSp) {
106 size = std::min(highAddrLength, static_cast<uintptr_t>(((curSp - prevSp) / STEP) - 1));
107 } else {
108 break;
109 }
110
111 prevEndAddr = AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
112 prevSp = curSp;
113 }
114
115 if ((blocks_.size() < MAX_FAULT_STACK_SZ) && (prevSp > minAddr)) {
116 size = highAddrLength;
117 AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
118 }
119 return true;
120 }
121
PrintMemoryBlock(const MemoryBlockInfo & info) const122 uintptr_t FaultStack::PrintMemoryBlock(const MemoryBlockInfo& info) const
123 {
124 uintptr_t targetAddr = info.startAddr;
125 for (uint64_t i = 0; i < static_cast<uint64_t>(info.content.size()); i++) {
126 if (targetAddr == info.nameAddr) {
127 DfxRingBufferWrapper::GetInstance().AppendBuf("%s:" PRINT_FORMAT " " PRINT_FORMAT "\n",
128 info.name.c_str(),
129 targetAddr,
130 info.content.at(i));
131 } else {
132 DfxRingBufferWrapper::GetInstance().AppendBuf(" " PRINT_FORMAT " " PRINT_FORMAT "\n",
133 targetAddr,
134 info.content.at(i));
135 }
136 targetAddr += STEP;
137 }
138 return targetAddr;
139 }
140
Print() const141 void FaultStack::Print() const
142 {
143 PrintRegisterMemory();
144
145 if (blocks_.empty()) {
146 return;
147 }
148
149 DfxRingBufferWrapper::GetInstance().AppendMsg("FaultStack:\n");
150 uintptr_t end = 0;
151 for (const auto& block : blocks_) {
152 if (end != 0 && end < block.startAddr) {
153 DfxRingBufferWrapper::GetInstance().AppendMsg(" ...\n");
154 }
155 end = PrintMemoryBlock(block);
156 }
157 }
158
CreateMemoryBlock(uintptr_t addr,uintptr_t offset,uintptr_t size,const std::string & name) const159 MemoryBlockInfo FaultStack::CreateMemoryBlock(
160 uintptr_t addr,
161 uintptr_t offset,
162 uintptr_t size,
163 const std::string& name) const
164 {
165 MemoryBlockInfo info;
166 info.startAddr = addr;
167 info.nameAddr = offset;
168 info.size = size;
169 info.name = name;
170 uintptr_t targetAddr = addr;
171 for (uint64_t i = 0; i < static_cast<uint64_t>(size); i++) {
172 uintptr_t value = 0;
173 if (ReadTargetMemory(targetAddr, value)) {
174 info.content.push_back(value);
175 } else {
176 info.content.push_back(-1);
177 }
178 targetAddr += STEP;
179 }
180 return info;
181 }
182
CollectRegistersBlock(std::shared_ptr<DfxRegs> regs,std::shared_ptr<DfxElfMaps> maps)183 void FaultStack::CollectRegistersBlock(std::shared_ptr<DfxRegs> regs, std::shared_ptr<DfxElfMaps> maps)
184 {
185 if (regs == nullptr || maps == nullptr) {
186 return;
187 }
188
189 auto regData = regs->GetRegsData();
190 int index = 0;
191 for (auto data : regData) {
192 index++;
193 std::shared_ptr<DfxElfMap> map;
194 if (!maps->FindMapByAddr(data, map)) {
195 continue;
196 }
197
198 if (map->perms.find("r") == std::string::npos) {
199 continue;
200 }
201
202 std::string name = regs->GetSpecialRegisterName(data);
203 if (name.empty()) {
204 #if defined(__arm__)
205 #define NAME_PREFIX "r"
206 #elif defined(__aarch64__)
207 #define NAME_PREFIX "x"
208 #else
209 #define NAME_PREFIX "x"
210 #endif
211 name = NAME_PREFIX + std::to_string(index - 1);
212 }
213
214 constexpr size_t SIZE = sizeof(uintptr_t);
215 constexpr int COUNT = 32;
216 constexpr int FORWARD_SZ = 2;
217 auto mapName = map->path;
218 if (!mapName.empty()) {
219 name.append("(" + mapName + ")");
220 }
221
222 data = data & ~(SIZE - 1);
223 data -= (FORWARD_SZ * SIZE);
224 auto block = CreateMemoryBlock(data, 0, COUNT, name);
225 registerBlocks_.push_back(block);
226 }
227 }
228
PrintRegisterMemory() const229 void FaultStack::PrintRegisterMemory() const
230 {
231 if (registerBlocks_.empty()) {
232 return;
233 }
234
235 DfxRingBufferWrapper::GetInstance().AppendMsg("Memory near registers:\n");
236 for (const auto& block : registerBlocks_) {
237 uintptr_t targetAddr = block.startAddr;
238 DfxRingBufferWrapper::GetInstance().AppendMsg(block.name + ":\n");
239 for (size_t i = 0; i < block.content.size(); i++) {
240 DfxRingBufferWrapper::GetInstance().AppendBuf(" " PRINT_FORMAT " " PRINT_FORMAT "\n",
241 targetAddr,
242 block.content.at(i));
243 targetAddr += STEP;
244 }
245 }
246 }
247 } // namespace HiviewDFX
248 } // namespace OHOS
249