1/* 2 * Copyright (c) 2022-2024 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#include "dfx_unwind_async_thread.h" 16 17#include "crash_exception.h" 18#include "dfx_config.h" 19#include "dfx_log.h" 20#include "dfx_memory.h" 21#include "dfx_maps.h" 22#include "dfx_regs.h" 23#include "dfx_ring_buffer_wrapper.h" 24#include "dfx_trace.h" 25#ifdef PARSE_LOCK_OWNER 26#include "lock_parser.h" 27#endif 28#include "process_dumper.h" 29#include "printer.h" 30#include "unique_stack_table.h" 31 32namespace OHOS { 33namespace HiviewDFX { 34bool DfxUnwindAsyncThread::UnwindStack(pid_t vmPid) 35{ 36 if (unwinder_ == nullptr || thread_ == nullptr) { 37 DFXLOGE("%{public}s::thread or unwinder is not initialized.", __func__); 38 return false; 39 } 40 // 1: get crash stack 41 // unwinding with context passed by dump request, only for crash thread or target thread. 42 auto regs = thread_->GetThreadRegs(); 43 unwinder_->SetRegs(regs); 44 pid_t tid = thread_->threadInfo_.nsTid; 45 DFXLOGI("%{public}s, unwind tid(%{public}d) start.", __func__, tid); 46 auto tmpPid = vmPid != 0 ? vmPid : tid; 47 DFX_TRACE_START("KeyThreadUnwindRemote:%d", tid); 48 bool ret = unwinder_->UnwindRemote(tmpPid, 49 regs != nullptr, 50 DfxConfig::GetConfig().maxFrameNums); 51 DFX_TRACE_FINISH(); 52 if (ProcessDumper::GetInstance().IsCrash()) { 53 ReportUnwinderException(unwinder_->GetLastErrorCode()); 54 if (!ret) { 55 UnwindThreadFallback(); 56 } 57 DFX_TRACE_START("KeyThreadGetFrames:%d", tid); 58 thread_->SetFrames(unwinder_->GetFrames()); 59 DFX_TRACE_FINISH(); 60 UnwindThreadByParseStackIfNeed(); 61 // 2: get submitterStack 62 std::vector<DfxFrame> submmiterFrames; 63 GetSubmitterStack(submmiterFrames); 64 // 3: merge two stack 65 MergeStack(submmiterFrames); 66 } else { 67#ifdef PARSE_LOCK_OWNER 68 DFX_TRACE_START("KeyThreadGetFrames:%d", tid); 69 thread_->SetFrames(unwinder_->GetFrames()); 70 DFX_TRACE_FINISH(); 71 LockParser::ParseLockInfo(unwinder_, tmpPid, thread_->threadInfo_.nsTid); 72#else 73 thread_->Detach(); 74 DFX_TRACE_START("KeyThreadGetFrames:%d", tid); 75 thread_->SetFrames(unwinder_->GetFrames()); 76 DFX_TRACE_FINISH(); 77#endif 78 } 79 80 DFXLOGI("%{public}s, unwind tid(%{public}d) finish ret(%{public}d).", __func__, tid, ret); 81 return ret; 82} 83 84void DfxUnwindAsyncThread::GetSubmitterStack(std::vector<DfxFrame> &submitterFrames) 85{ 86 if (stackId_ == 0) { 87 return; 88 } 89 const std::shared_ptr<DfxMaps>& maps = unwinder_->GetMaps(); 90 if (maps == nullptr) { 91 return; 92 } 93 std::vector<std::shared_ptr<DfxMap>> mapVec; 94 if (!maps->FindMapsByName("[anon:async_stack_table]", mapVec)) { 95 DFXLOGE("%{public}s::Can not find map of async stack table", __func__); 96 return; 97 } 98 auto map = mapVec.front(); 99 size_t size = map->end - map->begin; 100 auto tableData = std::make_shared<std::vector<uint8_t>>(size); 101 size_t byte = DfxMemory::ReadProcMemByPid(thread_->threadInfo_.nsTid, map->begin, tableData->data(), size); 102 if (byte != size) { 103 DFXLOGE("Failed to read unique_table from target"); 104 return; 105 } 106 auto table = std::make_shared<UniqueStackTable>(tableData->data(), size, false); 107 std::vector<uintptr_t> pcs; 108 StackId id; 109 id.value = stackId_; 110 if (table->GetPcsByStackId(id, pcs)) { 111 unwinder_->GetFramesByPcs(submitterFrames, pcs); 112 } else { 113 DFXLOGW("%{public}s::Failed to get pcs", __func__); 114 } 115} 116 117void DfxUnwindAsyncThread::MergeStack(std::vector<DfxFrame> &submitterFrames) 118{ 119 auto frames = thread_->GetFrames(); 120 frames.insert(frames.end(), submitterFrames.begin(), submitterFrames.end()); 121 thread_->SetFrames(frames); 122} 123 124void DfxUnwindAsyncThread::UnwindThreadFallback() 125{ 126#ifndef __x86_64__ 127 if (unwinder_->GetFrames().size() > 0) { 128 return; 129 } 130 // As we failed to init libunwind, just print pc and lr for first two frames 131 std::shared_ptr<DfxRegs> regs = thread_->GetThreadRegs(); 132 if (regs == nullptr) { 133 DfxRingBufferWrapper::GetInstance().AppendMsg("RegisterInfo is not existed for crash process"); 134 return; 135 } 136 137 std::shared_ptr<DfxMaps> maps = unwinder_->GetMaps(); 138 if (maps == nullptr) { 139 DfxRingBufferWrapper::GetInstance().AppendMsg("MapsInfo is not existed for crash process"); 140 return; 141 } 142 std::shared_ptr<Unwinder> unwinder = unwinder_; 143 144 auto createFrame = [maps, unwinder] (size_t index, uintptr_t pc, uintptr_t sp = 0) { 145 std::shared_ptr<DfxMap> map; 146 DfxFrame frame; 147 frame.pc = pc; 148 frame.sp = sp; 149 frame.index = index; 150 if (maps->FindMapByAddr(pc, map)) { 151 frame.relPc = map->GetRelPc(pc); 152 frame.mapName = map->name; 153 } else { 154 frame.relPc = pc; 155 frame.mapName = (index == 0 ? "Not mapped pc" : "Not mapped lr"); 156 } 157 unwinder->AddFrame(frame); 158 }; 159 160 createFrame(0, regs->GetPc(), regs->GetSp()); 161 createFrame(1, *(regs->GetReg(REG_LR))); 162#endif 163} 164 165void DfxUnwindAsyncThread::UnwindThreadByParseStackIfNeed() 166{ 167 if (thread_ == nullptr || unwinder_ == nullptr) { 168 return; 169 } 170 auto frames = thread_->GetFrames(); 171 constexpr int minFramesNum = 3; 172 size_t initSize = frames.size(); 173 if (initSize < minFramesNum || frames[minFramesNum - 1].mapName.find("Not mapped") != std::string::npos || 174 frames[minFramesNum - 1].mapName.find("[Unknown]") != std::string::npos) { 175 bool needParseStack = true; 176 thread_->InitFaultStack(needParseStack); 177 auto faultStack = thread_->GetFaultStack(); 178 if (faultStack == nullptr || !faultStack->ParseUnwindStack(unwinder_->GetMaps(), frames)) { 179 DFXLOGE("%{public}s : Failed to parse unwind stack.", __func__); 180 return; 181 } 182 thread_->SetFrames(frames); 183 tip = StringPrintf( 184 " Failed to unwind stack, try to get unreliable call stack from #%02zu by reparsing thread stack.", 185 initSize); 186 } 187} 188} 189}