blob: e7cde0d934cb94180fc5ba13f7f28d49cc49f8ea [file] [log] [blame]
Lawrence Tang1b0b00e2022-07-05 10:33:10 +01001/**
Ed Tanousfedd4572024-07-12 13:56:00 -07002 * Describes high level functions for converting an entire CPER log, and functions for parsing
Lawrence Tang2800cd82022-07-05 16:08:20 +01003 * CPER headers and section descriptions into an intermediate JSON format.
Ed Tanousfedd4572024-07-12 13:56:00 -07004 *
Lawrence Tang1b0b00e2022-07-05 10:33:10 +01005 * Author: Lawrence.Tang@arm.com
6 **/
7
Ed Tanous73498f62025-03-05 18:03:36 -08008#include <limits.h>
Lawrence Tang1b0b00e2022-07-05 10:33:10 +01009#include <stdio.h>
Karthik Rajagopalan5220c9b2024-08-08 00:24:44 -070010#include <string.h>
Lawrence Tang5202bbb2022-08-12 14:54:36 +010011#include <json.h>
Ed Tanous73498f62025-03-05 18:03:36 -080012
Thu Nguyene42fb482024-10-15 14:43:11 +000013#include <libcper/base64.h>
14#include <libcper/Cper.h>
15#include <libcper/cper-parse.h>
16#include <libcper/cper-parse-str.h>
17#include <libcper/cper-utils.h>
18#include <libcper/sections/cper-section.h>
Lawrence Tang1b0b00e2022-07-05 10:33:10 +010019
20//Private pre-definitions.
Lawrence Tange407b4c2022-07-21 13:54:01 +010021json_object *cper_header_to_ir(EFI_COMMON_ERROR_RECORD_HEADER *header);
22json_object *
23cper_section_descriptor_to_ir(EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +010024
Ed Tanous73498f62025-03-05 18:03:36 -080025json_object *cper_buf_section_to_ir(const void *cper_section_buf, size_t size,
26 EFI_ERROR_SECTION_DESCRIPTOR *descriptor);
27
28json_object *cper_buf_to_ir(const unsigned char *cper_buf, size_t size)
Ed Tanous8d47a372025-03-05 15:55:36 -080029{
Ed Tanous73498f62025-03-05 18:03:36 -080030 json_object *parent = NULL;
31 json_object *header_ir = NULL;
32 json_object *section_descriptors_ir = NULL;
33 json_object *sections_ir = NULL;
34
35 const unsigned char *pos = cper_buf;
36 unsigned int remaining = size;
37
38 if (remaining < sizeof(EFI_COMMON_ERROR_RECORD_HEADER)) {
39 printf("Invalid CPER file: Invalid header (incorrect signature).\n");
40 goto fail;
Ed Tanous8d47a372025-03-05 15:55:36 -080041 }
Ed Tanous73498f62025-03-05 18:03:36 -080042
43 EFI_COMMON_ERROR_RECORD_HEADER *header = NULL;
44 header = (EFI_COMMON_ERROR_RECORD_HEADER *)cper_buf;
45 pos += sizeof(EFI_COMMON_ERROR_RECORD_HEADER);
46 remaining -= sizeof(EFI_COMMON_ERROR_RECORD_HEADER);
47 if (header->SignatureStart != EFI_ERROR_RECORD_SIGNATURE_START) {
48 printf("Invalid CPER file: Invalid header (incorrect signature).\n");
49 goto fail;
50 }
51 if (header->SectionCount == 0) {
52 printf("Invalid CPER file: Invalid section count (0).\n");
53 goto fail;
54 }
55 if (remaining < sizeof(EFI_ERROR_SECTION_DESCRIPTOR)) {
56 printf("Invalid CPER file: Invalid section descriptor (section offset + length > size).\n");
57 goto fail;
58 }
59
60 //Create the header JSON object from the read bytes.
61 parent = json_object_new_object();
62 header_ir = cper_header_to_ir(header);
63
64 json_object_object_add(parent, "header", header_ir);
65
66 //Read the appropriate number of section descriptors & sections, and convert them into IR format.
67 section_descriptors_ir = json_object_new_array();
68 sections_ir = json_object_new_array();
69 for (int i = 0; i < header->SectionCount; i++) {
70 //Create the section descriptor.
71 if (remaining < sizeof(EFI_ERROR_SECTION_DESCRIPTOR)) {
72 printf("Invalid number of section headers: Header states %d sections, could not read section %d.\n",
73 header->SectionCount, i + 1);
74 goto fail;
75 }
76
77 EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor;
78 section_descriptor = (EFI_ERROR_SECTION_DESCRIPTOR *)(pos);
79 pos += sizeof(EFI_ERROR_SECTION_DESCRIPTOR);
80 remaining -= sizeof(EFI_ERROR_SECTION_DESCRIPTOR);
81
82 if (section_descriptor->SectionOffset > size) {
83 printf("Invalid section descriptor: Section offset > size.\n");
84 goto fail;
85 }
86
87 if (section_descriptor->SectionLength <= 0) {
88 printf("Invalid section descriptor: Section length <= 0.\n");
89 goto fail;
90 }
91
92 if (section_descriptor->SectionOffset >
93 UINT_MAX - section_descriptor->SectionLength) {
94 printf("Invalid section descriptor: Section offset + length would overflow.\n");
95 goto fail;
96 }
97
98 if (section_descriptor->SectionOffset +
99 section_descriptor->SectionLength >
100 size) {
101 printf("Invalid section descriptor: Section offset + length > size.\n");
102 goto fail;
103 }
104
105 const unsigned char *section_begin =
106 cper_buf + section_descriptor->SectionOffset;
107
108 json_object_array_add(
109 section_descriptors_ir,
110 cper_section_descriptor_to_ir(section_descriptor));
111
112 //Read the section itself.
113 json_object *section_ir = cper_buf_section_to_ir(
114 section_begin, section_descriptor->SectionLength,
115 section_descriptor);
116 json_object_array_add(sections_ir, section_ir);
117 }
118
119 //Add the header, section descriptors, and sections to a parent object.
120 json_object_object_add(parent, "sectionDescriptors",
121 section_descriptors_ir);
122 json_object_object_add(parent, "sections", sections_ir);
123
124 return parent;
125
126fail:
127 json_object_put(sections_ir);
128 json_object_put(section_descriptors_ir);
129 json_object_put(parent);
130 printf("Failed to parse CPER file.\n");
131 return NULL;
Ed Tanous8d47a372025-03-05 15:55:36 -0800132}
133
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100134//Reads a CPER log file at the given file location, and returns an intermediate
135//JSON representation of this CPER record.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100136json_object *cper_to_ir(FILE *cper_file)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100137{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100138 //Ensure this is really a CPER log.
139 EFI_COMMON_ERROR_RECORD_HEADER header;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100140 if (fread(&header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1,
141 cper_file) != 1) {
142 printf("Invalid CPER file: Invalid length (log too short).\n");
143 return NULL;
144 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100145
Lawrence Tange407b4c2022-07-21 13:54:01 +0100146 //Check if the header contains the magic bytes ("CPER").
147 if (header.SignatureStart != EFI_ERROR_RECORD_SIGNATURE_START) {
148 printf("Invalid CPER file: Invalid header (incorrect signature).\n");
149 return NULL;
150 }
Ed Tanous73498f62025-03-05 18:03:36 -0800151 fseek(cper_file, -sizeof(EFI_COMMON_ERROR_RECORD_HEADER), SEEK_CUR);
152 unsigned char *cper_buf = malloc(header.RecordLength);
153 if (fread(cper_buf, header.RecordLength, 1, cper_file) != 1) {
154 printf("File read failed\n");
155 free(cper_buf);
156 return NULL;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100157 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100158
Ed Tanous73498f62025-03-05 18:03:36 -0800159 json_object *ir = cper_buf_to_ir(cper_buf, header.RecordLength);
160 free(cper_buf);
161 return ir;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100162}
163
Karthik Rajagopalan5220c9b2024-08-08 00:24:44 -0700164char *cper_to_str_ir(FILE *cper_file)
165{
166 json_object *jobj = cper_to_ir(cper_file);
167 char *str = jobj ? strdup(json_object_to_json_string(jobj)) : NULL;
168
169 json_object_put(jobj);
170 return str;
171}
172
173char *cperbuf_to_str_ir(const unsigned char *cper, size_t size)
174{
175 FILE *cper_file = fmemopen((void *)cper, size, "r");
176
177 return cper_file ? cper_to_str_ir(cper_file) : NULL;
178}
179
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100180//Converts a parsed CPER record header into intermediate JSON object format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100181json_object *cper_header_to_ir(EFI_COMMON_ERROR_RECORD_HEADER *header)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100182{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100183 json_object *header_ir = json_object_new_object();
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100184
Lawrence Tange407b4c2022-07-21 13:54:01 +0100185 //Revision/version information.
186 json_object_object_add(header_ir, "revision",
187 revision_to_ir(header->Revision));
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100188
Lawrence Tange407b4c2022-07-21 13:54:01 +0100189 //Section count.
190 json_object_object_add(header_ir, "sectionCount",
191 json_object_new_int(header->SectionCount));
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100192
Lawrence Tange407b4c2022-07-21 13:54:01 +0100193 //Error severity (with interpreted string version).
194 json_object *error_severity = json_object_new_object();
195 json_object_object_add(error_severity, "code",
196 json_object_new_uint64(header->ErrorSeverity));
197 json_object_object_add(error_severity, "name",
198 json_object_new_string(severity_to_string(
199 header->ErrorSeverity)));
200 json_object_object_add(header_ir, "severity", error_severity);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100201
Lawrence Tange407b4c2022-07-21 13:54:01 +0100202 //Total length of the record (including headers) in bytes.
203 json_object_object_add(header_ir, "recordLength",
204 json_object_new_uint64(header->RecordLength));
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100205
Lawrence Tange407b4c2022-07-21 13:54:01 +0100206 //If a timestamp exists according to validation bits, then add it.
John Chungf8fc7052024-05-03 20:05:29 +0800207 if (header->ValidationBits & 0x2) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100208 char timestamp_string[TIMESTAMP_LENGTH];
Ed Tanous596c59e2025-03-10 13:15:58 -0700209 if (timestamp_to_string(timestamp_string, TIMESTAMP_LENGTH,
210 &header->TimeStamp) < 0) {
211 goto fail;
212 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100213 json_object_object_add(
214 header_ir, "timestamp",
215 json_object_new_string(timestamp_string));
Ed Tanous596c59e2025-03-10 13:15:58 -0700216
Lawrence Tange407b4c2022-07-21 13:54:01 +0100217 json_object_object_add(
218 header_ir, "timestampIsPrecise",
219 json_object_new_boolean(header->TimeStamp.Flag));
220 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100221
Lawrence Tange407b4c2022-07-21 13:54:01 +0100222 //If a platform ID exists according to the validation bits, then add it.
John Chungf8fc7052024-05-03 20:05:29 +0800223 if (header->ValidationBits & 0x1) {
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700224 add_guid(header_ir, "platformID", &header->PlatformID);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100225 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100226
Lawrence Tange407b4c2022-07-21 13:54:01 +0100227 //If a partition ID exists according to the validation bits, then add it.
John Chungf8fc7052024-05-03 20:05:29 +0800228 if (header->ValidationBits & 0x4) {
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700229 add_guid(header_ir, "partitionID", &header->PartitionID);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100230 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100231
Lawrence Tange407b4c2022-07-21 13:54:01 +0100232 //Creator ID of the header.
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700233 add_guid(header_ir, "creatorID", &header->CreatorID);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100234 //Notification type for the header. Some defined types are available.
235 json_object *notification_type = json_object_new_object();
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700236 add_guid(notification_type, "guid", &header->NotificationType);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100237
Lawrence Tange407b4c2022-07-21 13:54:01 +0100238 //Add the human readable notification type if possible.
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700239 const char *notification_type_readable = "Unknown";
Ed Tanous1a648562025-03-10 15:23:38 -0700240
241 EFI_GUID *guids[] = {
242 &gEfiEventNotificationTypeCmcGuid,
243 &gEfiEventNotificationTypeCpeGuid,
244 &gEfiEventNotificationTypeMceGuid,
245 &gEfiEventNotificationTypePcieGuid,
246 &gEfiEventNotificationTypeInitGuid,
247 &gEfiEventNotificationTypeNmiGuid,
248 &gEfiEventNotificationTypeBootGuid,
249 &gEfiEventNotificationTypeDmarGuid,
250 &gEfiEventNotificationTypeSeaGuid,
251 &gEfiEventNotificationTypeSeiGuid,
252 &gEfiEventNotificationTypePeiGuid,
253 &gEfiEventNotificationTypeCxlGuid,
254 };
255
256 const char *readable_names[] = {
257 "CMC", "CPE", "MCE", "PCIe", "INIT", "NMI",
258 "Boot", "DMAr", "SEA", "SEI", "PEI", "CXL Component"
259 };
260
261 int index = select_guid_from_list(&header->NotificationType, guids,
262 sizeof(guids) / sizeof(EFI_GUID *));
263 if (index < (int)(sizeof(readable_names) / sizeof(char *))) {
264 notification_type_readable = readable_names[index];
John Chungf8fc7052024-05-03 20:05:29 +0800265 }
Ed Tanous1a648562025-03-10 15:23:38 -0700266
Lawrence Tange407b4c2022-07-21 13:54:01 +0100267 json_object_object_add(
268 notification_type, "type",
269 json_object_new_string(notification_type_readable));
270 json_object_object_add(header_ir, "notificationType",
271 notification_type);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100272
Lawrence Tange407b4c2022-07-21 13:54:01 +0100273 //The record ID for this record, unique on a given system.
274 json_object_object_add(header_ir, "recordID",
275 json_object_new_uint64(header->RecordID));
276
277 //Flag for the record, and a human readable form.
278 json_object *flags = integer_to_readable_pair(
279 header->Flags,
280 sizeof(CPER_HEADER_FLAG_TYPES_KEYS) / sizeof(int),
281 CPER_HEADER_FLAG_TYPES_KEYS, CPER_HEADER_FLAG_TYPES_VALUES,
282 "Unknown");
283 json_object_object_add(header_ir, "flags", flags);
284
285 //Persistence information. Outside the scope of specification, so just a uint32 here.
286 json_object_object_add(header_ir, "persistenceInfo",
287 json_object_new_uint64(header->PersistenceInfo));
288 return header_ir;
Ed Tanous596c59e2025-03-10 13:15:58 -0700289
290fail:
291 json_object_put(header_ir);
292 return NULL;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100293}
294
295//Converts the given EFI section descriptor into JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100296json_object *
297cper_section_descriptor_to_ir(EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100298{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100299 json_object *section_descriptor_ir = json_object_new_object();
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100300
Lawrence Tange407b4c2022-07-21 13:54:01 +0100301 //The offset of the section from the base of the record header, length.
302 json_object_object_add(
303 section_descriptor_ir, "sectionOffset",
304 json_object_new_uint64(section_descriptor->SectionOffset));
305 json_object_object_add(
306 section_descriptor_ir, "sectionLength",
307 json_object_new_uint64(section_descriptor->SectionLength));
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100308
Lawrence Tange407b4c2022-07-21 13:54:01 +0100309 //Revision.
310 json_object_object_add(section_descriptor_ir, "revision",
311 revision_to_ir(section_descriptor->Revision));
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100312
Lawrence Tange407b4c2022-07-21 13:54:01 +0100313 //Flag bits.
314 json_object *flags =
315 bitfield_to_ir(section_descriptor->SectionFlags, 8,
316 CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES);
317 json_object_object_add(section_descriptor_ir, "flags", flags);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100318
Lawrence Tange407b4c2022-07-21 13:54:01 +0100319 //Section type (GUID).
320 json_object *section_type = json_object_new_object();
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100321
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700322 add_guid(section_type, "data", &section_descriptor->SectionType);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100323 //Readable section type, if possible.
Lawrence Tang580423f2022-08-24 09:37:53 +0100324 const char *section_type_readable = "Unknown";
Ed Tanous1a648562025-03-10 15:23:38 -0700325
326 CPER_SECTION_DEFINITION *section =
327 select_section_by_guid(&section_descriptor->SectionType);
328 if (section != NULL) {
329 section_type_readable = section->ReadableName;
Lawrence Tang580423f2022-08-24 09:37:53 +0100330 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100331
Lawrence Tange407b4c2022-07-21 13:54:01 +0100332 json_object_object_add(section_type, "type",
333 json_object_new_string(section_type_readable));
334 json_object_object_add(section_descriptor_ir, "sectionType",
335 section_type);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100336
Lawrence Tange407b4c2022-07-21 13:54:01 +0100337 //If validation bits indicate it exists, add FRU ID.
John Chungf8fc7052024-05-03 20:05:29 +0800338 if (section_descriptor->SecValidMask & 0x1) {
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700339 add_guid(section_descriptor_ir, "fruID",
340 &section_descriptor->FruId);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100341 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100342
Lawrence Tange407b4c2022-07-21 13:54:01 +0100343 //If validation bits indicate it exists, add FRU text.
John Chungf8fc7052024-05-03 20:05:29 +0800344 if ((section_descriptor->SecValidMask & 0x2) >> 1) {
Ed Tanous8121f7e2025-03-06 14:39:07 -0800345 int fru_text_len = 0;
346 for (;
347 fru_text_len < (int)sizeof(section_descriptor->FruString);
348 fru_text_len++) {
349 char c = section_descriptor->FruString[fru_text_len];
350 if (c < 0) {
351 //printf("Fru text contains non-ASCII character\n");
352 fru_text_len = -1;
353 break;
354 }
355 if (c == '\0') {
356 break;
357 }
358 }
359 if (fru_text_len >= 0) {
360 json_object_object_add(
361 section_descriptor_ir, "fruText",
362 json_object_new_string_len(
363 section_descriptor->FruString,
364 fru_text_len));
365 }
John Chungf8fc7052024-05-03 20:05:29 +0800366 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100367
Lawrence Tange407b4c2022-07-21 13:54:01 +0100368 //Section severity.
369 json_object *section_severity = json_object_new_object();
370 json_object_object_add(
371 section_severity, "code",
372 json_object_new_uint64(section_descriptor->Severity));
373 json_object_object_add(section_severity, "name",
374 json_object_new_string(severity_to_string(
375 section_descriptor->Severity)));
376 json_object_object_add(section_descriptor_ir, "severity",
377 section_severity);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100378
Lawrence Tange407b4c2022-07-21 13:54:01 +0100379 return section_descriptor_ir;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100380}
381
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800382json_object *read_section(const unsigned char *cper_section_buf, size_t size,
383 CPER_SECTION_DEFINITION *definition)
Ed Tanousd759a182025-03-07 15:51:45 -0800384{
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800385 if (definition->ToIR == NULL) {
386 return NULL;
387 }
388 json_object *section_ir = definition->ToIR(cper_section_buf, size);
Ed Tanousd759a182025-03-07 15:51:45 -0800389 json_object *result = json_object_new_object();
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800390 json_object_object_add(result, definition->ShortName, section_ir);
Ed Tanousd759a182025-03-07 15:51:45 -0800391 return result;
392}
393
Ed Tanous1a648562025-03-10 15:23:38 -0700394CPER_SECTION_DEFINITION *select_section_by_guid(EFI_GUID *guid)
395{
396 size_t i = 0;
397 for (; i < section_definitions_len; i++) {
398 if (guid_equal(guid, section_definitions[i].Guid)) {
399 break;
400 }
401 }
402 // It's unlikely fuzzing can reliably come up with a correct guid, given how
403 // much entropy there is. If we're in fuzzing mode, and if we haven't found
404 // a match, try to force a match so we get some coverage. Note, we still
405 // want coverage of the section failed to convert code, so treat index ==
406 // size as section failed to convert.
407#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
408 if (i == section_definitions_len) {
409 i = guid->Data1 % (section_definitions_len + 1);
410 }
411#endif
412 if (i < section_definitions_len) {
413 return &section_definitions[i];
414 }
415
416 return NULL;
417}
418
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100419//Converts the section described by a single given section descriptor.
Ed Tanous73498f62025-03-05 18:03:36 -0800420json_object *cper_buf_section_to_ir(const void *cper_section_buf, size_t size,
421 EFI_ERROR_SECTION_DESCRIPTOR *descriptor)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100422{
Ed Tanous73498f62025-03-05 18:03:36 -0800423 if (descriptor->SectionLength > size) {
424 printf("Invalid CPER file: Invalid header (incorrect signature).\n");
Lawrence Tange407b4c2022-07-21 13:54:01 +0100425 return NULL;
426 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100427
Lawrence Tange407b4c2022-07-21 13:54:01 +0100428 //Parse section to IR based on GUID.
429 json_object *result = NULL;
Ed Tanousb07061a2024-09-22 10:33:29 -0700430
431 json_object *section_ir = NULL;
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800432
Ed Tanous1a648562025-03-10 15:23:38 -0700433 CPER_SECTION_DEFINITION *section =
434 select_section_by_guid(&descriptor->SectionType);
435 if (section != NULL) {
436 result = read_section(cper_section_buf, size, section);
Ed Tanousd759a182025-03-07 15:51:45 -0800437 }
Ed Tanousb07061a2024-09-22 10:33:29 -0700438
Lawrence Tang580423f2022-08-24 09:37:53 +0100439 //Was it an unknown GUID/failed read?
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800440 if (result == NULL) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100441 //Output the data as formatted base64.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700442 int32_t encoded_len = 0;
Ed Tanous73498f62025-03-05 18:03:36 -0800443 char *encoded = base64_encode(cper_section_buf,
444 descriptor->SectionLength,
445 &encoded_len);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700446 if (encoded == NULL) {
Ed Tanous8121f7e2025-03-06 14:39:07 -0800447 //printf("Failed to allocate encode output buffer. \n");
John Chungf8fc7052024-05-03 20:05:29 +0800448 } else {
Ed Tanousb07061a2024-09-22 10:33:29 -0700449 section_ir = json_object_new_object();
450 json_object_object_add(section_ir, "data",
John Chungf8fc7052024-05-03 20:05:29 +0800451 json_object_new_string_len(
452 encoded, encoded_len));
453 free(encoded);
Ed Tanousb07061a2024-09-22 10:33:29 -0700454
455 result = json_object_new_object();
456 json_object_object_add(result, "Unknown", section_ir);
John Chungf8fc7052024-05-03 20:05:29 +0800457 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100458 }
Ed Tanousb07061a2024-09-22 10:33:29 -0700459
Lawrence Tange407b4c2022-07-21 13:54:01 +0100460 return result;
Lawrence Tang617949e2022-08-08 14:21:42 +0100461}
462
Ed Tanous73498f62025-03-05 18:03:36 -0800463json_object *cper_buf_single_section_to_ir(const unsigned char *cper_buf,
464 size_t size)
Ed Tanous8d47a372025-03-05 15:55:36 -0800465{
Ed Tanous8121f7e2025-03-06 14:39:07 -0800466 const unsigned char *cper_end;
467 const unsigned char *section_begin;
468 json_object *ir;
469
470 cper_end = cper_buf + size;
Ed Tanous73498f62025-03-05 18:03:36 -0800471
472 //Read the section descriptor out.
473 EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor;
474 if (sizeof(EFI_ERROR_SECTION_DESCRIPTOR) > size) {
Ed Tanousd759a182025-03-07 15:51:45 -0800475 printf("Size of cper buffer was too small to read section descriptor %zu\n",
476 size);
Ed Tanous8d47a372025-03-05 15:55:36 -0800477 return NULL;
478 }
Ed Tanous8121f7e2025-03-06 14:39:07 -0800479
480 ir = json_object_new_object();
Ed Tanous73498f62025-03-05 18:03:36 -0800481 section_descriptor = (EFI_ERROR_SECTION_DESCRIPTOR *)cper_buf;
482 //Convert the section descriptor to IR.
483 json_object *section_descriptor_ir =
484 cper_section_descriptor_to_ir(section_descriptor);
485 json_object_object_add(ir, "sectionDescriptor", section_descriptor_ir);
Ed Tanous8121f7e2025-03-06 14:39:07 -0800486 section_begin = cper_buf + section_descriptor->SectionOffset;
Ed Tanous73498f62025-03-05 18:03:36 -0800487
Ed Tanous8121f7e2025-03-06 14:39:07 -0800488 if (section_begin + section_descriptor->SectionLength >= cper_end) {
489 json_object_put(ir);
490 //printf("Invalid CPER file: Invalid section descriptor (section offset + length > size).\n");
Ed Tanous73498f62025-03-05 18:03:36 -0800491 return NULL;
492 }
493
494 const unsigned char *section =
495 cper_buf + section_descriptor->SectionOffset;
496
497 //Parse the single section.
498 json_object *section_ir = cper_buf_section_to_ir(
499 section, section_descriptor->SectionLength, section_descriptor);
500 json_object_object_add(ir, "section", section_ir);
Ed Tanous8d47a372025-03-05 15:55:36 -0800501 return ir;
502}
503
Lawrence Tang617949e2022-08-08 14:21:42 +0100504//Converts a single CPER section, without a header but with a section descriptor, to JSON.
505json_object *cper_single_section_to_ir(FILE *cper_section_file)
506{
507 json_object *ir = json_object_new_object();
508
Lawrence Tang94153492022-09-05 13:07:54 +0100509 //Read the current file pointer location as base record position.
510 long base_pos = ftell(cper_section_file);
511
Lawrence Tang617949e2022-08-08 14:21:42 +0100512 //Read the section descriptor out.
513 EFI_ERROR_SECTION_DESCRIPTOR section_descriptor;
514 if (fread(&section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1,
515 cper_section_file) != 1) {
516 printf("Failed to read section descriptor for CPER single section (fread() returned an unexpected value).\n");
Ed Tanous8121f7e2025-03-06 14:39:07 -0800517 json_object_put(ir);
Lawrence Tang617949e2022-08-08 14:21:42 +0100518 return NULL;
519 }
520
521 //Convert the section descriptor to IR.
522 json_object *section_descriptor_ir =
523 cper_section_descriptor_to_ir(&section_descriptor);
524 json_object_object_add(ir, "sectionDescriptor", section_descriptor_ir);
525
Ed Tanous73498f62025-03-05 18:03:36 -0800526 //Save our current position in the stream.
527 long position = ftell(cper_section_file);
528
529 //Read section as described by the section descriptor.
530 fseek(cper_section_file, base_pos + section_descriptor.SectionOffset,
531 SEEK_SET);
532 void *section = malloc(section_descriptor.SectionLength);
533 if (fread(section, section_descriptor.SectionLength, 1,
534 cper_section_file) != 1) {
535 printf("Section read failed: Could not read %u bytes from global offset %d.\n",
536 section_descriptor.SectionLength,
537 section_descriptor.SectionOffset);
Ed Tanous8121f7e2025-03-06 14:39:07 -0800538 json_object_put(ir);
Ed Tanous73498f62025-03-05 18:03:36 -0800539 free(section);
540 return NULL;
541 }
542
543 //Seek back to our original position.
544 fseek(cper_section_file, position, SEEK_SET);
545
Lawrence Tang617949e2022-08-08 14:21:42 +0100546 //Parse the single section.
Ed Tanous73498f62025-03-05 18:03:36 -0800547 json_object *section_ir = cper_buf_section_to_ir(
548 section, section_descriptor.SectionLength, &section_descriptor);
Lawrence Tang617949e2022-08-08 14:21:42 +0100549 json_object_object_add(ir, "section", section_ir);
Ed Tanous73498f62025-03-05 18:03:36 -0800550 free(section);
Lawrence Tang617949e2022-08-08 14:21:42 +0100551 return ir;
John Chungf8fc7052024-05-03 20:05:29 +0800552}
Karthik Rajagopalan5220c9b2024-08-08 00:24:44 -0700553
Karthik Rajagopalan5220c9b2024-08-08 00:24:44 -0700554char *cperbuf_single_section_to_str_ir(const unsigned char *cper_section,
555 size_t size)
556{
Ed Tanous73498f62025-03-05 18:03:36 -0800557 json_object *jobj = cper_buf_single_section_to_ir(cper_section, size);
558 char *str = jobj ? strdup(json_object_to_json_string(jobj)) : NULL;
Karthik Rajagopalan5220c9b2024-08-08 00:24:44 -0700559
Ed Tanous73498f62025-03-05 18:03:36 -0800560 json_object_put(jobj);
561 return str;
Karthik Rajagopalan5220c9b2024-08-08 00:24:44 -0700562}