Home > Software engineering >  Rust, winapi, and Debug no longer implemented
Rust, winapi, and Debug no longer implemented

Time:08-08

TL;DR:

In older version of code Debug was implemented for structs in external crates (winapi 0.2 and kernel32-sys 0.2). Updating code with newest version of crates (winapi 0.3, kernel32-sys now just part of that crate), Debug is no longer implemented?

More details:

I'm reading through Rust in Action and chapter 6 gives an example of examining your program's memory (ch6-meminfo-win).

Aside from code not working b/c of an aliasing mistake, it's out of date and I get a depreciation warning for kernel32-sys. So I've tried to bring the code up to date with the current version of winapi (0.3.9 - kernel32-sys is now integrated into that crate) and I think I have everything working, but lines 44 and 56 in the original program ( println!("{:?}", proc_info); and println!("{:#?}", mem_info);) give the following errors:

SYSTEM_INFO cannot be formatted using {:?} because it doesn't implement Debug

the trait Debug is not implemented for MEMORY_BASIC_INFORMATION

I think with my own structs this would be fairly easy, just adding #[derive(Debug)] above the struct definition, right? But I don't know how to handle it with the struct being defined in winapi crate.

What I tried: I used 'Go to SYSTEM_INFO' in my IDE and then added #[derive(Debug)] above the code it directed me to (line 26 in sysinfoapi.rs) but it's a STRUCT! macro and adding derive debug no effect. I also tried adding the line above the struct definition inside of the STRUCT! and still no effect.

Full code:

use winapi::shared::{
    minwindef::DWORD,
    minwindef::LPCVOID,                    
    basetsd::SIZE_T,
};

use winapi::um::{
    winnt::HANDLE,
    winnt::PVOID,
    sysinfoapi::SYSTEM_INFO,
    winnt::MEMORY_BASIC_INFORMATION,
    winnt::PMEMORY_BASIC_INFORMATION,
    sysinfoapi::LPSYSTEM_INFO,
    processthreadsapi::GetCurrentProcessId,
    processthreadsapi::GetCurrentProcess,
    sysinfoapi::GetSystemInfo,
    memoryapi::VirtualQueryEx,
};
 
 
fn main() {
    let this_pid: DWORD;
    let this_proc: HANDLE;
    let min_addr: LPCVOID;
    let max_addr: LPCVOID;
    let mut base_addr: PVOID;                     
    let mut proc_info: SYSTEM_INFO;               
    let mut mem_info: MEMORY_BASIC_INFORMATION;   
 
    const MEMINFO_SIZE: usize = std::mem::size_of::<MEMORY_BASIC_INFORMATION>();
 
    unsafe {                                      
        base_addr = std::mem::zeroed();
        proc_info = std::mem::zeroed();
        mem_info = std::mem::zeroed();
    }
 
    unsafe {                                        
        this_pid = GetCurrentProcessId();
        this_proc = GetCurrentProcess();
 
        GetSystemInfo(                   
          &mut proc_info as LPSYSTEM_INFO          
        );                                         
    };
 
    min_addr = proc_info.lpMinimumApplicationAddress; 
    max_addr = proc_info.lpMaximumApplicationAddress; 
 
    println!("{:?} @ {:p}", this_pid, this_proc);
    println!("{:?}", proc_info);
    println!("min: {:p}, max: {:p}", min_addr, max_addr);
 
    loop {
        let rc: SIZE_T = unsafe {
            VirtualQueryEx(    
                this_proc,                // HANDLE, hProcess
                base_addr,                // LPCVOID, lpAddress
                &mut mem_info,            // PMEMORY_BASIC_INFORMATION, lpBuffer
                MEMINFO_SIZE as SIZE_T,   // SIZE_T, dwLength
            )
        };
 
        if rc == 0 {
            break
        }
        println!("{:#?}", mem_info);
        base_addr = ((base_addr as SIZE_T)   mem_info.RegionSize) as PVOID;
    }
}

Edit: Fixed const MEMINFO_SIZE

CodePudding user response:

Try using a struct wrapper. When you need to access the wrapped value, use wrapper_name.0. Here's an example:

struct SystemInfoWrapper(SYSTEM_INFO);
impl std::fmt::Debug for SystemInfoWrapper {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, 
            "SYSTEM_INFO {{ 
                lpMinimumApplicationAddress: {:?}, 
                lpMaximumApplicationAddress: {:?},
                dwActiveProcessorMask: {:?},
                dwNumberOfProcessors: {:?},
                dwProcessorType: {:?},
                dwAllocationGranularity: {:?},
                wProcessorLevel: {:?},
                wProcessorRevision: {:?}
             }}", 
            self.0.lpMinimumApplicationAddress, 
            self.0.lpMaximumApplicationAddress,
            self.0.dwActiveProcessorMask,
            self.0.dwNumberOfProcessors,
            self.0.dwProcessorType,
            self.0.dwAllocationGranularity,
            self.0.wProcessorLevel,
            self.0.wProcessorRevision
        )
    }
}

struct MemoryBasicInformationWrapper(MEMORY_BASIC_INFORMATION);
impl std::fmt::Debug for MemoryBasicInformationWrapper {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, 
            "MEMORY_BASIC_INFORMATION {{ 
                BaseAddress: {:?}, 
                AllocationBase: {:?}, 
                AllocationProtect: {:?}, 
                RegionSize: {:?}, 
                State: {:?}, 
                Protect: {:?}, 
                Type: {:?}
             }}", 
            self.0.BaseAddress, 
            self.0.AllocationBase, 
            self.0.AllocationProtect, 
            self.0.RegionSize, 
            self.0.State, 
            self.0.Protect, 
            self.0.Type
        )
    }
}
  • Related