blob: ce2a27d68812bc1f08e0defab8257a280032d1dd [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080016#include "json_utils.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050017
Matt Spinlerb832aa52023-03-21 15:32:34 -050018#include "paths.hpp"
19
Aatir186ce8c2019-10-20 15:13:39 -050020#include <stdio.h>
21
Matt Spinlerb832aa52023-03-21 15:32:34 -050022#include <nlohmann/json.hpp>
23
Aatir186ce8c2019-10-20 15:13:39 -050024#include <cstring>
Matt Spinlerb832aa52023-03-21 15:32:34 -050025#include <filesystem>
26#include <optional>
Aatir186ce8c2019-10-20 15:13:39 -050027#include <sstream>
28#include <string>
29
30namespace openpower
31{
32namespace pels
33{
34
35std::string escapeJSON(const std::string& input)
36{
37 std::string output;
38 output.reserve(input.length());
39
40 for (const auto c : input)
41 {
42 switch (c)
43 {
44 case '"':
45 output += "\\\"";
46 break;
47 case '/':
48 output += "\\/";
49 break;
50 case '\b':
51 output += "\\b";
52 break;
53 case '\f':
54 output += "\\f";
55 break;
56 case '\n':
57 output += "\\n";
58 break;
59 case '\r':
60 output += "\\r";
61 break;
62 case '\t':
63 output += "\\t";
64 break;
65 case '\\':
66 output += "\\\\";
67 break;
68 default:
69 output += c;
70 break;
71 }
72 }
73
74 return output;
75}
Arya K Padman8c8aaa02024-04-28 23:23:45 -050076std::unique_ptr<char[]> dumpHex(const void* data, size_t size,
77 size_t indentCount, bool toJson)
Aatir186ce8c2019-10-20 15:13:39 -050078{
79 const int symbolSize = 100;
Matt Spinler4220a152020-03-26 10:18:09 -050080 std::string jsonIndent(indentLevel * indentCount, 0x20);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080081 if (toJson)
82 {
83 jsonIndent.append("\"");
84 }
Arya K Padman8c8aaa02024-04-28 23:23:45 -050085 std::unique_ptr<char[]> buffer{new char[std::max(70, 10 * (int)size)]()};
Aatir186ce8c2019-10-20 15:13:39 -050086 char* symbol = (char*)calloc(symbolSize, sizeof(char));
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080087 char* byteCount = (char*)calloc(11, sizeof(char));
Aatir186ce8c2019-10-20 15:13:39 -050088 char ascii[17];
89 size_t i, j;
90 ascii[16] = '\0';
91 for (i = 0; i < size; ++i)
92 {
93 if (i % 16 == 0)
94 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080095 if (!toJson)
96 {
97 snprintf(byteCount, 11, "%08X ", static_cast<uint32_t>(i));
Arya K Padman8c8aaa02024-04-28 23:23:45 -050098 strcat(buffer.get(), byteCount);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080099 }
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500100 strcat(buffer.get(), jsonIndent.c_str());
Aatir186ce8c2019-10-20 15:13:39 -0500101 }
102 snprintf(symbol, symbolSize, "%02X ", ((unsigned char*)data)[i]);
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500103 strcat(buffer.get(), symbol);
Aatir186ce8c2019-10-20 15:13:39 -0500104 memset(symbol, 0, strlen(symbol));
105 if (((unsigned char*)data)[i] >= ' ' &&
106 ((unsigned char*)data)[i] <= '~')
107 {
108 ascii[i % 16] = ((unsigned char*)data)[i];
109 }
110 else
111 {
112 ascii[i % 16] = '.';
113 }
114 if ((i + 1) % 8 == 0 || i + 1 == size)
115 {
116 std::string asciiString(ascii);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800117 if (toJson)
118 {
119 asciiString = escapeJSON(asciiString);
120 }
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500121 strcat(buffer.get(), " ");
Aatir186ce8c2019-10-20 15:13:39 -0500122 if ((i + 1) % 16 == 0)
123 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800124 if (i + 1 != size && toJson)
Aatir186ce8c2019-10-20 15:13:39 -0500125 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800126 snprintf(symbol, symbolSize, "| %s\",\n",
127 asciiString.c_str());
128 }
129 else if (toJson)
130 {
131 snprintf(symbol, symbolSize, "| %s\"\n",
132 asciiString.c_str());
Aatir186ce8c2019-10-20 15:13:39 -0500133 }
134 else
135 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800136 snprintf(symbol, symbolSize, "| %s\n",
137 asciiString.c_str());
Aatir186ce8c2019-10-20 15:13:39 -0500138 }
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500139 strcat(buffer.get(), symbol);
Aatir186ce8c2019-10-20 15:13:39 -0500140 memset(symbol, 0, strlen(symbol));
141 }
142 else if (i + 1 == size)
143 {
144 ascii[(i + 1) % 16] = '\0';
145 if ((i + 1) % 16 <= 8)
146 {
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500147 strcat(buffer.get(), " ");
Aatir186ce8c2019-10-20 15:13:39 -0500148 }
149 for (j = (i + 1) % 16; j < 16; ++j)
150 {
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500151 strcat(buffer.get(), " ");
Aatir186ce8c2019-10-20 15:13:39 -0500152 }
Aatir6a538622019-11-11 13:13:42 -0600153 std::string asciiString2(ascii);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800154 if (toJson)
155 {
156 asciiString2 = escapeJSON(asciiString2);
157 snprintf(symbol, symbolSize, "| %s\"\n",
158 asciiString2.c_str());
159 }
160 else
161 {
162 snprintf(symbol, symbolSize, "| %s\n",
163 asciiString2.c_str());
164 }
165
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500166 strcat(buffer.get(), symbol);
Aatir186ce8c2019-10-20 15:13:39 -0500167 memset(symbol, 0, strlen(symbol));
168 }
169 }
170 }
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800171 free(byteCount);
Aatir186ce8c2019-10-20 15:13:39 -0500172 free(symbol);
173 return buffer;
174}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800175
176void jsonInsert(std::string& jsonStr, const std::string& fieldName,
Matt Spinler45796e82022-07-01 11:25:27 -0500177 const std::string& fieldValue, uint8_t indentCount)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800178{
Patrick Williams075c7922024-08-16 15:19:49 -0400179 const int8_t spacesToAppend =
180 colAlign - (indentCount * indentLevel) - fieldName.length() - 3;
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800181 const std::string jsonIndent(indentCount * indentLevel, 0x20);
182 jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
Harisuddin Mohamed Isac32e5512020-02-06 18:05:21 +0800183 if (spacesToAppend >= 0)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800184 {
185 jsonStr.append(spacesToAppend, 0x20);
186 }
187 else
188 {
189 jsonStr.append(1, 0x20);
190 }
191 jsonStr.append("\"" + fieldValue + "\",\n");
192}
193
194void jsonInsertArray(std::string& jsonStr, const std::string& fieldName,
Matt Spinler45796e82022-07-01 11:25:27 -0500195 const std::vector<std::string>& values,
196 uint8_t indentCount)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800197{
198 const std::string jsonIndent(indentCount * indentLevel, 0x20);
199 if (!values.empty())
200 {
201 jsonStr.append(jsonIndent + "\"" + fieldName + "\": [\n");
202 for (size_t i = 0; i < values.size(); i++)
203 {
204 jsonStr.append(colAlign, 0x20);
205 if (i == values.size() - 1)
206 {
207 jsonStr.append("\"" + values[i] + "\"\n");
208 }
209 else
210 {
211 jsonStr.append("\"" + values[i] + "\",\n");
212 }
213 }
214 jsonStr.append(jsonIndent + "],\n");
215 }
216 else
217 {
Patrick Williams075c7922024-08-16 15:19:49 -0400218 const int8_t spacesToAppend =
219 colAlign - (indentCount * indentLevel) - fieldName.length() - 3;
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800220 jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
221 if (spacesToAppend > 0)
222 {
223 jsonStr.append(spacesToAppend, 0x20);
224 }
225 else
226 {
227 jsonStr.append(1, 0x20);
228 }
229 jsonStr.append("[],\n");
230 }
231}
Harisuddin Mohamed Isae2d1bf32020-02-06 17:32:38 +0800232
233std::string trimEnd(std::string s)
234{
235 const char* t = " \t\n\r\f\v";
236 if (s.find_last_not_of(t) != std::string::npos)
237 {
238 s.erase(s.find_last_not_of(t) + 1);
239 }
240 return s;
241}
Matt Spinlerb832aa52023-03-21 15:32:34 -0500242
243/**
244 * @brief Lookup the component ID in a JSON file named
245 * after the creator ID.
246 *
247 * Keeps a cache of the JSON it reads to live throughout
248 * the peltool call as the JSON can be reused across
249 * PEL sections or even across PELs.
250 *
251 * @param[in] compID - The component ID
252 * @param[in] creatorID - The creator ID for the PEL
253 * @return optional<string> - The comp name, or std::nullopt
254 */
Patrick Williams075c7922024-08-16 15:19:49 -0400255static std::optional<std::string>
256 lookupComponentName(uint16_t compID, char creatorID)
Matt Spinlerb832aa52023-03-21 15:32:34 -0500257{
258 static std::map<char, nlohmann::json> jsonCache;
259 nlohmann::json jsonData;
260 nlohmann::json* jsonPtr = &jsonData;
Patrick Williams075c7922024-08-16 15:19:49 -0400261 std::filesystem::path filename{
262 std::string{creatorID} + "_component_ids.json"};
Matt Spinlerb832aa52023-03-21 15:32:34 -0500263 filename = getPELReadOnlyDataPath() / filename;
264
265 auto jsonIt = jsonCache.find(creatorID);
266 if (jsonIt != jsonCache.end())
267 {
268 jsonPtr = &(jsonIt->second);
269 }
270 else
271 {
272 std::error_code ec;
273 if (!std::filesystem::exists(filename, ec))
274 {
275 return std::nullopt;
276 }
277
278 std::ifstream file{filename};
279 if (!file)
280 {
281 return std::nullopt;
282 }
283
284 jsonData = nlohmann::json::parse(file, nullptr, false);
285 if (jsonData.is_discarded())
286 {
287 return std::nullopt;
288 }
289
290 jsonCache.emplace(creatorID, jsonData);
291 }
292
293 auto id = getNumberString("%04X", compID);
294
295 auto it = jsonPtr->find(id);
296 if (it == jsonPtr->end())
297 {
298 return std::nullopt;
299 }
300
301 return it->get<std::string>();
302}
303
304/**
305 * @brief Convert the component ID to a 2 character string
306 * if both bytes are nonzero
307 *
308 * e.g. 0x4552 -> "ER"
309 *
310 * @param[in] compID - The component ID
311 * @return optional<string> - The two character string, or std::nullopt.
312 */
313static std::optional<std::string> convertCompIDToChars(uint16_t compID)
314{
315 uint8_t first = (compID >> 8) & 0xFF;
316 uint8_t second = compID & 0xFF;
317 if ((first != 0) && (second != 0))
318 {
319 std::string id{static_cast<char>(first)};
320 id += static_cast<char>(second);
321 return id;
322 }
323
324 return std::nullopt;
325}
326
327std::string getComponentName(uint16_t compID, uint8_t creatorID)
328{
329 // See if there's a JSON file with the names
330 auto name = lookupComponentName(compID, creatorID);
331
332 // If PHYP, convert to ASCII
333 if (!name && ('H' == creatorID))
334 {
335 name = convertCompIDToChars(compID);
336 }
337
338 if (!name)
339 {
340 name = getNumberString("0x%04X", compID);
341 }
342
343 return *name;
344}
345
Aatir186ce8c2019-10-20 15:13:39 -0500346} // namespace pels
347} // namespace openpower