Struct MethodBody
pub struct MethodBody {
pub size_code: usize,
pub size_header: usize,
pub local_var_sig_token: u32,
pub max_stack: usize,
pub is_fat: bool,
pub is_init_local: bool,
pub is_exception_data: bool,
pub exception_handlers: Vec<ExceptionHandler>,
}Expand description
Describes one method that has been compiled to CIL bytecode.
The MethodBody struct represents the parsed body of a .NET method, including header information,
code size, stack requirements, local variable signature, and exception handling regions.
§Header Format Detection
The structure automatically detects whether the method uses a tiny or fat header format based on the first byte(s) of the method body data:
- Tiny Format: Single byte header for methods with ≤63 bytes of code
- Fat Format: 12-byte header for complex methods with extensive metadata
§Field Organization
§Size Information
Self::size_code: Length of the actual CIL instructions in bytesSelf::size_header: Length of the method header (1 for tiny, 12+ for fat)
§Stack and Variables
Self::max_stack: Maximum operand stack depth during executionSelf::local_var_sig_token: Metadata token for local variable type signatureSelf::is_init_local: Whether local variables are zero-initialized
§Format and Features
Self::is_fat: Whether this method uses the fat header formatSelf::is_exception_data: Whether exception handling data is presentSelf::exception_handlers: Collection of exception handling regions
§Memory Layout
Tiny Header (1 byte):
┌─────────────────────────────────────┐
│ Size(6) │ Reserved(2) │ Format(2) │
└─────────────────────────────────────┘
Fat Header (12 bytes):
┌─────────────────────────────────────┐
│ Flags(12) │ Size(4) │ Format(2) │ (bytes 0-1)
├─────────────────────────────────────┤
│ MaxStack (16 bits) │ (bytes 2-3)
├─────────────────────────────────────┤
│ CodeSize (32 bits) │ (bytes 4-7)
├─────────────────────────────────────┤
│ LocalVarSigTok (32 bits) │ (bytes 8-11)
└─────────────────────────────────────┘§Thread Safety
MethodBody is fully thread-safe:
- All fields are immutable after construction
- No interior mutability or shared state
- Safe to share across threads without synchronization
Fields§
§size_code: usizeSize of the method code (length of all CIL instructions, excluding the header) in bytes
size_header: usizeSize of the method header in bytes (1 for tiny format, 12+ for fat format)
local_var_sig_token: u32Metadata token for a signature describing the layout of local variables (0 = no locals)
max_stack: usizeMaximum number of items on the operand stack during method execution
is_fat: boolFlag indicating the method header format (false = tiny, true = fat)
is_init_local: boolFlag indicating whether to zero-initialize all local variables before method execution
is_exception_data: boolFlag indicating whether this method has exception handling data sections
exception_handlers: Vec<ExceptionHandler>Collection of exception handlers for this method (empty if no exception handling)
Implementations§
§impl MethodBody
impl MethodBody
pub fn from(data: &[u8]) -> Result<MethodBody>
pub fn from(data: &[u8]) -> Result<MethodBody>
Create a MethodBody object from a sequence of bytes.
Parses a complete .NET method body including header, CIL instructions, and optional exception handling sections. Automatically detects and handles both tiny and fat header formats according to ECMA-335 specifications.
§Arguments
data- The byte slice containing the complete method body data, starting with the method header and including all CIL instructions and exception handling sections
§Returns
Ok- Successfully parsed method body with all metadataErr- Parsing failed due to invalid format, insufficient data, or corruption
§Errors
This method returns an error in the following cases:
- Empty Data: The provided byte slice is empty
- Invalid Format: Header format bits don’t match tiny or fat patterns
- Insufficient Data: Not enough bytes for the declared header or code size
- Malformed Sections: Exception handling sections have invalid structure
§Examples
use dotscope::metadata::method::MethodBody;
let method_data = &[0x16, 0x00, 0x2A]; // Simple method: ldarg.0, ret
let body = MethodBody::from(method_data)?;
assert!(!body.is_fat);pub fn from_lenient(data: &[u8]) -> Result<(MethodBody, usize)>
pub fn from_lenient(data: &[u8]) -> Result<(MethodBody, usize)>
Create a MethodBody from bytes, filtering out invalid exception handlers.
This is useful for parsing method bodies with malformed exception handlers (e.g., injected by BitMono’s AntiDecompiler) where the handler offsets are garbage but the method header and IL code are valid. Invalid handlers are logged and skipped; only valid handlers are kept.
§Arguments
data- The byte slice containing the complete method body data
§Returns
pub fn from_raw(data: &[u8]) -> Result<MethodBody>
pub fn from_raw(data: &[u8]) -> Result<MethodBody>
pub fn size(&self) -> usize
pub fn size(&self) -> usize
Get the total serialized size including header, code, and exception handlers.
This calculates the complete size of the method body as it appears in the assembly file, including:
- Method header (1 byte for tiny, 12 bytes for fat)
- IL code bytes
- 4-byte alignment padding (for fat format with exception handlers)
- Exception handler sections
§Returns
The total serialized size in bytes.
pub fn write_to<W: Write>(&self, writer: &mut W, il_code: &[u8]) -> Result<u64>
pub fn write_to<W: Write>(&self, writer: &mut W, il_code: &[u8]) -> Result<u64>
Writes the method body to a writer.
Serializes the method header (tiny or fat format), IL code, and exception handlers directly to the provided writer. This avoids intermediate buffers for efficient streaming output.
§Arguments
writer- Any type implementingstd::io::Writeil_code- The IL bytecode for the method
§Returns
The total number of bytes written (header + code + exception handlers + padding).
§Format Selection
The format is automatically determined based on method characteristics:
- Tiny Format: Used when code size ≤ 63 bytes, no local variables, and no exceptions
- Fat Format: Used for all other methods
§Examples
use dotscope::metadata::method::MethodBody;
let body = MethodBody {
size_code: 2,
size_header: 1,
local_var_sig_token: 0,
max_stack: 8,
is_fat: false,
is_init_local: false,
is_exception_data: false,
exception_handlers: vec![],
};
let il_code = vec![0x17, 0x2A]; // ldc.i4.1, ret
let mut buffer = Vec::new();
let bytes_written = body.write_to(&mut buffer, &il_code)?;
assert_eq!(bytes_written, 3); // 1-byte header + 2-byte code§Errors
Returns an error if writing to the writer fails or if the method body parameters are invalid (e.g., code size exceeds limits).
Auto Trait Implementations§
impl Freeze for MethodBody
impl RefUnwindSafe for MethodBody
impl Send for MethodBody
impl Sync for MethodBody
impl Unpin for MethodBody
impl UnsafeUnpin for MethodBody
impl UnwindSafe for MethodBody
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for T
impl<T> Downcast for T
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.