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