1 /*
2  * Copyright (c) 2023-2024 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_stack_info_formatter.h"
17 
18 #include <cinttypes>
19 #include <string>
20 
21 #include "dfx_define.h"
22 #include "dfx_logger.h"
23 #include "dfx_maps.h"
24 #include "dfx_process.h"
25 #include "dfx_signal.h"
26 #include "dfx_thread.h"
27 #include "process_dumper.h"
28 #if defined(__aarch64__)
29 #include "printer.h"
30 #endif
31 
32 namespace OHOS {
33 namespace HiviewDFX {
34 namespace {
35 static const char NATIVE_CRASH_TYPE[] = "NativeCrash";
36 
37 #ifndef is_ohos_lite
FillJsFrame(const DfxFrame & frame,Json::Value & jsonInfo)38 void FillJsFrame(const DfxFrame& frame, Json::Value& jsonInfo)
39 {
40     Json::Value frameJson;
41     frameJson["file"] = frame.mapName;
42     frameJson["symbol"] = frame.funcName;
43     frameJson["line"] = frame.line;
44     frameJson["column"] = frame.column;
45     jsonInfo.append(frameJson);
46 }
47 #endif
48 }
49 
GetStackInfo(bool isJsonDump,std::string & jsonStringInfo) const50 bool DfxStackInfoFormatter::GetStackInfo(bool isJsonDump, std::string& jsonStringInfo) const
51 {
52     bool result = false;
53 #ifndef is_ohos_lite
54     DFXLOG_DEBUG("GetStackInfo isJsonDump:%d", isJsonDump);
55     Json::Value jsonInfo;
56     if (!GetStackInfo(isJsonDump, jsonInfo)) {
57         return result;
58     }
59     jsonStringInfo.append(Json::FastWriter().write(jsonInfo));
60     result = true;
61 #endif
62     return result;
63 }
64 
65 #ifndef is_ohos_lite
GetStackInfo(bool isJsonDump,Json::Value & jsonInfo) const66 bool DfxStackInfoFormatter::GetStackInfo(bool isJsonDump, Json::Value& jsonInfo) const
67 {
68     if ((process_ == nullptr) || (request_ == nullptr)) {
69         DFXLOG_ERROR("%s", "GetStackInfo var is null");
70         return false;
71     }
72     if (isJsonDump) {
73         GetDumpInfo(jsonInfo);
74     } else {
75         GetNativeCrashInfo(jsonInfo);
76     }
77     return true;
78 }
79 
GetNativeCrashInfo(Json::Value & jsonInfo) const80 void DfxStackInfoFormatter::GetNativeCrashInfo(Json::Value& jsonInfo) const
81 {
82     jsonInfo["time"] = request_->timeStamp;
83     jsonInfo["uuid"] = "";
84     jsonInfo["crash_type"] = NATIVE_CRASH_TYPE;
85     jsonInfo["pid"] = process_->processInfo_.pid;
86     jsonInfo["uid"] = process_->processInfo_.uid;
87     jsonInfo["app_running_unique_id"] = request_->appRunningId;
88 
89     DfxSignal dfxSignal(request_->siginfo.si_signo);
90     Json::Value signal;
91     signal["signo"] = request_->siginfo.si_signo;
92     signal["code"] = request_->siginfo.si_code;
93     if (dfxSignal.IsAddrAvailable()) {
94 #if defined(__LP64__)
95         signal["address"] = StringPrintf("%#018lx", reinterpret_cast<uint64_t>(request_->siginfo.si_addr));
96 #else
97         signal["address"] = StringPrintf("%#010llx", reinterpret_cast<uint64_t>(request_->siginfo.si_addr));
98 #endif
99     } else {
100         signal["address"] = "";
101     }
102     Json::Value exception;
103     exception["signal"] = signal;
104     exception["message"] = process_->GetFatalMessage();
105     if (process_->keyThread_ == nullptr) {
106         exception["thread_name"] = "";
107         exception["tid"] = 0;
108     } else {
109         exception["thread_name"] = process_->keyThread_->threadInfo_.threadName;
110         exception["tid"] = process_->keyThread_->threadInfo_.tid;
111     }
112 
113     Json::Value frames(Json::arrayValue);
114     if (process_->vmThread_ != nullptr) {
115         FillFrames(process_->vmThread_, frames);
116     } else if (process_->keyThread_ != nullptr) {
117         FillFrames(process_->keyThread_, frames);
118     }
119     exception["frames"] = frames;
120     jsonInfo["exception"] = exception;
121 
122     // fill other thread info
123     auto otherThreads = process_->GetOtherThreads();
124     if (otherThreads.size() > 0) {
125         Json::Value threadsJsonArray(Json::arrayValue);
126         AppendThreads(otherThreads, threadsJsonArray);
127         jsonInfo["threads"] = threadsJsonArray;
128     }
129 }
130 
GetDumpInfo(Json::Value & jsonInfo) const131 void DfxStackInfoFormatter::GetDumpInfo(Json::Value& jsonInfo) const
132 {
133     Json::Value thread;
134     Json::Value frames(Json::arrayValue);
135     if (process_->keyThread_ == nullptr) {
136         thread["thread_name"] = "";
137         thread["tid"] = 0;
138     } else {
139         thread["thread_name"] = process_->keyThread_->threadInfo_.threadName;
140         thread["tid"] = process_->keyThread_->threadInfo_.tid;
141         FillFrames(process_->keyThread_, frames);
142     }
143     thread["frames"] = frames;
144     jsonInfo.append(thread);
145 
146     // fill other thread info
147     auto otherThreads = process_->GetOtherThreads();
148     if (otherThreads.size() > 0) {
149         AppendThreads(otherThreads, jsonInfo);
150     }
151 }
152 
FillFrames(const std::shared_ptr<DfxThread> & thread,Json::Value & jsonInfo) const153 bool DfxStackInfoFormatter::FillFrames(const std::shared_ptr<DfxThread>& thread,
154                                        Json::Value& jsonInfo) const
155 {
156     if (thread == nullptr) {
157         DFXLOG_ERROR("%s", "FillFrames thread is null");
158         return false;
159     }
160     const auto& threadFrames = thread->GetFrames();
161     for (const auto& frame : threadFrames) {
162         if (frame.isJsFrame) {
163             FillJsFrame(frame, jsonInfo);
164             continue;
165         }
166         FillNativeFrame(frame, jsonInfo);
167 #if defined(__aarch64__)
168         if (Printer::IsLastValidFrame(frame)) {
169             break;
170         }
171 #endif
172     }
173     return true;
174 }
175 
FillNativeFrame(const DfxFrame & frame,Json::Value & jsonInfo) const176 void DfxStackInfoFormatter::FillNativeFrame(const DfxFrame& frame, Json::Value& jsonInfo) const
177 {
178     Json::Value frameJson;
179 #ifdef __LP64__
180     frameJson["pc"] = StringPrintf("%016lx", frame.relPc);
181 #else
182     frameJson["pc"] = StringPrintf("%08llx", frame.relPc);
183 #endif
184     if (frame.funcName.length() > MAX_FUNC_NAME_LEN) {
185         DFXLOG_DEBUG("%s", "length of funcName greater than 256 byte, do not report it");
186         frameJson["symbol"] = "";
187     } else {
188         frameJson["symbol"] = frame.funcName;
189     }
190     frameJson["offset"] = frame.funcOffset;
191     std::string strippedMapName = frame.mapName;
192     DfxMaps::UnFormatMapName(strippedMapName);
193     frameJson["file"] = strippedMapName;
194     frameJson["buildId"] = frame.buildId;
195     jsonInfo.append(frameJson);
196 }
197 
AppendThreads(const std::vector<std::shared_ptr<DfxThread>> & threads,Json::Value & jsonInfo) const198 void DfxStackInfoFormatter::AppendThreads(const std::vector<std::shared_ptr<DfxThread>>& threads,
199                                           Json::Value& jsonInfo) const
200 {
201     for (auto const& oneThread : threads) {
202         Json::Value threadJson;
203         threadJson["thread_name"] = oneThread->threadInfo_.threadName;
204         threadJson["tid"] = oneThread->threadInfo_.tid;
205         Json::Value frames(Json::arrayValue);
206         FillFrames(oneThread, frames);
207         threadJson["frames"] = frames;
208         jsonInfo.append(threadJson);
209     }
210 }
211 #endif
212 } // namespace HiviewDFX
213 } // namespace OHOS
214