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#include "dfx_unwind_async_thread.h" 16800b99b8Sopenharmony_ci 17800b99b8Sopenharmony_ci#include "crash_exception.h" 18800b99b8Sopenharmony_ci#include "dfx_config.h" 19800b99b8Sopenharmony_ci#include "dfx_log.h" 20800b99b8Sopenharmony_ci#include "dfx_memory.h" 21800b99b8Sopenharmony_ci#include "dfx_maps.h" 22800b99b8Sopenharmony_ci#include "dfx_regs.h" 23800b99b8Sopenharmony_ci#include "dfx_ring_buffer_wrapper.h" 24800b99b8Sopenharmony_ci#include "dfx_trace.h" 25800b99b8Sopenharmony_ci#ifdef PARSE_LOCK_OWNER 26800b99b8Sopenharmony_ci#include "lock_parser.h" 27800b99b8Sopenharmony_ci#endif 28800b99b8Sopenharmony_ci#include "process_dumper.h" 29800b99b8Sopenharmony_ci#include "printer.h" 30800b99b8Sopenharmony_ci#include "unique_stack_table.h" 31800b99b8Sopenharmony_ci 32800b99b8Sopenharmony_cinamespace OHOS { 33800b99b8Sopenharmony_cinamespace HiviewDFX { 34800b99b8Sopenharmony_cibool DfxUnwindAsyncThread::UnwindStack(pid_t vmPid) 35800b99b8Sopenharmony_ci{ 36800b99b8Sopenharmony_ci if (unwinder_ == nullptr || thread_ == nullptr) { 37800b99b8Sopenharmony_ci DFXLOGE("%{public}s::thread or unwinder is not initialized.", __func__); 38800b99b8Sopenharmony_ci return false; 39800b99b8Sopenharmony_ci } 40800b99b8Sopenharmony_ci // 1: get crash stack 41800b99b8Sopenharmony_ci // unwinding with context passed by dump request, only for crash thread or target thread. 42800b99b8Sopenharmony_ci auto regs = thread_->GetThreadRegs(); 43800b99b8Sopenharmony_ci unwinder_->SetRegs(regs); 44800b99b8Sopenharmony_ci pid_t tid = thread_->threadInfo_.nsTid; 45800b99b8Sopenharmony_ci DFXLOGI("%{public}s, unwind tid(%{public}d) start.", __func__, tid); 46800b99b8Sopenharmony_ci auto tmpPid = vmPid != 0 ? vmPid : tid; 47800b99b8Sopenharmony_ci DFX_TRACE_START("KeyThreadUnwindRemote:%d", tid); 48800b99b8Sopenharmony_ci bool ret = unwinder_->UnwindRemote(tmpPid, 49800b99b8Sopenharmony_ci regs != nullptr, 50800b99b8Sopenharmony_ci DfxConfig::GetConfig().maxFrameNums); 51800b99b8Sopenharmony_ci DFX_TRACE_FINISH(); 52800b99b8Sopenharmony_ci if (ProcessDumper::GetInstance().IsCrash()) { 53800b99b8Sopenharmony_ci ReportUnwinderException(unwinder_->GetLastErrorCode()); 54800b99b8Sopenharmony_ci if (!ret) { 55800b99b8Sopenharmony_ci UnwindThreadFallback(); 56800b99b8Sopenharmony_ci } 57800b99b8Sopenharmony_ci DFX_TRACE_START("KeyThreadGetFrames:%d", tid); 58800b99b8Sopenharmony_ci thread_->SetFrames(unwinder_->GetFrames()); 59800b99b8Sopenharmony_ci DFX_TRACE_FINISH(); 60800b99b8Sopenharmony_ci UnwindThreadByParseStackIfNeed(); 61800b99b8Sopenharmony_ci // 2: get submitterStack 62800b99b8Sopenharmony_ci std::vector<DfxFrame> submmiterFrames; 63800b99b8Sopenharmony_ci GetSubmitterStack(submmiterFrames); 64800b99b8Sopenharmony_ci // 3: merge two stack 65800b99b8Sopenharmony_ci MergeStack(submmiterFrames); 66800b99b8Sopenharmony_ci } else { 67800b99b8Sopenharmony_ci#ifdef PARSE_LOCK_OWNER 68800b99b8Sopenharmony_ci DFX_TRACE_START("KeyThreadGetFrames:%d", tid); 69800b99b8Sopenharmony_ci thread_->SetFrames(unwinder_->GetFrames()); 70800b99b8Sopenharmony_ci DFX_TRACE_FINISH(); 71800b99b8Sopenharmony_ci LockParser::ParseLockInfo(unwinder_, tmpPid, thread_->threadInfo_.nsTid); 72800b99b8Sopenharmony_ci#else 73800b99b8Sopenharmony_ci thread_->Detach(); 74800b99b8Sopenharmony_ci DFX_TRACE_START("KeyThreadGetFrames:%d", tid); 75800b99b8Sopenharmony_ci thread_->SetFrames(unwinder_->GetFrames()); 76800b99b8Sopenharmony_ci DFX_TRACE_FINISH(); 77800b99b8Sopenharmony_ci#endif 78800b99b8Sopenharmony_ci } 79800b99b8Sopenharmony_ci 80800b99b8Sopenharmony_ci DFXLOGI("%{public}s, unwind tid(%{public}d) finish ret(%{public}d).", __func__, tid, ret); 81800b99b8Sopenharmony_ci return ret; 82800b99b8Sopenharmony_ci} 83800b99b8Sopenharmony_ci 84800b99b8Sopenharmony_civoid DfxUnwindAsyncThread::GetSubmitterStack(std::vector<DfxFrame> &submitterFrames) 85800b99b8Sopenharmony_ci{ 86800b99b8Sopenharmony_ci if (stackId_ == 0) { 87800b99b8Sopenharmony_ci return; 88800b99b8Sopenharmony_ci } 89800b99b8Sopenharmony_ci const std::shared_ptr<DfxMaps>& maps = unwinder_->GetMaps(); 90800b99b8Sopenharmony_ci if (maps == nullptr) { 91800b99b8Sopenharmony_ci return; 92800b99b8Sopenharmony_ci } 93800b99b8Sopenharmony_ci std::vector<std::shared_ptr<DfxMap>> mapVec; 94800b99b8Sopenharmony_ci if (!maps->FindMapsByName("[anon:async_stack_table]", mapVec)) { 95800b99b8Sopenharmony_ci DFXLOGE("%{public}s::Can not find map of async stack table", __func__); 96800b99b8Sopenharmony_ci return; 97800b99b8Sopenharmony_ci } 98800b99b8Sopenharmony_ci auto map = mapVec.front(); 99800b99b8Sopenharmony_ci size_t size = map->end - map->begin; 100800b99b8Sopenharmony_ci auto tableData = std::make_shared<std::vector<uint8_t>>(size); 101800b99b8Sopenharmony_ci size_t byte = DfxMemory::ReadProcMemByPid(thread_->threadInfo_.nsTid, map->begin, tableData->data(), size); 102800b99b8Sopenharmony_ci if (byte != size) { 103800b99b8Sopenharmony_ci DFXLOGE("Failed to read unique_table from target"); 104800b99b8Sopenharmony_ci return; 105800b99b8Sopenharmony_ci } 106800b99b8Sopenharmony_ci auto table = std::make_shared<UniqueStackTable>(tableData->data(), size, false); 107800b99b8Sopenharmony_ci std::vector<uintptr_t> pcs; 108800b99b8Sopenharmony_ci StackId id; 109800b99b8Sopenharmony_ci id.value = stackId_; 110800b99b8Sopenharmony_ci if (table->GetPcsByStackId(id, pcs)) { 111800b99b8Sopenharmony_ci unwinder_->GetFramesByPcs(submitterFrames, pcs); 112800b99b8Sopenharmony_ci } else { 113800b99b8Sopenharmony_ci DFXLOGW("%{public}s::Failed to get pcs", __func__); 114800b99b8Sopenharmony_ci } 115800b99b8Sopenharmony_ci} 116800b99b8Sopenharmony_ci 117800b99b8Sopenharmony_civoid DfxUnwindAsyncThread::MergeStack(std::vector<DfxFrame> &submitterFrames) 118800b99b8Sopenharmony_ci{ 119800b99b8Sopenharmony_ci auto frames = thread_->GetFrames(); 120800b99b8Sopenharmony_ci frames.insert(frames.end(), submitterFrames.begin(), submitterFrames.end()); 121800b99b8Sopenharmony_ci thread_->SetFrames(frames); 122800b99b8Sopenharmony_ci} 123800b99b8Sopenharmony_ci 124800b99b8Sopenharmony_civoid DfxUnwindAsyncThread::UnwindThreadFallback() 125800b99b8Sopenharmony_ci{ 126800b99b8Sopenharmony_ci#ifndef __x86_64__ 127800b99b8Sopenharmony_ci if (unwinder_->GetFrames().size() > 0) { 128800b99b8Sopenharmony_ci return; 129800b99b8Sopenharmony_ci } 130800b99b8Sopenharmony_ci // As we failed to init libunwind, just print pc and lr for first two frames 131800b99b8Sopenharmony_ci std::shared_ptr<DfxRegs> regs = thread_->GetThreadRegs(); 132800b99b8Sopenharmony_ci if (regs == nullptr) { 133800b99b8Sopenharmony_ci DfxRingBufferWrapper::GetInstance().AppendMsg("RegisterInfo is not existed for crash process"); 134800b99b8Sopenharmony_ci return; 135800b99b8Sopenharmony_ci } 136800b99b8Sopenharmony_ci 137800b99b8Sopenharmony_ci std::shared_ptr<DfxMaps> maps = unwinder_->GetMaps(); 138800b99b8Sopenharmony_ci if (maps == nullptr) { 139800b99b8Sopenharmony_ci DfxRingBufferWrapper::GetInstance().AppendMsg("MapsInfo is not existed for crash process"); 140800b99b8Sopenharmony_ci return; 141800b99b8Sopenharmony_ci } 142800b99b8Sopenharmony_ci std::shared_ptr<Unwinder> unwinder = unwinder_; 143800b99b8Sopenharmony_ci 144800b99b8Sopenharmony_ci auto createFrame = [maps, unwinder] (size_t index, uintptr_t pc, uintptr_t sp = 0) { 145800b99b8Sopenharmony_ci std::shared_ptr<DfxMap> map; 146800b99b8Sopenharmony_ci DfxFrame frame; 147800b99b8Sopenharmony_ci frame.pc = pc; 148800b99b8Sopenharmony_ci frame.sp = sp; 149800b99b8Sopenharmony_ci frame.index = index; 150800b99b8Sopenharmony_ci if (maps->FindMapByAddr(pc, map)) { 151800b99b8Sopenharmony_ci frame.relPc = map->GetRelPc(pc); 152800b99b8Sopenharmony_ci frame.mapName = map->name; 153800b99b8Sopenharmony_ci } else { 154800b99b8Sopenharmony_ci frame.relPc = pc; 155800b99b8Sopenharmony_ci frame.mapName = (index == 0 ? "Not mapped pc" : "Not mapped lr"); 156800b99b8Sopenharmony_ci } 157800b99b8Sopenharmony_ci unwinder->AddFrame(frame); 158800b99b8Sopenharmony_ci }; 159800b99b8Sopenharmony_ci 160800b99b8Sopenharmony_ci createFrame(0, regs->GetPc(), regs->GetSp()); 161800b99b8Sopenharmony_ci createFrame(1, *(regs->GetReg(REG_LR))); 162800b99b8Sopenharmony_ci#endif 163800b99b8Sopenharmony_ci} 164800b99b8Sopenharmony_ci 165800b99b8Sopenharmony_civoid DfxUnwindAsyncThread::UnwindThreadByParseStackIfNeed() 166800b99b8Sopenharmony_ci{ 167800b99b8Sopenharmony_ci if (thread_ == nullptr || unwinder_ == nullptr) { 168800b99b8Sopenharmony_ci return; 169800b99b8Sopenharmony_ci } 170800b99b8Sopenharmony_ci auto frames = thread_->GetFrames(); 171800b99b8Sopenharmony_ci constexpr int minFramesNum = 3; 172800b99b8Sopenharmony_ci size_t initSize = frames.size(); 173800b99b8Sopenharmony_ci if (initSize < minFramesNum || frames[minFramesNum - 1].mapName.find("Not mapped") != std::string::npos || 174800b99b8Sopenharmony_ci frames[minFramesNum - 1].mapName.find("[Unknown]") != std::string::npos) { 175800b99b8Sopenharmony_ci bool needParseStack = true; 176800b99b8Sopenharmony_ci thread_->InitFaultStack(needParseStack); 177800b99b8Sopenharmony_ci auto faultStack = thread_->GetFaultStack(); 178800b99b8Sopenharmony_ci if (faultStack == nullptr || !faultStack->ParseUnwindStack(unwinder_->GetMaps(), frames)) { 179800b99b8Sopenharmony_ci DFXLOGE("%{public}s : Failed to parse unwind stack.", __func__); 180800b99b8Sopenharmony_ci return; 181800b99b8Sopenharmony_ci } 182800b99b8Sopenharmony_ci thread_->SetFrames(frames); 183800b99b8Sopenharmony_ci tip = StringPrintf( 184800b99b8Sopenharmony_ci " Failed to unwind stack, try to get unreliable call stack from #%02zu by reparsing thread stack.", 185800b99b8Sopenharmony_ci initSize); 186800b99b8Sopenharmony_ci } 187800b99b8Sopenharmony_ci} 188800b99b8Sopenharmony_ci} 189800b99b8Sopenharmony_ci}