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 exception["thread_name"] = process_->keyThread_->threadInfo_.threadName;
106 exception["tid"] = process_->keyThread_->threadInfo_.tid;
107 Json::Value frames(Json::arrayValue);
108 if (process_->vmThread_ != nullptr) {
109 FillFrames(process_->vmThread_, frames);
110 } else {
111 FillFrames(process_->keyThread_, frames);
112 }
113 exception["frames"] = frames;
114 jsonInfo["exception"] = exception;
115
116 // fill other thread info
117 auto otherThreads = process_->GetOtherThreads();
118 if (otherThreads.size() > 0) {
119 Json::Value threadsJsonArray(Json::arrayValue);
120 AppendThreads(otherThreads, threadsJsonArray);
121 jsonInfo["threads"] = threadsJsonArray;
122 }
123 }
124
GetDumpInfo(Json::Value & jsonInfo) const125 void DfxStackInfoFormatter::GetDumpInfo(Json::Value& jsonInfo) const
126 {
127 Json::Value thread;
128 thread["thread_name"] = process_->keyThread_->threadInfo_.threadName;
129 thread["tid"] = process_->keyThread_->threadInfo_.tid;
130 Json::Value frames(Json::arrayValue);
131 FillFrames(process_->keyThread_, frames);
132 thread["frames"] = frames;
133 jsonInfo.append(thread);
134
135 // fill other thread info
136 auto otherThreads = process_->GetOtherThreads();
137 if (otherThreads.size() > 0) {
138 AppendThreads(otherThreads, jsonInfo);
139 }
140 }
141
FillFrames(const std::shared_ptr<DfxThread> & thread,Json::Value & jsonInfo) const142 bool DfxStackInfoFormatter::FillFrames(const std::shared_ptr<DfxThread>& thread,
143 Json::Value& jsonInfo) const
144 {
145 if (thread == nullptr) {
146 DFXLOG_ERROR("%s", "FillFrames thread is null");
147 return false;
148 }
149 const auto& threadFrames = thread->GetFrames();
150 for (const auto& frame : threadFrames) {
151 if (frame.isJsFrame) {
152 FillJsFrame(frame, jsonInfo);
153 continue;
154 }
155 FillNativeFrame(frame, jsonInfo);
156 #if defined(__aarch64__)
157 if (Printer::IsLastValidFrame(frame)) {
158 break;
159 }
160 #endif
161 }
162 return true;
163 }
164
FillNativeFrame(const DfxFrame & frame,Json::Value & jsonInfo) const165 void DfxStackInfoFormatter::FillNativeFrame(const DfxFrame& frame, Json::Value& jsonInfo) const
166 {
167 Json::Value frameJson;
168 #ifdef __LP64__
169 frameJson["pc"] = StringPrintf("%016lx", frame.relPc);
170 #else
171 frameJson["pc"] = StringPrintf("%08llx", frame.relPc);
172 #endif
173 if (frame.funcName.length() > MAX_FUNC_NAME_LEN) {
174 DFXLOG_DEBUG("%s", "length of funcName greater than 256 byte, do not report it");
175 frameJson["symbol"] = "";
176 } else {
177 frameJson["symbol"] = frame.funcName;
178 }
179 frameJson["offset"] = frame.funcOffset;
180 std::string strippedMapName = frame.mapName;
181 DfxMaps::UnFormatMapName(strippedMapName);
182 frameJson["file"] = strippedMapName;
183 frameJson["buildId"] = frame.buildId;
184 jsonInfo.append(frameJson);
185 }
186
AppendThreads(const std::vector<std::shared_ptr<DfxThread>> & threads,Json::Value & jsonInfo) const187 void DfxStackInfoFormatter::AppendThreads(const std::vector<std::shared_ptr<DfxThread>>& threads,
188 Json::Value& jsonInfo) const
189 {
190 for (auto const& oneThread : threads) {
191 Json::Value threadJson;
192 threadJson["thread_name"] = oneThread->threadInfo_.threadName;
193 threadJson["tid"] = oneThread->threadInfo_.tid;
194 Json::Value frames(Json::arrayValue);
195 FillFrames(oneThread, frames);
196 threadJson["frames"] = frames;
197 jsonInfo.append(threadJson);
198 }
199 }
200 #endif
201 } // namespace HiviewDFX
202 } // namespace OHOS
203