Skip to content

Add method to dump C definition - #160

Merged
Schamper merged 1 commit into
mainfrom
add-cdef
Jul 13, 2026
Merged

Add method to dump C definition#160
Schamper merged 1 commit into
mainfrom
add-cdef

Conversation

@Schamper

@Schamper Schamper commented Jul 8, 2026

Copy link
Copy Markdown
Member

Closes #153

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 89 lines in your changes missing coverage. Please review.
✅ Project coverage is 0.00%. Comparing base (0191708) to head (351b5f1).

Files with missing lines Patch % Lines
dissect/cstruct/types/structure.py 0.00% 60 Missing ⚠️
dissect/cstruct/cstruct.py 0.00% 19 Missing ⚠️
dissect/cstruct/types/enum.py 0.00% 10 Missing ⚠️
Additional details and impacted files
@@          Coverage Diff          @@
##            main    #160   +/-   ##
=====================================
  Coverage   0.00%   0.00%           
=====================================
  Files         22      22           
  Lines       2611    2700   +89     
=====================================
- Misses      2611    2700   +89     
Flag Coverage Δ
unittests 0.00% <0.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codspeed-hq

codspeed-hq Bot commented Jul 8, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 14 untouched benchmarks


Comparing add-cdef (351b5f1) with main (0191708)

Open in CodSpeed

@Schamper
Schamper requested a review from Miauwkeru July 9, 2026 11:07
@Miauwkeru

Copy link
Copy Markdown
Contributor

after some initial checks, i got one remark. It doesn´t seem it shows the #defines while those defines are use by name inside expressions.
e,g it returns the following struct:

struct _IMAGE_ENCLAVE_CONFIG64 {
    uint32 Size;
    uint32 MinimumRequiredConfigSize;
    uint32 PolicyFlags;
    uint32 NumberOfImports;
    uint32 ImportList;
    uint32 ImportEntrySize;
    uint8 FamilyID[IMAGE_ENCLAVE_SHORT_ID_LENGTH];
    uint8 ImageID[IMAGE_ENCLAVE_SHORT_ID_LENGTH];
    uint32 ImageVersion;
    uint32 SecurityVersion;
    uint64 EnclaveSize;
    uint32 NumberOfThreads;
    uint32 EnclaveFlags;
};

but IMAGE_ENCLAVE_SHORT_ID_LENGTH does not get returned.

@Schamper

Copy link
Copy Markdown
Member Author

@Miauwkeru can you post a complete example? Because in your example that's not how constants work in cstruct, those should be eagerly resolved to whatever value the constant has (so uint8 FamilyID[16]; for example).

I did add support for resolving dependencies on dynamic expressions. For example Size * IMAGE_ENCLAVE_SHORT_ID_LENGTH.

@Miauwkeru

Miauwkeru commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@Miauwkeru can you post a complete example? Because in your example that's not how constants work in cstruct, those should be eagerly resolved to whatever value the constant has (so uint8 FamilyID[16]; for example).

I did add support for resolving dependencies on dynamic expressions. For example Size * IMAGE_ENCLAVE_SHORT_ID_LENGTH.

I just used it in the result of using cdef() on c_pe.py in dissect.executable, after using this patch to make it cstruct compatible.
Then you can look for some specific structs such as _IMAGE_ENCLAVE_CONFIG32 or _IMAGE_ENCLAVE_CONFIG64 where the define name is used instead of the resolved value.

