/*
* Process Hacker -
* run-time library debug buffer
*
* Copyright (C) 2009 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see .
*/
using System;
using System.Collections.Generic;
using ProcessHacker.Common.Objects;
using ProcessHacker.Native.Api;
using ProcessHacker.Native.Objects;
namespace ProcessHacker.Native.Debugging
{
public delegate bool DebugEnumHeapsDelegate(HeapInformation heapInfo);
public delegate bool DebugEnumLocksDelegate(LockInformation lockInfo);
public delegate bool DebugEnumModulesDelegate(ModuleInformation moduleInfo);
///
/// Represents a debug buffer managed by the run-time library.
///
public sealed class DebugBuffer : BaseObject
{
private IntPtr _buffer;
///
/// Creates a new debug buffer.
///
public DebugBuffer()
{
_buffer = Win32.RtlCreateQueryDebugBuffer(0, false);
if (_buffer == IntPtr.Zero)
{
this.DisableOwnership(false);
throw new WindowsException(NtStatus.Unsuccessful);
}
}
protected override void DisposeObject(bool disposing)
{
Win32.RtlDestroyQueryDebugBuffer(_buffer);
}
///
/// Enumerates heap information.
///
/// The callback for the enumeration.
public void EnumHeaps(DebugEnumHeapsDelegate callback)
{
var debugInfo = this.GetDebugInformation();
if (debugInfo.Heaps == IntPtr.Zero)
throw new InvalidOperationException("Heap information does not exist.");
MemoryRegion heapInfo = new MemoryRegion(debugInfo.Heaps);
var heaps = heapInfo.ReadStruct();
for (int i = 0; i < heaps.NumberOfHeaps; i++)
{
var heap = heapInfo.ReadStruct(RtlProcessHeaps.HeapsOffset, i);
if (!callback(new HeapInformation(heap)))
break;
}
}
///
/// Enumerates lock information.
///
/// The callback for the enumeration.
public void EnumLocks(DebugEnumLocksDelegate callback)
{
var debugInfo = this.GetDebugInformation();
if (debugInfo.Locks == IntPtr.Zero)
throw new InvalidOperationException("Lock information does not exist.");
MemoryRegion locksInfo = new MemoryRegion(debugInfo.Locks);
var locks = locksInfo.ReadStruct();
for (int i = 0; i < locks.NumberOfLocks; i++)
{
var lock_ = locksInfo.ReadStruct(sizeof(int), i);
if (!callback(new LockInformation(lock_)))
break;
}
}
///
/// Enumerates module information.
///
/// The callback for the enumeration.
public void EnumModules(DebugEnumModulesDelegate callback)
{
var debugInfo = this.GetDebugInformation();
if (debugInfo.Modules == IntPtr.Zero)
throw new InvalidOperationException("Module information does not exist.");
MemoryRegion modulesInfo = new MemoryRegion(debugInfo.Modules);
var modules = modulesInfo.ReadStruct();
for (int i = 0; i < modules.NumberOfModules; i++)
{
var module = modulesInfo.ReadStruct(RtlProcessModules.ModulesOffset, i);
if (!callback(new ModuleInformation(module)))
break;
}
}
///
/// Reads the debug information structure from the buffer.
///
/// A RtlDebugInformation structure.
private RtlDebugInformation GetDebugInformation()
{
MemoryRegion data = new MemoryRegion(_buffer);
return data.ReadStruct();
}
///
/// Gets heap information.
///
/// An array of heap information objects.
public HeapInformation[] GetHeaps()
{
List heaps = new List();
this.EnumHeaps((heap) =>
{
heaps.Add(heap);
return true;
});
return heaps.ToArray();
}
///
/// Gets lock information.
///
/// An array of lock information objects.
public LockInformation[] GetLocks()
{
List locks = new List();
this.EnumLocks((lock_) =>
{
locks.Add(lock_);
return true;
});
return locks.ToArray();
}
///
/// Gets module information.
///
/// An array of module information objects.
public ModuleInformation[] GetModules()
{
List modules = new List();
this.EnumModules((module) =>
{
modules.Add(module);
return true;
});
return modules.ToArray();
}
///
/// Queries debug information for the current process.
///
/// The information to query.
public void Query(RtlQueryProcessDebugFlags flags)
{
this.Query(ProcessHandle.GetCurrentId(), flags);
}
///
/// Queries debug information for the specified process.
///
/// The PID of the process to query.
/// The information to query.
public void Query(int pid, RtlQueryProcessDebugFlags flags)
{
NtStatus status;
if ((status = Win32.RtlQueryProcessDebugInformation(
pid.ToIntPtr(),
flags,
_buffer
)) >= NtStatus.Error)
Win32.Throw(status);
}
///
/// Queries back trace information for the current process.
///
public void QueryBackTraces()
{
NtStatus status;
if ((status = Win32.RtlQueryProcessBackTraceInformation(_buffer)) >= NtStatus.Error)
Win32.Throw(status);
}
///
/// Queries heap information for the current process.
///
public void QueryHeaps()
{
NtStatus status;
if ((status = Win32.RtlQueryProcessHeapInformation(_buffer)) >= NtStatus.Error)
Win32.Throw(status);
}
///
/// Queries lock information for the current process.
///
public void QueryLocks()
{
NtStatus status;
if ((status = Win32.RtlQueryProcessLockInformation(_buffer)) >= NtStatus.Error)
Win32.Throw(status);
}
//public void QueryModules()
//{
// this.QueryModules(null, RtlQueryProcessDebugFlags.Modules);
//}
//public void QueryModules(ProcessHandle processHandle, RtlQueryProcessDebugFlags flags)
//{
// NtStatus status;
// if ((status = Win32.RtlQueryProcessModuleInformation(
// processHandle ?? IntPtr.Zero,
// flags,
// _buffer
// )) >= NtStatus.Error)
// Win32.ThrowLastError(status);
//}
}
}