• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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