use crate::metadata::token::Token;
pub mod reflection {
use crate::metadata::token::Token;
pub const TYPE: Token = Token::new(0x7F00_0001);
pub const METHOD: Token = Token::new(0x7F00_0002);
pub const MODULE: Token = Token::new(0x7F00_0003);
pub const FIELD: Token = Token::new(0x7F00_0004);
pub const PROPERTY: Token = Token::new(0x7F00_0005);
pub const PARAMETER: Token = Token::new(0x7F00_0013);
pub const METHOD_BODY: Token = Token::new(0x7F00_0015);
pub const CUSTOM_ATTRIBUTE_DATA: Token = Token::new(0x7F00_0020);
pub const ASSEMBLY_NAME: Token = Token::new(0x7F00_0014);
}
pub mod crypto {
use crate::metadata::token::Token;
pub const KEY_DERIVATION: Token = Token::new(0x7F00_0007);
pub const CRYPTO_ALGORITHM: Token = Token::new(0x7F00_1004);
pub const SYMMETRIC_ALGORITHM: Token = Token::new(0x7F00_1005);
pub const CRYPTO_TRANSFORM: Token = Token::new(0x7F00_1006);
}
pub mod io {
use crate::metadata::token::Token;
pub const STREAM: Token = Token::new(0x7F00_0008);
pub const CRYPTO_STREAM: Token = Token::new(0x7F00_0009);
pub const COMPRESSED_STREAM: Token = Token::new(0x7F00_0017);
}
pub mod collections {
use crate::metadata::token::Token;
pub const DICTIONARY: Token = Token::new(0x7F00_000D);
pub const LIST: Token = Token::new(0x7F00_000E);
pub const STACK: Token = Token::new(0x7F00_0010);
pub const QUEUE: Token = Token::new(0x7F00_0011);
pub const HASH_SET: Token = Token::new(0x7F00_0012);
pub const ENUMERATOR: Token = Token::new(0x7F00_0030);
}
pub mod codegen {
use crate::metadata::token::Token;
pub const DYNAMIC_METHOD: Token = Token::new(0x7F00_000A);
pub const IL_GENERATOR: Token = Token::new(0x7F00_000B);
}
pub mod system {
use crate::metadata::token::Token;
pub const STRING: Token = Token::new(0x7F00_1001);
pub const ARRAY: Token = Token::new(0x7F00_1002);
pub const ENCODING: Token = Token::new(0x7F00_1003);
pub const STRING_BUILDER: Token = Token::new(0x7F00_000F);
pub const THREAD: Token = Token::new(0x7F00_0016);
pub const TASK: Token = Token::new(0x7F00_0021);
pub const SPAN: Token = Token::new(0x7F00_0022);
pub const MEMORY: Token = Token::new(0x7F00_0023);
pub const TYPED_REFERENCE: Token = Token::new(0x7F00_0024);
pub const OPCODE: Token = Token::new(0x7F00_0025);
pub const PROCESS: Token = Token::new(0x7F00_0026);
pub const PROCESS_MODULE: Token = Token::new(0x7F00_0027);
}
pub mod singletons {
use crate::metadata::token::Token;
pub const ASSEMBLY: Token = Token::new(0x7F00_00F0);
pub const APP_DOMAIN: Token = Token::new(0x7F00_00F1);
}
pub mod native {
use crate::metadata::token::Token;
pub const RANGE_BASE: u32 = 0x7F03_0000;
pub const NATIVE_FUNCTION_POINTER: Token = Token::new(RANGE_BASE | 0x0001);
#[must_use]
pub const fn token_for_id(id: u32) -> Token {
Token::new(RANGE_BASE | id)
}
}
pub mod native_addresses {
pub const CURRENT_MODULE: i64 = 0x0040_0000;
pub const OTHER_MODULE: i64 = 0x7FFE_0000;
pub const LOADED_LIBRARY: i64 = 0x7FFE_2000;
pub const PROC_ADDRESS_BASE: u64 = 0x7FFD_0000;
pub const PROC_ADDRESS_PAGE: u64 = 0x1000;
pub const DELEGATE_FUNCTION_POINTER_FALLBACK: i64 = 0x7FFC_0000;
}
pub mod helpers {
use crate::metadata::token::Token;
pub const LIST_ENUMERATOR: Token = Token::new(0x7FFF_0001);
pub const RNG: Token = Token::new(0x7FFF_0010);
}
pub mod exception_fields {
use crate::metadata::token::Token;
pub const MESSAGE: Token = Token::new(0xEF00_0010);
pub const INNER_EXCEPTION: Token = Token::new(0xEF00_0011);
pub const HRESULT: Token = Token::new(0xEF00_0012);
pub const SOURCE: Token = Token::new(0xEF00_0013);
}
pub mod enumerator_fields {
use crate::metadata::token::Token;
pub const LIST_REF: Token = Token::new(0xEF00_0001);
pub const POSITION: Token = Token::new(0xEF00_0002);
}
pub mod rng_fields {
use crate::metadata::token::Token;
pub const STATE: Token = Token::new(0xEF00_FF01);
}
pub mod attribute_fields {
use crate::metadata::token::Token;
pub const INTERFACE_TYPE: Token = Token::new(0x7F04_0001);
pub const INTERFACE_METHODS: Token = Token::new(0x7F04_0002);
pub const TARGET_METHODS: Token = Token::new(0x7F04_0003);
}
pub mod io_fields {
use crate::metadata::token::Token;
pub const BINARY_READER_STREAM: Token = Token::new(0xFFFF_0001);
pub const BINARY_WRITER_STREAM: Token = Token::new(0xFFFF_0002);
pub const FILEINFO_PATH: Token = Token::new(0xFFFF_0020);
pub const STREAMREADER_STREAM: Token = Token::new(0xFFFF_0030);
}
pub mod span_fields {
use crate::metadata::token::Token;
pub const SPAN_ARRAY: Token = Token::new(0x7F04_0022);
pub const MEMORY_ARRAY: Token = Token::new(0x7F04_0023);
}
pub mod misc_fields {
use crate::metadata::token::Token;
pub const STACKFRAME_METHOD: Token = Token::new(0x04FF_0001);
pub const ASSEMBLY_NAME_NAME: Token = Token::new(0x04FF_0010);
pub const OPCODE_VALUE: Token = Token::new(0x7F00_0E01);
}
pub mod process_fields {
use crate::metadata::token::Token;
pub const MAIN_MODULE: Token = Token::new(0xEF00_0020);
pub const FILE_NAME: Token = Token::new(0xEF00_0021);
pub const BASE_ADDRESS: Token = Token::new(0xEF00_0022);
pub const MODULE_MEMORY_SIZE: Token = Token::new(0xEF00_0023);
pub const MODULE_NAME: Token = Token::new(0xEF00_0024);
}
pub mod ranges {
pub const SYNTHETIC_METHOD_BASE: u32 = 0x7F02_0000;
pub const SYNTHETIC_METHOD_MASK: u32 = 0xFFFF_0000;
pub const GENERIC_INSTANTIATION_BASE: u32 = 0xF100_0000;
pub const GENERIC_INSTANTIATION_MASK: u32 = 0xFF00_0000;
pub const SZARRAY_PRIMITIVE_BASE: u32 = 0xF000_0100;
pub const SZARRAY_PRIMITIVE_MASK: u32 = 0xFFFF_FF00;
}
#[must_use]
pub fn is_exception_type(token: Token) -> bool {
token.value() & 0xFFFF_0000 == 0x7F01_0000
}
#[must_use]
pub fn is_heap_type(token: Token) -> bool {
token.value() & 0xFFFF_0000 == 0x7F00_0000
}
#[must_use]
pub fn is_helper_type(token: Token) -> bool {
token.value() & 0xFFFF_0000 == 0x7FFF_0000
}
#[must_use]
pub fn is_synthetic_method(token: Token) -> bool {
token.value() & ranges::SYNTHETIC_METHOD_MASK == ranges::SYNTHETIC_METHOD_BASE
}
#[must_use]
pub fn is_native_function_pointer(token: Token) -> bool {
token.value() & 0xFFFF_0000 == native::RANGE_BASE
}
#[must_use]
pub fn is_generic_instantiation(token: Token) -> bool {
token.value() & ranges::GENERIC_INSTANTIATION_MASK == ranges::GENERIC_INSTANTIATION_BASE
}
#[must_use]
pub fn is_szarray_primitive(token: Token) -> bool {
token.value() & ranges::SZARRAY_PRIMITIVE_MASK == ranges::SZARRAY_PRIMITIVE_BASE
}
#[must_use]
pub fn szarray_element_token(token: Token) -> Option<Token> {
if !is_szarray_primitive(token) {
return None;
}
let kind_id = token.value() & 0xFF;
Some(Token::new(0xF000_0000 | kind_id))
}
#[must_use]
pub fn is_synthetic(token: Token) -> bool {
let table = token.value() >> 24;
matches!(table, 0x7F | 0xEF | 0xF1 | 0xFF)
}
#[cfg(test)]
mod tests {
use crate::{
emulation::{
synthetic_exception,
tokens::{
self, codegen, collections, crypto, helpers, io, io_fields, native, ranges,
reflection, singletons, system,
},
},
metadata::token::Token,
};
#[test]
fn exception_type_detection() {
assert!(tokens::is_exception_type(
synthetic_exception::BASE_EXCEPTION
));
assert!(tokens::is_exception_type(
synthetic_exception::NULL_REFERENCE
));
assert!(tokens::is_exception_type(
synthetic_exception::NOT_IMPLEMENTED
));
assert!(!tokens::is_exception_type(reflection::TYPE));
assert!(!tokens::is_exception_type(Token::new(0x0200_0001)));
}
#[test]
fn heap_type_detection() {
assert!(tokens::is_heap_type(reflection::TYPE));
assert!(tokens::is_heap_type(system::STRING));
assert!(tokens::is_heap_type(singletons::ASSEMBLY));
assert!(!tokens::is_heap_type(helpers::LIST_ENUMERATOR));
assert!(!tokens::is_heap_type(Token::new(0x7F01_0000)));
}
#[test]
fn helper_type_detection() {
assert!(tokens::is_helper_type(helpers::LIST_ENUMERATOR));
assert!(tokens::is_helper_type(helpers::RNG));
assert!(!tokens::is_helper_type(reflection::TYPE));
}
#[test]
fn synthetic_method_detection() {
assert!(tokens::is_synthetic_method(Token::new(
ranges::SYNTHETIC_METHOD_BASE | 1
)));
assert!(tokens::is_synthetic_method(Token::new(
ranges::SYNTHETIC_METHOD_BASE | 0xFFFF
)));
assert!(!tokens::is_synthetic_method(reflection::TYPE));
}
#[test]
fn native_function_pointer_detection() {
assert!(tokens::is_native_function_pointer(
native::NATIVE_FUNCTION_POINTER
));
assert!(tokens::is_native_function_pointer(Token::new(0x7F03_0002)));
assert!(!tokens::is_native_function_pointer(reflection::TYPE));
assert!(!tokens::is_native_function_pointer(Token::new(
ranges::SYNTHETIC_METHOD_BASE | 1
)));
}
#[test]
fn generic_instantiation_detection() {
assert!(tokens::is_generic_instantiation(Token::new(
ranges::GENERIC_INSTANTIATION_BASE | 42
)));
assert!(!tokens::is_generic_instantiation(reflection::TYPE));
}
#[test]
fn is_synthetic_covers_all_ranges() {
assert!(tokens::is_synthetic(reflection::TYPE));
assert!(tokens::is_synthetic(helpers::LIST_ENUMERATOR));
assert!(tokens::is_synthetic(Token::new(
ranges::SYNTHETIC_METHOD_BASE | 1
)));
assert!(tokens::is_synthetic(Token::new(0x7F04_0001)));
assert!(tokens::is_synthetic(native::NATIVE_FUNCTION_POINTER));
assert!(tokens::is_synthetic(Token::new(0xEF00_0010)));
assert!(tokens::is_synthetic(Token::new(
ranges::GENERIC_INSTANTIATION_BASE | 1
)));
assert!(tokens::is_synthetic(io_fields::BINARY_READER_STREAM));
assert!(tokens::is_synthetic(io_fields::FILEINFO_PATH));
assert!(!tokens::is_synthetic(Token::new(0x0200_0001)));
assert!(!tokens::is_synthetic(Token::new(0x0600_0001)));
}
#[test]
fn no_value_collisions_within_type_tokens() {
let type_tokens = [
reflection::TYPE,
reflection::METHOD,
reflection::MODULE,
reflection::FIELD,
reflection::PROPERTY,
reflection::PARAMETER,
reflection::METHOD_BODY,
reflection::CUSTOM_ATTRIBUTE_DATA,
reflection::ASSEMBLY_NAME,
crypto::KEY_DERIVATION,
crypto::CRYPTO_ALGORITHM,
crypto::SYMMETRIC_ALGORITHM,
crypto::CRYPTO_TRANSFORM,
io::STREAM,
io::CRYPTO_STREAM,
io::COMPRESSED_STREAM,
collections::DICTIONARY,
collections::LIST,
collections::STACK,
collections::QUEUE,
collections::HASH_SET,
codegen::DYNAMIC_METHOD,
codegen::IL_GENERATOR,
system::STRING,
system::ARRAY,
system::ENCODING,
system::STRING_BUILDER,
system::THREAD,
system::TASK,
system::SPAN,
system::MEMORY,
system::PROCESS,
system::PROCESS_MODULE,
singletons::ASSEMBLY,
singletons::APP_DOMAIN,
helpers::LIST_ENUMERATOR,
helpers::RNG,
];
for (i, a) in type_tokens.iter().enumerate() {
for (j, b) in type_tokens.iter().enumerate() {
if i != j {
assert_ne!(
a.value(),
b.value(),
"collision between type_tokens[{i}] (0x{:08X}) and type_tokens[{j}] (0x{:08X})",
a.value(),
b.value()
);
}
}
}
}
}