use core::{fmt, marker::PhantomData, mem::MaybeUninit, slice};
use std::{
ffi::CStr,
os::raw::{c_char, c_void},
};
use super::{
enums::*,
status::{Result, Status},
};
#[rustfmt::skip]
pub type FormatterFunc = Option<unsafe extern "C" fn(
*const ZydisFormatter,
*mut FormatterBuffer,
*mut FormatterContext) -> Status>;
#[rustfmt::skip]
pub type FormatterDecoratorFunc = Option<unsafe extern "C" fn(
*const ZydisFormatter,
*mut FormatterBuffer,
*mut FormatterContext,
Decorator) -> Status>;
#[rustfmt::skip]
pub type FormatterRegisterFunc = Option<unsafe extern "C" fn(
*const ZydisFormatter,
*mut FormatterBuffer,
*mut FormatterContext,
Register) -> Status>;
pub type RegisterWidth = u16;
#[derive(Debug)]
#[repr(C, packed)]
pub struct FormatterToken<'a> {
ty: Token,
next: u8,
_p: PhantomData<&'a ()>,
}
impl<'a> FormatterToken<'a> {
#[inline]
pub fn get_value(&self) -> Result<(Token, &'a str)> {
unsafe {
let mut ty = MaybeUninit::uninit();
let mut val = MaybeUninit::uninit();
check!(ZydisFormatterTokenGetValue(
self,
ty.as_mut_ptr(),
val.as_mut_ptr()
))?;
let val = CStr::from_ptr(val.assume_init() as *const _)
.to_str()
.map_err(|_| Status::NotUTF8)?;
Ok((ty.assume_init(), val))
}
}
#[inline]
pub fn next(&self) -> Result<&'a Self> {
unsafe {
let mut res = self as *const _;
check!(ZydisFormatterTokenNext(&mut res))?;
if res.is_null() {
Err(Status::User)
} else {
Ok(&*res)
}
}
}
}
impl<'a> IntoIterator for &'a FormatterToken<'a> {
type IntoIter = FormatterTokenIterator<'a>;
type Item = (Token, &'a str);
fn into_iter(self) -> Self::IntoIter {
FormatterTokenIterator { next: Some(self) }
}
}
pub struct FormatterTokenIterator<'a> {
next: Option<&'a FormatterToken<'a>>,
}
impl<'a> Iterator for FormatterTokenIterator<'a> {
type Item = (Token, &'a str);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let res = self.next;
self.next = self.next.and_then(|x| x.next().ok());
res.and_then(|x| x.get_value().ok())
}
}
#[derive(Debug)]
#[repr(C)]
pub struct FormatterBuffer {
is_token_list: bool,
capacity: usize,
string: ZyanString,
}
impl FormatterBuffer {
#[inline]
pub fn get_string(&mut self) -> Result<&mut ZyanString> {
unsafe {
let mut str = MaybeUninit::uninit();
check!(ZydisFormatterBufferGetString(self, str.as_mut_ptr()))?;
let str = str.assume_init();
if str.is_null() {
Err(Status::User)
} else {
Ok(&mut *str)
}
}
}
#[inline]
pub fn get_token(&self) -> Result<&FormatterToken<'_>> {
unsafe {
let mut res = MaybeUninit::uninit();
check!(
ZydisFormatterBufferGetToken(self, res.as_mut_ptr()),
&*res.assume_init()
)
}
}
#[inline]
pub fn append(&mut self, token: Token) -> Result<()> {
unsafe { check!(ZydisFormatterBufferAppend(self, token)) }
}
#[inline]
pub fn remember(&self) -> Result<FormatterBufferState> {
unsafe {
let mut res = MaybeUninit::uninit();
check!(
ZydisFormatterBufferRemember(self, res.as_mut_ptr()),
res.assume_init()
)
}
}
#[inline]
pub fn restore(&mut self, state: FormatterBufferState) -> Result<()> {
unsafe { check!(ZydisFormatterBufferRestore(self, state)) }
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(transparent)]
pub struct FormatterBufferState(usize);
#[derive(Debug)]
#[repr(C)]
pub struct ZyanString {
flags: u8,
vector: ZyanVector,
}
impl ZyanString {
#[inline]
pub fn new(buffer: &mut [u8]) -> Result<Self> {
Self::new_ptr(buffer.as_mut_ptr(), buffer.len())
}
#[inline]
pub fn new_ptr(buffer: *mut u8, capacity: usize) -> Result<Self> {
unsafe {
let mut string = MaybeUninit::uninit();
check!(ZyanStringInitCustomBuffer(
string.as_mut_ptr(),
buffer as *mut i8,
capacity
))?;
Ok(string.assume_init())
}
}
#[inline]
pub fn append<S: AsRef<str> + ?Sized>(&mut self, s: &S) -> Result<()> {
unsafe {
let bytes = s.as_ref().as_bytes();
let view = ZyanStringView::new(bytes)?;
check!(ZyanStringAppend(self, &view))
}
}
}
impl fmt::Write for ZyanString {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.append(s).map_err(|_| fmt::Error)
}
}
#[derive(Debug)]
#[repr(C)]
pub struct ZyanStringView {
string: ZyanString,
}
impl ZyanStringView {
#[inline]
pub fn new(buffer: &[u8]) -> Result<Self> {
unsafe {
let mut view = MaybeUninit::uninit();
check!(ZyanStringViewInsideBufferEx(
view.as_mut_ptr(),
buffer.as_ptr() as *const i8,
buffer.len()
))?;
Ok(view.assume_init())
}
}
}
#[derive(Debug)]
#[repr(C)]
struct ZyanVector {
allocator: *mut c_void,
growth_factor: f32,
shrink_threshold: f32,
size: usize,
capacity: usize,
element_size: usize,
destructor: *mut c_void,
data: *mut c_void,
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Decoder {
machine_mode: MachineMode,
address_width: AddressWidth,
decoder_mode: [bool; 9],
}
impl Decoder {
#[inline]
pub fn new(machine_mode: MachineMode, address_width: AddressWidth) -> Result<Self> {
unsafe {
let mut decoder = MaybeUninit::uninit();
check!(
ZydisDecoderInit(decoder.as_mut_ptr(), machine_mode, address_width),
decoder.assume_init()
)
}
}
#[inline]
pub fn enable_mode(&mut self, mode: DecoderMode, value: bool) -> Result<()> {
unsafe { check!(ZydisDecoderEnableMode(self, mode, value as _)) }
}
#[inline]
pub fn decode(&self, buffer: &[u8]) -> Result<Option<DecodedInstruction>> {
unsafe {
let mut instruction = MaybeUninit::uninit();
check_option!(
ZydisDecoderDecodeBuffer(
self,
buffer.as_ptr() as *const c_void,
buffer.len(),
instruction.as_mut_ptr(),
),
instruction.assume_init()
)
}
}
#[inline]
pub fn instruction_iterator<'a, 'b>(
&'a self,
buffer: &'b [u8],
ip: u64,
) -> InstructionIterator<'a, 'b> {
InstructionIterator {
decoder: self,
buffer,
ip,
}
}
}
pub struct InstructionIterator<'a, 'b> {
decoder: &'a Decoder,
buffer: &'b [u8],
ip: u64,
}
impl Iterator for InstructionIterator<'_, '_> {
type Item = (DecodedInstruction, u64);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.decoder.decode(self.buffer) {
Ok(Some(insn)) => {
self.buffer = &self.buffer[insn.length as usize..];
let ip = self.ip;
self.ip += u64::from(insn.length);
Some((insn, ip))
}
_ => None,
}
}
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct DecodedOperand {
pub id: u8,
pub ty: OperandType,
pub visibility: OperandVisibility,
pub action: OperandAction,
pub encoding: OperandEncoding,
pub size: u16,
pub element_type: ElementType,
pub element_size: u16,
pub element_count: u16,
pub reg: Register,
pub mem: MemoryInfo,
pub ptr: PointerInfo,
pub imm: ImmediateInfo,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct MemoryInfo {
pub ty: MemoryOperandType,
pub segment: Register,
pub base: Register,
pub index: Register,
pub scale: u8,
pub disp: DisplacementInfo,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct DisplacementInfo {
pub has_displacement: bool,
pub displacement: i64,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct PointerInfo {
pub segment: u16,
pub offset: u32,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct ImmediateInfo {
pub is_signed: bool,
pub is_relative: bool,
pub value: u64,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct DecodedInstruction {
pub machine_mode: MachineMode,
pub mnemonic: Mnemonic,
pub length: u8,
pub encoding: InstructionEncoding,
pub opcode_map: OpcodeMap,
pub opcode: u8,
pub stack_width: u8,
pub operand_width: u8,
pub address_width: u8,
pub operand_count: u8,
pub operands: [DecodedOperand; 10],
pub attributes: InstructionAttributes,
pub accessed_flags: [CPUFlagAction; 21],
pub avx: AvxInfo,
pub meta: MetaInfo,
pub raw: RawInfo,
}
impl DecodedInstruction {
#[inline]
pub fn calc_absolute_address(&self, address: u64, operand: &DecodedOperand) -> Result<u64> {
unsafe {
let mut addr = 0u64;
check!(
ZydisCalcAbsoluteAddress(self, operand, address, &mut addr),
addr
)
}
}
#[inline]
pub fn calc_absolute_address_ex(
&self,
address: u64,
operand: &DecodedOperand,
context: &RegisterContext,
) -> Result<u64> {
unsafe {
let mut addr = 0u64;
check!(
ZydisCalcAbsoluteAddressEx(self, operand, address, context, &mut addr),
addr
)
}
}
pub fn get_flags(&self, action: CPUFlagAction) -> Result<CPUFlag> {
unsafe {
let mut flags = MaybeUninit::uninit();
check!(
ZydisGetAccessedFlagsByAction(self, action, flags.as_mut_ptr()),
flags.assume_init()
)
}
}
#[inline]
pub fn get_flags_read(&self) -> Result<CPUFlag> {
unsafe {
let mut flags = MaybeUninit::uninit();
check!(
ZydisGetAccessedFlagsRead(self, flags.as_mut_ptr()),
flags.assume_init()
)
}
}
#[inline]
pub fn get_flags_written(&self) -> Result<CPUFlag> {
unsafe {
let mut flags = MaybeUninit::uninit();
check!(
ZydisGetAccessedFlagsWritten(self, flags.as_mut_ptr()),
flags.assume_init()
)
}
}
#[inline]
pub fn get_segments(&self) -> Result<InstructionSegments> {
unsafe {
let mut segments = MaybeUninit::uninit();
check!(
ZydisGetInstructionSegments(self, segments.as_mut_ptr()),
segments.assume_init()
)
}
}
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct AvxInfo {
pub vector_length: u16,
pub mask_mode: MaskMode,
pub mask_reg: Register,
pub broadcast_static: bool,
pub broadcast_mode: BroadcastMode,
pub rounding_mode: RoundingMode,
pub swizzle_mode: SwizzleMode,
pub conversion_mode: ConversionMode,
pub has_sae: bool,
pub has_eviction_hint: bool,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct MetaInfo {
pub category: InstructionCategory,
pub isa_set: ISASet,
pub isa_ext: ISAExt,
pub branch_type: BranchType,
pub exception_class: ExceptionClass,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
#[allow(non_snake_case)]
pub struct RawInfo {
pub prefix_count: u8,
pub prefixes: [Prefix; 15],
pub rex_W: u8,
pub rex_R: u8,
pub rex_X: u8,
pub rex_B: u8,
pub rex_offset: u8,
pub xop_R: u8,
pub xop_X: u8,
pub xop_B: u8,
pub xop_m_mmmm: u8,
pub xop_W: u8,
pub xop_vvvv: u8,
pub xop_L: u8,
pub xop_pp: u8,
pub xop_offset: u8,
pub vex_R: u8,
pub vex_X: u8,
pub vex_B: u8,
pub vex_mmmm: u8,
pub vex_W: u8,
pub vex_vvvv: u8,
pub vex_L: u8,
pub vex_pp: u8,
pub vex_offset: u8,
pub vex_size: u8,
pub evex_R: u8,
pub evex_X: u8,
pub evex_B: u8,
pub evex_R2: u8,
pub evex_mm: u8,
pub evex_W: u8,
pub evex_vvvv: u8,
pub evex_pp: u8,
pub evex_z: u8,
pub evex_L2: u8,
pub evex_L: u8,
pub evex_b: u8,
pub evex_V2: u8,
pub evex_aaa: u8,
pub evex_offset: u8,
pub mvex_R: u8,
pub mvex_X: u8,
pub mvex_B: u8,
pub mvex_R2: u8,
pub mvex_mmmm: u8,
pub mvex_W: u8,
pub mvex_vvvv: u8,
pub mvex_pp: u8,
pub mvex_E: u8,
pub mvex_SSS: u8,
pub mvex_V2: u8,
pub mvex_kkk: u8,
pub mvex_offset: u8,
pub modrm_mod: u8,
pub modrm_reg: u8,
pub modrm_rm: u8,
pub modrm_offset: u8,
pub sib_scale: u8,
pub sib_index: u8,
pub sib_base: u8,
pub sib_offset: u8,
pub disp_value: i64,
pub disp_size: u8,
pub disp_offset: u8,
pub imm: [RawImmediateInfo; 2],
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct RawImmediateInfo {
pub is_signed: bool,
pub is_relative: bool,
pub value: u64,
pub size: u8,
pub offset: u8,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Prefix {
pub ty: PrefixType,
pub value: u8,
}
#[repr(C)]
pub struct RegisterContext {
pub values: [u64; crate::enums::REGISTER_MAX_VALUE + 1],
}
#[derive(Debug)]
#[repr(C)]
pub struct ZydisFormatter {
style: FormatterStyle,
force_memory_size: bool,
force_memory_segment: bool,
force_relative_branches: bool,
force_relative_riprel: bool,
print_branch_size: bool,
detailed_prefixes: bool,
addr_base: NumericBase,
addr_signedness: Signedness,
addr_padding_absolute: Padding,
addr_padding_relative: Padding,
disp_base: NumericBase,
disp_signedness: Signedness,
disp_padding: Padding,
imm_base: NumericBase,
imm_signedness: Signedness,
imm_padding: Padding,
case_prefixes: i32,
case_mnemonic: i32,
case_registers: i32,
case_typecasts: i32,
case_decorators: i32,
hex_uppercase: bool,
number_format: [[ZydisFormatterStringData; 2]; 2],
func_pre_instruction: FormatterFunc,
func_post_instruction: FormatterFunc,
func_format_instruction: FormatterFunc,
func_pre_operand: FormatterFunc,
func_post_operand: FormatterFunc,
func_format_operand_reg: FormatterFunc,
func_format_operand_mem: FormatterFunc,
func_format_operand_ptr: FormatterFunc,
func_format_operand_imm: FormatterFunc,
func_print_mnemonic: FormatterFunc,
func_print_register: FormatterRegisterFunc,
func_print_address_abs: FormatterFunc,
func_print_address_rel: FormatterFunc,
func_print_disp: FormatterFunc,
func_print_imm: FormatterFunc,
func_print_typecast: FormatterFunc,
func_print_segment: FormatterFunc,
func_print_prefixes: FormatterFunc,
func_print_decorator: FormatterDecoratorFunc,
}
#[derive(Debug)]
#[repr(C)]
struct ZydisFormatterStringData {
string: *const ZyanStringView,
string_data: ZyanStringView,
buffer: [c_char; 11],
}
#[derive(Debug)]
#[repr(C)]
pub struct FormatterContext {
pub instruction: *const DecodedInstruction,
pub operand: *const DecodedOperand,
pub runtime_address: u64,
pub user_data: *mut c_void,
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
#[repr(C)]
pub struct InstructionSegments {
pub count: u8,
pub segments: [InstructionSegmentsElement; 9],
}
impl<'a> IntoIterator for &'a InstructionSegments {
type IntoIter = slice::Iter<'a, InstructionSegmentsElement>;
type Item = &'a InstructionSegmentsElement;
fn into_iter(self) -> Self::IntoIter {
(&self.segments[..self.count as usize]).into_iter()
}
}
#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
#[repr(C)]
pub struct InstructionSegmentsElement {
pub ty: InstructionSegment,
pub offset: u8,
pub size: u8,
}
#[repr(C)]
pub struct ShortString {
pub data: *const c_char,
pub size: u8,
}
pub fn get_version() -> (u16, u16, u16, u16) {
let combined_ver = unsafe { ZydisGetVersion() };
let major = ((combined_ver << 0) >> 48) as u16;
let minor = ((combined_ver << 16) >> 48) as u16;
let patch = ((combined_ver << 32) >> 48) as u16;
let build = ((combined_ver << 48) >> 48) as u16;
(major, minor, patch, build)
}
extern "C" {
pub fn ZydisGetVersion() -> u64;
pub fn ZydisIsFeatureEnabled(feature: Feature) -> Status;
pub fn ZydisCalcAbsoluteAddress(
instruction: *const DecodedInstruction,
operand: *const DecodedOperand,
runtime_address: u64,
result_address: *mut u64,
) -> Status;
pub fn ZydisCalcAbsoluteAddressEx(
instruction: *const DecodedInstruction,
operand: *const DecodedOperand,
runtime_address: u64,
register_context: *const RegisterContext,
result_address: *mut u64,
) -> Status;
pub fn ZydisGetAccessedFlagsByAction(
instruction: *const DecodedInstruction,
action: CPUFlagAction,
flags: *mut CPUFlag,
) -> Status;
pub fn ZydisGetAccessedFlagsRead(
instruction: *const DecodedInstruction,
flags: *mut CPUFlag,
) -> Status;
pub fn ZydisGetAccessedFlagsWritten(
instruction: *const DecodedInstruction,
flags: *mut CPUFlag,
) -> Status;
pub fn ZydisGetInstructionSegments(
instruction: *const DecodedInstruction,
segments: *mut InstructionSegments,
) -> Status;
pub fn ZydisDecoderInit(
decoder: *mut Decoder,
machine_mode: MachineMode,
address_width: AddressWidth,
) -> Status;
pub fn ZydisDecoderEnableMode(
decoder: *mut Decoder,
mode: DecoderMode,
enabled: bool,
) -> Status;
pub fn ZydisDecoderDecodeBuffer(
decoder: *const Decoder,
buffer: *const c_void,
length: usize,
instruction: *mut DecodedInstruction,
) -> Status;
pub fn ZydisMnemonicGetString(mnemonic: Mnemonic) -> *const c_char;
pub fn ZydisMnemonicGetShortString(mnemonic: Mnemonic) -> *const ShortString;
pub fn ZydisRegisterEncode(register_class: RegisterClass, id: u8) -> Register;
pub fn ZydisRegisterGetId(regster: Register) -> i8;
pub fn ZydisRegisterGetClass(register: Register) -> RegisterClass;
pub fn ZydisRegisterGetWidth(mode: MachineMode, register: Register) -> RegisterWidth;
pub fn ZydisRegisterGetString(register: Register) -> *const c_char;
pub fn ZydisRegisterGetStringWrapped(register: Register) -> *const ShortString;
pub fn ZydisRegisterGetLargestEnclosing(mode: MachineMode, reg: Register) -> Register;
pub fn ZydisRegisterClassGetWidth(mode: MachineMode, class: RegisterClass) -> RegisterWidth;
pub fn ZydisCategoryGetString(category: InstructionCategory) -> *const c_char;
pub fn ZydisISASetGetString(isa_set: ISASet) -> *const c_char;
pub fn ZydisISAExtGetString(isa_ext: ISAExt) -> *const c_char;
pub fn ZydisFormatterInit(formatter: *mut ZydisFormatter, style: FormatterStyle) -> Status;
pub fn ZydisFormatterSetProperty(
formatter: *mut ZydisFormatter,
property: ZydisFormatterProperty,
value: usize,
) -> Status;
pub fn ZydisFormatterSetHook(
formatter: *mut ZydisFormatter,
hook: FormatterFunction,
callback: *mut *const c_void,
) -> Status;
pub fn ZydisFormatterFormatInstruction(
formatter: *const ZydisFormatter,
instruction: *const DecodedInstruction,
buffer: *mut c_char,
buffer_length: usize,
runtime_address: u64,
) -> Status;
pub fn ZydisFormatterFormatInstructionEx(
formatter: *const ZydisFormatter,
instruction: *const DecodedInstruction,
buffer: *mut c_char,
buffer_length: usize,
runtime_address: u64,
user_data: *mut c_void,
) -> Status;
pub fn ZydisFormatterFormatOperand(
formatter: *const ZydisFormatter,
instruction: *const DecodedInstruction,
operand_index: u8,
buffer: *mut c_char,
buffer_length: usize,
runtime_address: u64,
) -> Status;
pub fn ZydisFormatterFormatOperandEx(
formatter: *const ZydisFormatter,
instruction: *const DecodedInstruction,
operand_index: u8,
buffer: *mut c_char,
buffer_length: usize,
runtime_address: u64,
user_data: *mut c_void,
) -> Status;
pub fn ZydisFormatterTokenizeInstruction(
formatter: *const ZydisFormatter,
instruction: *const DecodedInstruction,
buffer: *mut c_void,
length: usize,
runtime_address: u64,
token: *mut *const FormatterToken,
) -> Status;
pub fn ZydisFormatterTokenizeInstructionEx(
formatter: *const ZydisFormatter,
instruction: *const DecodedInstruction,
buffer: *mut c_void,
length: usize,
runtime_address: u64,
token: *mut *const FormatterToken,
user_data: *mut c_void,
) -> Status;
pub fn ZydisFormatterTokenizeOperand(
formatter: *const ZydisFormatter,
instruction: *const DecodedInstruction,
index: u8,
buffer: *mut c_void,
length: usize,
runtime_address: u64,
token: *mut *const FormatterToken,
) -> Status;
pub fn ZydisFormatterTokenizeOperandEx(
formatter: *const ZydisFormatter,
instruction: *const DecodedInstruction,
index: u8,
buffer: *mut c_void,
length: usize,
runtime_address: u64,
token: *mut *const FormatterToken,
user_data: *mut c_void,
) -> Status;
pub fn ZydisFormatterTokenGetValue(
token: *const FormatterToken,
ty: *mut Token,
value: *mut *const c_char,
) -> Status;
pub fn ZydisFormatterTokenNext(token: *mut *const FormatterToken) -> Status;
pub fn ZydisFormatterBufferGetString(
buffer: *mut FormatterBuffer,
string: *mut *mut ZyanString,
) -> Status;
pub fn ZydisFormatterBufferGetToken(
buffer: *const FormatterBuffer,
token: *mut *const FormatterToken,
) -> Status;
pub fn ZydisFormatterBufferAppend(buffer: *mut FormatterBuffer, ty: Token) -> Status;
pub fn ZydisFormatterBufferRemember(
buffer: *const FormatterBuffer,
state: *mut FormatterBufferState,
) -> Status;
pub fn ZydisFormatterBufferRestore(
buffer: *mut FormatterBuffer,
state: FormatterBufferState,
) -> Status;
pub fn ZyanStringInitCustomBuffer(
string: *mut ZyanString,
buffer: *mut c_char,
capacity: usize,
) -> Status;
pub fn ZyanStringAppend(destination: *mut ZyanString, source: *const ZyanStringView) -> Status;
pub fn ZyanStringDestroy(string: *mut ZyanString) -> Status;
pub fn ZyanStringViewInsideBufferEx(
view: *mut ZyanStringView,
buffer: *const c_char,
length: usize,
) -> Status;
}