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