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