• 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 "cppcrash_reporter.h"
17 
18 #include <cinttypes>
19 #include <dlfcn.h>
20 #include <fcntl.h>
21 #include <map>
22 #include <sstream>
23 #include <string>
24 #include "dfx_define.h"
25 #include "dfx_logger.h"
26 #include "dfx_process.h"
27 #include "dfx_signal.h"
28 #include "dfx_thread.h"
29 
30 struct FaultLogInfoInner {
31     uint64_t time {0};
32     uint32_t id {0};
33     int32_t pid {-1};
34     int32_t pipeFd {-1};
35     int32_t faultLogType {0};
36     std::string module;
37     std::string reason;
38     std::string summary;
39     std::string logPath;
40     std::string registers;
41     std::map<std::string, std::string> sectionMaps;
42 };
43 static const char FOUNDATION_PROCESS_NAME[] = "foundation";
44 static const char HIVIEW_PROCESS_NAME[] = "/system/bin/hiview";
45 static const char REGS_KEY_WORD[] = "Registers:\n";
46 
47 using AddFaultLog = void (*)(FaultLogInfoInner* info);
48 using RecordAppExitReason = int (*)(int reason);
49 
50 namespace OHOS {
51 namespace HiviewDFX {
52 
Format()53 bool CppCrashReporter::Format()
54 {
55     if (process_ == nullptr) {
56         return false;
57     }
58 
59     cmdline_ = process_->processInfo_.processName;
60     pid_ = process_->processInfo_.pid;
61     uid_ = process_->processInfo_.uid;
62     reason_ = process_->reason;
63     auto msg = process_->GetFatalMessage();
64     if (!msg.empty()) {
65         stack_ = "LastFatalMessage:" + msg + "\n";
66     }
67 
68     if (process_->vmThread_ != nullptr) {
69         std::string threadInfo = process_->vmThread_->ToString();
70         auto iterator = threadInfo.begin();
71         while (iterator != threadInfo.end() && *iterator != '\n') {
72             if (isdigit(*iterator)) {
73                 iterator = threadInfo.erase(iterator);
74             } else {
75                 iterator++;
76             }
77         }
78         stack_ += threadInfo;
79 
80         // regs
81         registers_ = GetRegsString(process_->vmThread_);
82     }
83     return true;
84 }
85 
ReportToHiview()86 void CppCrashReporter::ReportToHiview()
87 {
88     if (!Format()) {
89         DFXLOG_WARN("Failed to format crash report.");
90         return;
91     }
92     if (process_->processInfo_.processName.find(HIVIEW_PROCESS_NAME) != std::string::npos) {
93         DFXLOG_WARN("Failed to report, hiview is crashed.");
94         return;
95     }
96 
97     void* handle = dlopen("libfaultlogger.z.so", RTLD_LAZY | RTLD_NODELETE);
98     if (handle == nullptr) {
99         DFXLOG_WARN("Failed to dlopen libfaultlogger, %s\n", dlerror());
100         return;
101     }
102 
103     AddFaultLog addFaultLog = (AddFaultLog)dlsym(handle, "AddFaultLog");
104     if (addFaultLog == nullptr) {
105         DFXLOG_WARN("Failed to dlsym AddFaultLog, %s\n", dlerror());
106         dlclose(handle);
107         return;
108     }
109 
110     FaultLogInfoInner info;
111     info.time = time_;
112     info.id = uid_;
113     info.pid = pid_;
114     info.pipeFd = WriteCppCrashInfoByPipe();
115     info.faultLogType = 2; // 2 : CPP_CRASH_TYPE
116     info.module = cmdline_;
117     info.reason = reason_;
118     info.summary = stack_;
119     info.registers = registers_;
120     addFaultLog(&info);
121     DFXLOG_INFO("Finish report fault to FaultLogger %s(%d,%d)", cmdline_.c_str(), pid_, uid_);
122     dlclose(handle);
123 }
124 
125 // read fd will be closed after transfering to hiview
WriteCppCrashInfoByPipe()126 int32_t CppCrashReporter::WriteCppCrashInfoByPipe()
127 {
128     size_t sz = cppCrashInfo_.size();
129     if (sz > MAX_PIPE_SIZE) {
130         DFXLOG_ERROR("the size of json string is greater than max pipe size, do not report");
131         return -1;
132     }
133     int pipeFd[2] = {-1, -1};
134     if (pipe(pipeFd) != 0) {
135         DFXLOG_ERROR("Failed to create pipe.");
136     }
137     if (fcntl(pipeFd[PIPE_READ], F_SETPIPE_SZ, sz) < 0 ||
138         fcntl(pipeFd[PIPE_WRITE], F_SETPIPE_SZ, sz) < 0) {
139         DFXLOG_ERROR("Failed to set pipe size.");
140     }
141     int flags = fcntl(pipeFd[PIPE_READ], F_GETFL);
142     flags |= O_NONBLOCK;
143     if (fcntl(pipeFd[PIPE_READ], F_SETFL, flags) < 0) {
144         DFXLOG_ERROR("Failed to set pipe flag.");
145     }
146     ssize_t realWriteSize = -1;
147     realWriteSize = OHOS_TEMP_FAILURE_RETRY(write(pipeFd[PIPE_WRITE], cppCrashInfo_.c_str(), sz));
148     close(pipeFd[PIPE_WRITE]);
149     if ((ssize_t)cppCrashInfo_.size() != realWriteSize) {
150         DFXLOG_ERROR("Failed to write pipe. realWriteSize %zd, json size %zd", realWriteSize, sz);
151         close(pipeFd[PIPE_READ]);
152         return -1;
153     }
154     return pipeFd[PIPE_READ];
155 }
156 
ReportToAbilityManagerService()157 void CppCrashReporter::ReportToAbilityManagerService()
158 {
159     if (process_->processInfo_.processName.find(FOUNDATION_PROCESS_NAME) != std::string::npos) {
160         DFXLOG_WARN("Do not to report to AbilityManagerService, foundation is crashed.");
161         return;
162     }
163 
164     void* handle = dlopen("libability_manager_c.z.so", RTLD_LAZY | RTLD_NODELETE);
165     if (handle == nullptr) {
166         DFXLOG_WARN("Failed to dlopen libabilityms, %s\n", dlerror());
167         return;
168     }
169 
170     RecordAppExitReason recordAppExitReason = (RecordAppExitReason)dlsym(handle, "RecordAppExitReason");
171     if (recordAppExitReason == nullptr) {
172         DFXLOG_WARN("Failed to dlsym RecordAppExitReason, %s\n", dlerror());
173         dlclose(handle);
174         return;
175     }
176 
177     // defined in interfaces/inner_api/ability_manager/include/ability_state.h
178     const int cppCrashExitReason = 2;
179     recordAppExitReason(cppCrashExitReason);
180     dlclose(handle);
181 }
182 
GetRegsString(std::shared_ptr<DfxThread> thread)183 std::string CppCrashReporter::GetRegsString(std::shared_ptr<DfxThread> thread)
184 {
185     std::string regsString = "";
186     if (thread == nullptr) {
187         return regsString;
188     }
189     std::shared_ptr<DfxRegs> regs = thread->GetThreadRegs();
190     if (regs == nullptr) {
191         return regsString;
192     }
193     regsString = regs->PrintRegs();
194     // if start with 'Registers:\n', need remove
195     if (regsString.find(REGS_KEY_WORD) == 0) {
196         regsString = regsString.substr(strlen(REGS_KEY_WORD));
197     }
198     return regsString;
199 }
200 } // namespace HiviewDFX
201 } // namespace OHOS
202