• 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 <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 #if defined(__x86_64__)
28 #include "dfx_memory_file.h"
29 #endif
30 
31 namespace OHOS {
32 namespace HiviewDFX {
33 namespace {
34 #if defined(__arm__)
35 constexpr uint64_t STEP = 4;
36 #define PRINT_FORMAT "%08x"
37 #elif defined(__aarch64__)
38 constexpr uint64_t STEP = 8;
39 #define PRINT_FORMAT "%016llx"
40 #else
41 constexpr uint64_t STEP = 8;
42 #define PRINT_FORMAT "%016llx"
43 #endif
44 }
ReadTargetMemory(uintptr_t addr,uintptr_t & value) const45 bool FaultStack::ReadTargetMemory(uintptr_t addr, uintptr_t &value) const
46 {
47     uintptr_t targetAddr = addr;
48     auto retAddr = reinterpret_cast<long*>(&value);
49     for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
50         *retAddr = ptrace(PTRACE_PEEKTEXT, tid_, reinterpret_cast<void*>(targetAddr), nullptr);
51         if (*retAddr == -1) {
52             return false;
53         }
54         targetAddr += sizeof(long);
55         retAddr += 1;
56     }
57 
58     return true;
59 }
60 
AdjustAndCreateMemoryBlock(size_t index,uintptr_t prevSp,uintptr_t prevEndAddr,uintptr_t size)61 uintptr_t FaultStack::AdjustAndCreateMemoryBlock(size_t index, uintptr_t prevSp, uintptr_t prevEndAddr, uintptr_t size)
62 {
63     uintptr_t lowAddrLength = DfxConfig::GetConfig().lowAddressStep;
64     uintptr_t startAddr = prevSp - lowAddrLength * STEP;
65     if (prevEndAddr != 0 && startAddr <= prevEndAddr) {
66         startAddr = prevEndAddr;
67     } else {
68         size += lowAddrLength;
69     }
70 
71     if (size == 0) {
72         return prevEndAddr;
73     }
74 
75     std::string name = "sp" + std::to_string(index - 1);
76     auto block = CreateMemoryBlock(startAddr, prevSp, size, name);
77     blocks_.push_back(block);
78     return startAddr + size * STEP;
79 }
80 
CollectStackInfo(const std::vector<DfxFrame> & frames,bool needParseStack)81 bool FaultStack::CollectStackInfo(const std::vector<DfxFrame>& frames, bool needParseStack)
82 {
83     if (frames.empty()) {
84         DFXLOG_WARN("null frames.");
85         return false;
86     }
87 
88     size_t index = 1;
89     uintptr_t minAddr = 4096;
90     uintptr_t size = 0;
91     uintptr_t prevSp = 0;
92     uintptr_t prevEndAddr = 0;
93     uintptr_t highAddrLength = DfxConfig::GetConfig().highAddressStep;
94     if (needParseStack) {
95         highAddrLength = 8192; // 8192 : 32k / STEP
96     }
97 
98     auto firstFrame = frames.at(0);
99     prevSp = static_cast<uintptr_t>(firstFrame.sp);
100     constexpr size_t MAX_FAULT_STACK_SZ = 4;
101     for (index = 1; index < frames.size(); index++) {
102         if (index > MAX_FAULT_STACK_SZ) {
103             break;
104         }
105 
106         auto frame = frames.at(index);
107         uintptr_t curSp = static_cast<uintptr_t>(frame.sp);
108 
109         size = 0;
110         if (curSp > prevSp) {
111             size = std::min(highAddrLength, static_cast<uintptr_t>(((curSp - prevSp) / STEP) - 1));
112         } else {
113             break;
114         }
115 
116         prevEndAddr = AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
117         prevSp = curSp;
118     }
119 
120     if ((blocks_.size() < MAX_FAULT_STACK_SZ) && (prevSp > minAddr)) {
121         size = highAddrLength;
122         prevEndAddr = AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
123     }
124 
125     const uintptr_t minCorruptedStackSz = 1024;
126     CreateBlockForCorruptedStack(frames, prevEndAddr, minCorruptedStackSz);
127     return true;
128 }
129 
CreateBlockForCorruptedStack(const std::vector<DfxFrame> & frames,uintptr_t prevEndAddr,uintptr_t size)130 bool FaultStack::CreateBlockForCorruptedStack(const std::vector<DfxFrame>& frames, uintptr_t prevEndAddr,
131                                               uintptr_t size)
132 {
133     const auto& frame = frames.back();
134     // stack trace should end with libc or ffrt or */bin/*
135     if (frame.mapName.find("ld-musl") != std::string::npos ||
136         frame.mapName.find("ffrt") != std::string::npos ||
137         frame.mapName.find("bin") != std::string::npos) {
138         return false;
139     }
140 
141     AdjustAndCreateMemoryBlock(frame.index, frame.sp, prevEndAddr, size);
142     return true;
143 }
144 
PrintMemoryBlock(const MemoryBlockInfo & info,uintptr_t stackStartAddr) const145 uintptr_t FaultStack::PrintMemoryBlock(const MemoryBlockInfo& info, uintptr_t stackStartAddr) const
146 {
147     uintptr_t targetAddr = info.startAddr;
148     for (uint64_t i = 0; i < static_cast<uint64_t>(info.content.size()); i++) {
149         if (targetAddr == info.nameAddr) {
150             DfxRingBufferWrapper::GetInstance().AppendBuf("%s:" PRINT_FORMAT " " PRINT_FORMAT "\n",
151                 info.name.c_str(),
152                 targetAddr,
153                 info.content.at(i));
154         } else {
155             DfxRingBufferWrapper::GetInstance().AppendBuf("    " PRINT_FORMAT " " PRINT_FORMAT "\n",
156                 targetAddr,
157                 info.content.at(i));
158         }
159         if (targetAddr - stackStartAddr > STEP * DfxConfig::GetConfig().highAddressStep) {
160             break;
161         }
162         targetAddr += STEP;
163     }
164     return targetAddr;
165 }
166 
Print() const167 void FaultStack::Print() const
168 {
169     PrintRegisterMemory();
170 
171     if (blocks_.empty()) {
172         return;
173     }
174 
175     DfxRingBufferWrapper::GetInstance().AppendMsg("FaultStack:\n");
176     uintptr_t end = 0;
177     uintptr_t stackStartAddr = blocks_.at(0).startAddr;
178     for (const auto& block : blocks_) {
179         if (end != 0 && end < block.startAddr) {
180             DfxRingBufferWrapper::GetInstance().AppendMsg("    ...\n");
181         }
182         end = PrintMemoryBlock(block, stackStartAddr);
183     }
184 }
185 
CreateMemoryBlock(uintptr_t addr,uintptr_t offset,uintptr_t size,const std::string & name) const186 MemoryBlockInfo FaultStack::CreateMemoryBlock(
187     uintptr_t addr,
188     uintptr_t offset,
189     uintptr_t size,
190     const std::string& name) const
191 {
192     MemoryBlockInfo info;
193     info.startAddr = addr;
194     info.nameAddr = offset;
195     info.size = size;
196     info.name = name;
197     uintptr_t targetAddr = addr;
198     for (uint64_t i = 0; i < static_cast<uint64_t>(size); i++) {
199         uintptr_t value = 0;
200         if (ReadTargetMemory(targetAddr, value)) {
201             info.content.push_back(value);
202         } else {
203             info.content.push_back(-1);
204         }
205         targetAddr += STEP;
206     }
207     return info;
208 }
209 
210 #if defined(__x86_64__)
CollectRegistersBlock(std::shared_ptr<DfxRegs> regs,std::shared_ptr<DfxElfMaps> maps)211 void FaultStack::CollectRegistersBlock(std::shared_ptr<DfxRegs> regs, std::shared_ptr<DfxElfMaps> maps)
212 #else
213 void FaultStack::CollectRegistersBlock(std::shared_ptr<DfxRegs> regs, std::shared_ptr<DfxMaps> maps)
214 #endif
215 {
216     if (regs == nullptr || maps == nullptr) {
217         return;
218     }
219 
220     auto regData = regs->GetRegsData();
221     int index = 0;
222     for (auto data : regData) {
223         index++;
224 #if defined(__x86_64__)
225         std::shared_ptr<DfxElfMap> map;
226 #else
227         std::shared_ptr<DfxMap> map;
228 #endif
229         if (!maps->FindMapByAddr(data, map)) {
230             continue;
231         }
232 
233         if (map->perms.find("r") == std::string::npos) {
234             continue;
235         }
236 
237 #if defined(__x86_64__)
238         std::string name = regs->GetSpecialRegisterName(data);
239 #else
240         std::string name = regs->GetSpecialRegsName(data);
241 #endif
242         if (name.empty()) {
243 #if defined(__arm__)
244 #define NAME_PREFIX "r"
245 #elif defined(__aarch64__)
246 #define NAME_PREFIX "x"
247 #else
248 #define NAME_PREFIX "x"
249 #endif
250             name = NAME_PREFIX + std::to_string(index - 1);
251         }
252 
253         constexpr size_t SIZE = sizeof(uintptr_t);
254         constexpr int COUNT = 32;
255         constexpr int FORWARD_SZ = 2;
256 #if defined(__x86_64__)
257         auto mapName = map->path;
258 #else
259         auto mapName = map->name;
260 #endif
261         if (!mapName.empty()) {
262             name.append("(" + mapName + ")");
263         }
264 
265         data = data & ~(SIZE - 1);
266         data -= (FORWARD_SZ * SIZE);
267         auto block = CreateMemoryBlock(data, 0, COUNT, name);
268         registerBlocks_.push_back(block);
269     }
270 }
271 
PrintRegisterMemory() const272 void FaultStack::PrintRegisterMemory() const
273 {
274     if (registerBlocks_.empty()) {
275         return;
276     }
277 
278     DfxRingBufferWrapper::GetInstance().AppendMsg("Memory near registers:\n");
279     for (const auto& block : registerBlocks_) {
280         uintptr_t targetAddr = block.startAddr;
281         DfxRingBufferWrapper::GetInstance().AppendMsg(block.name + ":\n");
282         for (size_t i = 0; i < block.content.size(); i++) {
283             DfxRingBufferWrapper::GetInstance().AppendBuf("    " PRINT_FORMAT " " PRINT_FORMAT "\n",
284                 targetAddr,
285                 block.content.at(i));
286             targetAddr += STEP;
287         }
288     }
289 }
290 
291 #if defined(__x86_64__)
ParseUnwindStack(std::shared_ptr<DfxElfMaps> maps,std::vector<DfxFrame> & frames)292 bool FaultStack::ParseUnwindStack(std::shared_ptr<DfxElfMaps> maps, std::vector<DfxFrame>& frames)
293 {
294     if (maps == nullptr) {
295         DFXLOG_ERROR("%s : maps is null.", __func__);
296         return false;
297     }
298     size_t index = frames.size();
299     for (const auto& block : blocks_) {
300         std::shared_ptr<DfxElfMap> map;
301         for (size_t i = 0; i < block.content.size(); i++) {
302             if (!maps->FindMapByAddr(block.content[i], map) ||
303                 map->perms.find("x") == std::string::npos) {
304                 continue;
305             }
306             DfxFrame frame;
307             frame.index = index;
308             frame.pc = block.content[i];
309             frame.mapName = map->path;
310             int64_t loadBias = 0;
311             struct stat st;
312             if (stat(map->path.c_str(), &st) == 0 && (st.st_mode & S_IFREG)) {
313                 auto memoryFile = DfxMemoryFile::CreateFileMemory(frame.mapName, 0);
314                 if (memoryFile == nullptr) {
315                     DFXLOG_ERROR("%s : Failed to CreateFileMemory, elf path(%s).", __func__, frame.mapName.c_str());
316                     return false;
317                 }
318                 std::shared_ptr<DfxElf> elf = std::make_shared<DfxElf>(memoryFile);
319                 if (elf == nullptr || !elf->Init()) {
320                     DFXLOG_ERROR("%s : Failed to create DfxElf, elf path(%s).", __func__, frame.mapName.c_str());
321                     return false;
322                 }
323                 loadBias = elf->GetLoadBias();
324                 frame.buildId = DfxElf::GetReadableBuildID(elf->GetBuildID());
325             } else {
326                 DFXLOG_WARN("%s : mapName(%s) is not file.", __func__, frame.mapName.c_str());
327             }
328 
329             frame.relPc = frame.pc - map->begin + map->offset + static_cast<uint64_t>(loadBias);
330             frames.emplace_back(frame);
331             constexpr int MAX_VALID_ADDRESS_NUM = 32;
332             if (++index >= MAX_VALID_ADDRESS_NUM) {
333                 return true;
334             }
335         }
336     }
337     return true;
338 }
339 #else
ParseUnwindStack(std::shared_ptr<DfxMaps> maps,std::vector<DfxFrame> & frames)340 bool FaultStack::ParseUnwindStack(std::shared_ptr<DfxMaps> maps, std::vector<DfxFrame>& frames)
341 {
342     if (maps == nullptr) {
343         DFXLOG_ERROR("%s : maps is null.", __func__);
344         return false;
345     }
346     size_t index = frames.size();
347     for (const auto& block : blocks_) {
348         std::shared_ptr<DfxMap> map;
349         for (size_t i = 0; i < block.content.size(); i++) {
350             if (!maps->FindMapByAddr(block.content[i], map) ||
351                 map->perms.find("x") == std::string::npos) {
352                 continue;
353             }
354             DfxFrame frame;
355             frame.index = index;
356             frame.pc = block.content[i];
357             frame.map = map;
358             frame.mapName = map->name;
359             int64_t loadBias = 0;
360             struct stat st;
361             if (stat(map->name.c_str(), &st) == 0 && (st.st_mode & S_IFREG)) {
362                 auto elf = DfxElf::Create(frame.mapName);
363                 if (elf == nullptr || !elf->IsValid()) {
364                     DFXLOG_ERROR("%s : Failed to create DfxElf, elf path(%s).", __func__, frame.mapName.c_str());
365                     return false;
366                 }
367                 loadBias = elf->GetLoadBias();
368                 frame.buildId = elf->GetBuildId();
369             } else {
370                 DFXLOG_WARN("%s : mapName(%s) is not file.", __func__, frame.mapName.c_str());
371             }
372 
373             frame.relPc = frame.pc - map->begin + map->offset + static_cast<uint64_t>(loadBias);
374             frames.emplace_back(frame);
375             constexpr int MAX_VALID_ADDRESS_NUM = 32;
376             if (++index >= MAX_VALID_ADDRESS_NUM) {
377                 return true;
378             }
379         }
380     }
381     return true;
382 }
383 #endif
384 } // namespace HiviewDFX
385 } // namespace OHOS
386