0

I am trying to write a test app that unmarshals a binary blob. The blob is generated by a low-level h/w interface. Based on the c header I found that the binary blob is defined in this way,

typedef struct Report { uint32_t SnpVersion; uint32_t SnpGuestSvn; union { uint64_t ModelVer_t; struct { uint64_t AbiMinor:8; uint64_t AbiMajor:8; uint64_t TTAllowed:1; uint64_t RrvdTrue:1; uint64_t MigrateTTAllowed:1; uint64_t DebugAllowed:1; uint64_t RrvdFalse:44; } TuneConfig; } TunePolicy; union { uint64_t Asuint64_t; struct { uint64_t TTEnabled:1; uint64_t RRvd:63; } ChannelConfig; } ChannelPolicy; uint8_t PolicyDigest[48]; } 

I need to do unmarshalling of the binary blob in c#. Based on the ref at this link, https://learn.microsoft.com/en-us/dotnet/framework/interop/marshalling-classes-structures-and-unions, I should be able to generate it. However, I am still not sure about the syntax of representing the AbiMinor:8; The reserved bits in managed code.

1

1 Answer 1

2

The way to represent the reserved bits is through the [StructLayout] and [FieldOffset] attributes applied to to the fields of a struct. However ... this union has several fields that are less than a byte, so I'd recommend not doing that at all because [FieldOffset] is in units of whole bytes, so you're not buying yourself anything by trying to replicate this union.

If you're going to marshal a struct, then just use primitives of the appropriate size and write code to get at the underlying values.

[StructLayout(LayoutKind.Sequential)] public struct ReportManaged { // the actual fields of the struct private readonly uint SnpVersion; private readonly uint SnpGuestSvn; private readonly ulong TunePolicyUnion; private readonly ulong ChannelPolicyUnion; private fixed byte[48] PolicyDigest; // properties to access the struct's data public ulong ModelVer => TunePolicy; public byte TuneConfig_AbiMinor => //most significant byte of TunePolicyUnion public byte TuneConfig_AbiMajor => //2nd most significant byte of TunePolicyUnion public bool TuneConfig_TTAllowed => //17th bit of TunePolicyUnion public bool TuneConfig_RvrdTrue => //18th bit of TunePolicyUnion public bool TuneConfig_MigrateTTAllowed => //19th bit of TunePolicyUnion public bool TuneConfig_DebugAllowed => //20th bit of TunePolicyUnion public bool TuneConfig_RrvdFalse => //rest of TunePolicyUnion public ulong ChannelPolicy_AsUInt64 => ChannelPolicyUnion; public bool ChannelConfig_TTEnabled => //most significant byte of ChannelPolicyUnion public ulong ChannelConfig_RRvd => //rest of ChannelPolicyUnion } 

Another option, and the one I prefer to use myself for this sort of thing, is to marshal the Report over simply as a byte array then read it like it's a stream, building a C# object as you go along. The union defines a message format. Each message starts with a 32-bit SnpVersion and a 32-bit SnpGuestSvn, and then it has either a 64-bit Model Version or a Tune Config, and then a 64-bit field or a ChannelConfig, and it always ends with 48 bytes of data.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.