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 printf("%.*s\n", cper_buf_hex_len, cper_buf_hex); 377 printf("%.*s\n", buf_hex_len, buf_hex); 378 assert(buf_hex_len == cper_buf_hex_len); 379 assert(memcmp(buf_hex, cper_buf_hex, buf_hex_len) == 0); 380 381 free(buf_hex); 382 free(cper_buf_hex); 383 384 //Free everything up. 385 fclose(record); 386 free(buf); 387 free(cper_buf); 388 json_object_put(ir); 389 } 390 391 //Tests randomly generated CPER sections for IR validity of a given type, in both single section mode and full CPER log mode. 392 void cper_log_section_dual_ir_test(const char *section_name) 393 { 394 cper_log_section_ir_test(section_name, 0, allValidbitsSet); 395 cper_log_section_ir_test(section_name, 1, allValidbitsSet); 396 //Validate against examples 397 cper_example_section_ir_test(section_name); 398 } 399 400 //Tests randomly generated CPER sections for binary compatibility of a given type, in both single section mode and full CPER log mode. 401 void cper_log_section_dual_binary_test(const char *section_name) 402 { 403 cper_log_section_binary_test(section_name, 0, allValidbitsSet); 404 cper_log_section_binary_test(section_name, 1, allValidbitsSet); 405 } 406 407 /* 408 * Non-single section assertions. 409 */ 410 void CompileTimeAssertions_TwoWayConversion() 411 { 412 for (size_t i = 0; i < section_definitions_len; i++) { 413 //If a conversion one way exists, a conversion the other way must exist. 414 if (section_definitions[i].ToCPER != NULL) { 415 assert(section_definitions[i].ToIR != NULL); 416 } 417 if (section_definitions[i].ToIR != NULL) { 418 assert(section_definitions[i].ToCPER != NULL); 419 } 420 } 421 } 422 423 void CompileTimeAssertions_ShortcodeNoSpaces() 424 { 425 for (size_t i = 0; i < generator_definitions_len; i++) { 426 for (int j = 0; 427 generator_definitions[i].ShortName[j + 1] != '\0'; j++) { 428 assert(isspace(generator_definitions[i].ShortName[j]) == 429 0); 430 } 431 } 432 } 433 434 /* 435 * Single section tests. 436 */ 437 438 //Generic processor tests. 439 void GenericProcessorTests_IRValid() 440 { 441 cper_log_section_dual_ir_test("generic"); 442 } 443 void GenericProcessorTests_BinaryEqual() 444 { 445 cper_log_section_dual_binary_test("generic"); 446 } 447 448 //IA32/x64 tests. 449 void IA32x64Tests_IRValid() 450 { 451 cper_log_section_dual_ir_test("ia32x64"); 452 } 453 void IA32x64Tests_BinaryEqual() 454 { 455 cper_log_section_dual_binary_test("ia32x64"); 456 } 457 458 // void IPFTests_IRValid() { 459 // cper_log_section_dual_ir_test("ipf"); 460 // } 461 462 //ARM tests. 463 void ArmTests_IRValid() 464 { 465 cper_log_section_dual_ir_test("arm"); 466 } 467 void ArmTests_BinaryEqual() 468 { 469 cper_log_section_dual_binary_test("arm"); 470 } 471 472 //Memory tests. 473 void MemoryTests_IRValid() 474 { 475 cper_log_section_dual_ir_test("memory"); 476 } 477 void MemoryTests_BinaryEqual() 478 { 479 cper_log_section_dual_binary_test("memory"); 480 } 481 482 //Memory 2 tests. 483 void Memory2Tests_IRValid() 484 { 485 cper_log_section_dual_ir_test("memory2"); 486 } 487 void Memory2Tests_BinaryEqual() 488 { 489 cper_log_section_dual_binary_test("memory2"); 490 } 491 492 //PCIe tests. 493 void PCIeTests_IRValid() 494 { 495 cper_log_section_dual_ir_test("pcie"); 496 } 497 void PCIeTests_BinaryEqual() 498 { 499 cper_log_section_dual_binary_test("pcie"); 500 } 501 502 //Firmware tests. 503 void FirmwareTests_IRValid() 504 { 505 cper_log_section_dual_ir_test("firmware"); 506 } 507 void FirmwareTests_BinaryEqual() 508 { 509 cper_log_section_dual_binary_test("firmware"); 510 } 511 512 //PCI Bus tests. 513 void PCIBusTests_IRValid() 514 { 515 cper_log_section_dual_ir_test("pcibus"); 516 } 517 void PCIBusTests_BinaryEqual() 518 { 519 cper_log_section_dual_binary_test("pcibus"); 520 } 521 522 //PCI Device tests. 523 void PCIDevTests_IRValid() 524 { 525 cper_log_section_dual_ir_test("pcidev"); 526 } 527 void PCIDevTests_BinaryEqual() 528 { 529 cper_log_section_dual_binary_test("pcidev"); 530 } 531 532 //Generic DMAr tests. 533 void DMArGenericTests_IRValid() 534 { 535 cper_log_section_dual_ir_test("dmargeneric"); 536 } 537 void DMArGenericTests_BinaryEqual() 538 { 539 cper_log_section_dual_binary_test("dmargeneric"); 540 } 541 542 //VT-d DMAr tests. 543 void DMArVtdTests_IRValid() 544 { 545 cper_log_section_dual_ir_test("dmarvtd"); 546 } 547 void DMArVtdTests_BinaryEqual() 548 { 549 cper_log_section_dual_binary_test("dmarvtd"); 550 } 551 552 //IOMMU DMAr tests. 553 void DMArIOMMUTests_IRValid() 554 { 555 cper_log_section_dual_ir_test("dmariommu"); 556 } 557 void DMArIOMMUTests_BinaryEqual() 558 { 559 cper_log_section_dual_binary_test("dmariommu"); 560 } 561 562 //CCIX PER tests. 563 void CCIXPERTests_IRValid() 564 { 565 cper_log_section_dual_ir_test("ccixper"); 566 } 567 void CCIXPERTests_BinaryEqual() 568 { 569 cper_log_section_dual_binary_test("ccixper"); 570 } 571 572 //CXL Protocol tests. 573 void CXLProtocolTests_IRValid() 574 { 575 cper_log_section_dual_ir_test("cxlprotocol"); 576 } 577 void CXLProtocolTests_BinaryEqual() 578 { 579 cper_log_section_dual_binary_test("cxlprotocol"); 580 } 581 582 //CXL Component tests. 583 void CXLComponentTests_IRValid() 584 { 585 cper_log_section_dual_ir_test("cxlcomponent-media"); 586 } 587 void CXLComponentTests_BinaryEqual() 588 { 589 cper_log_section_dual_binary_test("cxlcomponent-media"); 590 } 591 592 //NVIDIA section tests. 593 void NVIDIASectionTests_IRValid() 594 { 595 cper_log_section_dual_ir_test("nvidia"); 596 } 597 void NVIDIASectionTests_BinaryEqual() 598 { 599 cper_log_section_dual_binary_test("nvidia"); 600 } 601 602 void NVIDIACMETSectionTests_IRValid() 603 { 604 cper_example_section_ir_test("nvidia_cmet_info"); 605 } 606 607 //Unknown section tests. 608 void UnknownSectionTests_IRValid() 609 { 610 cper_log_section_dual_ir_test("unknown"); 611 } 612 void UnknownSectionTests_BinaryEqual() 613 { 614 cper_log_section_dual_binary_test("unknown"); 615 } 616 617 //Entrypoint for the testing program. 618 int main() 619 { 620 if (GEN_EXAMPLES) { 621 cper_create_examples("arm"); 622 cper_create_examples("ia32x64"); 623 cper_create_examples("memory"); 624 cper_create_examples("memory2"); 625 cper_create_examples("pcie"); 626 cper_create_examples("firmware"); 627 cper_create_examples("pcibus"); 628 cper_create_examples("pcidev"); 629 cper_create_examples("dmargeneric"); 630 cper_create_examples("dmarvtd"); 631 cper_create_examples("dmariommu"); 632 cper_create_examples("ccixper"); 633 cper_create_examples("cxlprotocol"); 634 cper_create_examples("cxlcomponent-media"); 635 cper_create_examples("nvidia"); 636 cper_create_examples("unknown"); 637 } 638 test_base64_encode_good(); 639 test_base64_decode_good(); 640 GenericProcessorTests_IRValid(); 641 GenericProcessorTests_BinaryEqual(); 642 IA32x64Tests_IRValid(); 643 IA32x64Tests_BinaryEqual(); 644 ArmTests_IRValid(); 645 ArmTests_BinaryEqual(); 646 MemoryTests_IRValid(); 647 MemoryTests_BinaryEqual(); 648 Memory2Tests_IRValid(); 649 Memory2Tests_BinaryEqual(); 650 PCIeTests_IRValid(); 651 PCIeTests_BinaryEqual(); 652 FirmwareTests_IRValid(); 653 FirmwareTests_BinaryEqual(); 654 PCIBusTests_IRValid(); 655 PCIBusTests_BinaryEqual(); 656 PCIDevTests_IRValid(); 657 PCIDevTests_BinaryEqual(); 658 DMArGenericTests_IRValid(); 659 DMArGenericTests_BinaryEqual(); 660 DMArVtdTests_IRValid(); 661 DMArVtdTests_BinaryEqual(); 662 DMArIOMMUTests_IRValid(); 663 DMArIOMMUTests_BinaryEqual(); 664 CCIXPERTests_IRValid(); 665 CCIXPERTests_BinaryEqual(); 666 CXLProtocolTests_IRValid(); 667 CXLProtocolTests_BinaryEqual(); 668 CXLComponentTests_IRValid(); 669 CXLComponentTests_BinaryEqual(); 670 NVIDIASectionTests_IRValid(); 671 NVIDIASectionTests_BinaryEqual(); 672 NVIDIACMETSectionTests_IRValid(); 673 UnknownSectionTests_IRValid(); 674 UnknownSectionTests_BinaryEqual(); 675 CompileTimeAssertions_TwoWayConversion(); 676 CompileTimeAssertions_ShortcodeNoSpaces(); 677 678 printf("\n\nTest completed successfully.\n"); 679 680 return 0; 681 } 682