• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 "dfx_unwind_remote.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 "dfx_config.h"
26 #include "dfx_define.h"
27 #include "dfx_logger.h"
28 #include "dfx_maps.h"
29 #include "dfx_process.h"
30 #include "dfx_regs.h"
31 #include "dfx_ring_buffer_wrapper.h"
32 #include "dfx_symbols.h"
33 #include "dfx_thread.h"
34 #include "dfx_util.h"
35 #include "process_dumper.h"
36 #include "printer.h"
37 
38 namespace OHOS {
39 namespace HiviewDFX {
40 namespace {
UnwindThreadByParseStackIfNeed(std::shared_ptr<DfxProcess> & process,std::shared_ptr<DfxThread> & thread,std::shared_ptr<Unwinder> unwinder)41 void UnwindThreadByParseStackIfNeed(std::shared_ptr<DfxProcess> &process,
42     std::shared_ptr<DfxThread> &thread, std::shared_ptr<Unwinder> unwinder)
43 {
44     if (process == nullptr || thread == nullptr) {
45         return;
46     }
47     auto frames = unwinder->GetFrames();
48     constexpr int minFramesNum = 3;
49     size_t initSize = frames.size();
50     if (initSize < minFramesNum || frames[minFramesNum - 1].mapName.find("Not mapped") != std::string::npos) {
51         bool needParseStack = true;
52         thread->InitFaultStack(needParseStack);
53         auto faultStack = thread->GetFaultStack();
54         if (faultStack == nullptr || !faultStack->ParseUnwindStack(unwinder->GetMaps(), frames)) {
55             DFXLOG_ERROR("%s : Failed to parse unwind stack.", __func__);
56             return;
57         }
58         thread->SetFrames(frames);
59         std::string tip = StringPrintf(
60             " Failed to unwind stack, try to get unreliable call stack from #%02zu by reparsing thread stack",
61             initSize);
62         std::string msg = process->GetFatalMessage() + tip;
63         process->SetFatalMessage(msg);
64     }
65 }
66 }
67 
GetInstance()68 DfxUnwindRemote &DfxUnwindRemote::GetInstance()
69 {
70     static DfxUnwindRemote ins;
71     return ins;
72 }
73 
UnwindProcess(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder)74 bool DfxUnwindRemote::UnwindProcess(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
75                                     std::shared_ptr<Unwinder> unwinder)
76 {
77     bool ret = false;
78     if (process == nullptr || unwinder == nullptr) {
79         DFXLOG_WARN("%s::process or unwinder is not initialized.", __func__);
80         return ret;
81     }
82 
83     std::shared_ptr<DfxThread> unwThread = process->keyThread_;
84     if (ProcessDumper::GetInstance().IsCrash() && (process->vmThread_ != nullptr)) {
85         unwThread = process->vmThread_;
86     }
87 
88     do {
89         if (unwThread == nullptr) {
90             break;
91         }
92 
93         // unwinding with context passed by dump request, only for crash thread or target thread.
94         unwinder->SetRegs(unwThread->GetThreadRegs());
95         ret = unwinder->UnwindRemote(unwThread->threadInfo_.nsTid,
96                                      ProcessDumper::GetInstance().IsCrash(),
97                                      DfxConfig::GetConfig().maxFrameNums);
98         if (!ret && ProcessDumper::GetInstance().IsCrash()) {
99             UnwindThreadFallback(process, unwThread, unwinder);
100         }
101         unwThread->SetFrames(unwinder->GetFrames());
102         UnwindThreadByParseStackIfNeed(process, unwThread, unwinder);
103         Printer::PrintDumpHeader(request, process, unwinder);
104         Printer::PrintThreadHeaderByConfig(process->keyThread_);
105         Printer::PrintThreadBacktraceByConfig(unwThread);
106         if (ProcessDumper::GetInstance().IsCrash()) {
107             // Registers of unwThread has been changed, we should print regs from request context.
108             Printer::PrintRegsByConfig(DfxRegs::CreateFromUcontext(request->context));
109             if (!DfxConfig::GetConfig().dumpOtherThreads) {
110                 break;
111             }
112         }
113 
114         auto threads = process->GetOtherThreads();
115         if (threads.empty()) {
116             break;
117         }
118 
119         size_t index = 0;
120         for (auto thread : threads) {
121             if ((index == 0) && ProcessDumper::GetInstance().IsCrash()) {
122                 Printer::PrintOtherThreadHeaderByConfig();
123             }
124 
125             if (thread->Attach()) {
126                 Printer::PrintThreadHeaderByConfig(thread);
127                 unwinder->UnwindRemote(thread->threadInfo_.nsTid, false, DfxConfig::GetConfig().maxFrameNums);
128                 thread->Detach();
129                 thread->SetFrames(unwinder->GetFrames());
130                 Printer::PrintThreadBacktraceByConfig(thread);
131             }
132             index++;
133         }
134         ret = true;
135     } while (false);
136 
137     if (ProcessDumper::GetInstance().IsCrash()) {
138         Printer::PrintThreadFaultStackByConfig(process, unwThread, unwinder);
139         Printer::PrintProcessMapsByConfig(unwinder->GetMaps());
140     }
141 
142     return ret;
143 }
144 
UnwindThreadFallback(std::shared_ptr<DfxProcess> process,std::shared_ptr<DfxThread> thread,std::shared_ptr<Unwinder> unwinder)145 void DfxUnwindRemote::UnwindThreadFallback(std::shared_ptr<DfxProcess> process, std::shared_ptr<DfxThread> thread,
146                                            std::shared_ptr<Unwinder> unwinder)
147 {
148     if (unwinder->GetFrames().size() > 0) {
149         return;
150     }
151     // As we failed to init libunwind, just print pc and lr for first two frames
152     std::shared_ptr<DfxRegs> regs = thread->GetThreadRegs();
153     if (regs == nullptr) {
154         DfxRingBufferWrapper::GetInstance().AppendMsg("RegisterInfo is not existed for crash process");
155         return;
156     }
157 
158     std::shared_ptr<DfxMaps> maps = unwinder->GetMaps();
159     if (maps == nullptr) {
160         DfxRingBufferWrapper::GetInstance().AppendMsg("MapsInfo is not existed for crash process");
161         return;
162     }
163 
164     auto createFrame = [maps, unwinder] (size_t index, uintptr_t pc, uintptr_t sp = 0) {
165         std::shared_ptr<DfxMap> map;
166         DfxFrame frame;
167         frame.pc = pc;
168         frame.sp = sp;
169         frame.index = index;
170         if (maps->FindMapByAddr(pc, map)) {
171             frame.relPc = map->GetRelPc(pc);
172             frame.mapName = map->name;
173         } else {
174             frame.relPc = pc;
175             frame.mapName = (index == 0 ? "Not mapped pc" : "Not mapped lr");
176         }
177         unwinder->AddFrame(frame);
178     };
179 
180     createFrame(0, regs->GetPc(), regs->GetSp());
181     createFrame(1, *(regs->GetReg(REG_LR)));
182 }
183 } // namespace HiviewDFX
184 } // namespace OHOS
185