diff --git a/dissect/executable/pe/c_pe.py b/dissect/executable/pe/c_pe.py
index 777a500..234bba2 100644
--- a/../../../dissect.executable/dissect/executable/pe/c_pe.py
+++ b/c_pe.py
@@ -139,7 +139,7 @@ flag IMAGE_FILE : USHORT {
     AGGRESSIVE_WS_TRIM          = 0x0010,       // Agressively trim working set
     LARGE_ADDRESS_AWARE         = 0x0020,       // App can handle >2gb addresses
     BYTES_REVERSED_LO           = 0x0080,       // Bytes of machine word are reversed.
-    32BIT_MACHINE               = 0x0100,       // 32 bit word machine.
+    _32BIT_MACHINE               = 0x0100,       // 32 bit word machine.
     DEBUG_STRIPPED              = 0x0200,       // Debugging info stripped from file in .DBG file
     REMOVABLE_RUN_FROM_SWAP     = 0x0400,       // If Image is on removable media, copy and run from the swap file.
     NET_RUN_FROM_SWAP           = 0x0800,       // If Image is on Net, copy and run from the swap file.
@@ -493,9 +493,9 @@ typedef struct _IMAGE_BASE_RELOCATION {
 //
 
 #define IMAGE_ARCHIVE_START_SIZE             8
-#define IMAGE_ARCHIVE_START                  b"!<arch>\n"
-#define IMAGE_ARCHIVE_END                    b"`\n"
-#define IMAGE_ARCHIVE_PAD                    b"\n"
+#define IMAGE_ARCHIVE_START                  b"!<arch>\\n"
+#define IMAGE_ARCHIVE_END                    b"`\\n"
+#define IMAGE_ARCHIVE_PAD                    b"\\n"
 #define IMAGE_ARCHIVE_LINKER_MEMBER          b"/               "
 #define IMAGE_ARCHIVE_LONGNAMES_MEMBER       b"//              "
 
@@ -913,16 +913,16 @@ enum VK {
  * VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A)
  */
 
-    0                           = 0x30,
-    1                           = 0x31,
-    2                           = 0x32,
-    3                           = 0x33,
-    4                           = 0x34,
-    5                           = 0x35,
-    6                           = 0x36,
-    7                           = 0x37,
-    8                           = 0x38,
-    9                           = 0x39,
+    _0                           = 0x30,
+    _1                           = 0x31,
+    _2                           = 0x32,
+    _3                           = 0x33,
+    _4                           = 0x34,
+    _5                           = 0x35,
+    _6                           = 0x36,
+    _7                           = 0x37,
+    _8                           = 0x38,
+    _9                           = 0x39,
     A                           = 0x41,
     B                           = 0x42,
     C                           = 0x43,
@@ -2144,12 +2144,12 @@ typedef struct IMPORT_OBJECT_HEADER {
 // COM+ Header entry point flags.
 flag COMIMAGE_FLAGS : ULONG {
     ILONLY                      = 0x00000001,
-    32BITREQUIRED               = 0x00000002,
+    _32BITREQUIRED               = 0x00000002,
     IL_LIBRARY                  = 0x00000004,
     STRONGNAMESIGNED            = 0x00000008,
     NATIVE_ENTRYPOINT           = 0x00000010,
     TRACKDEBUGDATA              = 0x00010000,
-    32BITPREFERRED              = 0x00020000
+    _32BITPREFERRED              = 0x00020000
 };
 
 // Version flags for image.

@Schamper

Copy link
Copy Markdown
Member Author

Can you point to anything specific in this PR that's causing a break?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “dump back to C-style definitions” capability for cstruct and its parsed types, addressing issue #153 by enabling round-trippable C definitions to be emitted from parsed structures/enums/unions/flags.

Changes:

  • Add cstruct.cdef() to emit all known definitions (constants, structs/unions, enums/flags, and relevant typedefs).
  • Add cdef() on enum/flag metatypes and on structure/union metatypes (with optional recursive dependency emission).
  • Add comprehensive tests covering structs, unions, enums, flags, recursive emission, and round-trip parsing.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_basic.py Adds end-to-end tests for cstruct.cdef() and define round-tripping.
tests/test_types_enum.py Adds Enum.cdef() rendering test coverage.
tests/test_types_flag.py Adds Flag.cdef() rendering test coverage.
tests/test_types_structure.py Adds extensive Structure.cdef() tests, including recursion and round-trip parsing.
tests/test_types_union.py Adds Union.cdef() rendering test coverage.
dissect/cstruct/types/structure.py Implements StructureMetaType.cdef() for structs/unions (and recursive emission).
dissect/cstruct/types/enum.py Implements EnumMetaType.cdef() for enums/flags.
dissect/cstruct/cstruct.py Implements cstruct.cdef() to emit all known definitions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread dissect/cstruct/cstruct.py
Comment thread dissect/cstruct/types/structure.py Outdated
Comment thread dissect/cstruct/types/structure.py Outdated
@Miauwkeru

Copy link
Copy Markdown
Contributor

Can you point to anything specific in this PR that's causing a break?

In this PR not specifically. I did figure out the issue i saw. But that was related to the define it was referencing ENCLAVE_LONG_ID_LENGTH not being defined, so the expression referenced a string.
So it might be a good validation to check whether an expression in an array resolves to an int and fails otherwise in a different pr.

I'll make an issue for it.

@Schamper
Schamper merged commit 0edfc10 into main Jul 13, 2026
24 checks passed
@Schamper
Schamper deleted the add-cdef branch July 13, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add feature to print C definition with dissect.cstruct

3 participants