1 /**
2 * Describes utility functions for parsing CPER into JSON IR.
3 *
4 * Author: Lawrence.Tang@arm.com
5 **/
6
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <json.h>
10 #include <string.h>
11 #include <libcper/Cper.h>
12 #include <libcper/cper-utils.h>
13 #include <libcper/log.h>
14 #include <libcper/base64.h>
15
16 //The available severity types for CPER.
17 const char *CPER_SEVERITY_TYPES[4] = { "Recoverable", "Fatal", "Corrected",
18 "Informational" };
19
20 //Converts the given generic CPER error status to JSON IR.
21 json_object *
cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS * error_status)22 cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS *error_status)
23 {
24 json_object *error_status_ir = json_object_new_object();
25
26 //Error type.
27 json_object_object_add(error_status_ir, "errorType",
28 integer_to_readable_pair_with_desc(
29 error_status->Type, 18,
30 CPER_GENERIC_ERROR_TYPES_KEYS,
31 CPER_GENERIC_ERROR_TYPES_VALUES,
32 CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS,
33 "Unknown (Reserved)"));
34
35 //Boolean bit fields.
36 add_bool(error_status_ir, "addressSignal", error_status->AddressSignal);
37 add_bool(error_status_ir, "controlSignal", error_status->ControlSignal);
38 add_bool(error_status_ir, "dataSignal", error_status->DataSignal);
39 add_bool(error_status_ir, "detectedByResponder",
40 error_status->DetectedByResponder);
41 add_bool(error_status_ir, "detectedByRequester",
42 error_status->DetectedByRequester);
43 add_bool(error_status_ir, "firstError", error_status->FirstError);
44 add_bool(error_status_ir, "overflowDroppedLogs",
45 error_status->OverflowNotLogged);
46
47 return error_status_ir;
48 }
49
50 //Converts the given CPER-JSON generic error status into a CPER structure.
ir_generic_error_status_to_cper(json_object * error_status,EFI_GENERIC_ERROR_STATUS * error_status_cper)51 void ir_generic_error_status_to_cper(
52 json_object *error_status, EFI_GENERIC_ERROR_STATUS *error_status_cper)
53 {
54 error_status_cper->Type = readable_pair_to_integer(
55 json_object_object_get(error_status, "errorType"));
56 error_status_cper->AddressSignal = json_object_get_boolean(
57 json_object_object_get(error_status, "addressSignal"));
58 error_status_cper->ControlSignal = json_object_get_boolean(
59 json_object_object_get(error_status, "controlSignal"));
60 error_status_cper->DataSignal = json_object_get_boolean(
61 json_object_object_get(error_status, "dataSignal"));
62 error_status_cper->DetectedByResponder = json_object_get_boolean(
63 json_object_object_get(error_status, "detectedByResponder"));
64 error_status_cper->DetectedByRequester = json_object_get_boolean(
65 json_object_object_get(error_status, "detectedByRequester"));
66 error_status_cper->FirstError = json_object_get_boolean(
67 json_object_object_get(error_status, "firstError"));
68 error_status_cper->OverflowNotLogged = json_object_get_boolean(
69 json_object_object_get(error_status, "overflowDroppedLogs"));
70 }
71
72 //Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order.
uniform_struct64_to_ir(UINT64 * start,int len,const char * names[])73 json_object *uniform_struct64_to_ir(UINT64 *start, int len, const char *names[])
74 {
75 json_object *result = json_object_new_object();
76
77 UINT64 *cur = start;
78 for (int i = 0; i < len; i++) {
79 add_uint(result, names[i], *cur);
80 cur++;
81 }
82
83 return result;
84 }
85
86 //Converts a single uniform struct of UINT32s into intermediate JSON IR format, given names for each field in byte order.
uniform_struct_to_ir(UINT32 * start,int len,const char * names[])87 json_object *uniform_struct_to_ir(UINT32 *start, int len, const char *names[])
88 {
89 json_object *result = json_object_new_object();
90
91 UINT32 *cur = start;
92 for (int i = 0; i < len; i++) {
93 UINT32 value;
94 memcpy(&value, cur, sizeof(UINT32));
95 add_uint(result, names[i], value);
96 cur++;
97 }
98
99 return result;
100 }
101
102 //Converts a single object containing UINT32s into a uniform struct.
ir_to_uniform_struct64(json_object * ir,UINT64 * start,int len,const char * names[])103 void ir_to_uniform_struct64(json_object *ir, UINT64 *start, int len,
104 const char *names[])
105 {
106 UINT64 *cur = start;
107 for (int i = 0; i < len; i++) {
108 *cur = json_object_get_uint64(
109 json_object_object_get(ir, names[i]));
110 cur++;
111 }
112 }
113
114 //Converts a single object containing UINT32s into a uniform struct.
ir_to_uniform_struct(json_object * ir,UINT32 * start,int len,const char * names[])115 void ir_to_uniform_struct(json_object *ir, UINT32 *start, int len,
116 const char *names[])
117 {
118 UINT32 *cur = start;
119 for (int i = 0; i < len; i++) {
120 *cur = (UINT32)json_object_get_uint64(
121 json_object_object_get(ir, names[i]));
122 cur++;
123 }
124 }
125
126 //Converts a single integer value to an object containing a value, and a readable name if possible.
integer_to_readable_pair(UINT64 value,int len,const int keys[],const char * values[],const char * default_value)127 json_object *integer_to_readable_pair(UINT64 value, int len, const int keys[],
128 const char *values[],
129 const char *default_value)
130 {
131 json_object *result = json_object_new_object();
132 add_uint(result, "value", value);
133
134 //Search for human readable name, add.
135 const char *name = default_value;
136 for (int i = 0; i < len; i++) {
137 if ((UINT64)keys[i] == value) {
138 name = values[i];
139 }
140 }
141
142 add_string(result, "name", name);
143 return result;
144 }
145
146 //Converts a single integer value to an object containing a value, readable name and description if possible.
integer_to_readable_pair_with_desc(int value,int len,const int keys[],const char * values[],const char * descriptions[],const char * default_value)147 json_object *integer_to_readable_pair_with_desc(int value, int len,
148 const int keys[],
149 const char *values[],
150 const char *descriptions[],
151 const char *default_value)
152 {
153 json_object *result = json_object_new_object();
154 add_int(result, "value", value);
155
156 //Search for human readable name, add.
157 const char *name = default_value;
158 for (int i = 0; i < len; i++) {
159 if (keys[i] == value) {
160 name = values[i];
161 add_string(result, "description", descriptions[i]);
162 }
163 }
164
165 add_string(result, "name", name);
166 return result;
167 }
168
169 //Returns a single UINT64 value from the given readable pair object.
170 //Assumes the integer value is held in the "value" field.
readable_pair_to_integer(json_object * pair)171 UINT64 readable_pair_to_integer(json_object *pair)
172 {
173 return json_object_get_uint64(json_object_object_get(pair, "value"));
174 }
175
176 //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left.
bitfield_to_ir(UINT64 bitfield,int num_fields,const char * names[])177 json_object *bitfield_to_ir(UINT64 bitfield, int num_fields,
178 const char *names[])
179 {
180 json_object *result = json_object_new_object();
181 for (int i = 0; i < num_fields; i++) {
182 add_bool(result, names[i], (bitfield >> i) & 0x1);
183 }
184
185 return result;
186 }
187
188 //Filters properties based on Validation Bits.
189 // Refer to CPER spec for vbit_idx to be passed here.
add_to_valid_bitfield(ValidationTypes * val,int vbit_idx)190 void add_to_valid_bitfield(ValidationTypes *val, int vbit_idx)
191 {
192 switch (val->size) {
193 case UINT_8T:
194 val->value.ui8 |= (0x01 << vbit_idx);
195 break;
196 case UINT_16T:
197 val->value.ui16 |= (0x01 << vbit_idx);
198 break;
199 case UINT_32T:
200 val->value.ui32 |= (0x01 << vbit_idx);
201 break;
202 case UINT_64T:
203 val->value.ui64 |= (0x01 << vbit_idx);
204 break;
205 default:
206 cper_print_log(
207 "IR to CPER: Unknown validation bits size passed, Enum IntType=%d",
208 val->size);
209 }
210 }
211
212 //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0.
ir_to_bitfield(json_object * ir,int num_fields,const char * names[])213 UINT64 ir_to_bitfield(json_object *ir, int num_fields, const char *names[])
214 {
215 UINT64 result = 0x0;
216 for (int i = 0; i < num_fields; i++) {
217 if (json_object_get_boolean(
218 json_object_object_get(ir, names[i]))) {
219 result |= (0x1 << i);
220 }
221 }
222
223 return result;
224 }
225
226 // Filters properties based on Validation Bits.
227 // Refer to CPER spec for vbit_idx to be passed here.
228 // Overload function for 16, 32, 64b
isvalid_prop_to_ir(ValidationTypes * val,int vbit_idx)229 bool isvalid_prop_to_ir(ValidationTypes *val, int vbit_idx)
230 {
231 // If the option is enabled, output invalid properties
232 // as well as valid ones.
233 #ifdef OUTPUT_ALL_PROPERTIES
234 return true;
235 #endif //OUTPUT_ALL_PROPERTIES
236 UINT64 vbit_mask = 0x01 << vbit_idx;
237 switch (val->size) {
238 case UINT_16T:
239 return (vbit_mask & val->value.ui16);
240
241 case UINT_32T:
242 return (vbit_mask & val->value.ui32);
243
244 case UINT_64T:
245 return (vbit_mask & val->value.ui64);
246
247 default:
248 cper_print_log(
249 "CPER to IR:Unknown validation bits size passed. Enum IntType: %d",
250 val->size);
251 }
252 return 0;
253 }
254
print_val(ValidationTypes * val)255 void print_val(ValidationTypes *val)
256 {
257 switch (val->size) {
258 case UINT_8T:
259 cper_print_log("Validation bits: %x\n", val->value.ui8);
260 break;
261 case UINT_16T:
262 cper_print_log("Validation bits: %x\n", val->value.ui16);
263 break;
264
265 case UINT_32T:
266 cper_print_log("Validation bits: %x\n", val->value.ui32);
267 break;
268
269 case UINT_64T:
270 cper_print_log("Validation bits: %llx\n", val->value.ui64);
271 break;
272
273 default:
274 cper_print_log(
275 "CPER to IR:Unknown validation bits size passed. Enum IntType: %d",
276 val->size);
277 }
278 }
279
280 //Converts the given UINT64 array into a JSON IR array, given the length.
uint64_array_to_ir_array(UINT64 * array,int len)281 json_object *uint64_array_to_ir_array(UINT64 *array, int len)
282 {
283 json_object *array_ir = json_object_new_array();
284 for (int i = 0; i < len; i++) {
285 json_object_array_add(array_ir,
286 json_object_new_uint64(array[i]));
287 }
288 return array_ir;
289 }
290
291 //Converts a single UINT16 revision number into JSON IR representation.
revision_to_ir(UINT16 revision)292 json_object *revision_to_ir(UINT16 revision)
293 {
294 json_object *revision_info = json_object_new_object();
295 add_int(revision_info, "major", revision >> 8);
296 add_int(revision_info, "minor", revision & 0xFF);
297 return revision_info;
298 }
299
300 //Returns the appropriate string for the given integer severity.
severity_to_string(UINT32 severity)301 const char *severity_to_string(UINT32 severity)
302 {
303 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown";
304 }
305
306 //Converts a single EFI timestamp to string, at the given output.
307 //Output must be at least TIMESTAMP_LENGTH bytes long.
timestamp_to_string(char * out,int out_len,EFI_ERROR_TIME_STAMP * timestamp)308 int timestamp_to_string(char *out, int out_len, EFI_ERROR_TIME_STAMP *timestamp)
309 {
310 //Cannot go to three digits.
311 int century = bcd_to_int(timestamp->Century) % 100;
312 if (century >= 100) {
313 return -1;
314 }
315 int year = bcd_to_int(timestamp->Year) % 100;
316 if (year >= 100) {
317 return -1;
318 }
319 int month = bcd_to_int(timestamp->Month);
320 if (month > 12) {
321 return -1;
322 }
323 int day = bcd_to_int(timestamp->Day);
324 if (day > 31) {
325 return -1;
326 }
327 int hours = bcd_to_int(timestamp->Hours);
328 if (hours > 24) {
329 return -1;
330 }
331 int minutes = bcd_to_int(timestamp->Minutes);
332 if (minutes > 60) {
333 return -1;
334 }
335 int seconds = bcd_to_int(timestamp->Seconds);
336 if (seconds >= 60) {
337 return -1;
338 }
339 int written = snprintf(
340 out, out_len,
341 "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu+00:00",
342 century, year, month, day, hours, minutes, seconds);
343
344 if (written < 0 || written >= out_len) {
345 cper_print_log("Timestamp buffer of insufficient size\n");
346 return -1;
347 }
348 return 0;
349 }
350
351 //Converts a single timestamp string to an EFI timestamp.
string_to_timestamp(EFI_ERROR_TIME_STAMP * out,const char * timestamp)352 void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp)
353 {
354 //Ignore invalid timestamps.
355 if (timestamp == NULL) {
356 return;
357 }
358
359 sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu+00:00",
360 &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours,
361 &out->Minutes, &out->Seconds);
362
363 //Convert back to BCD.
364 out->Century = int_to_bcd(out->Century);
365 out->Year = int_to_bcd(out->Year);
366 out->Month = int_to_bcd(out->Month);
367 out->Day = int_to_bcd(out->Day);
368 out->Hours = int_to_bcd(out->Hours);
369 out->Minutes = int_to_bcd(out->Minutes);
370 out->Seconds = int_to_bcd(out->Seconds);
371 }
372
373 //Helper function to convert an EDK EFI GUID into a string for intermediate use.
guid_to_string(char * out,size_t out_len,EFI_GUID * guid)374 int guid_to_string(char *out, size_t out_len, EFI_GUID *guid)
375 {
376 size_t len = snprintf(
377 out, out_len,
378 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->Data1,
379 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
380 guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5],
381 guid->Data4[6], guid->Data4[7]);
382 if (len != out_len) {
383 return -1;
384 }
385 return len;
386 }
387
388 //Helper function to convert a string into an EDK EFI GUID.
string_to_guid(EFI_GUID * out,const char * guid)389 void string_to_guid(EFI_GUID *out, const char *guid)
390 {
391 //Ignore invalid GUIDs.
392 if (guid == NULL) {
393 return;
394 }
395
396 sscanf(guid,
397 "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
398 &out->Data1, &out->Data2, &out->Data3, out->Data4,
399 out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4,
400 out->Data4 + 5, out->Data4 + 6, out->Data4 + 7);
401 }
402
403 //Returns one if two EFI GUIDs are equal, zero otherwise.
guid_equal(const EFI_GUID * a,const EFI_GUID * b)404 int guid_equal(const EFI_GUID *a, const EFI_GUID *b)
405 {
406 //Check top base 3 components.
407 if (a->Data1 != b->Data1 || a->Data2 != b->Data2 ||
408 a->Data3 != b->Data3) {
409 return 0;
410 }
411
412 //Check Data4 array for equality.
413 for (int i = 0; i < 8; i++) {
414 if (a->Data4[i] != b->Data4[i]) {
415 return 0;
416 }
417 }
418
419 return 1;
420 }
421
select_guid_from_list(EFI_GUID * guid,EFI_GUID * guid_list[],int len)422 int select_guid_from_list(EFI_GUID *guid, EFI_GUID *guid_list[], int len)
423 {
424 int i = 0;
425 for (; i < len; i++) {
426 if (guid_equal(guid, guid_list[i])) {
427 break;
428 }
429 }
430 // It's unlikely fuzzing can reliably come up with a correct guid, given how
431 // much entropy there is. If we're in fuzzing mode, and if we haven't found
432 // a match, try to force a match so we get some coverage. Note, we still
433 // want coverage of the section failed to convert code, so treat index ==
434 // size as section failed to convert.
435 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
436 if (i == len) {
437 i = guid->Data1 % (len + 1);
438 }
439 #endif
440
441 return i;
442 }
443
cper_printable_string_length(const char * str,int number_chars)444 int cper_printable_string_length(const char *str, int number_chars)
445 {
446 if (str == NULL) {
447 return -1; // Return 0 for a null pointer input
448 }
449
450 int fru_text_len = 0;
451 for (; fru_text_len < number_chars; fru_text_len++) {
452 char c = str[fru_text_len];
453 if (c == '\0') {
454 break;
455 }
456 if (!isprint(c)) {
457 fru_text_len = -1;
458 break;
459 }
460 }
461
462 if (fru_text_len == 0 || fru_text_len == number_chars) {
463 // string was not null terminated
464 return -1;
465 }
466
467 return fru_text_len;
468 }
469
hex_string_to_bytes(const char * hex_string,size_t hex_string_len,UINT8 * bytes,size_t bytes_len)470 size_t hex_string_to_bytes(const char *hex_string, size_t hex_string_len,
471 UINT8 *bytes, size_t bytes_len)
472 {
473 if (hex_string == NULL || bytes == NULL) {
474 return -1;
475 }
476
477 size_t index = 0;
478 UINT8 value = 0;
479 while (index < hex_string_len) {
480 char c = hex_string[index];
481 if (c >= '0' && c <= '9') {
482 value += (c - '0');
483 } else if (c >= 'A' && c <= 'F') {
484 value += (10 + (c - 'A'));
485 } else if (c >= 'a' && c <= 'f') {
486 value += (10 + (c - 'a'));
487 } else {
488 return -1;
489 }
490 if (index % 2 == 1) {
491 bytes[index / 2] = value;
492 value = 0;
493 } else {
494 value <<= 4;
495 }
496
497 index++;
498 }
499
500 // Failed to write all bytes
501 if (index != bytes_len * 2) {
502 return -1;
503 }
504
505 return bytes_len;
506 }
507
add_untrusted_string(json_object * ir,const char * field_name,const char * str,int len)508 void add_untrusted_string(json_object *ir, const char *field_name,
509 const char *str, int len)
510 {
511 int fru_text_len = cper_printable_string_length(str, len);
512 if (fru_text_len >= 0) {
513 add_string_len(ir, field_name, str, fru_text_len);
514 }
515 }
516
add_guid(json_object * ir,const char * field_name,EFI_GUID * guid)517 void add_guid(json_object *ir, const char *field_name, EFI_GUID *guid)
518 {
519 char platform_string[GUID_STRING_LENGTH + 1];
520 if (!guid_to_string(platform_string, sizeof(platform_string), guid)) {
521 return;
522 }
523 add_string_len(ir, field_name, platform_string,
524 sizeof(platform_string) - 1);
525 }
add_string(json_object * register_ir,const char * field_name,const char * value)526 void add_string(json_object *register_ir, const char *field_name,
527 const char *value)
528 {
529 json_object_object_add(register_ir, field_name,
530 json_object_new_string(value));
531 }
532
add_string_len(json_object * register_ir,const char * field_name,const char * value,int len)533 void add_string_len(json_object *register_ir, const char *field_name,
534 const char *value, int len)
535 {
536 json_object_object_add(register_ir, field_name,
537 json_object_new_string_len(value, len));
538 }
539
free_char_ptr(char ** char_ptr)540 void free_char_ptr(char **char_ptr)
541 {
542 free(*char_ptr);
543 }
544
add_binary_base64(json_object * register_ir,const char * field_name,const UINT8 * value,int32_t len)545 void add_binary_base64(json_object *register_ir, const char *field_name,
546 const UINT8 *value, int32_t len)
547 {
548 if (value == NULL || len <= 0) {
549 return;
550 }
551 int32_t encoded_len = 0;
552 char *encoded __attribute__((cleanup(free_char_ptr))) =
553 base64_encode(value, len, &encoded_len);
554 if (encoded == NULL) {
555 return;
556 }
557 add_string_len(register_ir, field_name, encoded, encoded_len);
558 }
559
add_uint(json_object * register_ir,const char * field_name,uint64_t value)560 void add_uint(json_object *register_ir, const char *field_name, uint64_t value)
561 {
562 json_object_object_add(register_ir, field_name,
563 json_object_new_uint64(value));
564 }
565
add_int(json_object * register_ir,const char * field_name,int64_t value)566 void add_int(json_object *register_ir, const char *field_name, int64_t value)
567 {
568 json_object_object_add(register_ir, field_name,
569 json_object_new_int(value));
570 }
571
add_int_hex_common(json_object * register_ir,const char * field_name,UINT64 value,int len)572 static void add_int_hex_common(json_object *register_ir, const char *field_name,
573 UINT64 value, int len)
574 {
575 char hexstring_buf[EFI_UINT64_HEX_STRING_LEN];
576 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%0*llX", len,
577 value);
578 add_string(register_ir, field_name, hexstring_buf);
579 }
580
add_int_hex_8(json_object * register_ir,const char * field_name,UINT8 value)581 void add_int_hex_8(json_object *register_ir, const char *field_name,
582 UINT8 value)
583 {
584 add_int_hex_common(register_ir, field_name, value, 2);
585 }
586
add_int_hex_16(json_object * register_ir,const char * field_name,UINT16 value)587 void add_int_hex_16(json_object *register_ir, const char *field_name,
588 UINT16 value)
589 {
590 add_int_hex_common(register_ir, field_name, value, 4);
591 }
592
add_int_hex_24(json_object * register_ir,const char * field_name,UINT64 value)593 void add_int_hex_24(json_object *register_ir, const char *field_name,
594 UINT64 value)
595 {
596 add_int_hex_common(register_ir, field_name, value, 6);
597 }
598
add_int_hex_32(json_object * register_ir,const char * field_name,UINT64 value)599 void add_int_hex_32(json_object *register_ir, const char *field_name,
600 UINT64 value)
601 {
602 add_int_hex_common(register_ir, field_name, value, 8);
603 }
604
605 // TODO, deduplicate with get_value_hex_64/32
get_value_hex_8(json_object * obj,const char * field_name,UINT8 * value_out)606 void get_value_hex_8(json_object *obj, const char *field_name, UINT8 *value_out)
607 {
608 json_object *value = json_object_object_get(obj, field_name);
609 if (!value) {
610 return;
611 }
612 const char *hex_string = json_object_get_string(value);
613 if (!hex_string) {
614 return;
615 }
616 UINT8 byte;
617 size_t hex_string_len = strlen(hex_string);
618 if (hex_string_len != 4) {
619 return;
620 }
621 if (hex_string[0] != '0' || hex_string[1] != 'x') {
622 return;
623 }
624
625 if (hex_string_to_bytes(hex_string + 2, hex_string_len - 2, &byte, 1) !=
626 1) {
627 return;
628 }
629 *value_out = byte;
630 }
631
632 // TODO, deduplicate with get_value_hex_64
get_value_hex_32(json_object * obj,const char * field_name,UINT32 * value_out)633 void get_value_hex_32(json_object *obj, const char *field_name,
634 UINT32 *value_out)
635 {
636 json_object *value = json_object_object_get(obj, field_name);
637 if (!value) {
638 return;
639 }
640 const char *hex_string = json_object_get_string(value);
641 if (!hex_string) {
642 return;
643 }
644 UINT8 bytes[4];
645 size_t hex_string_len = strlen(hex_string);
646 if (hex_string_len != 10) {
647 return;
648 }
649 if (hex_string[0] != '0' || hex_string[1] != 'x') {
650 return;
651 }
652
653 if (hex_string_to_bytes(hex_string + 2, hex_string_len - 2, bytes,
654 sizeof(bytes)) != 4) {
655 return;
656 }
657 *value_out = (UINT32)bytes[0] << 24 | (UINT32)bytes[1] << 16 |
658 (UINT32)bytes[2] << 8 | (UINT32)bytes[3];
659 }
660
get_value_hex_64(json_object * obj,const char * field_name,UINT64 * value_out)661 void get_value_hex_64(json_object *obj, const char *field_name,
662 UINT64 *value_out)
663 {
664 json_object *value = json_object_object_get(obj, field_name);
665 if (!value) {
666 return;
667 }
668 const char *hex_string = json_object_get_string(value);
669 if (!hex_string) {
670 return;
671 }
672 UINT8 bytes[8];
673 size_t hex_string_len = strlen(hex_string);
674 if (hex_string_len != 18) {
675 return;
676 }
677 if (hex_string[0] != '0' || hex_string[1] != 'x') {
678 return;
679 }
680
681 if (hex_string_to_bytes(hex_string + 2, hex_string_len - 2, bytes,
682 sizeof(bytes)) != 8) {
683 return;
684 }
685 *value_out = (UINT64)bytes[0] << 56 | (UINT64)bytes[1] << 48 |
686 (UINT64)bytes[2] << 40 | (UINT64)bytes[3] << 32 |
687 (UINT64)bytes[4] << 24 | (UINT64)bytes[5] << 16 |
688 (UINT64)bytes[6] << 8 | (UINT64)bytes[7];
689 }
690
add_int_hex_64(json_object * register_ir,const char * field_name,UINT64 value)691 void add_int_hex_64(json_object *register_ir, const char *field_name,
692 UINT64 value)
693 {
694 add_int_hex_common(register_ir, field_name, value, 16);
695 }
696
add_bytes_hex(json_object * obj,const char * field_name,const UINT8 * bytes,size_t byte_len)697 void add_bytes_hex(json_object *obj, const char *field_name, const UINT8 *bytes,
698 size_t byte_len)
699 {
700 if (obj == NULL || bytes == NULL || byte_len == 0) {
701 return;
702 }
703
704 size_t hex_len = byte_len * 2;
705 char *hex_buf = (char *)malloc(hex_len + 1);
706 if (hex_buf == NULL) {
707 return;
708 }
709
710 for (size_t i = 0; i < byte_len; i++) {
711 snprintf(&hex_buf[i * 2], 3, "%02x", bytes[i]);
712 }
713 hex_buf[hex_len] = '\0';
714
715 json_object_object_add(obj, field_name,
716 json_object_new_string_len(hex_buf,
717 (int)hex_len));
718 free(hex_buf);
719 }
720
721 // Convert hex character to nibble value, returns -1 on invalid input
hex_char_to_nibble(char c)722 static int hex_char_to_nibble(char c)
723 {
724 if (c >= '0' && c <= '9') {
725 return c - '0';
726 }
727 if (c >= 'a' && c <= 'f') {
728 return c - 'a' + 10;
729 }
730 if (c >= 'A' && c <= 'F') {
731 return c - 'A' + 10;
732 }
733 return -1;
734 }
735
736 // Returns malloc'd buffer (caller must free), or NULL on error
get_bytes_hex(json_object * obj,const char * field_name,size_t * out_len)737 UINT8 *get_bytes_hex(json_object *obj, const char *field_name, size_t *out_len)
738 {
739 if (obj == NULL || out_len == NULL) {
740 return NULL;
741 }
742
743 json_object *field = json_object_object_get(obj, field_name);
744 if (field == NULL || !json_object_is_type(field, json_type_string)) {
745 return NULL;
746 }
747
748 const char *hex_str = json_object_get_string(field);
749 if (hex_str == NULL) {
750 return NULL;
751 }
752 size_t hex_len = (size_t)json_object_get_string_len(field);
753
754 // Must have even number of hex characters
755 if (hex_len % 2 != 0) {
756 return NULL;
757 }
758
759 size_t byte_len = hex_len / 2;
760 UINT8 *bytes = (UINT8 *)malloc(byte_len);
761 if (bytes == NULL) {
762 return NULL;
763 }
764
765 for (size_t i = 0; i < byte_len; i++) {
766 int high = hex_char_to_nibble(hex_str[i * 2]);
767 int low = hex_char_to_nibble(hex_str[i * 2 + 1]);
768 if (high < 0 || low < 0) {
769 free(bytes);
770 return NULL;
771 }
772 bytes[i] = (UINT8)((high << 4) | low);
773 }
774
775 *out_len = byte_len;
776 return bytes;
777 }
778
add_bool(json_object * register_ir,const char * field_name,UINT64 value)779 void add_bool(json_object *register_ir, const char *field_name, UINT64 value)
780 {
781 json_object_object_add(register_ir, field_name,
782 json_object_new_boolean(value));
783 }
784
add_bool_enum(json_object * register_ir,const char * field_name,const char * value_dict[2],UINT64 value_int)785 void add_bool_enum(json_object *register_ir, const char *field_name,
786 const char *value_dict[2], UINT64 value_int)
787 {
788 const char *value = value_dict[0];
789 if (value_int > 0) {
790 value = value_dict[1];
791 }
792 add_string(register_ir, field_name, value);
793 }
794
add_dict(json_object * register_ir,const char * field_name,UINT64 value,const char * dict[],size_t dict_size)795 void add_dict(json_object *register_ir, const char *field_name, UINT64 value,
796 const char *dict[], size_t dict_size)
797 {
798 json_object *field_ir = json_object_new_object();
799 json_object_object_add(register_ir, field_name, field_ir);
800 add_uint(field_ir, "raw", value);
801
802 if (dict != NULL) {
803 if (value < dict_size) {
804 const char *name = dict[value];
805 if (name != NULL) {
806 const char *value_name = name;
807
808 add_string(field_ir, "value", value_name);
809 }
810 }
811 }
812 }
813