• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }