1 /*
2 * Copyright (c) 2025 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 #include "key_thread_dump_info.h"
17
18 #include <algorithm>
19 #include <cstdio>
20 #include <cstring>
21 #include <elf.h>
22 #include <link.h>
23 #include <securec.h>
24
25 #include "crash_exception.h"
26 #include "decorative_dump_info.h"
27 #include "dfx_dump_request.h"
28 #include "dfx_log.h"
29 #include "dump_utils.h"
30 #include "process_dump_config.h"
31 #include "dfx_define.h"
32 #include "dfx_frame_formatter.h"
33 #include "dfx_kernel_stack.h"
34 #include "dfx_maps.h"
35 #include "dfx_process.h"
36 #include "dfx_ptrace.h"
37 #include "dfx_regs.h"
38 #include "dfx_buffer_writer.h"
39 #include "dfx_symbols.h"
40 #include "dfx_thread.h"
41 #include "dfx_trace.h"
42 #include "dfx_util.h"
43
44 namespace OHOS {
45 namespace HiviewDFX {
46 namespace {
ParseUnwindStack(const std::vector<uintptr_t> & stackValues,std::shared_ptr<DfxMaps> maps,std::vector<DfxFrame> & frames)47 bool ParseUnwindStack(const std::vector<uintptr_t>& stackValues,
48 std::shared_ptr<DfxMaps> maps, std::vector<DfxFrame>& frames)
49 {
50 bool hasAddFrame = false;
51 if (maps == nullptr) {
52 DFXLOGE("%{public}s : maps is null.", __func__);
53 return false;
54 }
55 size_t index = frames.size();
56 for (const auto& value : stackValues) {
57 std::shared_ptr<DfxMap> map;
58 if (!maps->FindMapByAddr(value, map) ||
59 (map->prots & PROT_EXEC) == 0) {
60 continue;
61 }
62 DfxFrame frame;
63 frame.index = index;
64 frame.pc = value;
65 frame.relPc = map->GetRelPc(frame.pc);
66 frame.map = map;
67 frame.mapName = map->name;
68 frames.emplace_back(frame);
69 hasAddFrame = true;
70 constexpr int MAX_VALID_ADDRESS_NUM = 32;
71 if (++index >= MAX_VALID_ADDRESS_NUM) {
72 return true;
73 }
74 }
75 return hasAddFrame;
76 }
77 }
78
79 REGISTER_DUMP_INFO_CLASS(KeyThreadDumpInfo);
80
Symbolize(DfxProcess & process,Unwinder & unwinder)81 void KeyThreadDumpInfo::Symbolize(DfxProcess& process, Unwinder& unwinder)
82 {
83 auto thread = process.GetKeyThread();
84 if (thread == nullptr) {
85 DFXLOGE("key thread is nullptr!");
86 return;
87 }
88 DFX_TRACE_START("ParseSymbol keyThread:%d", thread->GetThreadInfo().nsTid);
89 thread->ParseSymbol(unwinder);
90 DFX_TRACE_FINISH();
91 }
92
Print(DfxProcess & process,const ProcessDumpRequest & request,Unwinder & unwinder)93 void KeyThreadDumpInfo::Print(DfxProcess& process, const ProcessDumpRequest& request, Unwinder& unwinder)
94 {
95 auto thread = process.GetKeyThread();
96 if (thread == nullptr) {
97 DFXLOGE("key thread is nullptr!");
98 return;
99 }
100 std::string dumpInfo;
101 if (request.type != ProcessDumpType::DUMP_TYPE_DUMP_CATCH) {
102 dumpInfo += "Fault thread info:\n";
103 }
104
105 dumpInfo += thread->ToString();
106 DfxBufferWriter::GetInstance().WriteMsg(dumpInfo);
107 DfxBufferWriter::GetInstance().AppendBriefDumpInfo(dumpInfo);
108 }
109
UnwindStack(DfxProcess & process,const ProcessDumpRequest & request,Unwinder & unwinder)110 int KeyThreadDumpInfo::UnwindStack(DfxProcess& process, const ProcessDumpRequest& request, Unwinder& unwinder)
111 {
112 DFXLOGI("unwind key thread dump start");
113 int result = 0;
114 if (process.GetKeyThread() == nullptr) {
115 DFXLOGW("%{public}s::unwind thread is not initialized.", __func__);
116 return result;
117 }
118 if (process.GetVmPid() == 0) {
119 DFXLOGW("vm pid is null, can not unwind key thread!");
120 return result;
121 }
122 unwinder.SetIsJitCrashFlag(request.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH);
123 if (process.GetKeyThread()->GetThreadRegs() != nullptr) {
124 result = GetKeyThreadStack(process, unwinder) ? 1 : 0;
125 } else {
126 DumpUtils::GetThreadKernelStack(*process.GetKeyThread());
127 }
128 unwinder.SetIsJitCrashFlag(false);
129 if (!unwindFailTip_.empty()) {
130 ReportCrashException(CrashExceptionCode::CRASH_UNWIND_ESTACK);
131 process.AppendFatalMessage(unwindFailTip_);
132 }
133 return result;
134 }
135
GetKeyThreadStack(DfxProcess & process,Unwinder & unwinder)136 bool KeyThreadDumpInfo::GetKeyThreadStack(DfxProcess& process, Unwinder& unwinder)
137 {
138 // unwinding with context passed by dump request, only for crash thread or target thread
139 auto thread = process.GetKeyThread();
140 pid_t tid = thread->GetThreadInfo().nsTid;
141 DFXLOGI("%{public}s, unwind tid(%{public}d) start.", __func__, tid);
142 auto tmpPid = process.GetVmPid() != 0 ? process.GetVmPid() : tid;
143 auto regs = thread->GetThreadRegs();
144 unwinder.SetRegs(regs);
145 DFX_TRACE_START("KeyThreadUnwindRemote:%d", tid);
146 bool ret = unwinder.UnwindRemote(tmpPid, regs != nullptr,
147 ProcessDumpConfig::GetInstance().GetConfig().maxFrameNums);
148 DFX_TRACE_FINISH();
149 DFX_TRACE_START("KeyThreadGetFrames:%d", tid);
150 thread->SetFrames(unwinder.GetFrames());
151 DFX_TRACE_FINISH();
152 ReportUnwinderException(unwinder.GetLastErrorCode());
153 UnwindThreadByParseStackIfNeed(thread, unwinder.GetMaps());
154 #ifdef PARSE_LOCK_OWNER
155 DumpUtils::ParseLockInfo(unwinder, tmpPid, thread->GetThreadInfo().nsTid);
156 #endif
157 DFXLOGI("%{public}s, unwind tid(%{public}d) finish ret(%{public}d).", __func__, tid, ret);
158 return ret;
159 }
160
UnwindThreadByParseStackIfNeed(std::shared_ptr<DfxThread> thread,std::shared_ptr<DfxMaps> maps)161 void KeyThreadDumpInfo::UnwindThreadByParseStackIfNeed(std::shared_ptr<DfxThread> thread, std::shared_ptr<DfxMaps> maps)
162 {
163 auto frames = thread->GetFrames();
164 constexpr int minFramesNum = 3;
165 size_t initSize = frames.size();
166 if (initSize < minFramesNum || frames[minFramesNum - 1].mapName.find("Not mapped") != std::string::npos ||
167 frames[minFramesNum - 1].mapName.find("[Unknown]") != std::string::npos) {
168 bool needParseStack = true;
169 auto faultStack = std::make_shared<FaultStack>();
170 if (faultStack == nullptr) {
171 return;
172 }
173 faultStack->CollectStackInfo(thread->GetThreadInfo().nsTid, frames, needParseStack);
174 if (!ParseUnwindStack(faultStack->GetStackValues(), maps, frames)) {
175 DFXLOGE("%{public}s : Failed to parse unwind stack.", __func__);
176 return;
177 }
178 thread->SetFrames(frames);
179 unwindFailTip_ = StringPrintf(
180 "Failed to unwind stack, try to get unreliable call stack from #%02zu by reparsing thread stack.",
181 initSize);
182 }
183 }
184 }
185 }