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