|
10 | 10 | Note: This module runs in Ghidra's Jython environment and uses Ghidra's API. |
11 | 11 | """ |
12 | 12 |
|
| 13 | +import os |
13 | 14 | import re |
14 | 15 |
|
15 | 16 | # Ghidra undefined type to standard C type mapping |
@@ -443,3 +444,175 @@ def write_file_header(f, module_name, func_count, program_name=None): |
443 | 444 | f.write("#include <stdint.h>\n") |
444 | 445 | f.write("#include <stdbool.h>\n") |
445 | 446 | f.write("#include <stddef.h>\n\n") |
| 447 | + |
| 448 | + |
| 449 | +# ============================================================ |
| 450 | +# Header File Generation Functions |
| 451 | +# ============================================================ |
| 452 | + |
| 453 | + |
| 454 | +def extract_function_signature(decompiled_code): |
| 455 | + """ |
| 456 | + Extract function signature from decompiled code. |
| 457 | + Returns the normalized function signature string or None if extraction fails. |
| 458 | + """ |
| 459 | + if not decompiled_code: |
| 460 | + return None |
| 461 | + |
| 462 | + # Find the first function definition (before the opening brace) |
| 463 | + lines = decompiled_code.strip().split("\n") |
| 464 | + signature_lines = [] |
| 465 | + |
| 466 | + for line in lines: |
| 467 | + if "{" in line: |
| 468 | + # Include part before the brace |
| 469 | + signature_lines.append(line.split("{")[0].strip()) |
| 470 | + break |
| 471 | + signature_lines.append(line.strip()) |
| 472 | + |
| 473 | + if not signature_lines: |
| 474 | + return None |
| 475 | + |
| 476 | + signature = " ".join(signature_lines).strip() |
| 477 | + |
| 478 | + # Clean up the signature |
| 479 | + signature = re.sub(r"\s+", " ", signature) |
| 480 | + |
| 481 | + # Skip if it looks like a variable declaration or empty |
| 482 | + if not signature or signature.endswith(";"): |
| 483 | + return None |
| 484 | + |
| 485 | + # Normalize types in the signature |
| 486 | + signature = normalize_code_types(signature) |
| 487 | + |
| 488 | + return signature |
| 489 | + |
| 490 | + |
| 491 | +def generate_header_file( |
| 492 | + output_dir, module_name, func_signatures, source_type="decompilation" |
| 493 | +): |
| 494 | + """ |
| 495 | + Generate a header file for a module with function declarations. |
| 496 | +
|
| 497 | + Args: |
| 498 | + output_dir: Directory to write the header file |
| 499 | + module_name: Name of the module |
| 500 | + func_signatures: List of (func_name, signature) tuples |
| 501 | + source_type: Description of the source (e.g., "ELF decompilation", "library decompilation") |
| 502 | +
|
| 503 | + Returns: |
| 504 | + Path to the generated header file |
| 505 | + """ |
| 506 | + safe_name = sanitize_filename(module_name) |
| 507 | + header_file = os.path.join(output_dir, "{}.h".format(safe_name)) |
| 508 | + |
| 509 | + guard_name = "_{}_H_".format(safe_name.upper()) |
| 510 | + |
| 511 | + with open(header_file, "w") as f: |
| 512 | + f.write("/**\n") |
| 513 | + f.write(" * Header: {}.h\n".format(safe_name)) |
| 514 | + f.write(" * Module: {}\n".format(module_name)) |
| 515 | + f.write(" * Functions: {}\n".format(len(func_signatures))) |
| 516 | + f.write(" * \n") |
| 517 | + f.write(" * Auto-generated by LibSurgeon from {}\n".format(source_type)) |
| 518 | + f.write(" */\n\n") |
| 519 | + |
| 520 | + f.write("#ifndef {}\n".format(guard_name)) |
| 521 | + f.write("#define {}\n\n".format(guard_name)) |
| 522 | + |
| 523 | + f.write("#include <stdint.h>\n") |
| 524 | + f.write("#include <stdbool.h>\n") |
| 525 | + f.write("#include <stddef.h>\n") |
| 526 | + f.write('#include "_types.h"\n\n') |
| 527 | + |
| 528 | + f.write("#ifdef __cplusplus\n") |
| 529 | + f.write('extern "C" {\n') |
| 530 | + f.write("#endif\n\n") |
| 531 | + |
| 532 | + # Write function declarations |
| 533 | + f.write("/* Function Declarations */\n\n") |
| 534 | + for func_name, signature in sorted(func_signatures, key=lambda x: x[0]): |
| 535 | + if signature: |
| 536 | + f.write("/* {} */\n".format(func_name)) |
| 537 | + f.write("{};\n\n".format(signature)) |
| 538 | + |
| 539 | + f.write("#ifdef __cplusplus\n") |
| 540 | + f.write("}\n") |
| 541 | + f.write("#endif\n\n") |
| 542 | + |
| 543 | + f.write("#endif /* {} */\n".format(guard_name)) |
| 544 | + |
| 545 | + return header_file |
| 546 | + |
| 547 | + |
| 548 | +def generate_master_header(output_dir, module_names, program_name): |
| 549 | + """ |
| 550 | + Generate a master header file that includes all module headers. |
| 551 | +
|
| 552 | + Args: |
| 553 | + output_dir: Directory to write the header file |
| 554 | + module_names: Iterable of module names |
| 555 | + program_name: Name of the source program |
| 556 | +
|
| 557 | + Returns: |
| 558 | + Path to the generated master header file |
| 559 | + """ |
| 560 | + header_file = os.path.join(output_dir, "_all_headers.h") |
| 561 | + |
| 562 | + with open(header_file, "w") as f: |
| 563 | + f.write("/**\n") |
| 564 | + f.write(" * Master Header File\n") |
| 565 | + f.write(" * Source: {}\n".format(program_name)) |
| 566 | + f.write(" * Modules: {}\n".format(len(list(module_names)))) |
| 567 | + f.write(" * \n") |
| 568 | + f.write(" * Auto-generated by LibSurgeon\n") |
| 569 | + f.write(" * Include this file to get all function declarations.\n") |
| 570 | + f.write(" */\n\n") |
| 571 | + |
| 572 | + f.write("#ifndef _ALL_HEADERS_H_\n") |
| 573 | + f.write("#define _ALL_HEADERS_H_\n\n") |
| 574 | + |
| 575 | + f.write('#include "_types.h"\n\n') |
| 576 | + |
| 577 | + for module_name in sorted(module_names): |
| 578 | + safe_name = sanitize_filename(module_name) |
| 579 | + f.write('#include "{}.h"\n'.format(safe_name)) |
| 580 | + |
| 581 | + f.write("\n#endif /* _ALL_HEADERS_H_ */\n") |
| 582 | + |
| 583 | + return header_file |
| 584 | + |
| 585 | + |
| 586 | +def generate_types_header(output_dir): |
| 587 | + """ |
| 588 | + Generate _types.h header with type definitions. |
| 589 | +
|
| 590 | + Args: |
| 591 | + output_dir: Directory to write the header file |
| 592 | +
|
| 593 | + Returns: |
| 594 | + Path to the generated types header file |
| 595 | + """ |
| 596 | + types_file = os.path.join(output_dir, "_types.h") |
| 597 | + |
| 598 | + with open(types_file, "w") as f: |
| 599 | + f.write("/**\n") |
| 600 | + f.write(" * Type Definitions for Decompiled Code\n") |
| 601 | + f.write(" * \n") |
| 602 | + f.write(" * This file contains typedef mappings for Ghidra-generated types.\n") |
| 603 | + f.write(" * Auto-generated by LibSurgeon\n") |
| 604 | + f.write(" */\n\n") |
| 605 | + |
| 606 | + f.write("#ifndef _LIBSURGEON_TYPES_H_\n") |
| 607 | + f.write("#define _LIBSURGEON_TYPES_H_\n\n") |
| 608 | + |
| 609 | + f.write("#include <stdint.h>\n") |
| 610 | + f.write("#include <stdbool.h>\n\n") |
| 611 | + |
| 612 | + f.write("/* Unknown type definitions (signedness uncertain) */\n") |
| 613 | + f.write(UNKNOWN_TYPE_DEFS) |
| 614 | + f.write("\n") |
| 615 | + |
| 616 | + f.write("#endif /* _LIBSURGEON_TYPES_H_ */\n") |
| 617 | + |
| 618 | + return types_file |
0 commit comments