11b0b00e3SLawrence Tang /** 22800cd8eSLawrence Tang * Describes high level functions for converting an entire CPER log, and functions for parsing 32800cd8eSLawrence Tang * CPER headers and section descriptions into an intermediate JSON format. 41b0b00e3SLawrence Tang * 51b0b00e3SLawrence Tang * Author: Lawrence.Tang@arm.com 61b0b00e3SLawrence Tang **/ 71b0b00e3SLawrence Tang 81b0b00e3SLawrence Tang #include <stdio.h> 95202bbb4SLawrence Tang #include <json.h> 10d7e8ca34SLawrence Tang #include "b64.h" 111b0b00e3SLawrence Tang #include "edk/Cper.h" 121b0b00e3SLawrence Tang #include "cper-parse.h" 131b0b00e3SLawrence Tang #include "cper-utils.h" 14*580423feSLawrence Tang #include "sections/cper-section.h" 151b0b00e3SLawrence Tang 161b0b00e3SLawrence Tang //Private pre-definitions. 171b0b00e3SLawrence Tang json_object *cper_header_to_ir(EFI_COMMON_ERROR_RECORD_HEADER *header); 18e407b4c8SLawrence Tang json_object * 19e407b4c8SLawrence Tang cper_section_descriptor_to_ir(EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor); 20e407b4c8SLawrence Tang json_object *cper_section_to_ir(FILE *handle, 21e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor); 221b0b00e3SLawrence Tang 231b0b00e3SLawrence Tang //Reads a CPER log file at the given file location, and returns an intermediate 241b0b00e3SLawrence Tang //JSON representation of this CPER record. 25f0f95574SLawrence Tang json_object *cper_to_ir(FILE *cper_file) 261b0b00e3SLawrence Tang { 271b0b00e3SLawrence Tang //Ensure this is really a CPER log. 281b0b00e3SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER header; 291b0b00e3SLawrence Tang fseek(cper_file, 0, SEEK_SET); 30e407b4c8SLawrence Tang if (fread(&header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, 31e407b4c8SLawrence Tang cper_file) != 1) { 3202c801a5SLawrence Tang printf("Invalid CPER file: Invalid length (log too short).\n"); 331b0b00e3SLawrence Tang return NULL; 341b0b00e3SLawrence Tang } 351b0b00e3SLawrence Tang 361b0b00e3SLawrence Tang //Check if the header contains the magic bytes ("CPER"). 371b0b00e3SLawrence Tang if (header.SignatureStart != EFI_ERROR_RECORD_SIGNATURE_START) { 3802c801a5SLawrence Tang printf("Invalid CPER file: Invalid header (incorrect signature).\n"); 391b0b00e3SLawrence Tang return NULL; 401b0b00e3SLawrence Tang } 411b0b00e3SLawrence Tang 421b0b00e3SLawrence Tang //Create the header JSON object from the read bytes. 431b0b00e3SLawrence Tang json_object *header_ir = cper_header_to_ir(&header); 441b0b00e3SLawrence Tang 451b0b00e3SLawrence Tang //Read the appropriate number of section descriptors & sections, and convert them into IR format. 461b0b00e3SLawrence Tang json_object *section_descriptors_ir = json_object_new_array(); 471b0b00e3SLawrence Tang json_object *sections_ir = json_object_new_array(); 48e407b4c8SLawrence Tang for (int i = 0; i < header.SectionCount; i++) { 491b0b00e3SLawrence Tang //Create the section descriptor. 501b0b00e3SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR section_descriptor; 51e407b4c8SLawrence Tang if (fread(§ion_descriptor, 52e407b4c8SLawrence Tang sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 53e407b4c8SLawrence Tang cper_file) != 1) { 54e407b4c8SLawrence Tang printf("Invalid number of section headers: Header states %d sections, could not read section %d.\n", 55e407b4c8SLawrence Tang header.SectionCount, i + 1); 561b0b00e3SLawrence Tang return NULL; 571b0b00e3SLawrence Tang } 58e407b4c8SLawrence Tang json_object_array_add( 59e407b4c8SLawrence Tang section_descriptors_ir, 60e407b4c8SLawrence Tang cper_section_descriptor_to_ir(§ion_descriptor)); 611b0b00e3SLawrence Tang 621b0b00e3SLawrence Tang //Read the section itself. 63e407b4c8SLawrence Tang json_object_array_add(sections_ir, 64e407b4c8SLawrence Tang cper_section_to_ir(cper_file, 65e407b4c8SLawrence Tang §ion_descriptor)); 661b0b00e3SLawrence Tang } 671b0b00e3SLawrence Tang 681b0b00e3SLawrence Tang //Add the header, section descriptors, and sections to a parent object. 691b0b00e3SLawrence Tang json_object *parent = json_object_new_object(); 701b0b00e3SLawrence Tang json_object_object_add(parent, "header", header_ir); 71e407b4c8SLawrence Tang json_object_object_add(parent, "sectionDescriptors", 72e407b4c8SLawrence Tang section_descriptors_ir); 732800cd8eSLawrence Tang json_object_object_add(parent, "sections", sections_ir); 741b0b00e3SLawrence Tang 751b0b00e3SLawrence Tang return parent; 761b0b00e3SLawrence Tang } 771b0b00e3SLawrence Tang 781b0b00e3SLawrence Tang //Converts a parsed CPER record header into intermediate JSON object format. 791b0b00e3SLawrence Tang json_object *cper_header_to_ir(EFI_COMMON_ERROR_RECORD_HEADER *header) 801b0b00e3SLawrence Tang { 811b0b00e3SLawrence Tang json_object *header_ir = json_object_new_object(); 821b0b00e3SLawrence Tang 831b0b00e3SLawrence Tang //Revision/version information. 84e407b4c8SLawrence Tang json_object_object_add(header_ir, "revision", 85e407b4c8SLawrence Tang revision_to_ir(header->Revision)); 861b0b00e3SLawrence Tang 871b0b00e3SLawrence Tang //Section count. 88e407b4c8SLawrence Tang json_object_object_add(header_ir, "sectionCount", 89e407b4c8SLawrence Tang json_object_new_int(header->SectionCount)); 901b0b00e3SLawrence Tang 911b0b00e3SLawrence Tang //Error severity (with interpreted string version). 921b0b00e3SLawrence Tang json_object *error_severity = json_object_new_object(); 93e407b4c8SLawrence Tang json_object_object_add(error_severity, "code", 94e407b4c8SLawrence Tang json_object_new_uint64(header->ErrorSeverity)); 95e407b4c8SLawrence Tang json_object_object_add(error_severity, "name", 96e407b4c8SLawrence Tang json_object_new_string(severity_to_string( 97e407b4c8SLawrence Tang header->ErrorSeverity))); 981b0b00e3SLawrence Tang json_object_object_add(header_ir, "severity", error_severity); 991b0b00e3SLawrence Tang 1001b0b00e3SLawrence Tang //The validation bits for each section. 101e407b4c8SLawrence Tang json_object *validation_bits = bitfield_to_ir( 102e407b4c8SLawrence Tang header->ValidationBits, 3, CPER_HEADER_VALID_BITFIELD_NAMES); 1031b0b00e3SLawrence Tang json_object_object_add(header_ir, "validationBits", validation_bits); 1041b0b00e3SLawrence Tang 1051b0b00e3SLawrence Tang //Total length of the record (including headers) in bytes. 106e407b4c8SLawrence Tang json_object_object_add(header_ir, "recordLength", 107e407b4c8SLawrence Tang json_object_new_uint64(header->RecordLength)); 1081b0b00e3SLawrence Tang 1091b0b00e3SLawrence Tang //If a timestamp exists according to validation bits, then add it. 110e407b4c8SLawrence Tang if (header->ValidationBits & 0b10) { 1111b0b00e3SLawrence Tang char timestamp_string[TIMESTAMP_LENGTH]; 112aacf0e26SLawrence Tang timestamp_to_string(timestamp_string, &header->TimeStamp); 1131b0b00e3SLawrence Tang 114e407b4c8SLawrence Tang json_object_object_add( 115e407b4c8SLawrence Tang header_ir, "timestamp", 116e407b4c8SLawrence Tang json_object_new_string(timestamp_string)); 117e407b4c8SLawrence Tang json_object_object_add( 118e407b4c8SLawrence Tang header_ir, "timestampIsPrecise", 119e407b4c8SLawrence Tang json_object_new_boolean(header->TimeStamp.Flag)); 1201b0b00e3SLawrence Tang } 1211b0b00e3SLawrence Tang 1221b0b00e3SLawrence Tang //If a platform ID exists according to the validation bits, then add it. 123e407b4c8SLawrence Tang if (header->ValidationBits & 0b1) { 1241b0b00e3SLawrence Tang char platform_string[GUID_STRING_LENGTH]; 1251b0b00e3SLawrence Tang guid_to_string(platform_string, &header->PlatformID); 126e407b4c8SLawrence Tang json_object_object_add(header_ir, "platformID", 127e407b4c8SLawrence Tang json_object_new_string(platform_string)); 1281b0b00e3SLawrence Tang } 1291b0b00e3SLawrence Tang 1301b0b00e3SLawrence Tang //If a partition ID exists according to the validation bits, then add it. 131e407b4c8SLawrence Tang if (header->ValidationBits & 0b100) { 1321b0b00e3SLawrence Tang char partition_string[GUID_STRING_LENGTH]; 1331b0b00e3SLawrence Tang guid_to_string(partition_string, &header->PartitionID); 134e407b4c8SLawrence Tang json_object_object_add( 135e407b4c8SLawrence Tang header_ir, "partitionID", 136e407b4c8SLawrence Tang json_object_new_string(partition_string)); 1371b0b00e3SLawrence Tang } 1381b0b00e3SLawrence Tang 1391b0b00e3SLawrence Tang //Creator ID of the header. 1401b0b00e3SLawrence Tang char creator_string[GUID_STRING_LENGTH]; 1411b0b00e3SLawrence Tang guid_to_string(creator_string, &header->CreatorID); 142e407b4c8SLawrence Tang json_object_object_add(header_ir, "creatorID", 143e407b4c8SLawrence Tang json_object_new_string(creator_string)); 1441b0b00e3SLawrence Tang 1451b0b00e3SLawrence Tang //Notification type for the header. Some defined types are available. 1461b0b00e3SLawrence Tang json_object *notification_type = json_object_new_object(); 1471b0b00e3SLawrence Tang char notification_type_string[GUID_STRING_LENGTH]; 1481b0b00e3SLawrence Tang guid_to_string(notification_type_string, &header->NotificationType); 149e407b4c8SLawrence Tang json_object_object_add( 150e407b4c8SLawrence Tang notification_type, "guid", 151e407b4c8SLawrence Tang json_object_new_string(notification_type_string)); 1521b0b00e3SLawrence Tang 1531b0b00e3SLawrence Tang //Add the human readable notification type if possible. 1541b0b00e3SLawrence Tang char *notification_type_readable = "Unknown"; 155e407b4c8SLawrence Tang if (guid_equal(&header->NotificationType, 156e407b4c8SLawrence Tang &gEfiEventNotificationTypeCmcGuid)) 1571b0b00e3SLawrence Tang notification_type_readable = "CMC"; 158e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 159e407b4c8SLawrence Tang &gEfiEventNotificationTypeCpeGuid)) 1601b0b00e3SLawrence Tang notification_type_readable = "CPE"; 161e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 162e407b4c8SLawrence Tang &gEfiEventNotificationTypeMceGuid)) 1631b0b00e3SLawrence Tang notification_type_readable = "MCE"; 164e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 165e407b4c8SLawrence Tang &gEfiEventNotificationTypePcieGuid)) 1661b0b00e3SLawrence Tang notification_type_readable = "PCIe"; 167e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 168e407b4c8SLawrence Tang &gEfiEventNotificationTypeInitGuid)) 1691b0b00e3SLawrence Tang notification_type_readable = "INIT"; 170e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 171e407b4c8SLawrence Tang &gEfiEventNotificationTypeNmiGuid)) 1721b0b00e3SLawrence Tang notification_type_readable = "NMI"; 173e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 174e407b4c8SLawrence Tang &gEfiEventNotificationTypeBootGuid)) 1751b0b00e3SLawrence Tang notification_type_readable = "Boot"; 176e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 177e407b4c8SLawrence Tang &gEfiEventNotificationTypeDmarGuid)) 1781b0b00e3SLawrence Tang notification_type_readable = "DMAr"; 179e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 180e407b4c8SLawrence Tang &gEfiEventNotificationTypeSeaGuid)) 1811b0b00e3SLawrence Tang notification_type_readable = "SEA"; 182e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 183e407b4c8SLawrence Tang &gEfiEventNotificationTypeSeiGuid)) 1841b0b00e3SLawrence Tang notification_type_readable = "SEI"; 185e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 186e407b4c8SLawrence Tang &gEfiEventNotificationTypePeiGuid)) 1871b0b00e3SLawrence Tang notification_type_readable = "PEI"; 188e407b4c8SLawrence Tang else if (guid_equal(&header->NotificationType, 189e407b4c8SLawrence Tang &gEfiEventNotificationTypeCxlGuid)) 1901b0b00e3SLawrence Tang notification_type_readable = "CXL Component"; 191e407b4c8SLawrence Tang json_object_object_add( 192e407b4c8SLawrence Tang notification_type, "type", 193e407b4c8SLawrence Tang json_object_new_string(notification_type_readable)); 194e407b4c8SLawrence Tang json_object_object_add(header_ir, "notificationType", 195e407b4c8SLawrence Tang notification_type); 1961b0b00e3SLawrence Tang 1971b0b00e3SLawrence Tang //The record ID for this record, unique on a given system. 198e407b4c8SLawrence Tang json_object_object_add(header_ir, "recordID", 199e407b4c8SLawrence Tang json_object_new_uint64(header->RecordID)); 2001b0b00e3SLawrence Tang 2011b0b00e3SLawrence Tang //Flag for the record, and a human readable form. 202e407b4c8SLawrence Tang json_object *flags = integer_to_readable_pair( 203e407b4c8SLawrence Tang header->Flags, 2043c43f743SLawrence Tang sizeof(CPER_HEADER_FLAG_TYPES_KEYS) / sizeof(int), 205e407b4c8SLawrence Tang CPER_HEADER_FLAG_TYPES_KEYS, CPER_HEADER_FLAG_TYPES_VALUES, 2063c43f743SLawrence Tang "Unknown"); 2071b0b00e3SLawrence Tang json_object_object_add(header_ir, "flags", flags); 2081b0b00e3SLawrence Tang 2091b0b00e3SLawrence Tang //Persistence information. Outside the scope of specification, so just a uint32 here. 210e407b4c8SLawrence Tang json_object_object_add(header_ir, "persistenceInfo", 211e407b4c8SLawrence Tang json_object_new_uint64(header->PersistenceInfo)); 2121b0b00e3SLawrence Tang return header_ir; 2131b0b00e3SLawrence Tang } 2141b0b00e3SLawrence Tang 2151b0b00e3SLawrence Tang //Converts the given EFI section descriptor into JSON IR format. 216e407b4c8SLawrence Tang json_object * 217e407b4c8SLawrence Tang cper_section_descriptor_to_ir(EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor) 2181b0b00e3SLawrence Tang { 2191b0b00e3SLawrence Tang json_object *section_descriptor_ir = json_object_new_object(); 2201b0b00e3SLawrence Tang 2211b0b00e3SLawrence Tang //The offset of the section from the base of the record header, length. 222e407b4c8SLawrence Tang json_object_object_add( 223e407b4c8SLawrence Tang section_descriptor_ir, "sectionOffset", 224e407b4c8SLawrence Tang json_object_new_uint64(section_descriptor->SectionOffset)); 225e407b4c8SLawrence Tang json_object_object_add( 226e407b4c8SLawrence Tang section_descriptor_ir, "sectionLength", 227e407b4c8SLawrence Tang json_object_new_uint64(section_descriptor->SectionLength)); 2281b0b00e3SLawrence Tang 2291b0b00e3SLawrence Tang //Revision. 230e407b4c8SLawrence Tang json_object_object_add(section_descriptor_ir, "revision", 231e407b4c8SLawrence Tang revision_to_ir(section_descriptor->Revision)); 2321b0b00e3SLawrence Tang 2331b0b00e3SLawrence Tang //Validation bits. 234e407b4c8SLawrence Tang json_object *validation_bits = 235e407b4c8SLawrence Tang bitfield_to_ir(section_descriptor->SecValidMask, 2, 236e407b4c8SLawrence Tang CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 237e407b4c8SLawrence Tang json_object_object_add(section_descriptor_ir, "validationBits", 238e407b4c8SLawrence Tang validation_bits); 2391b0b00e3SLawrence Tang 2401b0b00e3SLawrence Tang //Flag bits. 241e407b4c8SLawrence Tang json_object *flags = 242e407b4c8SLawrence Tang bitfield_to_ir(section_descriptor->SectionFlags, 8, 243e407b4c8SLawrence Tang CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 2441b0b00e3SLawrence Tang json_object_object_add(section_descriptor_ir, "flags", flags); 2451b0b00e3SLawrence Tang 2461b0b00e3SLawrence Tang //Section type (GUID). 2471b0b00e3SLawrence Tang json_object *section_type = json_object_new_object(); 2481b0b00e3SLawrence Tang char section_type_string[GUID_STRING_LENGTH]; 2491b0b00e3SLawrence Tang guid_to_string(section_type_string, §ion_descriptor->SectionType); 250e407b4c8SLawrence Tang json_object_object_add(section_type, "data", 251e407b4c8SLawrence Tang json_object_new_string(section_type_string)); 2521b0b00e3SLawrence Tang 2531b0b00e3SLawrence Tang //Readable section type, if possible. 254*580423feSLawrence Tang const char *section_type_readable = "Unknown"; 255*580423feSLawrence Tang for (int i=0; i<section_definitions_len; i++) 256*580423feSLawrence Tang { 257*580423feSLawrence Tang if (guid_equal(section_definitions[i].Guid, §ion_descriptor->SectionType)) { 258*580423feSLawrence Tang section_type_readable = section_definitions[i].ReadableName; 259*580423feSLawrence Tang break; 260*580423feSLawrence Tang } 261*580423feSLawrence Tang } 2621b0b00e3SLawrence Tang 263e407b4c8SLawrence Tang json_object_object_add(section_type, "type", 264e407b4c8SLawrence Tang json_object_new_string(section_type_readable)); 265e407b4c8SLawrence Tang json_object_object_add(section_descriptor_ir, "sectionType", 266e407b4c8SLawrence Tang section_type); 2671b0b00e3SLawrence Tang 2681b0b00e3SLawrence Tang //If validation bits indicate it exists, add FRU ID. 269e407b4c8SLawrence Tang if (section_descriptor->SecValidMask & 0b1) { 2701b0b00e3SLawrence Tang char fru_id_string[GUID_STRING_LENGTH]; 2711b0b00e3SLawrence Tang guid_to_string(fru_id_string, §ion_descriptor->FruId); 272e407b4c8SLawrence Tang json_object_object_add(section_descriptor_ir, "fruID", 273e407b4c8SLawrence Tang json_object_new_string(fru_id_string)); 2741b0b00e3SLawrence Tang } 2751b0b00e3SLawrence Tang 2761b0b00e3SLawrence Tang //If validation bits indicate it exists, add FRU text. 2771b0b00e3SLawrence Tang if ((section_descriptor->SecValidMask & 0b10) >> 1) 278e407b4c8SLawrence Tang json_object_object_add( 279e407b4c8SLawrence Tang section_descriptor_ir, "fruText", 280e407b4c8SLawrence Tang json_object_new_string(section_descriptor->FruString)); 2811b0b00e3SLawrence Tang 2821b0b00e3SLawrence Tang //Section severity. 2831b0b00e3SLawrence Tang json_object *section_severity = json_object_new_object(); 284e407b4c8SLawrence Tang json_object_object_add( 285e407b4c8SLawrence Tang section_severity, "code", 286e407b4c8SLawrence Tang json_object_new_uint64(section_descriptor->Severity)); 287e407b4c8SLawrence Tang json_object_object_add(section_severity, "name", 288e407b4c8SLawrence Tang json_object_new_string(severity_to_string( 289e407b4c8SLawrence Tang section_descriptor->Severity))); 290e407b4c8SLawrence Tang json_object_object_add(section_descriptor_ir, "severity", 291e407b4c8SLawrence Tang section_severity); 2921b0b00e3SLawrence Tang 2931b0b00e3SLawrence Tang return section_descriptor_ir; 2941b0b00e3SLawrence Tang } 2951b0b00e3SLawrence Tang 2961b0b00e3SLawrence Tang //Converts the section described by a single given section descriptor. 297e407b4c8SLawrence Tang json_object *cper_section_to_ir(FILE *handle, 298e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor) 2991b0b00e3SLawrence Tang { 300de9707f9SLawrence Tang //Save our current position in the stream. 301de9707f9SLawrence Tang long position = ftell(handle); 302de9707f9SLawrence Tang 3031b0b00e3SLawrence Tang //Read section as described by the section descriptor. 3041b0b00e3SLawrence Tang fseek(handle, descriptor->SectionOffset, SEEK_SET); 305e18aaee9SLawrence Tang void *section = malloc(descriptor->SectionLength); 306e407b4c8SLawrence Tang if (fread(section, descriptor->SectionLength, 1, handle) != 1) { 30702c801a5SLawrence Tang printf("Section read failed: Could not read %d bytes from global offset %d.\n", 308e407b4c8SLawrence Tang descriptor->SectionLength, descriptor->SectionOffset); 309e18aaee9SLawrence Tang free(section); 310e18aaee9SLawrence Tang return NULL; 3111b0b00e3SLawrence Tang } 3121b0b00e3SLawrence Tang 313de9707f9SLawrence Tang //Seek back to our original position. 314de9707f9SLawrence Tang fseek(handle, position, SEEK_SET); 315de9707f9SLawrence Tang 316db1b7ce2SLawrence Tang //Parse section to IR based on GUID. 3171b0b00e3SLawrence Tang json_object *result = NULL; 318*580423feSLawrence Tang int section_converted = 0; 319*580423feSLawrence Tang for (int i=0; i<section_definitions_len; i++) 320*580423feSLawrence Tang { 321*580423feSLawrence Tang if (guid_equal(section_definitions[i].Guid, &descriptor->SectionType) && section_definitions[i].ToIR != NULL) { 322*580423feSLawrence Tang result = section_definitions[i].ToIR(section, descriptor); 323*580423feSLawrence Tang section_converted = 1; 324*580423feSLawrence Tang break; 325*580423feSLawrence Tang } 326*580423feSLawrence Tang } 327*580423feSLawrence Tang 328*580423feSLawrence Tang //Was it an unknown GUID/failed read? 329*580423feSLawrence Tang if (!section_converted) { 330d7e8ca34SLawrence Tang //Output the data as formatted base64. 331d7e8ca34SLawrence Tang result = json_object_new_object(); 332e407b4c8SLawrence Tang char *encoded = b64_encode((unsigned char *)section, 333e407b4c8SLawrence Tang descriptor->SectionLength); 334e407b4c8SLawrence Tang json_object_object_add(result, "data", 335e407b4c8SLawrence Tang json_object_new_string(encoded)); 336d7e8ca34SLawrence Tang free(encoded); 337db1b7ce2SLawrence Tang } 3381b0b00e3SLawrence Tang 3391b0b00e3SLawrence Tang //Free section memory, return result. 3401b0b00e3SLawrence Tang free(section); 3411b0b00e3SLawrence Tang return result; 3421b0b00e3SLawrence Tang } 343617949e4SLawrence Tang 344617949e4SLawrence Tang //Converts a single CPER section, without a header but with a section descriptor, to JSON. 345617949e4SLawrence Tang json_object *cper_single_section_to_ir(FILE *cper_section_file) 346617949e4SLawrence Tang { 347617949e4SLawrence Tang json_object *ir = json_object_new_object(); 348617949e4SLawrence Tang 349617949e4SLawrence Tang //Read the section descriptor out. 350617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR section_descriptor; 351617949e4SLawrence Tang if (fread(§ion_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 352617949e4SLawrence Tang cper_section_file) != 1) { 353617949e4SLawrence Tang printf("Failed to read section descriptor for CPER single section (fread() returned an unexpected value).\n"); 354617949e4SLawrence Tang return NULL; 355617949e4SLawrence Tang } 356617949e4SLawrence Tang 357617949e4SLawrence Tang //Convert the section descriptor to IR. 358617949e4SLawrence Tang json_object *section_descriptor_ir = 359617949e4SLawrence Tang cper_section_descriptor_to_ir(§ion_descriptor); 360617949e4SLawrence Tang json_object_object_add(ir, "sectionDescriptor", section_descriptor_ir); 361617949e4SLawrence Tang 362617949e4SLawrence Tang //Parse the single section. 363617949e4SLawrence Tang json_object *section_ir = 364617949e4SLawrence Tang cper_section_to_ir(cper_section_file, §ion_descriptor); 365617949e4SLawrence Tang json_object_object_add(ir, "section", section_ir); 366617949e4SLawrence Tang 367617949e4SLawrence Tang return ir; 368617949e4SLawrence Tang }