1 /*
2 * Copyright (c) 2022-2025 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 "decorative_dump_info.h"
17
18 #include <algorithm>
19 #include <csignal>
20 #include <sys/ptrace.h>
21 #include <sys/stat.h>
22
23 #include "dfx_buffer_writer.h"
24 #include "dfx_elf.h"
25 #include "dfx_log.h"
26 #include "dfx_util.h"
27 #include "dump_utils.h"
28 #include "process_dump_config.h"
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 REGISTER_DUMP_INFO_CLASS(FaultStack);
33
Print(DfxProcess & process,const ProcessDumpRequest & request,Unwinder & unwinder)34 void FaultStack::Print(DfxProcess& process, const ProcessDumpRequest& request, Unwinder& unwinder)
35 {
36 DecorativeDumpInfo::Print(process, request, unwinder);
37 DfxBufferWriter::GetInstance().WriteMsg("FaultStack:\n");
38 CollectStackInfo(process.GetKeyThread()->GetThreadInfo().nsTid, process.GetKeyThread()->GetFrames());
39 if (blocks_.empty()) {
40 return;
41 }
42 uintptr_t end = 0;
43 uintptr_t stackStartAddr = blocks_.at(0).startAddr;
44 for (const auto& block : blocks_) {
45 if (end != 0 && end < block.startAddr) {
46 DfxBufferWriter::GetInstance().WriteMsg(" ...\n");
47 }
48 end = PrintMemoryBlock(block, stackStartAddr);
49 }
50 if (ProcessDumpConfig::GetInstance().GetConfig().simplifyVmaPrinting ||
51 process.GetCrashLogConfig().simplifyVmaPrinting) {
52 std::set<uintptr_t> memoryValues;
53 GetMemoryValues(memoryValues);
54 process.SetMemoryValues(memoryValues);
55 }
56 }
57
GetStackValues()58 const std::vector<uintptr_t>& FaultStack::GetStackValues()
59 {
60 for (const auto& block : blocks_) {
61 for (const auto& value : block.content) {
62 stackValues_.emplace_back(StripPac(value, 0));
63 }
64 }
65 return stackValues_;
66 }
67
GetMemoryValues(std::set<uintptr_t> & memoryValues)68 void FaultStack::GetMemoryValues(std::set<uintptr_t>& memoryValues)
69 {
70 DecorativeDumpInfo::GetMemoryValues(memoryValues);
71 for (const auto& block : blocks_) {
72 for (const auto& value : block.content) {
73 memoryValues.emplace(StripPac(value, 0));
74 }
75 }
76 }
77
AdjustAndCreateMemoryBlock(pid_t tid,size_t index,uintptr_t prevSp,uintptr_t prevEndAddr,uintptr_t size)78 uintptr_t FaultStack::AdjustAndCreateMemoryBlock(pid_t tid, size_t index, uintptr_t prevSp,
79 uintptr_t prevEndAddr, uintptr_t size)
80 {
81 uintptr_t lowAddrLength = ProcessDumpConfig::GetInstance().GetConfig().faultStackLowAddrStep;
82 uintptr_t startAddr = prevSp - lowAddrLength * STEP;
83 if (prevEndAddr != 0 && startAddr <= prevEndAddr) {
84 startAddr = prevEndAddr;
85 } else {
86 size += lowAddrLength;
87 }
88
89 if (size == 0 || index == 0) {
90 return prevEndAddr;
91 }
92
93 std::string name = "sp" + std::to_string(index - 1);
94 MemoryBlockInfo blockInfo = {
95 .startAddr = startAddr,
96 .nameAddr = prevSp,
97 .size = size,
98 .name = name,
99 };
100 CreateMemoryBlock(tid, blockInfo);
101 blocks_.push_back(blockInfo);
102 return startAddr + size * STEP;
103 }
104
CollectStackInfo(pid_t tid,const std::vector<DfxFrame> & frames,bool needParseStack)105 void FaultStack::CollectStackInfo(pid_t tid, const std::vector<DfxFrame>& frames, bool needParseStack)
106 {
107 if (frames.empty()) {
108 DFXLOGW("null frames.");
109 return;
110 }
111 size_t index = 1;
112 uintptr_t minAddr = 4096;
113 uintptr_t size = 0;
114 uintptr_t prevSp = 0;
115 uintptr_t prevEndAddr = 0;
116 uintptr_t highAddrLength = ProcessDumpConfig::GetInstance().GetConfig().faultStackHighAddrStep;
117 if (needParseStack) {
118 highAddrLength = 8192; // 8192 : 32k / STEP
119 }
120
121 auto firstFrame = frames.at(0);
122 prevSp = static_cast<uintptr_t>(firstFrame.sp);
123 constexpr size_t maxFaultStackSz = 4;
124 for (index = 1; index < frames.size(); index++) {
125 if (index > maxFaultStackSz) {
126 break;
127 }
128
129 auto frame = frames.at(index);
130 uintptr_t curSp = static_cast<uintptr_t>(frame.sp);
131
132 size = 0;
133 if (curSp > prevSp) {
134 size = std::min(highAddrLength, static_cast<uintptr_t>(((curSp - prevSp) / STEP) - 1));
135 } else {
136 break;
137 }
138
139 prevEndAddr = AdjustAndCreateMemoryBlock(tid, index, prevSp, prevEndAddr, size);
140 prevSp = curSp;
141 }
142
143 if ((blocks_.size() < maxFaultStackSz) && (prevSp > minAddr)) {
144 size = highAddrLength;
145 prevEndAddr = AdjustAndCreateMemoryBlock(tid, index, prevSp, prevEndAddr, size);
146 }
147
148 const uintptr_t minCorruptedStackSz = 1024;
149 CreateBlockForCorruptedStack(tid, frames, prevEndAddr, minCorruptedStackSz);
150 }
151
CreateBlockForCorruptedStack(pid_t tid,const std::vector<DfxFrame> & frames,uintptr_t prevEndAddr,uintptr_t size)152 bool FaultStack::CreateBlockForCorruptedStack(pid_t tid, const std::vector<DfxFrame>& frames, uintptr_t prevEndAddr,
153 uintptr_t size)
154 {
155 const auto& frame = frames.back();
156 // stack trace should end with libc or ffrt or */bin/*
157 if (frame.mapName.find("ld-musl") != std::string::npos ||
158 frame.mapName.find("ffrt") != std::string::npos ||
159 frame.mapName.find("bin") != std::string::npos) {
160 return false;
161 }
162
163 AdjustAndCreateMemoryBlock(tid, frame.index, frame.sp, prevEndAddr, size);
164 return true;
165 }
166
PrintMemoryBlock(const MemoryBlockInfo & info,uintptr_t stackStartAddr) const167 uintptr_t FaultStack::PrintMemoryBlock(const MemoryBlockInfo& info, uintptr_t stackStartAddr) const
168 {
169 uintptr_t targetAddr = info.startAddr;
170 for (uint64_t i = 0; i < static_cast<uint64_t>(info.content.size()); i++) {
171 if (targetAddr == info.nameAddr) {
172 DfxBufferWriter::GetInstance().WriteFormatMsg("%s:" PRINT_FORMAT " " PRINT_FORMAT "\n",
173 info.name.c_str(),
174 targetAddr,
175 info.content.at(i));
176 } else {
177 DfxBufferWriter::GetInstance().WriteFormatMsg(" " PRINT_FORMAT " " PRINT_FORMAT "\n",
178 targetAddr,
179 info.content.at(i));
180 }
181 if (targetAddr - stackStartAddr > STEP * ProcessDumpConfig::GetInstance().GetConfig().faultStackHighAddrStep) {
182 break;
183 }
184 targetAddr += STEP;
185 }
186 return targetAddr;
187 }
188
CreateMemoryBlock(pid_t tid,MemoryBlockInfo & blockInfo) const189 void FaultStack::CreateMemoryBlock(pid_t tid, MemoryBlockInfo& blockInfo) const
190 {
191 uintptr_t targetAddr = blockInfo.startAddr;
192 for (uint64_t i = 0; i < static_cast<uint64_t>(blockInfo.size); i++) {
193 uintptr_t value = 0;
194 if (DumpUtils::ReadTargetMemory(tid, targetAddr, value)) {
195 blockInfo.content.push_back(value);
196 } else {
197 blockInfo.content.push_back(-1);
198 }
199 targetAddr += STEP;
200 }
201 }
202 } // namespace HiviewDFX
203 } // namespace OHOS
204