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_json_formatter.h"
17
18 #include <cstdlib>
19 #include <iostream>
20 #include <ostream>
21 #include <securec.h>
22 #include <sstream>
23 #include "dfx_kernel_stack.h"
24 #ifndef is_ohos_lite
25 #include "json/json.h"
26 #endif
27
28 namespace OHOS {
29 namespace HiviewDFX {
30 #ifndef is_ohos_lite
31 namespace {
32 const int FRAME_BUF_LEN = 1024;
FormatJsFrame(const Json::Value & frames,const uint32_t & frameIdx,std::string & outStr)33 static bool FormatJsFrame(const Json::Value& frames, const uint32_t& frameIdx, std::string& outStr)
34 {
35 const int jsIdxLen = 10;
36 char buf[jsIdxLen] = { 0 };
37 char idxFmt[] = "#%02u at ";
38 if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, idxFmt, frameIdx) <= 0) {
39 return false;
40 }
41 outStr = std::string(buf, strlen(buf));
42 std::string symbol = frames[frameIdx]["symbol"].asString();
43 std::string file = frames[frameIdx]["file"].asString();
44 std::string line = frames[frameIdx]["line"].asString();
45 std::string column = frames[frameIdx]["column"].asString();
46 outStr.append(symbol + " (" + file + ":" + line + ":" + column + ")");
47 return true;
48 }
49
FormatNativeFrame(const Json::Value & frames,const uint32_t & frameIdx,std::string & outStr)50 static bool FormatNativeFrame(const Json::Value& frames, const uint32_t& frameIdx, std::string& outStr)
51 {
52 char buf[FRAME_BUF_LEN] = {0};
53 char format[] = "#%02u pc %s %s";
54 std::string buildId = frames[frameIdx]["buildId"].asString();
55 std::string file = frames[frameIdx]["file"].asString();
56 std::string offset = frames[frameIdx]["offset"].asString();
57 std::string pc = frames[frameIdx]["pc"].asString();
58 std::string symbol = frames[frameIdx]["symbol"].asString();
59 if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, frameIdx, pc.c_str(),
60 file.empty() ? "Unknown" : file.c_str()) <= 0) {
61 return false;
62 }
63 outStr = std::string(buf, strlen(buf));
64 if (!symbol.empty()) {
65 outStr.append("(" + symbol + "+" + offset + ")");
66 }
67 if (!buildId.empty()) {
68 outStr.append("(" + buildId + ")");
69 }
70 return true;
71 }
72 }
73
FormatJsonStack(std::string jsonStack,std::string & outStackStr)74 bool DfxJsonFormatter::FormatJsonStack(std::string jsonStack, std::string& outStackStr)
75 {
76 Json::Reader reader;
77 Json::Value threads;
78 if (!(reader.parse(jsonStack, threads))) {
79 outStackStr.append("Failed to parse json stack info.");
80 return false;
81 }
82
83 for (uint32_t i = 0; i < threads.size(); ++i) {
84 std::ostringstream ss;
85 Json::Value thread = threads[i];
86 if (thread["tid"].isConvertibleTo(Json::stringValue) &&
87 thread["thread_name"].isConvertibleTo(Json::stringValue)) {
88 ss << "Tid:" << thread["tid"].asString() << ", Name:" << thread["thread_name"].asString() << std::endl;
89 }
90 const Json::Value frames = thread["frames"];
91 for (uint32_t j = 0; j < frames.size(); ++j) {
92 std::string frameStr = "";
93 bool formatStatus = false;
94 if (frames[j]["line"].asString().empty()) {
95 formatStatus = FormatNativeFrame(frames, j, frameStr);
96 } else {
97 formatStatus = FormatJsFrame(frames, j, frameStr);
98 }
99 if (formatStatus) {
100 ss << frameStr << std::endl;
101 } else {
102 // Shall we try to print more information?
103 outStackStr.append("Frame info is illegal.");
104 return false;
105 }
106 }
107 outStackStr.append(ss.str());
108 }
109 return true;
110 }
111
112 #ifdef __aarch64__
FormatKernelStackStr(const std::vector<DfxThreadStack> & processStack,std::string & formattedStack)113 static bool FormatKernelStackStr(const std::vector<DfxThreadStack>& processStack, std::string& formattedStack)
114 {
115 if (processStack.empty()) {
116 return false;
117 }
118 formattedStack = "";
119 for (const auto &threadStack : processStack) {
120 std::ostringstream ss;
121 ss << "Tid:" << threadStack.tid << ", Name:" << threadStack.threadName << std::endl;
122 formattedStack.append(ss.str());
123 for (size_t frameIdx = 0; frameIdx < threadStack.frames.size(); ++frameIdx) {
124 std::string file = threadStack.frames[frameIdx].mapName;
125 char buf[FRAME_BUF_LEN] = {0};
126 char format[] = "#%02zu pc %016" PRIx64 " %s";
127 if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, frameIdx, threadStack.frames[frameIdx].relPc,
128 file.empty() ? "Unknown" : file.c_str()) <= 0) {
129 continue;
130 }
131 formattedStack.append(std::string(buf, strlen(buf)) + "\n");
132 }
133 }
134 return true;
135 }
136
FormatKernelStackJson(std::vector<DfxThreadStack> processStack,std::string & formattedStack)137 static bool FormatKernelStackJson(std::vector<DfxThreadStack> processStack, std::string& formattedStack)
138 {
139 if (processStack.empty()) {
140 return false;
141 }
142 Json::Value jsonInfo;
143 for (const auto &threadStack : processStack) {
144 Json::Value threadInfo;
145 threadInfo["thread_name"] = threadStack.threadName;
146 threadInfo["tid"] = threadStack.tid;
147 Json::Value frames(Json::arrayValue);
148 for (const auto& frame : threadStack.frames) {
149 Json::Value frameJson;
150 char buf[FRAME_BUF_LEN] = {0};
151 char format[] = "%016" PRIx64;
152 if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, frame.relPc) <= 0) {
153 continue;
154 }
155 frameJson["pc"] = std::string(buf, strlen(buf));
156 frameJson["symbol"] = "";
157 frameJson["offset"] = 0;
158 frameJson["file"] = frame.mapName.empty() ? "Unknown" : frame.mapName;
159 frameJson["buildId"] = "";
160 frames.append(frameJson);
161 }
162 threadInfo["frames"] = frames;
163 jsonInfo.append(threadInfo);
164 }
165 formattedStack = Json::FastWriter().write(jsonInfo);
166 return true;
167 }
168 #endif
169
FormatKernelStack(const std::string & kernelStack,std::string & formattedStack,bool jsonFormat)170 bool DfxJsonFormatter::FormatKernelStack(const std::string& kernelStack, std::string& formattedStack, bool jsonFormat)
171 {
172 #ifdef __aarch64__
173 std::vector<DfxThreadStack> processStack;
174 if (!FormatProcessKernelStack(kernelStack, processStack)) {
175 return false;
176 }
177 if (jsonFormat) {
178 return FormatKernelStackJson(processStack, formattedStack);
179 } else {
180 return FormatKernelStackStr(processStack, formattedStack);
181 }
182 #else
183 return false;
184 #endif
185 }
186 #endif
187 } // namespace HiviewDFX
188 } // namespace OHOS
189