blob: acdd133368c0b8232dbaac8ef24970c5b654a811 [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +08004#include "json_utils.hpp"
Aatir186ce8c2019-10-20 15:13:39 -05005
Matt Spinlerb832aa52023-03-21 15:32:34 -05006#include "paths.hpp"
7
Aatir186ce8c2019-10-20 15:13:39 -05008#include <stdio.h>
9
Matt Spinlerb832aa52023-03-21 15:32:34 -050010#include <nlohmann/json.hpp>
11
Aatir186ce8c2019-10-20 15:13:39 -050012#include <cstring>
Matt Spinlerb832aa52023-03-21 15:32:34 -050013#include <filesystem>
Matt Spinler8a09b982025-05-09 14:09:10 -050014#include <fstream>
Matt Spinlerb832aa52023-03-21 15:32:34 -050015#include <optional>
Aatir186ce8c2019-10-20 15:13:39 -050016#include <string>
17
18namespace openpower
19{
20namespace pels
21{
22
23std::string escapeJSON(const std::string& input)
24{
25 std::string output;
26 output.reserve(input.length());
27
28 for (const auto c : input)
29 {
30 switch (c)
31 {
32 case '"':
33 output += "\\\"";
34 break;
35 case '/':
36 output += "\\/";
37 break;
38 case '\b':
39 output += "\\b";
40 break;
41 case '\f':
42 output += "\\f";
43 break;
44 case '\n':
45 output += "\\n";
46 break;
47 case '\r':
48 output += "\\r";
49 break;
50 case '\t':
51 output += "\\t";
52 break;
53 case '\\':
54 output += "\\\\";
55 break;
56 default:
57 output += c;
58 break;
59 }
60 }
61
62 return output;
63}
Arya K Padman8c8aaa02024-04-28 23:23:45 -050064std::unique_ptr<char[]> dumpHex(const void* data, size_t size,
65 size_t indentCount, bool toJson)
Aatir186ce8c2019-10-20 15:13:39 -050066{
67 const int symbolSize = 100;
Matt Spinler4220a152020-03-26 10:18:09 -050068 std::string jsonIndent(indentLevel * indentCount, 0x20);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080069 if (toJson)
70 {
71 jsonIndent.append("\"");
72 }
Arya K Padman8c8aaa02024-04-28 23:23:45 -050073 std::unique_ptr<char[]> buffer{new char[std::max(70, 10 * (int)size)]()};
Aatir186ce8c2019-10-20 15:13:39 -050074 char* symbol = (char*)calloc(symbolSize, sizeof(char));
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080075 char* byteCount = (char*)calloc(11, sizeof(char));
Aatir186ce8c2019-10-20 15:13:39 -050076 char ascii[17];
77 size_t i, j;
78 ascii[16] = '\0';
79 for (i = 0; i < size; ++i)
80 {
81 if (i % 16 == 0)
82 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080083 if (!toJson)
84 {
85 snprintf(byteCount, 11, "%08X ", static_cast<uint32_t>(i));
Arya K Padman8c8aaa02024-04-28 23:23:45 -050086 strcat(buffer.get(), byteCount);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +080087 }
Arya K Padman8c8aaa02024-04-28 23:23:45 -050088 strcat(buffer.get(), jsonIndent.c_str());
Aatir186ce8c2019-10-20 15:13:39 -050089 }
90 snprintf(symbol, symbolSize, "%02X ", ((unsigned char*)data)[i]);
Arya K Padman8c8aaa02024-04-28 23:23:45 -050091 strcat(buffer.get(), symbol);
Aatir186ce8c2019-10-20 15:13:39 -050092 memset(symbol, 0, strlen(symbol));
93 if (((unsigned char*)data)[i] >= ' ' &&
94 ((unsigned char*)data)[i] <= '~')
95 {
96 ascii[i % 16] = ((unsigned char*)data)[i];
97 }
98 else
99 {
100 ascii[i % 16] = '.';
101 }
102 if ((i + 1) % 8 == 0 || i + 1 == size)
103 {
104 std::string asciiString(ascii);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800105 if (toJson)
106 {
107 asciiString = escapeJSON(asciiString);
108 }
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500109 strcat(buffer.get(), " ");
Aatir186ce8c2019-10-20 15:13:39 -0500110 if ((i + 1) % 16 == 0)
111 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800112 if (i + 1 != size && toJson)
Aatir186ce8c2019-10-20 15:13:39 -0500113 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800114 snprintf(symbol, symbolSize, "| %s\",\n",
115 asciiString.c_str());
116 }
117 else if (toJson)
118 {
119 snprintf(symbol, symbolSize, "| %s\"\n",
120 asciiString.c_str());
Aatir186ce8c2019-10-20 15:13:39 -0500121 }
122 else
123 {
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800124 snprintf(symbol, symbolSize, "| %s\n",
125 asciiString.c_str());
Aatir186ce8c2019-10-20 15:13:39 -0500126 }
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500127 strcat(buffer.get(), symbol);
Aatir186ce8c2019-10-20 15:13:39 -0500128 memset(symbol, 0, strlen(symbol));
129 }
130 else if (i + 1 == size)
131 {
132 ascii[(i + 1) % 16] = '\0';
133 if ((i + 1) % 16 <= 8)
134 {
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500135 strcat(buffer.get(), " ");
Aatir186ce8c2019-10-20 15:13:39 -0500136 }
137 for (j = (i + 1) % 16; j < 16; ++j)
138 {
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500139 strcat(buffer.get(), " ");
Aatir186ce8c2019-10-20 15:13:39 -0500140 }
Aatir6a538622019-11-11 13:13:42 -0600141 std::string asciiString2(ascii);
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800142 if (toJson)
143 {
144 asciiString2 = escapeJSON(asciiString2);
145 snprintf(symbol, symbolSize, "| %s\"\n",
146 asciiString2.c_str());
147 }
148 else
149 {
150 snprintf(symbol, symbolSize, "| %s\n",
151 asciiString2.c_str());
152 }
153
Arya K Padman8c8aaa02024-04-28 23:23:45 -0500154 strcat(buffer.get(), symbol);
Aatir186ce8c2019-10-20 15:13:39 -0500155 memset(symbol, 0, strlen(symbol));
156 }
157 }
158 }
Harisuddin Mohamed Isaed32c8d2020-10-01 18:12:39 +0800159 free(byteCount);
Aatir186ce8c2019-10-20 15:13:39 -0500160 free(symbol);
161 return buffer;
162}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800163
164void jsonInsert(std::string& jsonStr, const std::string& fieldName,
Matt Spinler45796e82022-07-01 11:25:27 -0500165 const std::string& fieldValue, uint8_t indentCount)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800166{
Patrick Williams075c7922024-08-16 15:19:49 -0400167 const int8_t spacesToAppend =
168 colAlign - (indentCount * indentLevel) - fieldName.length() - 3;
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800169 const std::string jsonIndent(indentCount * indentLevel, 0x20);
170 jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
Harisuddin Mohamed Isac32e5512020-02-06 18:05:21 +0800171 if (spacesToAppend >= 0)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800172 {
173 jsonStr.append(spacesToAppend, 0x20);
174 }
175 else
176 {
177 jsonStr.append(1, 0x20);
178 }
179 jsonStr.append("\"" + fieldValue + "\",\n");
180}
181
182void jsonInsertArray(std::string& jsonStr, const std::string& fieldName,
Matt Spinler45796e82022-07-01 11:25:27 -0500183 const std::vector<std::string>& values,
184 uint8_t indentCount)
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800185{
186 const std::string jsonIndent(indentCount * indentLevel, 0x20);
187 if (!values.empty())
188 {
189 jsonStr.append(jsonIndent + "\"" + fieldName + "\": [\n");
190 for (size_t i = 0; i < values.size(); i++)
191 {
192 jsonStr.append(colAlign, 0x20);
193 if (i == values.size() - 1)
194 {
195 jsonStr.append("\"" + values[i] + "\"\n");
196 }
197 else
198 {
199 jsonStr.append("\"" + values[i] + "\",\n");
200 }
201 }
202 jsonStr.append(jsonIndent + "],\n");
203 }
204 else
205 {
Patrick Williams075c7922024-08-16 15:19:49 -0400206 const int8_t spacesToAppend =
207 colAlign - (indentCount * indentLevel) - fieldName.length() - 3;
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800208 jsonStr.append(jsonIndent + "\"" + fieldName + "\":");
209 if (spacesToAppend > 0)
210 {
211 jsonStr.append(spacesToAppend, 0x20);
212 }
213 else
214 {
215 jsonStr.append(1, 0x20);
216 }
217 jsonStr.append("[],\n");
218 }
219}
Harisuddin Mohamed Isae2d1bf32020-02-06 17:32:38 +0800220
221std::string trimEnd(std::string s)
222{
223 const char* t = " \t\n\r\f\v";
224 if (s.find_last_not_of(t) != std::string::npos)
225 {
226 s.erase(s.find_last_not_of(t) + 1);
227 }
228 return s;
229}
Matt Spinlerb832aa52023-03-21 15:32:34 -0500230
231/**
232 * @brief Lookup the component ID in a JSON file named
233 * after the creator ID.
234 *
235 * Keeps a cache of the JSON it reads to live throughout
236 * the peltool call as the JSON can be reused across
237 * PEL sections or even across PELs.
238 *
239 * @param[in] compID - The component ID
240 * @param[in] creatorID - The creator ID for the PEL
241 * @return optional<string> - The comp name, or std::nullopt
242 */
Patrick Williams25291152025-02-01 08:21:42 -0500243static std::optional<std::string> lookupComponentName(uint16_t compID,
244 char creatorID)
Matt Spinlerb832aa52023-03-21 15:32:34 -0500245{
246 static std::map<char, nlohmann::json> jsonCache;
247 nlohmann::json jsonData;
248 nlohmann::json* jsonPtr = &jsonData;
Patrick Williams075c7922024-08-16 15:19:49 -0400249 std::filesystem::path filename{
250 std::string{creatorID} + "_component_ids.json"};
Matt Spinlerb832aa52023-03-21 15:32:34 -0500251 filename = getPELReadOnlyDataPath() / filename;
252
253 auto jsonIt = jsonCache.find(creatorID);
254 if (jsonIt != jsonCache.end())
255 {
256 jsonPtr = &(jsonIt->second);
257 }
258 else
259 {
260 std::error_code ec;
261 if (!std::filesystem::exists(filename, ec))
262 {
263 return std::nullopt;
264 }
265
266 std::ifstream file{filename};
267 if (!file)
268 {
269 return std::nullopt;
270 }
271
272 jsonData = nlohmann::json::parse(file, nullptr, false);
273 if (jsonData.is_discarded())
274 {
275 return std::nullopt;
276 }
277
278 jsonCache.emplace(creatorID, jsonData);
279 }
280
281 auto id = getNumberString("%04X", compID);
282
283 auto it = jsonPtr->find(id);
284 if (it == jsonPtr->end())
285 {
286 return std::nullopt;
287 }
288
289 return it->get<std::string>();
290}
291
292/**
293 * @brief Convert the component ID to a 2 character string
294 * if both bytes are nonzero
295 *
296 * e.g. 0x4552 -> "ER"
297 *
298 * @param[in] compID - The component ID
299 * @return optional<string> - The two character string, or std::nullopt.
300 */
301static std::optional<std::string> convertCompIDToChars(uint16_t compID)
302{
303 uint8_t first = (compID >> 8) & 0xFF;
304 uint8_t second = compID & 0xFF;
305 if ((first != 0) && (second != 0))
306 {
307 std::string id{static_cast<char>(first)};
308 id += static_cast<char>(second);
309 return id;
310 }
311
312 return std::nullopt;
313}
314
315std::string getComponentName(uint16_t compID, uint8_t creatorID)
316{
317 // See if there's a JSON file with the names
318 auto name = lookupComponentName(compID, creatorID);
319
320 // If PHYP, convert to ASCII
321 if (!name && ('H' == creatorID))
322 {
323 name = convertCompIDToChars(compID);
324 }
325
326 if (!name)
327 {
328 name = getNumberString("0x%04X", compID);
329 }
330
331 return *name;
332}
333
Aatir186ce8c2019-10-20 15:13:39 -0500334} // namespace pels
335} // namespace openpower