• 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 "process_dumper.h"
17 
18 #include <cerrno>
19 #include <cinttypes>
20 #include <csignal>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 #include <iostream>
25 #include <memory>
26 #include <string>
27 #include <fcntl.h>
28 #include <pthread.h>
29 #include <syscall.h>
30 #include <ucontext.h>
31 #include <unistd.h>
32 #include <securec.h>
33 
34 #include "faultloggerd_client.h"
35 #include "cppcrash_reporter.h"
36 #include "printer.h"
37 #include "procinfo.h"
38 #include "dfx_config.h"
39 #include "dfx_define.h"
40 #include "dfx_dump_request.h"
41 #include "dfx_dump_res.h"
42 #include "dfx_logger.h"
43 #include "dfx_process.h"
44 #include "dfx_regs.h"
45 #include "dfx_ring_buffer_wrapper.h"
46 #include "dfx_thread.h"
47 #include "dfx_unwind_remote.h"
48 #include "dfx_util.h"
49 
50 namespace OHOS {
51 namespace HiviewDFX {
GetInstance()52 ProcessDumper &ProcessDumper::GetInstance()
53 {
54     static ProcessDumper ins;
55     return ins;
56 }
57 
Dump()58 void ProcessDumper::Dump()
59 {
60     std::shared_ptr<ProcessDumpRequest> request = std::make_shared<ProcessDumpRequest>();
61     resDump_ = DumpProcess(request);
62     if (process_ == nullptr) {
63         DFXLOG_ERROR("Dump process failed, please check permission and whether pid is valid.");
64     } else {
65         if (isCrash_) {
66             process_->vmThread_->Detach();
67             process_->Detach();
68         }
69         process_->keyThread_->Detach();
70     }
71 
72     WriteDumpRes(resDump_);
73     DfxRingBufferWrapper::GetInstance().StopThread();
74     DFXLOG_INFO("Finish dump stacktrace for %s(%d:%d).", request->processName, request->pid, request->tid);
75     CloseDebugLog();
76 
77     // check dump result ?
78     if (reporter_ != nullptr) {
79         reporter_->ReportToHiview();
80         reporter_->ReportToAbilityManagerService();
81     }
82 }
83 
DumpProcess(std::shared_ptr<ProcessDumpRequest> request)84 int ProcessDumper::DumpProcess(std::shared_ptr<ProcessDumpRequest> request)
85 {
86     int dumpRes = DumpErrorCode::DUMP_ESUCCESS;
87     do {
88         ssize_t readCount = read(STDIN_FILENO, request.get(), sizeof(ProcessDumpRequest));
89         if (readCount != static_cast<long>(sizeof(ProcessDumpRequest))) {
90             DFXLOG_ERROR("Fail to read DumpRequest(%d).", errno);
91             dumpRes = DumpErrorCode::DUMP_EREADREQUEST;
92             break;
93         }
94 
95         isCrash_ = (request->siginfo.si_signo != SIGDUMP);
96         // We need check pid is same with getppid().
97         // As in signal handler, current process is a child process, and target pid is our parent process.
98         // If pid namespace is enalbed, both ppid and pid are equal one.
99         // In this case, we have to parse /proc/self/status
100         if ((!isCrash_ && (syscall(SYS_getppid) != request->nsPid)) ||
101             (isCrash_ && (syscall(SYS_getppid) != request->vmNsPid))) {
102             DFXLOG_ERROR("Target process(%s:%d) is not parent pid(%d), exit processdump for signal(%d).",
103                 request->processName, request->nsPid, syscall(SYS_getppid), request->siginfo.si_signo);
104             dumpRes = DumpErrorCode::DUMP_EGETPPID;
105             break;
106         }
107         DFXLOG_INFO("Processdump SigVal(%d), TargetPid(%d:%d), TargetTid(%d), threadname(%s).",
108             request->siginfo.si_value.sival_int, request->pid, request->nsPid, request->tid, request->threadName);
109 
110         if (InitProcessInfo(request) < 0) {
111             DFXLOG_ERROR("Failed to init crash process info.");
112             dumpRes = DumpErrorCode::DUMP_EATTACH;
113             break;
114         }
115 
116         if (InitPrintThread(request) < 0) {
117             DFXLOG_ERROR("Failed to init print thread.");
118             dumpRes = DumpErrorCode::DUMP_EGETFD;
119         }
120 
121         if (isCrash_) {
122             reporter_ = std::make_shared<CppCrashReporter>(request->timeStamp, request->siginfo, process_);
123         }
124 
125         Printer::PrintDumpHeader(request, process_);
126         if (DfxUnwindRemote::GetInstance().UnwindProcess(process_) == false) {
127             DFXLOG_ERROR("Failed to unwind process.");
128             dumpRes = DumpErrorCode::DUMP_ESTOPUNWIND;
129         }
130 
131         if ((!isCrash_ && (syscall(SYS_getppid) != request->nsPid)) ||
132             (isCrash_ && (syscall(SYS_getppid) != request->vmNsPid))) {
133             DfxRingBufferWrapper::GetInstance().AppendMsg(
134                 "Target process has been killed, the crash log may not be fully generated.");
135             dumpRes = DumpErrorCode::DUMP_EGETPPID;
136             break;
137         }
138     } while (false);
139     return dumpRes;
140 }
141 
InitProcessInfo(std::shared_ptr<ProcessDumpRequest> request)142 int ProcessDumper::InitProcessInfo(std::shared_ptr<ProcessDumpRequest> request)
143 {
144     if (request->pid <= 0) {
145         return -1;
146     }
147     process_ = DfxProcess::Create(request->pid, request->nsPid);
148     if (process_ == nullptr) {
149         return -1;
150     }
151     if (process_->processInfo_.processName.empty()) {
152         process_->processInfo_.processName = std::string(request->processName);
153     }
154     process_->processInfo_.uid = request->uid;
155     process_->recycleTid_ = request->recycleTid;
156     process_->SetFatalMessage(request->lastFatalMessage);
157 
158     if (isCrash_ && request->vmPid != 0) {
159         if (getppid() != request->vmNsPid) {
160             DFXLOG_ERROR("VM process(%d) should be parent pid.", request->vmNsPid);
161             return -1;
162         }
163         process_->vmThread_ = DfxThread::Create(request->vmPid, request->vmPid, request->vmNsPid);
164         if (!process_->vmThread_->Attach()) {
165             DFXLOG_ERROR("Fail to attach vm thread(%d).", request->vmNsPid);
166             return -1;
167         }
168 
169         process_->vmThread_->SetThreadRegs(DfxRegs::CreateFromContext(request->context));
170         process_->vmThread_->threadInfo_.threadName = std::string(request->threadName);
171     }
172 
173     pid_t dumpTid = request->siginfo.si_value.sival_int;
174     pid_t nsTid = request->tid;
175     pid_t tid = process_->ChangeTid(nsTid, true);
176     if (!isCrash_) {
177         if (dumpTid != 0 && dumpTid != tid && (IsThreadInPid(process_->processInfo_.pid, dumpTid))) {
178             tid = dumpTid;
179             nsTid = process_->ChangeTid(tid, false);
180         }
181     }
182     process_->keyThread_ = DfxThread::Create(process_->processInfo_.pid, tid, nsTid);
183     if (!process_->keyThread_->Attach()) {
184         DFXLOG_ERROR("Fail to attach key thread(%d).", nsTid);
185         if (!isCrash_) {
186             return -1;
187         }
188     }
189     if (process_->keyThread_->threadInfo_.threadName.empty()) {
190         process_->keyThread_->threadInfo_.threadName = std::string(request->threadName);
191     }
192 
193     if (isCrash_) {
194         process_->InitOtherThreads();
195         process_->Attach();
196     } else {
197         if (dumpTid == 0) {
198             process_->InitOtherThreads();
199         }
200     }
201     return 0;
202 }
203 
InitPrintThread(std::shared_ptr<ProcessDumpRequest> request)204 int ProcessDumper::InitPrintThread(std::shared_ptr<ProcessDumpRequest> request)
205 {
206     int fd = -1;
207     FaultLoggerType type = isCrash_ ? FaultLoggerType::CPP_CRASH : FaultLoggerType::CPP_STACKTRACE;
208 
209     struct FaultLoggerdRequest faultloggerdRequest;
210     (void)memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest));
211 
212     if (isCrash_) {
213         if (DfxConfig::GetConfig().logPersist) {
214             InitDebugLog((int)type, request->pid, request->tid, request->uid);
215         }
216 
217         faultloggerdRequest.type = (int32_t)type;
218         faultloggerdRequest.pid = request->pid;
219         faultloggerdRequest.tid = request->tid;
220         faultloggerdRequest.uid = request->uid;
221         faultloggerdRequest.time = request->timeStamp;
222         fd = RequestFileDescriptorEx(&faultloggerdRequest);
223 
224         DfxRingBufferWrapper::GetInstance().SetWriteFunc(ProcessDumper::WriteDumpBuf);
225     } else {
226         fd = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_WRITE_BUF);
227         DFXLOG_DEBUG("write buf fd: %d", fd);
228 
229         resFd_ = RequestPipeFd(request->pid, FaultLoggerPipeType::PIPE_FD_WRITE_RES);
230         DFXLOG_DEBUG("write res fd: %d", resFd_);
231     }
232 
233     if (fd < 0) {
234         DFXLOG_WARN("Failed to request fd from faultloggerd.");
235     }
236 
237     DfxRingBufferWrapper::GetInstance().SetWriteBufFd(fd);
238     DfxRingBufferWrapper::GetInstance().StartThread();
239     return fd;
240 }
241 
WriteDumpBuf(int fd,const char * buf,const int len)242 int ProcessDumper::WriteDumpBuf(int fd, const char* buf, const int len)
243 {
244     if (buf == nullptr) {
245         return -1;
246     }
247     return WriteLog(fd, "%s", buf);
248 }
249 
WriteDumpRes(int32_t res)250 void ProcessDumper::WriteDumpRes(int32_t res)
251 {
252     DFXLOG_DEBUG("%s :: res: %d", __func__, res);
253     if (resFd_ > 0) {
254         write(resFd_, &res, sizeof(res));
255         close(resFd_);
256     } else {
257         if (res != DUMP_ESUCCESS) {
258             DfxRingBufferWrapper::GetInstance().AppendMsg("Result:\n");
259             DfxRingBufferWrapper::GetInstance().AppendMsg(DfxDumpRes::ToString(res) + "\n");
260         }
261     }
262 }
263 
IsCrash() const264 bool ProcessDumper::IsCrash() const
265 {
266     return isCrash_;
267 }
268 } // namespace HiviewDFX
269 } // namespace OHOS
270