1 /** 2 * Defines tests for validating CPER-JSON IR output from the cper-parse library. 3 * 4 * Author: Lawrence.Tang@arm.com 5 **/ 6 7 #include "test-utils.h" 8 #include "string.h" 9 #include "assert.h" 10 #include <ctype.h> 11 #include <json.h> 12 #include <libcper/cper-parse.h> 13 #include <libcper/generator/cper-generate.h> 14 #include <libcper/generator/sections/gen-section.h> 15 #include <libcper/json-schema.h> 16 #include <libcper/sections/cper-section.h> 17 18 #include "base64_test.h" 19 20 /* 21 * Test templates. 22 */ 23 static const GEN_VALID_BITS_TEST_TYPE allValidbitsSet = ALL_VALID; 24 static const GEN_VALID_BITS_TEST_TYPE fixedValidbitsSet = SOME_VALID; 25 static const int GEN_EXAMPLES = 0; 26 27 static const char *cper_ext = "cperhex"; 28 static const char *json_ext = "json"; 29 30 struct file_info { 31 char *cper_out; 32 char *json_out; 33 }; 34 35 void free_file_info(struct file_info *info) 36 { 37 if (info == NULL) { 38 return; 39 } 40 free(info->cper_out); 41 free(info->json_out); 42 free(info); 43 } 44 45 struct file_info *file_info_init(const char *section_name) 46 { 47 struct file_info *info = NULL; 48 char *buf = NULL; 49 size_t size; 50 int ret; 51 52 info = (struct file_info *)calloc(1, sizeof(struct file_info)); 53 if (info == NULL) { 54 goto fail; 55 } 56 57 size = strlen(LIBCPER_EXAMPLES) + 1 + strlen(section_name) + 1 + 58 strlen(cper_ext) + 1; 59 info->cper_out = (char *)malloc(size); 60 ret = snprintf(info->cper_out, size, "%s/%s.%s", LIBCPER_EXAMPLES, 61 section_name, cper_ext); 62 if (ret != (int)size - 1) { 63 printf("snprintf0 failed\n"); 64 goto fail; 65 } 66 size = strlen(LIBCPER_EXAMPLES) + 1 + strlen(section_name) + 1 + 67 strlen(json_ext) + 1; 68 info->json_out = (char *)malloc(size); 69 ret = snprintf(info->json_out, size, "%s/%s.%s", LIBCPER_EXAMPLES, 70 section_name, json_ext); 71 if (ret != (int)size - 1) { 72 printf("snprintf3 failed\n"); 73 goto fail; 74 } 75 free(buf); 76 return info; 77 78 fail: 79 free(buf); 80 free_file_info(info); 81 return NULL; 82 } 83 84 void cper_create_examples(const char *section_name) 85 { 86 //Generate full CPER record for the given type. 87 json_object *ir = NULL; 88 size_t size; 89 size_t file_size; 90 FILE *outFile = NULL; 91 unsigned char *file_data; 92 FILE *record = NULL; 93 char *buf = NULL; 94 struct file_info *info = file_info_init(section_name); 95 if (info == NULL) { 96 goto done; 97 } 98 99 record = generate_record_memstream(§ion_name, 1, &buf, &size, 0, 100 fixedValidbitsSet); 101 102 // Write example CPER to disk 103 outFile = fopen(info->cper_out, "wb"); 104 if (outFile == NULL) { 105 printf("Failed to create/open CPER output file: %s\n", 106 info->cper_out); 107 goto done; 108 } 109 110 fseek(record, 0, SEEK_END); 111 file_size = ftell(record); 112 rewind(record); 113 file_data = malloc(file_size); 114 if (fread(file_data, 1, file_size, record) != file_size) { 115 printf("Failed to read CPER data from memstream."); 116 fclose(outFile); 117 assert(0); 118 119 goto done; 120 } 121 for (size_t index = 0; index < file_size; index++) { 122 char hex_str[3]; 123 int out = snprintf(hex_str, sizeof(hex_str), "%02x", 124 file_data[index]); 125 if (out != 2) { 126 printf("snprintf1 failed\n"); 127 goto done; 128 } 129 fwrite(hex_str, sizeof(char), 2, outFile); 130 if (index % 30 == 29) { 131 fwrite("\n", sizeof(char), 1, outFile); 132 } 133 } 134 fclose(outFile); 135 136 //Convert to IR, free resources. 137 rewind(record); 138 ir = cper_to_ir(record); 139 if (ir == NULL) { 140 printf("Empty JSON from CPER bin2\n"); 141 assert(0); 142 goto done; 143 } 144 145 //Write json output to disk 146 json_object_to_file_ext(info->json_out, ir, JSON_C_TO_STRING_PRETTY); 147 json_object_put(ir); 148 149 done: 150 free_file_info(info); 151 if (record != NULL) { 152 fclose(record); 153 } 154 if (outFile != NULL) { 155 fclose(outFile); 156 } 157 free(buf); 158 } 159 160 int hex2int(char ch) 161 { 162 if ((ch >= '0') && (ch <= '9')) { 163 return ch - '0'; 164 } 165 if ((ch >= 'A') && (ch <= 'F')) { 166 return ch - 'A' + 10; 167 } 168 if ((ch >= 'a') && (ch <= 'f')) { 169 return ch - 'a' + 10; 170 } 171 return -1; 172 } 173 174 int string_to_binary(const char *source, size_t length, unsigned char **retval) 175 { 176 size_t retval_size = length * 2; 177 *retval = malloc(retval_size); 178 int uppernibble = 1; 179 180 size_t ret_index = 0; 181 182 for (size_t i = 0; i < length; i++) { 183 char c = source[i]; 184 if (c == '\n') { 185 continue; 186 } 187 int val = hex2int(c); 188 if (val < 0) { 189 printf("Invalid hex character in test file: %c\n", c); 190 return -1; 191 } 192 193 if (uppernibble) { 194 (*retval)[ret_index] = (unsigned char)(val << 4); 195 } else { 196 (*retval)[ret_index] += (unsigned char)val; 197 ret_index++; 198 } 199 uppernibble = !uppernibble; 200 } 201 return ret_index; 202 } 203 204 //Tests fixed CPER sections for IR validity with an example set. 205 void cper_example_section_ir_test(const char *section_name) 206 { 207 //Open CPER record for the given type. 208 struct file_info *info = file_info_init(section_name); 209 if (info == NULL) { 210 return; 211 } 212 213 FILE *cper_file = fopen(info->cper_out, "rb"); 214 if (cper_file == NULL) { 215 printf("Failed to open CPER file: %s\n", info->cper_out); 216 free_file_info(info); 217 assert(0); 218 return; 219 } 220 fseek(cper_file, 0, SEEK_END); 221 size_t length = ftell(cper_file); 222 fseek(cper_file, 0, SEEK_SET); 223 char *buffer = (char *)malloc(length); 224 if (!buffer) { 225 free_file_info(info); 226 return; 227 } 228 if (fread(buffer, 1, length, cper_file) != length) { 229 printf("Failed to read CPER file: %s\n", info->cper_out); 230 free(buffer); 231 free_file_info(info); 232 return; 233 } 234 fclose(cper_file); 235 236 unsigned char *cper_bin; 237 int cper_bin_len = string_to_binary(buffer, length, &cper_bin); 238 if (cper_bin_len <= 0) { 239 free(buffer); 240 free_file_info(info); 241 assert(0); 242 return; 243 } 244 printf("cper_bin: %s\n", cper_bin); 245 printf("cper_bin_len: %d\n", cper_bin_len); 246 247 //Convert to IR, free resources. 248 json_object *ir = cper_buf_to_ir(cper_bin, cper_bin_len); 249 if (ir == NULL) { 250 printf("Empty JSON from CPER bin3\n"); 251 free(cper_bin); 252 free(buffer); 253 free_file_info(info); 254 assert(0); 255 return; 256 } 257 258 json_object *expected = json_object_from_file(info->json_out); 259 assert(expected != NULL); 260 if (expected == NULL) { 261 free(buffer); 262 free(cper_bin); 263 free_file_info(info); 264 const char *str = json_object_to_json_string(ir); 265 266 const char *expected_str = json_object_to_json_string(expected); 267 assert(strcmp(str, expected_str) == 0); 268 return; 269 } 270 271 assert(json_object_equal(ir, expected)); 272 free(buffer); 273 free(cper_bin); 274 json_object_put(ir); 275 json_object_put(expected); 276 free_file_info(info); 277 } 278 279 //Tests a single randomly generated CPER section of the given type to ensure CPER-JSON IR validity. 280 void cper_log_section_ir_test(const char *section_name, int single_section, 281 GEN_VALID_BITS_TEST_TYPE validBitsType) 282 { 283 //Generate full CPER record for the given type. 284 char *buf; 285 size_t size; 286 FILE *record = generate_record_memstream(§ion_name, 1, &buf, &size, 287 single_section, validBitsType); 288 289 //Convert to IR, free resources. 290 json_object *ir; 291 if (single_section) { 292 ir = cper_single_section_to_ir(record); 293 } else { 294 ir = cper_to_ir(record); 295 } 296 297 fclose(record); 298 free(buf); 299 300 //Validate against schema. 301 int valid = schema_validate_from_file(ir, single_section, 302 /*all_valid_bits*/ 1); 303 json_object_put(ir); 304 305 if (valid < 0) { 306 printf("IR validation test failed (single section mode = %d)\n", 307 single_section); 308 assert(0); 309 } 310 } 311 312 int to_hex(const unsigned char *input, size_t size, char **out) 313 { 314 *out = (char *)malloc(size * 2); 315 if (out == NULL) { 316 return -1; 317 } 318 int out_index = 0; 319 for (size_t i = 0; i < size; i++) { 320 unsigned char c = input[i]; 321 char hex_str[3]; 322 int n = snprintf(hex_str, sizeof(hex_str), "%02x", c); 323 if (n != 2) { 324 printf("snprintf2 failed with code %d\n", n); 325 return -1; 326 } 327 (*out)[out_index] = hex_str[0]; 328 out_index++; 329 (*out)[out_index] = hex_str[1]; 330 out_index++; 331 } 332 return out_index; 333 } 334 335 //Checks for binary round-trip equality for a given randomly generated CPER record. 336 void cper_log_section_binary_test(const char *section_name, int single_section, 337 GEN_VALID_BITS_TEST_TYPE validBitsType) 338 { 339 //Generate CPER record for the given type. 340 char *buf; 341 size_t size; 342 FILE *record = generate_record_memstream(§ion_name, 1, &buf, &size, 343 single_section, validBitsType); 344 if (record == NULL) { 345 printf("Could not generate memstream for binary test"); 346 return; 347 } 348 349 //Convert to IR. 350 json_object *ir; 351 if (single_section) { 352 ir = cper_single_section_to_ir(record); 353 } else { 354 ir = cper_to_ir(record); 355 } 356 357 //Now convert back to binary, and get a stream out. 358 char *cper_buf; 359 size_t cper_buf_size; 360 FILE *stream = open_memstream(&cper_buf, &cper_buf_size); 361 if (single_section) { 362 ir_single_section_to_cper(ir, stream); 363 } else { 364 ir_to_cper(ir, stream); 365 } 366 fclose(stream); 367 368 printf("size: %zu, cper_buf_size: %zu\n", size, cper_buf_size); 369 370 char *buf_hex; 371 int buf_hex_len = to_hex((unsigned char *)buf, size, &buf_hex); 372 char *cper_buf_hex; 373 int cper_buf_hex_len = 374 to_hex((unsigned char *)cper_buf, cper_buf_size, &cper_buf_hex); 375 376 assert(buf_hex_len == cper_buf_hex_len); 377 assert(memcmp(buf_hex, cper_buf_hex, buf_hex_len) == 0); 378 379 free(buf_hex); 380 free(cper_buf_hex); 381 382 //Free everything up. 383 fclose(record); 384 free(buf); 385 free(cper_buf); 386 json_object_put(ir); 387 } 388 389 //Tests randomly generated CPER sections for IR validity of a given type, in both single section mode and full CPER log mode. 390 void cper_log_section_dual_ir_test(const char *section_name) 391 { 392 cper_log_section_ir_test(section_name, 0, allValidbitsSet); 393 cper_log_section_ir_test(section_name, 1, allValidbitsSet); 394 //Validate against examples 395 cper_example_section_ir_test(section_name); 396 } 397 398 //Tests randomly generated CPER sections for binary compatibility of a given type, in both single section mode and full CPER log mode. 399 void cper_log_section_dual_binary_test(const char *section_name) 400 { 401 cper_log_section_binary_test(section_name, 0, allValidbitsSet); 402 cper_log_section_binary_test(section_name, 1, allValidbitsSet); 403 } 404 405 /* 406 * Non-single section assertions. 407 */ 408 void CompileTimeAssertions_TwoWayConversion() 409 { 410 for (size_t i = 0; i < section_definitions_len; i++) { 411 //If a conversion one way exists, a conversion the other way must exist. 412 if (section_definitions[i].ToCPER != NULL) { 413 assert(section_definitions[i].ToIR != NULL); 414 } 415 if (section_definitions[i].ToIR != NULL) { 416 assert(section_definitions[i].ToCPER != NULL); 417 } 418 } 419 } 420 421 void CompileTimeAssertions_ShortcodeNoSpaces() 422 { 423 for (size_t i = 0; i < generator_definitions_len; i++) { 424 for (int j = 0; 425 generator_definitions[i].ShortName[j + 1] != '\0'; j++) { 426 assert(isspace(generator_definitions[i].ShortName[j]) == 427 0); 428 } 429 } 430 } 431 432 /* 433 * Single section tests. 434 */ 435 436 //Generic processor tests. 437 void GenericProcessorTests_IRValid() 438 { 439 cper_log_section_dual_ir_test("generic"); 440 } 441 void GenericProcessorTests_BinaryEqual() 442 { 443 cper_log_section_dual_binary_test("generic"); 444 } 445 446 //IA32/x64 tests. 447 void IA32x64Tests_IRValid() 448 { 449 cper_log_section_dual_ir_test("ia32x64"); 450 } 451 void IA32x64Tests_BinaryEqual() 452 { 453 cper_log_section_dual_binary_test("ia32x64"); 454 } 455 456 // void IPFTests_IRValid() { 457 // cper_log_section_dual_ir_test("ipf"); 458 // } 459 460 //ARM tests. 461 void ArmTests_IRValid() 462 { 463 cper_log_section_dual_ir_test("arm"); 464 } 465 void ArmTests_BinaryEqual() 466 { 467 cper_log_section_dual_binary_test("arm"); 468 } 469 470 //Memory tests. 471 void MemoryTests_IRValid() 472 { 473 cper_log_section_dual_ir_test("memory"); 474 } 475 void MemoryTests_BinaryEqual() 476 { 477 cper_log_section_dual_binary_test("memory"); 478 } 479 480 //Memory 2 tests. 481 void Memory2Tests_IRValid() 482 { 483 cper_log_section_dual_ir_test("memory2"); 484 } 485 void Memory2Tests_BinaryEqual() 486 { 487 cper_log_section_dual_binary_test("memory2"); 488 } 489 490 //PCIe tests. 491 void PCIeTests_IRValid() 492 { 493 cper_log_section_dual_ir_test("pcie"); 494 } 495 void PCIeTests_BinaryEqual() 496 { 497 cper_log_section_dual_binary_test("pcie"); 498 } 499 500 //Firmware tests. 501 void FirmwareTests_IRValid() 502 { 503 cper_log_section_dual_ir_test("firmware"); 504 } 505 void FirmwareTests_BinaryEqual() 506 { 507 cper_log_section_dual_binary_test("firmware"); 508 } 509 510 //PCI Bus tests. 511 void PCIBusTests_IRValid() 512 { 513 cper_log_section_dual_ir_test("pcibus"); 514 } 515 void PCIBusTests_BinaryEqual() 516 { 517 cper_log_section_dual_binary_test("pcibus"); 518 } 519 520 //PCI Device tests. 521 void PCIDevTests_IRValid() 522 { 523 cper_log_section_dual_ir_test("pcidev"); 524 } 525 void PCIDevTests_BinaryEqual() 526 { 527 cper_log_section_dual_binary_test("pcidev"); 528 } 529 530 //Generic DMAr tests. 531 void DMArGenericTests_IRValid() 532 { 533 cper_log_section_dual_ir_test("dmargeneric"); 534 } 535 void DMArGenericTests_BinaryEqual() 536 { 537 cper_log_section_dual_binary_test("dmargeneric"); 538 } 539 540 //VT-d DMAr tests. 541 void DMArVtdTests_IRValid() 542 { 543 cper_log_section_dual_ir_test("dmarvtd"); 544 } 545 void DMArVtdTests_BinaryEqual() 546 { 547 cper_log_section_dual_binary_test("dmarvtd"); 548 } 549 550 //IOMMU DMAr tests. 551 void DMArIOMMUTests_IRValid() 552 { 553 cper_log_section_dual_ir_test("dmariommu"); 554 } 555 void DMArIOMMUTests_BinaryEqual() 556 { 557 cper_log_section_dual_binary_test("dmariommu"); 558 } 559 560 //CCIX PER tests. 561 void CCIXPERTests_IRValid() 562 { 563 cper_log_section_dual_ir_test("ccixper"); 564 } 565 void CCIXPERTests_BinaryEqual() 566 { 567 cper_log_section_dual_binary_test("ccixper"); 568 } 569 570 //CXL Protocol tests. 571 void CXLProtocolTests_IRValid() 572 { 573 cper_log_section_dual_ir_test("cxlprotocol"); 574 } 575 void CXLProtocolTests_BinaryEqual() 576 { 577 cper_log_section_dual_binary_test("cxlprotocol"); 578 } 579 580 //CXL Component tests. 581 void CXLComponentTests_IRValid() 582 { 583 cper_log_section_dual_ir_test("cxlcomponent-media"); 584 } 585 void CXLComponentTests_BinaryEqual() 586 { 587 cper_log_section_dual_binary_test("cxlcomponent-media"); 588 } 589 590 //NVIDIA section tests. 591 void NVIDIASectionTests_IRValid() 592 { 593 cper_log_section_dual_ir_test("nvidia"); 594 } 595 void NVIDIASectionTests_BinaryEqual() 596 { 597 cper_log_section_dual_binary_test("nvidia"); 598 } 599 600 //Unknown section tests. 601 void UnknownSectionTests_IRValid() 602 { 603 cper_log_section_dual_ir_test("unknown"); 604 } 605 void UnknownSectionTests_BinaryEqual() 606 { 607 cper_log_section_dual_binary_test("unknown"); 608 } 609 610 //Entrypoint for the testing program. 611 int main() 612 { 613 if (GEN_EXAMPLES) { 614 cper_create_examples("arm"); 615 cper_create_examples("ia32x64"); 616 cper_create_examples("memory"); 617 cper_create_examples("memory2"); 618 cper_create_examples("pcie"); 619 cper_create_examples("firmware"); 620 cper_create_examples("pcibus"); 621 cper_create_examples("pcidev"); 622 cper_create_examples("dmargeneric"); 623 cper_create_examples("dmarvtd"); 624 cper_create_examples("dmariommu"); 625 cper_create_examples("ccixper"); 626 cper_create_examples("cxlprotocol"); 627 cper_create_examples("cxlcomponent-media"); 628 cper_create_examples("nvidia"); 629 cper_create_examples("unknown"); 630 } 631 test_base64_encode_good(); 632 test_base64_decode_good(); 633 GenericProcessorTests_IRValid(); 634 GenericProcessorTests_BinaryEqual(); 635 IA32x64Tests_IRValid(); 636 IA32x64Tests_BinaryEqual(); 637 ArmTests_IRValid(); 638 ArmTests_BinaryEqual(); 639 MemoryTests_IRValid(); 640 MemoryTests_BinaryEqual(); 641 Memory2Tests_IRValid(); 642 Memory2Tests_BinaryEqual(); 643 PCIeTests_IRValid(); 644 PCIeTests_BinaryEqual(); 645 FirmwareTests_IRValid(); 646 FirmwareTests_BinaryEqual(); 647 PCIBusTests_IRValid(); 648 PCIBusTests_BinaryEqual(); 649 PCIDevTests_IRValid(); 650 PCIDevTests_BinaryEqual(); 651 DMArGenericTests_IRValid(); 652 DMArGenericTests_BinaryEqual(); 653 DMArVtdTests_IRValid(); 654 DMArVtdTests_BinaryEqual(); 655 DMArIOMMUTests_IRValid(); 656 DMArIOMMUTests_BinaryEqual(); 657 CCIXPERTests_IRValid(); 658 CCIXPERTests_BinaryEqual(); 659 CXLProtocolTests_IRValid(); 660 CXLProtocolTests_BinaryEqual(); 661 CXLComponentTests_IRValid(); 662 CXLComponentTests_BinaryEqual(); 663 NVIDIASectionTests_IRValid(); 664 NVIDIASectionTests_BinaryEqual(); 665 UnknownSectionTests_IRValid(); 666 UnknownSectionTests_BinaryEqual(); 667 CompileTimeAssertions_TwoWayConversion(); 668 CompileTimeAssertions_ShortcodeNoSpaces(); 669 670 printf("\n\nTest completed successfully.\n"); 671 672 return 0; 673 } 674