1 /*
2 * Copyright (c) 2022 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 /* This files contains process dump elf module. */
17
18 #include "dfx_fault_stack.h"
19
20 #include <algorithm>
21 #include <csignal>
22 #include <sys/ptrace.h>
23 #include "dfx_config.h"
24 #include "dfx_logger.h"
25 #include "dfx_ring_buffer_wrapper.h"
26
27 namespace OHOS {
28 namespace HiviewDFX {
29 namespace {
30 constexpr size_t MEM_BLOCK_BUF_SZ = 64;
31 #if defined(__arm__)
32 constexpr uint64_t STEP = 4;
33 #elif defined(__aarch64__)
34 constexpr uint64_t STEP = 8;
35 #else
36 constexpr uint64_t STEP = 8;
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::GetInstance().GetFaultStackLowAddressStep();
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 CreateMemoryBlock(startAddr, prevSp, size, name);
71 return startAddr + size * STEP;
72 }
73
CollectStackInfo(std::shared_ptr<DfxRegs> reg,const std::vector<std::shared_ptr<DfxFrame>> & frames)74 bool FaultStack::CollectStackInfo(std::shared_ptr<DfxRegs> reg, const std::vector<std::shared_ptr<DfxFrame>> &frames)
75 {
76 if (reg == nullptr && frames.empty()) {
77 DfxLogWarn("null register or frames.");
78 return false;
79 }
80
81 size_t index = 1;
82 uintptr_t minAddr = 4096;
83 uintptr_t size = 0;
84 uintptr_t prevSp = 0;
85 uintptr_t curSp = 0;
86 uintptr_t prevEndAddr = 0;
87 uintptr_t highAddrLength = DfxConfig::GetInstance().GetFaultStackHighAddressStep();
88 auto firstFrame = frames.at(0);
89 if (firstFrame != nullptr) {
90 prevSp = static_cast<uintptr_t>(firstFrame->GetFrameSp());
91 }
92 constexpr size_t MAX_FAULT_STACK_SZ = 4;
93 for (index = 1; index < frames.size(); index++) {
94 if (index > MAX_FAULT_STACK_SZ) {
95 break;
96 }
97
98 auto frame = frames.at(index);
99 if (frame != nullptr) {
100 curSp = static_cast<uintptr_t>(frame->GetFrameSp());
101 }
102
103 size = 0;
104 if (curSp > prevSp) {
105 size = std::min(highAddrLength, static_cast<uintptr_t>(((curSp - prevSp) / STEP) - 1));
106 } else {
107 break;
108 }
109
110 prevEndAddr = AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
111 prevSp = curSp;
112 }
113
114 if ((blocks_.size() < MAX_FAULT_STACK_SZ) && (prevSp > minAddr)) {
115 size = highAddrLength;
116 AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
117 }
118 return true;
119 }
120
PrintMemoryBlock(const MemoryBlockInfo & info) const121 uintptr_t FaultStack::PrintMemoryBlock(const MemoryBlockInfo& info) const
122 {
123 #if defined(__arm__)
124 #define PRINT_FORMAT "%08x"
125 #elif defined(__aarch64__)
126 #define PRINT_FORMAT "%016llx"
127 #else
128 #define PRINT_FORMAT "%016llx"
129 #endif
130 uintptr_t targetAddr = info.startAddr;
131 for (uint64_t i = 0; i < static_cast<uint64_t>(info.content.size()); i++) {
132 if (targetAddr == info.nameAddr) {
133 DfxRingBufferWrapper::GetInstance().AppendBuf("%s:" PRINT_FORMAT " " PRINT_FORMAT "\n",
134 info.name.c_str(),
135 targetAddr,
136 info.content.at(i));
137 } else {
138 DfxRingBufferWrapper::GetInstance().AppendBuf(" " PRINT_FORMAT " " PRINT_FORMAT "\n",
139 targetAddr,
140 info.content.at(i));
141 }
142 targetAddr += STEP;
143 }
144 return targetAddr;
145 }
146
Print() const147 void FaultStack::Print() const
148 {
149 if (blocks_.empty()) {
150 return;
151 }
152
153 DfxRingBufferWrapper::GetInstance().AppendMsg("FaultStack:\n");
154 uintptr_t end = 0;
155 for (const auto& block : blocks_) {
156 if (end != 0 && end < block.startAddr) {
157 DfxRingBufferWrapper::GetInstance().AppendMsg(" ...\n");
158 }
159 end = PrintMemoryBlock(block);
160 }
161 }
162
CreateMemoryBlock(uintptr_t addr,uintptr_t offset,uintptr_t size,std::string name)163 void FaultStack::CreateMemoryBlock(uintptr_t addr, uintptr_t offset, uintptr_t size, std::string name)
164 {
165 DfxLogDebug("CreateMemoryBlock %p %p %llu %s.", addr, offset, size, name.c_str());
166 MemoryBlockInfo info;
167 info.startAddr = addr;
168 info.nameAddr = offset;
169 info.size = size;
170 info.name = name;
171 uintptr_t targetAddr = addr;
172 for (uint64_t i = 0; i < static_cast<uint64_t>(size); i++) {
173 uintptr_t value = 0;
174 if (ReadTargetMemory(targetAddr, value)) {
175 info.content.push_back(value);
176 } else {
177 info.content.push_back(-1);
178 }
179 targetAddr += STEP;
180 }
181 blocks_.push_back(info);
182 }
183 } // namespace HiviewDFX
184 } // namespace OHOS
185