• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 <sys/stat.h>
22 
23 #include "dfx_config.h"
24 #include "dfx_elf.h"
25 #include "dfx_logger.h"
26 #include "dfx_ring_buffer_wrapper.h"
27 
28 namespace OHOS {
29 namespace HiviewDFX {
30 namespace {
31 #if defined(__arm__)
32 constexpr uint64_t STEP = 4;
33 #define PRINT_FORMAT "%08x"
34 #elif defined(__aarch64__)
35 constexpr uint64_t STEP = 8;
36 #define PRINT_FORMAT "%016llx"
37 #else
38 constexpr uint64_t STEP = 8;
39 #define PRINT_FORMAT "%016llx"
40 #endif
41 }
ReadTargetMemory(uintptr_t addr,uintptr_t & value) const42 bool FaultStack::ReadTargetMemory(uintptr_t addr, uintptr_t &value) const
43 {
44     uintptr_t targetAddr = addr;
45     auto retAddr = reinterpret_cast<long*>(&value);
46     for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
47         *retAddr = ptrace(PTRACE_PEEKTEXT, tid_, reinterpret_cast<void*>(targetAddr), nullptr);
48         if (*retAddr == -1) {
49             if (errno != prevErrno_) {
50                 DFXLOGE("read target mem by ptrace failed, errno(%{public}s).", strerror(errno));
51                 prevErrno_ = errno;
52             }
53             return false;
54         }
55         targetAddr += sizeof(long);
56         retAddr += 1;
57     }
58 
59     return true;
60 }
61 
AdjustAndCreateMemoryBlock(size_t index,uintptr_t prevSp,uintptr_t prevEndAddr,uintptr_t size)62 uintptr_t FaultStack::AdjustAndCreateMemoryBlock(size_t index, uintptr_t prevSp, uintptr_t prevEndAddr, uintptr_t size)
63 {
64     uintptr_t lowAddrLength = DfxConfig::GetConfig().lowAddressStep;
65     uintptr_t startAddr = prevSp - lowAddrLength * STEP;
66     if (prevEndAddr != 0 && startAddr <= prevEndAddr) {
67         startAddr = prevEndAddr;
68     } else {
69         size += lowAddrLength;
70     }
71 
72     if (size == 0 || index == 0) {
73         return prevEndAddr;
74     }
75 
76     std::string name = "sp" + std::to_string(index - 1);
77     auto block = CreateMemoryBlock(startAddr, prevSp, size, name);
78     blocks_.push_back(block);
79     return startAddr + size * STEP;
80 }
81 
CollectStackInfo(const std::vector<DfxFrame> & frames,bool needParseStack)82 bool FaultStack::CollectStackInfo(const std::vector<DfxFrame>& frames, bool needParseStack)
83 {
84     if (frames.empty()) {
85         DFXLOGW("null frames.");
86         return false;
87     }
88 
89     size_t index = 1;
90     uintptr_t minAddr = 4096;
91     uintptr_t size = 0;
92     uintptr_t prevSp = 0;
93     uintptr_t prevEndAddr = 0;
94     uintptr_t highAddrLength = DfxConfig::GetConfig().highAddressStep;
95     if (needParseStack) {
96         highAddrLength = 8192; // 8192 : 32k / STEP
97     }
98 
99     auto firstFrame = frames.at(0);
100     prevSp = static_cast<uintptr_t>(firstFrame.sp);
101     constexpr size_t maxFaultStackSz = 4;
102     for (index = 1; index < frames.size(); index++) {
103         if (index > maxFaultStackSz) {
104             break;
105         }
106 
107         auto frame = frames.at(index);
108         uintptr_t curSp = static_cast<uintptr_t>(frame.sp);
109 
110         size = 0;
111         if (curSp > prevSp) {
112             size = std::min(highAddrLength, static_cast<uintptr_t>(((curSp - prevSp) / STEP) - 1));
113         } else {
114             break;
115         }
116 
117         prevEndAddr = AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
118         prevSp = curSp;
119     }
120 
121     if ((blocks_.size() < maxFaultStackSz) && (prevSp > minAddr)) {
122         size = highAddrLength;
123         prevEndAddr = AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
124     }
125 
126     const uintptr_t minCorruptedStackSz = 1024;
127     CreateBlockForCorruptedStack(frames, prevEndAddr, minCorruptedStackSz);
128     return true;
129 }
130 
CreateBlockForCorruptedStack(const std::vector<DfxFrame> & frames,uintptr_t prevEndAddr,uintptr_t size)131 bool FaultStack::CreateBlockForCorruptedStack(const std::vector<DfxFrame>& frames, uintptr_t prevEndAddr,
132                                               uintptr_t size)
133 {
134     const auto& frame = frames.back();
135     // stack trace should end with libc or ffrt or */bin/*
136     if (frame.mapName.find("ld-musl") != std::string::npos ||
137         frame.mapName.find("ffrt") != std::string::npos ||
138         frame.mapName.find("bin") != std::string::npos) {
139         return false;
140     }
141 
142     AdjustAndCreateMemoryBlock(frame.index, frame.sp, prevEndAddr, size);
143     return true;
144 }
145 
PrintMemoryBlock(const MemoryBlockInfo & info,uintptr_t stackStartAddr) const146 uintptr_t FaultStack::PrintMemoryBlock(const MemoryBlockInfo& info, uintptr_t stackStartAddr) const
147 {
148     uintptr_t targetAddr = info.startAddr;
149     for (uint64_t i = 0; i < static_cast<uint64_t>(info.content.size()); i++) {
150         if (targetAddr == info.nameAddr) {
151             DfxRingBufferWrapper::GetInstance().AppendBuf("%s:" PRINT_FORMAT " " PRINT_FORMAT "\n",
152                 info.name.c_str(),
153                 targetAddr,
154                 info.content.at(i));
155         } else {
156             DfxRingBufferWrapper::GetInstance().AppendBuf("    " PRINT_FORMAT " " PRINT_FORMAT "\n",
157                 targetAddr,
158                 info.content.at(i));
159         }
160         if (targetAddr - stackStartAddr > STEP * DfxConfig::GetConfig().highAddressStep) {
161             break;
162         }
163         targetAddr += STEP;
164     }
165     return targetAddr;
166 }
167 
Print() const168 void FaultStack::Print() const
169 {
170     PrintRegisterMemory();
171 
172     if (blocks_.empty()) {
173         return;
174     }
175 
176     DfxRingBufferWrapper::GetInstance().AppendMsg("FaultStack:\n");
177     uintptr_t end = 0;
178     uintptr_t stackStartAddr = blocks_.at(0).startAddr;
179     for (const auto& block : blocks_) {
180         if (end != 0 && end < block.startAddr) {
181             DfxRingBufferWrapper::GetInstance().AppendMsg("    ...\n");
182         }
183         end = PrintMemoryBlock(block, stackStartAddr);
184     }
185 }
186 
CreateMemoryBlock(uintptr_t addr,uintptr_t offset,uintptr_t size,const std::string & name) const187 MemoryBlockInfo FaultStack::CreateMemoryBlock(
188     uintptr_t addr,
189     uintptr_t offset,
190     uintptr_t size,
191     const std::string& name) const
192 {
193     MemoryBlockInfo info;
194     info.startAddr = addr;
195     info.nameAddr = offset;
196     info.size = size;
197     info.name = name;
198     uintptr_t targetAddr = addr;
199     for (uint64_t i = 0; i < static_cast<uint64_t>(size); i++) {
200         uintptr_t value = 0;
201         if (ReadTargetMemory(targetAddr, value)) {
202             info.content.push_back(value);
203         } else {
204             info.content.push_back(-1);
205         }
206         targetAddr += STEP;
207     }
208     return info;
209 }
210 
CollectRegistersBlock(std::shared_ptr<DfxRegs> regs,std::shared_ptr<DfxMaps> maps)211 void FaultStack::CollectRegistersBlock(std::shared_ptr<DfxRegs> regs, std::shared_ptr<DfxMaps> maps)
212 {
213     if (regs == nullptr || maps == nullptr) {
214         DFXLOGE("%{public}s : regs or maps is null.", __func__);
215         return;
216     }
217 
218     auto regsData = regs->GetRegsData();
219     int index = 0;
220     for (auto data : regsData) {
221 #if defined(ENABLE_HWASAN)
222         constexpr uintptr_t tbiMask = 0xff00000000000000; // the upper eight bits are TBI
223         data &= ~tbiMask;
224 #endif
225         index++;
226         std::shared_ptr<DfxMap> map;
227         if (!maps->FindMapByAddr(data, map)) {
228             continue;
229         }
230 
231         if ((map->prots & PROT_READ) == 0) {
232             continue;
233         }
234 
235         std::string name = regs->GetSpecialRegsNameByIndex(index - 1);
236         if (name.empty()) {
237 #if defined(__arm__)
238 #define NAME_PREFIX "r"
239 #elif defined(__aarch64__)
240 #define NAME_PREFIX "x"
241 #else
242 #define NAME_PREFIX "x"
243 #endif
244             name = NAME_PREFIX + std::to_string(index - 1);
245         }
246 
247         constexpr size_t SIZE = sizeof(uintptr_t);
248         constexpr int COUNT = 32;
249         constexpr int FORWARD_SZ = 2;
250         auto mapName = map->name;
251         if (!mapName.empty()) {
252             name.append("(" + mapName + ")");
253         }
254 
255         data = data & ~(SIZE - 1);
256         data -= (FORWARD_SZ * SIZE);
257         auto block = CreateMemoryBlock(data, 0, COUNT, name);
258         registerBlocks_.push_back(block);
259     }
260 }
261 
PrintRegisterMemory() const262 void FaultStack::PrintRegisterMemory() const
263 {
264     if (registerBlocks_.empty()) {
265         return;
266     }
267 
268     DfxRingBufferWrapper::GetInstance().AppendMsg("Memory near registers:\n");
269     for (const auto& block : registerBlocks_) {
270         uintptr_t targetAddr = block.startAddr;
271         DfxRingBufferWrapper::GetInstance().AppendMsg(block.name + ":\n");
272         for (size_t i = 0; i < block.content.size(); i++) {
273             DfxRingBufferWrapper::GetInstance().AppendBuf("    " PRINT_FORMAT " " PRINT_FORMAT "\n",
274                 targetAddr,
275                 block.content.at(i));
276             targetAddr += STEP;
277         }
278     }
279 }
280 
ParseUnwindStack(std::shared_ptr<DfxMaps> maps,std::vector<DfxFrame> & frames)281 bool FaultStack::ParseUnwindStack(std::shared_ptr<DfxMaps> maps, std::vector<DfxFrame>& frames)
282 {
283     bool hasAddFrame = false;
284     if (maps == nullptr) {
285         DFXLOGE("%{public}s : maps is null.", __func__);
286         return false;
287     }
288     size_t index = frames.size();
289     for (const auto& block : blocks_) {
290         std::shared_ptr<DfxMap> map;
291         for (size_t i = 0; i < block.content.size(); i++) {
292             if (!maps->FindMapByAddr(block.content[i], map) ||
293                 (map->prots & PROT_EXEC) == 0) {
294                 continue;
295             }
296             DfxFrame frame;
297             frame.index = index;
298             frame.pc = block.content[i];
299             frame.map = map;
300             frame.mapName = map->name;
301             frames.emplace_back(frame);
302             hasAddFrame = true;
303             constexpr int MAX_VALID_ADDRESS_NUM = 32;
304             if (++index >= MAX_VALID_ADDRESS_NUM) {
305                 return true;
306             }
307         }
308     }
309     return hasAddFrame;
310 }
311 } // namespace HiviewDFX
312 } // namespace OHOS
313