1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "dfx_fault_stack.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <algorithm>
19800b99b8Sopenharmony_ci#include <csignal>
20800b99b8Sopenharmony_ci#include <sys/ptrace.h>
21800b99b8Sopenharmony_ci#include <sys/stat.h>
22800b99b8Sopenharmony_ci
23800b99b8Sopenharmony_ci#include "dfx_config.h"
24800b99b8Sopenharmony_ci#include "dfx_elf.h"
25800b99b8Sopenharmony_ci#include "dfx_logger.h"
26800b99b8Sopenharmony_ci#include "dfx_ring_buffer_wrapper.h"
27800b99b8Sopenharmony_ci
28800b99b8Sopenharmony_cinamespace OHOS {
29800b99b8Sopenharmony_cinamespace HiviewDFX {
30800b99b8Sopenharmony_cinamespace {
31800b99b8Sopenharmony_ci#if defined(__arm__)
32800b99b8Sopenharmony_ciconstexpr uint64_t STEP = 4;
33800b99b8Sopenharmony_ci#define PRINT_FORMAT "%08x"
34800b99b8Sopenharmony_ci#elif defined(__aarch64__)
35800b99b8Sopenharmony_ciconstexpr uint64_t STEP = 8;
36800b99b8Sopenharmony_ci#define PRINT_FORMAT "%016llx"
37800b99b8Sopenharmony_ci#else
38800b99b8Sopenharmony_ciconstexpr uint64_t STEP = 8;
39800b99b8Sopenharmony_ci#define PRINT_FORMAT "%016llx"
40800b99b8Sopenharmony_ci#endif
41800b99b8Sopenharmony_ci}
42800b99b8Sopenharmony_cibool FaultStack::ReadTargetMemory(uintptr_t addr, uintptr_t &value) const
43800b99b8Sopenharmony_ci{
44800b99b8Sopenharmony_ci    uintptr_t targetAddr = addr;
45800b99b8Sopenharmony_ci    auto retAddr = reinterpret_cast<long*>(&value);
46800b99b8Sopenharmony_ci    for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) {
47800b99b8Sopenharmony_ci        *retAddr = ptrace(PTRACE_PEEKTEXT, tid_, reinterpret_cast<void*>(targetAddr), nullptr);
48800b99b8Sopenharmony_ci        if (*retAddr == -1) {
49800b99b8Sopenharmony_ci            if (errno != prevErrno_) {
50800b99b8Sopenharmony_ci                DFXLOGE("read target mem by ptrace failed, errno(%{public}s).", strerror(errno));
51800b99b8Sopenharmony_ci                prevErrno_ = errno;
52800b99b8Sopenharmony_ci            }
53800b99b8Sopenharmony_ci            return false;
54800b99b8Sopenharmony_ci        }
55800b99b8Sopenharmony_ci        targetAddr += sizeof(long);
56800b99b8Sopenharmony_ci        retAddr += 1;
57800b99b8Sopenharmony_ci    }
58800b99b8Sopenharmony_ci
59800b99b8Sopenharmony_ci    return true;
60800b99b8Sopenharmony_ci}
61800b99b8Sopenharmony_ci
62800b99b8Sopenharmony_ciuintptr_t FaultStack::AdjustAndCreateMemoryBlock(size_t index, uintptr_t prevSp, uintptr_t prevEndAddr, uintptr_t size)
63800b99b8Sopenharmony_ci{
64800b99b8Sopenharmony_ci    uintptr_t lowAddrLength = DfxConfig::GetConfig().lowAddressStep;
65800b99b8Sopenharmony_ci    uintptr_t startAddr = prevSp - lowAddrLength * STEP;
66800b99b8Sopenharmony_ci    if (prevEndAddr != 0 && startAddr <= prevEndAddr) {
67800b99b8Sopenharmony_ci        startAddr = prevEndAddr;
68800b99b8Sopenharmony_ci    } else {
69800b99b8Sopenharmony_ci        size += lowAddrLength;
70800b99b8Sopenharmony_ci    }
71800b99b8Sopenharmony_ci
72800b99b8Sopenharmony_ci    if (size == 0 || index == 0) {
73800b99b8Sopenharmony_ci        return prevEndAddr;
74800b99b8Sopenharmony_ci    }
75800b99b8Sopenharmony_ci
76800b99b8Sopenharmony_ci    std::string name = "sp" + std::to_string(index - 1);
77800b99b8Sopenharmony_ci    auto block = CreateMemoryBlock(startAddr, prevSp, size, name);
78800b99b8Sopenharmony_ci    blocks_.push_back(block);
79800b99b8Sopenharmony_ci    return startAddr + size * STEP;
80800b99b8Sopenharmony_ci}
81800b99b8Sopenharmony_ci
82800b99b8Sopenharmony_cibool FaultStack::CollectStackInfo(const std::vector<DfxFrame>& frames, bool needParseStack)
83800b99b8Sopenharmony_ci{
84800b99b8Sopenharmony_ci    if (frames.empty()) {
85800b99b8Sopenharmony_ci        DFXLOGW("null frames.");
86800b99b8Sopenharmony_ci        return false;
87800b99b8Sopenharmony_ci    }
88800b99b8Sopenharmony_ci
89800b99b8Sopenharmony_ci    size_t index = 1;
90800b99b8Sopenharmony_ci    uintptr_t minAddr = 4096;
91800b99b8Sopenharmony_ci    uintptr_t size = 0;
92800b99b8Sopenharmony_ci    uintptr_t prevSp = 0;
93800b99b8Sopenharmony_ci    uintptr_t prevEndAddr = 0;
94800b99b8Sopenharmony_ci    uintptr_t highAddrLength = DfxConfig::GetConfig().highAddressStep;
95800b99b8Sopenharmony_ci    if (needParseStack) {
96800b99b8Sopenharmony_ci        highAddrLength = 8192; // 8192 : 32k / STEP
97800b99b8Sopenharmony_ci    }
98800b99b8Sopenharmony_ci
99800b99b8Sopenharmony_ci    auto firstFrame = frames.at(0);
100800b99b8Sopenharmony_ci    prevSp = static_cast<uintptr_t>(firstFrame.sp);
101800b99b8Sopenharmony_ci    constexpr size_t MAX_FAULT_STACK_SZ = 4;
102800b99b8Sopenharmony_ci    for (index = 1; index < frames.size(); index++) {
103800b99b8Sopenharmony_ci        if (index > MAX_FAULT_STACK_SZ) {
104800b99b8Sopenharmony_ci            break;
105800b99b8Sopenharmony_ci        }
106800b99b8Sopenharmony_ci
107800b99b8Sopenharmony_ci        auto frame = frames.at(index);
108800b99b8Sopenharmony_ci        uintptr_t curSp = static_cast<uintptr_t>(frame.sp);
109800b99b8Sopenharmony_ci
110800b99b8Sopenharmony_ci        size = 0;
111800b99b8Sopenharmony_ci        if (curSp > prevSp) {
112800b99b8Sopenharmony_ci            size = std::min(highAddrLength, static_cast<uintptr_t>(((curSp - prevSp) / STEP) - 1));
113800b99b8Sopenharmony_ci        } else {
114800b99b8Sopenharmony_ci            break;
115800b99b8Sopenharmony_ci        }
116800b99b8Sopenharmony_ci
117800b99b8Sopenharmony_ci        prevEndAddr = AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
118800b99b8Sopenharmony_ci        prevSp = curSp;
119800b99b8Sopenharmony_ci    }
120800b99b8Sopenharmony_ci
121800b99b8Sopenharmony_ci    if ((blocks_.size() < MAX_FAULT_STACK_SZ) && (prevSp > minAddr)) {
122800b99b8Sopenharmony_ci        size = highAddrLength;
123800b99b8Sopenharmony_ci        prevEndAddr = AdjustAndCreateMemoryBlock(index, prevSp, prevEndAddr, size);
124800b99b8Sopenharmony_ci    }
125800b99b8Sopenharmony_ci
126800b99b8Sopenharmony_ci    const uintptr_t minCorruptedStackSz = 1024;
127800b99b8Sopenharmony_ci    CreateBlockForCorruptedStack(frames, prevEndAddr, minCorruptedStackSz);
128800b99b8Sopenharmony_ci    return true;
129800b99b8Sopenharmony_ci}
130800b99b8Sopenharmony_ci
131800b99b8Sopenharmony_cibool FaultStack::CreateBlockForCorruptedStack(const std::vector<DfxFrame>& frames, uintptr_t prevEndAddr,
132800b99b8Sopenharmony_ci                                              uintptr_t size)
133800b99b8Sopenharmony_ci{
134800b99b8Sopenharmony_ci    const auto& frame = frames.back();
135800b99b8Sopenharmony_ci    // stack trace should end with libc or ffrt or */bin/*
136800b99b8Sopenharmony_ci    if (frame.mapName.find("ld-musl") != std::string::npos ||
137800b99b8Sopenharmony_ci        frame.mapName.find("ffrt") != std::string::npos ||
138800b99b8Sopenharmony_ci        frame.mapName.find("bin") != std::string::npos) {
139800b99b8Sopenharmony_ci        return false;
140800b99b8Sopenharmony_ci    }
141800b99b8Sopenharmony_ci
142800b99b8Sopenharmony_ci    AdjustAndCreateMemoryBlock(frame.index, frame.sp, prevEndAddr, size);
143800b99b8Sopenharmony_ci    return true;
144800b99b8Sopenharmony_ci}
145800b99b8Sopenharmony_ci
146800b99b8Sopenharmony_ciuintptr_t FaultStack::PrintMemoryBlock(const MemoryBlockInfo& info, uintptr_t stackStartAddr) const
147800b99b8Sopenharmony_ci{
148800b99b8Sopenharmony_ci    uintptr_t targetAddr = info.startAddr;
149800b99b8Sopenharmony_ci    for (uint64_t i = 0; i < static_cast<uint64_t>(info.content.size()); i++) {
150800b99b8Sopenharmony_ci        if (targetAddr == info.nameAddr) {
151800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendBuf("%s:" PRINT_FORMAT " " PRINT_FORMAT "\n",
152800b99b8Sopenharmony_ci                info.name.c_str(),
153800b99b8Sopenharmony_ci                targetAddr,
154800b99b8Sopenharmony_ci                info.content.at(i));
155800b99b8Sopenharmony_ci        } else {
156800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendBuf("    " PRINT_FORMAT " " PRINT_FORMAT "\n",
157800b99b8Sopenharmony_ci                targetAddr,
158800b99b8Sopenharmony_ci                info.content.at(i));
159800b99b8Sopenharmony_ci        }
160800b99b8Sopenharmony_ci        if (targetAddr - stackStartAddr > STEP * DfxConfig::GetConfig().highAddressStep) {
161800b99b8Sopenharmony_ci            break;
162800b99b8Sopenharmony_ci        }
163800b99b8Sopenharmony_ci        targetAddr += STEP;
164800b99b8Sopenharmony_ci    }
165800b99b8Sopenharmony_ci    return targetAddr;
166800b99b8Sopenharmony_ci}
167800b99b8Sopenharmony_ci
168800b99b8Sopenharmony_civoid FaultStack::Print() const
169800b99b8Sopenharmony_ci{
170800b99b8Sopenharmony_ci    PrintRegisterMemory();
171800b99b8Sopenharmony_ci
172800b99b8Sopenharmony_ci    if (blocks_.empty()) {
173800b99b8Sopenharmony_ci        return;
174800b99b8Sopenharmony_ci    }
175800b99b8Sopenharmony_ci
176800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendMsg("FaultStack:\n");
177800b99b8Sopenharmony_ci    uintptr_t end = 0;
178800b99b8Sopenharmony_ci    uintptr_t stackStartAddr = blocks_.at(0).startAddr;
179800b99b8Sopenharmony_ci    for (const auto& block : blocks_) {
180800b99b8Sopenharmony_ci        if (end != 0 && end < block.startAddr) {
181800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendMsg("    ...\n");
182800b99b8Sopenharmony_ci        }
183800b99b8Sopenharmony_ci        end = PrintMemoryBlock(block, stackStartAddr);
184800b99b8Sopenharmony_ci    }
185800b99b8Sopenharmony_ci}
186800b99b8Sopenharmony_ci
187800b99b8Sopenharmony_ciMemoryBlockInfo FaultStack::CreateMemoryBlock(
188800b99b8Sopenharmony_ci    uintptr_t addr,
189800b99b8Sopenharmony_ci    uintptr_t offset,
190800b99b8Sopenharmony_ci    uintptr_t size,
191800b99b8Sopenharmony_ci    const std::string& name) const
192800b99b8Sopenharmony_ci{
193800b99b8Sopenharmony_ci    MemoryBlockInfo info;
194800b99b8Sopenharmony_ci    info.startAddr = addr;
195800b99b8Sopenharmony_ci    info.nameAddr = offset;
196800b99b8Sopenharmony_ci    info.size = size;
197800b99b8Sopenharmony_ci    info.name = name;
198800b99b8Sopenharmony_ci    uintptr_t targetAddr = addr;
199800b99b8Sopenharmony_ci    for (uint64_t i = 0; i < static_cast<uint64_t>(size); i++) {
200800b99b8Sopenharmony_ci        uintptr_t value = 0;
201800b99b8Sopenharmony_ci        if (ReadTargetMemory(targetAddr, value)) {
202800b99b8Sopenharmony_ci            info.content.push_back(value);
203800b99b8Sopenharmony_ci        } else {
204800b99b8Sopenharmony_ci            info.content.push_back(-1);
205800b99b8Sopenharmony_ci        }
206800b99b8Sopenharmony_ci        targetAddr += STEP;
207800b99b8Sopenharmony_ci    }
208800b99b8Sopenharmony_ci    return info;
209800b99b8Sopenharmony_ci}
210800b99b8Sopenharmony_ci
211800b99b8Sopenharmony_civoid FaultStack::CollectRegistersBlock(std::shared_ptr<DfxRegs> regs, std::shared_ptr<DfxMaps> maps)
212800b99b8Sopenharmony_ci{
213800b99b8Sopenharmony_ci    if (regs == nullptr || maps == nullptr) {
214800b99b8Sopenharmony_ci        DFXLOGE("%{public}s : regs or maps is null.", __func__);
215800b99b8Sopenharmony_ci        return;
216800b99b8Sopenharmony_ci    }
217800b99b8Sopenharmony_ci
218800b99b8Sopenharmony_ci    auto regsData = regs->GetRegsData();
219800b99b8Sopenharmony_ci    int index = 0;
220800b99b8Sopenharmony_ci    for (auto data : regsData) {
221800b99b8Sopenharmony_ci        index++;
222800b99b8Sopenharmony_ci        std::shared_ptr<DfxMap> map;
223800b99b8Sopenharmony_ci        if (!maps->FindMapByAddr(data, map)) {
224800b99b8Sopenharmony_ci            continue;
225800b99b8Sopenharmony_ci        }
226800b99b8Sopenharmony_ci
227800b99b8Sopenharmony_ci        if ((map->prots & PROT_READ) == 0) {
228800b99b8Sopenharmony_ci            continue;
229800b99b8Sopenharmony_ci        }
230800b99b8Sopenharmony_ci
231800b99b8Sopenharmony_ci        std::string name = regs->GetSpecialRegsNameByIndex(index - 1);
232800b99b8Sopenharmony_ci        if (name.empty()) {
233800b99b8Sopenharmony_ci#if defined(__arm__)
234800b99b8Sopenharmony_ci#define NAME_PREFIX "r"
235800b99b8Sopenharmony_ci#elif defined(__aarch64__)
236800b99b8Sopenharmony_ci#define NAME_PREFIX "x"
237800b99b8Sopenharmony_ci#else
238800b99b8Sopenharmony_ci#define NAME_PREFIX "x"
239800b99b8Sopenharmony_ci#endif
240800b99b8Sopenharmony_ci            name = NAME_PREFIX + std::to_string(index - 1);
241800b99b8Sopenharmony_ci        }
242800b99b8Sopenharmony_ci
243800b99b8Sopenharmony_ci        constexpr size_t SIZE = sizeof(uintptr_t);
244800b99b8Sopenharmony_ci        constexpr int COUNT = 32;
245800b99b8Sopenharmony_ci        constexpr int FORWARD_SZ = 2;
246800b99b8Sopenharmony_ci        auto mapName = map->name;
247800b99b8Sopenharmony_ci        if (!mapName.empty()) {
248800b99b8Sopenharmony_ci            name.append("(" + mapName + ")");
249800b99b8Sopenharmony_ci        }
250800b99b8Sopenharmony_ci
251800b99b8Sopenharmony_ci        data = data & ~(SIZE - 1);
252800b99b8Sopenharmony_ci        data -= (FORWARD_SZ * SIZE);
253800b99b8Sopenharmony_ci        auto block = CreateMemoryBlock(data, 0, COUNT, name);
254800b99b8Sopenharmony_ci        registerBlocks_.push_back(block);
255800b99b8Sopenharmony_ci    }
256800b99b8Sopenharmony_ci}
257800b99b8Sopenharmony_ci
258800b99b8Sopenharmony_civoid FaultStack::PrintRegisterMemory() const
259800b99b8Sopenharmony_ci{
260800b99b8Sopenharmony_ci    if (registerBlocks_.empty()) {
261800b99b8Sopenharmony_ci        return;
262800b99b8Sopenharmony_ci    }
263800b99b8Sopenharmony_ci
264800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendMsg("Memory near registers:\n");
265800b99b8Sopenharmony_ci    for (const auto& block : registerBlocks_) {
266800b99b8Sopenharmony_ci        uintptr_t targetAddr = block.startAddr;
267800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg(block.name + ":\n");
268800b99b8Sopenharmony_ci        for (size_t i = 0; i < block.content.size(); i++) {
269800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendBuf("    " PRINT_FORMAT " " PRINT_FORMAT "\n",
270800b99b8Sopenharmony_ci                targetAddr,
271800b99b8Sopenharmony_ci                block.content.at(i));
272800b99b8Sopenharmony_ci            targetAddr += STEP;
273800b99b8Sopenharmony_ci        }
274800b99b8Sopenharmony_ci    }
275800b99b8Sopenharmony_ci}
276800b99b8Sopenharmony_ci
277800b99b8Sopenharmony_cibool FaultStack::ParseUnwindStack(std::shared_ptr<DfxMaps> maps, std::vector<DfxFrame>& frames)
278800b99b8Sopenharmony_ci{
279800b99b8Sopenharmony_ci    if (maps == nullptr) {
280800b99b8Sopenharmony_ci        DFXLOGE("%{public}s : maps is null.", __func__);
281800b99b8Sopenharmony_ci        return false;
282800b99b8Sopenharmony_ci    }
283800b99b8Sopenharmony_ci    size_t index = frames.size();
284800b99b8Sopenharmony_ci    for (const auto& block : blocks_) {
285800b99b8Sopenharmony_ci        std::shared_ptr<DfxMap> map;
286800b99b8Sopenharmony_ci        for (size_t i = 0; i < block.content.size(); i++) {
287800b99b8Sopenharmony_ci            if (!maps->FindMapByAddr(block.content[i], map) ||
288800b99b8Sopenharmony_ci                (map->prots & PROT_EXEC) == 0) {
289800b99b8Sopenharmony_ci                continue;
290800b99b8Sopenharmony_ci            }
291800b99b8Sopenharmony_ci            DfxFrame frame;
292800b99b8Sopenharmony_ci            frame.index = index;
293800b99b8Sopenharmony_ci            frame.pc = block.content[i];
294800b99b8Sopenharmony_ci            frame.map = map;
295800b99b8Sopenharmony_ci            frame.mapName = map->name;
296800b99b8Sopenharmony_ci            int64_t loadBias = 0;
297800b99b8Sopenharmony_ci            struct stat st;
298800b99b8Sopenharmony_ci            if (stat(map->name.c_str(), &st) == 0 && (st.st_mode & S_IFREG)) {
299800b99b8Sopenharmony_ci                auto elf = DfxElf::Create(frame.mapName);
300800b99b8Sopenharmony_ci                if (elf == nullptr || !elf->IsValid()) {
301800b99b8Sopenharmony_ci                    DFXLOGE("%{public}s : Failed to create DfxElf, elf path(%{public}s).", __func__,
302800b99b8Sopenharmony_ci                        frame.mapName.c_str());
303800b99b8Sopenharmony_ci                    return false;
304800b99b8Sopenharmony_ci                }
305800b99b8Sopenharmony_ci                loadBias = elf->GetLoadBias();
306800b99b8Sopenharmony_ci                frame.buildId = elf->GetBuildId();
307800b99b8Sopenharmony_ci            } else {
308800b99b8Sopenharmony_ci                DFXLOGW("%{public}s : mapName(%{public}s) is not file.", __func__, frame.mapName.c_str());
309800b99b8Sopenharmony_ci            }
310800b99b8Sopenharmony_ci
311800b99b8Sopenharmony_ci            frame.relPc = frame.pc - map->begin + map->offset + static_cast<uint64_t>(loadBias);
312800b99b8Sopenharmony_ci            frames.emplace_back(frame);
313800b99b8Sopenharmony_ci            constexpr int MAX_VALID_ADDRESS_NUM = 32;
314800b99b8Sopenharmony_ci            if (++index >= MAX_VALID_ADDRESS_NUM) {
315800b99b8Sopenharmony_ci                return true;
316800b99b8Sopenharmony_ci            }
317800b99b8Sopenharmony_ci        }
318800b99b8Sopenharmony_ci    }
319800b99b8Sopenharmony_ci    return true;
320800b99b8Sopenharmony_ci}
321800b99b8Sopenharmony_ci} // namespace HiviewDFX
322800b99b8Sopenharmony_ci} // namespace OHOS
323