//----------------------------------------------------------------------------
//
// Module list abstraction.
//
// Copyright (C) Microsoft Corporation, 2001-2002.
//
//----------------------------------------------------------------------------

#ifndef __MODINFO_HPP__
#define __MODINFO_HPP__

//----------------------------------------------------------------------------
//
// ModuleInfo hierarchy.
//
//----------------------------------------------------------------------------

// If the image header is paged out the true values for
// certain fields cannot be retrieved.  These placeholders
// are used instead.
#define UNKNOWN_CHECKSUM 0xffffffff
#define UNKNOWN_TIMESTAMP 0xfffffffe

typedef struct _MODULE_INFO_ENTRY
{
    // NamePtr should include a path if one is available.
    // It is the responsibility of callers to find the
    // file tail if that's all they care about.
    // If UnicodeNamePtr is false NameLength is ignored.
    PSTR NamePtr;
    ULONG UnicodeNamePtr:1;
    ULONG ImageInfoValid:1;
    ULONG ImageInfoPartial:1;
    ULONG ImageDebugHeader:1;
    ULONG ImageVersionValid:1;
    ULONG ImageMachineTypeValid:1;
    ULONG UserMode:1;
    ULONG Unused:25;
    // Length in bytes not including the terminator.
    ULONG NameLength;
    PSTR ModuleName;
    HANDLE File;
    ULONG64 Base;
    ULONG Size;
    ULONG SizeOfCode;
    ULONG SizeOfData;
    ULONG CheckSum;
    ULONG TimeDateStamp;
    USHORT MajorImageVersion;
    USHORT MinorImageVersion;
    ULONG MachineType;
    PVOID DebugHeader;
    ULONG SizeOfDebugHeader;
    CHAR Buffer[MAX_IMAGE_PATH * sizeof(WCHAR)];
} MODULE_INFO_ENTRY, *PMODULE_INFO_ENTRY;

enum MODULE_INFO_LEVEL
{
    // Only the base and size are guaranteed to be valid.
    MODULE_INFO_BASE_SIZE,
    // Attempt to retrieve all available information.
    MODULE_INFO_ALL,
};

class ModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread) = 0;
    virtual HRESULT GetEntry(PMODULE_INFO_ENTRY Entry) = 0;
    // Base implementation does nothing.

    // Updates the entry image info by reading the
    // image header.
    void ReadImageHeaderInfo(PMODULE_INFO_ENTRY Entry);

    void InitSource(ThreadInfo* Thread);
    
    TargetInfo* m_Target;
    MachineInfo* m_Machine;
    ProcessInfo* m_Process;
    ThreadInfo* m_Thread;
    MODULE_INFO_LEVEL m_InfoLevel;
};

class NtModuleInfo : public ModuleInfo
{
public:
    virtual HRESULT GetEntry(PMODULE_INFO_ENTRY Entry);

protected:
    ULONG64 m_Head;
    ULONG64 m_Cur;
};

class NtKernelModuleInfo : public NtModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread);
    virtual HRESULT GetEntry(PMODULE_INFO_ENTRY Entry);
};

extern NtKernelModuleInfo g_NtKernelModuleIterator;

class NtUserModuleInfo : public NtModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread);
    virtual HRESULT GetEntry(PMODULE_INFO_ENTRY Entry);

protected:
    ULONG64 m_Peb;
};

class NtTargetUserModuleInfo : public NtUserModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread);
};

extern NtTargetUserModuleInfo g_NtTargetUserModuleIterator;

class NtWow64UserModuleInfo : public NtUserModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread);

private:
    HRESULT GetPeb32(PULONG64 Peb32);
};

extern NtWow64UserModuleInfo g_NtWow64UserModuleIterator;

class DebuggerModuleInfo : public ModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread);
    virtual HRESULT GetEntry(PMODULE_INFO_ENTRY Entry);

private:
    ImageInfo* m_Image;
};

extern DebuggerModuleInfo g_DebuggerModuleIterator;

//
// Define a generic maximum unloaded name length for all
// callers of the unloaded iterators.  This includes the terminator.
//
// Kernel mode dumps define a limit (MAX_UNLOADED_NAME_LENGTH) which
// works out to 13 characters.
//
// User-mode is currently limited to 32 characters.
//
// Pick a value which exceeds both to allow room for either.
//

#define MAX_INFO_UNLOADED_NAME 32

class UnloadedModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread) = 0;
    virtual HRESULT GetEntry(PSTR Name, PDEBUG_MODULE_PARAMETERS Params) = 0;

    void InitSource(ThreadInfo* Thread);
    
    TargetInfo* m_Target;
    MachineInfo* m_Machine;
    ProcessInfo* m_Process;
    ThreadInfo* m_Thread;
};

class NtKernelUnloadedModuleInfo : public UnloadedModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread);
    virtual HRESULT GetEntry(PSTR Name, PDEBUG_MODULE_PARAMETERS Params);

protected:
    ULONG64 m_Base;
    ULONG m_Index;
    ULONG m_Count;
};

extern NtKernelUnloadedModuleInfo g_NtKernelUnloadedModuleIterator;

class NtUserUnloadedModuleInfo : public UnloadedModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread);
    virtual HRESULT GetEntry(PSTR Name, PDEBUG_MODULE_PARAMETERS Params);

protected:
    ULONG64 m_Base;
    ULONG m_Index;
};

extern NtUserUnloadedModuleInfo g_NtUserUnloadedModuleIterator;

class ToolHelpModuleInfo : public ModuleInfo
{
public:
    virtual HRESULT Initialize(ThreadInfo* Thread);
    virtual HRESULT GetEntry(PMODULE_INFO_ENTRY Entry);

protected:
    HANDLE m_Snap;
    BOOL m_First;
    ULONG m_LastId;
};

extern ToolHelpModuleInfo g_ToolHelpModuleIterator;

//----------------------------------------------------------------------------
//
// Functions.
//
//----------------------------------------------------------------------------

BOOL
GetUserModuleListAddress(
    ThreadInfo* Thread,
    MachineInfo* Machine,
    ULONG64 Peb,
    BOOL Quiet,
    PULONG64 OrderModuleListStart,
    PULONG64 FirstEntry
    );

BOOL
GetModNameFromLoaderList(
    ThreadInfo* Thread,
    MachineInfo* Machine,
    ULONG64 Peb,
    ULONG64 ModuleBase,
    PSTR NameBuffer,
    ULONG BufferSize,
    BOOL FullPath
    );

void
ConvertLoaderEntry32To64(
    PKLDR_DATA_TABLE_ENTRY32 b32,
    PKLDR_DATA_TABLE_ENTRY64 b64
    );

#endif // #ifndef __MODINFO_HPP__
