/* $Id: dbg.h $ */
/** @file
 * IPRT - Debugging Routines.
 */

/*
 * Copyright (C) 2008-2013 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 * VirtualBox OSE distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 */

#ifndef ___iprt_dbg_h
#define ___iprt_dbg_h

#include <iprt/types.h>
#include <iprt/stdarg.h>
#include <iprt/ldr.h>

RT_C_DECLS_BEGIN

/** @defgroup grp_rt_dbg    RTDbg - Debugging Routines
 * @ingroup grp_rt
 * @{
 */


/** Debug segment index. */
typedef uint32_t            RTDBGSEGIDX;
/** Pointer to a debug segment index. */
typedef RTDBGSEGIDX        *PRTDBGSEGIDX;
/** Pointer to a const debug segment index. */
typedef RTDBGSEGIDX const  *PCRTDBGSEGIDX;
/** NIL debug segment index. */
#define NIL_RTDBGSEGIDX             UINT32_C(0xffffffff)
/** The last normal segment index. */
#define RTDBGSEGIDX_LAST            UINT32_C(0xffffffef)
/** Special segment index that indicates that the offset is a relative
 * virtual address (RVA). I.e. an offset from the start of the module. */
#define RTDBGSEGIDX_RVA             UINT32_C(0xfffffff0)
/** Special segment index that indicates that the offset is a absolute. */
#define RTDBGSEGIDX_ABS             UINT32_C(0xfffffff1)
/** The last valid special segment index. */
#define RTDBGSEGIDX_SPECIAL_LAST    RTDBGSEGIDX_ABS
/** The last valid special segment index. */
#define RTDBGSEGIDX_SPECIAL_FIRST   (RTDBGSEGIDX_LAST + 1U)


/** Max length (including '\\0') of a segment name. */
#define RTDBG_SEGMENT_NAME_LENGTH   (128 - 8 - 8 - 8 - 4 - 4)

/**
 * Debug module segment.
 */
typedef struct RTDBGSEGMENT
{
    /** The load address.
     * RTUINTPTR_MAX if not applicable. */
    RTUINTPTR           Address;
    /** The image relative virtual address of the segment.
     * RTUINTPTR_MAX if not applicable. */
    RTUINTPTR           uRva;
    /** The segment size. */
    RTUINTPTR           cb;
    /** The segment flags. (reserved) */
    uint32_t            fFlags;
    /** The segment index. */
    RTDBGSEGIDX         iSeg;
    /** Symbol name. */
    char                szName[RTDBG_SEGMENT_NAME_LENGTH];
} RTDBGSEGMENT;
/** Pointer to a debug module segment. */
typedef RTDBGSEGMENT *PRTDBGSEGMENT;
/** Pointer to a const debug module segment. */
typedef RTDBGSEGMENT const *PCRTDBGSEGMENT;



/** Max length (including '\\0') of a symbol name. */
#define RTDBG_SYMBOL_NAME_LENGTH    (384 - 8 - 8 - 8 - 4 - 4 - 8)

/**
 * Debug symbol.
 */
typedef struct RTDBGSYMBOL
{
    /** Symbol value (address).
     * This depends a bit who you ask. It will be the same as offSeg when you
     * as RTDbgMod, but the mapping address if you ask RTDbgAs. */
    RTUINTPTR           Value;
    /** Symbol size. */
    RTUINTPTR           cb;
    /** Offset into the segment specified by iSeg. */
    RTUINTPTR           offSeg;
    /** Segment number. */
    RTDBGSEGIDX         iSeg;
    /** Symbol Flags. (reserved). */
    uint32_t            fFlags;
    /** Symbol ordinal.
     * This is set to UINT32_MAX if the ordinals aren't supported. */
    uint32_t            iOrdinal;
    /** Symbol name. */
    char                szName[RTDBG_SYMBOL_NAME_LENGTH];
} RTDBGSYMBOL;
/** Pointer to debug symbol. */
typedef RTDBGSYMBOL *PRTDBGSYMBOL;
/** Pointer to const debug symbol. */
typedef const RTDBGSYMBOL *PCRTDBGSYMBOL;

/**
 * Allocate a new symbol structure.
 *
 * @returns Pointer to a new structure on success, NULL on failure.
 */
RTDECL(PRTDBGSYMBOL)    RTDbgSymbolAlloc(void);

/**
 * Duplicates a symbol structure.
 *
 * @returns Pointer to duplicate on success, NULL on failure.
 *
 * @param   pSymInfo        The symbol info to duplicate.
 */
RTDECL(PRTDBGSYMBOL)    RTDbgSymbolDup(PCRTDBGSYMBOL pSymInfo);

/**
 * Free a symbol structure previously allocated by a RTDbg method.
 *
 * @param   pSymInfo        The symbol info to free. NULL is ignored.
 */
RTDECL(void)            RTDbgSymbolFree(PRTDBGSYMBOL pSymInfo);


/** Max length (including '\\0') of a debug info file name. */
#define RTDBG_FILE_NAME_LENGTH      (260)


/**
 * Debug line number information.
 */
typedef struct RTDBGLINE
{
    /** Address.
     * This depends a bit who you ask. It will be the same as offSeg when you
     * as RTDbgMod, but the mapping address if you ask RTDbgAs. */
    RTUINTPTR           Address;
    /** Offset into the segment specified by iSeg. */
    RTUINTPTR           offSeg;
    /** Segment number. */
    RTDBGSEGIDX         iSeg;
    /** Line number. */
    uint32_t            uLineNo;
    /** Symbol ordinal.
     * This is set to UINT32_MAX if the ordinals aren't supported. */
    uint32_t            iOrdinal;
    /** Filename. */
    char                szFilename[RTDBG_FILE_NAME_LENGTH];
} RTDBGLINE;
/** Pointer to debug line number. */
typedef RTDBGLINE *PRTDBGLINE;
/** Pointer to const debug line number. */
typedef const RTDBGLINE *PCRTDBGLINE;

/**
 * Allocate a new line number structure.
 *
 * @returns Pointer to a new structure on success, NULL on failure.
 */
RTDECL(PRTDBGLINE)      RTDbgLineAlloc(void);

/**
 * Duplicates a line number structure.
 *
 * @returns Pointer to duplicate on success, NULL on failure.
 *
 * @param   pLine           The line number to duplicate.
 */
RTDECL(PRTDBGLINE)      RTDbgLineDup(PCRTDBGLINE pLine);

/**
 * Free a line number structure previously allocated by a RTDbg method.
 *
 * @param   pLine           The line number to free. NULL is ignored.
 */
RTDECL(void)            RTDbgLineFree(PRTDBGLINE pLine);


/** @defgroup grp_rt_dbgas      RTDbgAs - Debug Address Space
 * @{
 */

/**
 * Creates an empty address space.
 *
 * @returns IPRT status code.
 *
 * @param   phDbgAs         Where to store the address space handle on success.
 * @param   FirstAddr       The first address in the address space.
 * @param   LastAddr        The last address in the address space.
 * @param   pszName         The name of the address space.
 */
RTDECL(int) RTDbgAsCreate(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, const char *pszName);

/**
 * Variant of RTDbgAsCreate that takes a name format string.
 *
 * @returns IPRT status code.
 *
 * @param   phDbgAs         Where to store the address space handle on success.
 * @param   FirstAddr       The first address in the address space.
 * @param   LastAddr        The last address in the address space.
 * @param   pszNameFmt      The name format of the address space.
 * @param   va              Format arguments.
 */
RTDECL(int) RTDbgAsCreateV(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, const char *pszNameFmt, va_list va);

/**
 * Variant of RTDbgAsCreate that takes a name format string.
 *
 * @returns IPRT status code.
 *
 * @param   phDbgAs         Where to store the address space handle on success.
 * @param   FirstAddr       The first address in the address space.
 * @param   LastAddr        The last address in the address space.
 * @param   pszNameFmt      The name format of the address space.
 * @param   ...             Format arguments.
 */
RTDECL(int) RTDbgAsCreateF(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, const char *pszNameFmt, ...);

/**
 * Retains a reference to the address space.
 *
 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
 *
 * @param   hDbgAs          The address space handle.
 *
 * @remarks Will not take any locks.
 */
RTDECL(uint32_t) RTDbgAsRetain(RTDBGAS hDbgAs);

/**
 * Release a reference to the address space.
 *
 * When the reference count reaches zero, the address space is destroyed.
 * That means unlinking all the modules it currently contains, potentially
 * causing some or all of them to be destroyed as they are managed by
 * reference counting.
 *
 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
 *
 * @param   hDbgAs          The address space handle. The NIL handle is quietly
 *                          ignored and 0 is returned.
 *
 * @remarks Will not take any locks.
 */
RTDECL(uint32_t) RTDbgAsRelease(RTDBGAS hDbgAs);

/**
 * Gets the name of an address space.
 *
 * @returns read only address space name.
 *          NULL if hDbgAs is invalid.
 *
 * @param   hDbgAs          The address space handle.
 *
 * @remarks Will not take any locks.
 */
RTDECL(const char *) RTDbgAsName(RTDBGAS hDbgAs);

/**
 * Gets the first address in an address space.
 *
 * @returns The address.
 *          0 if hDbgAs is invalid.
 *
 * @param   hDbgAs          The address space handle.
 *
 * @remarks Will not take any locks.
 */
RTDECL(RTUINTPTR) RTDbgAsFirstAddr(RTDBGAS hDbgAs);

/**
 * Gets the last address in an address space.
 *
 * @returns The address.
 *          0 if hDbgAs is invalid.
 *
 * @param   hDbgAs          The address space handle.
 *
 * @remarks Will not take any locks.
 */
RTDECL(RTUINTPTR) RTDbgAsLastAddr(RTDBGAS hDbgAs);

/**
 * Gets the number of modules in the address space.
 *
 * This can be used together with RTDbgAsModuleByIndex
 * to enumerate the modules.
 *
 * @returns The number of modules.
 *
 * @param   hDbgAs          The address space handle.
 *
 * @remarks Will not take any locks.
 */
RTDECL(uint32_t) RTDbgAsModuleCount(RTDBGAS hDbgAs);

/** @name Flags for RTDbgAsModuleLink and RTDbgAsModuleLinkSeg
 * @{ */
/** Replace all conflicting module.
 * (The conflicting modules will be removed the address space and their
 * references released.) */
#define RTDBGASLINK_FLAGS_REPLACE       RT_BIT_32(0)
/** Mask containing the valid flags. */
#define RTDBGASLINK_FLAGS_VALID_MASK    UINT32_C(0x00000001)
/** @} */

/**
 * Links a module into the address space at the give address.
 *
 * The size of the mapping is determined using RTDbgModImageSize().
 *
 * @returns IPRT status code.
 * @retval  VERR_OUT_OF_RANGE if the specified address will put the module
 *          outside the address space.
 * @retval  VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings.
 *
 * @param   hDbgAs          The address space handle.
 * @param   hDbgMod         The module handle of the module to be linked in.
 * @param   ImageAddr       The address to link the module at.
 * @param   fFlags          See RTDBGASLINK_FLAGS_*.
 */
RTDECL(int) RTDbgAsModuleLink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTUINTPTR ImageAddr, uint32_t fFlags);

/**
 * Links a segment into the address space at the give address.
 *
 * The size of the mapping is determined using RTDbgModSegmentSize().
 *
 * @returns IPRT status code.
 * @retval  VERR_OUT_OF_RANGE if the specified address will put the module
 *          outside the address space.
 * @retval  VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings.
 *
 * @param   hDbgAs          The address space handle.
 * @param   hDbgMod         The module handle.
 * @param   iSeg            The segment number (0-based) of the segment to be
 *                          linked in.
 * @param   SegAddr         The address to link the segment at.
 * @param   fFlags          See RTDBGASLINK_FLAGS_*.
 */
RTDECL(int) RTDbgAsModuleLinkSeg(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR SegAddr, uint32_t fFlags);

/**
 * Unlinks all the mappings of a module from the address space.
 *
 * @returns IPRT status code.
 * @retval  VERR_NOT_FOUND if the module wasn't found.
 *
 * @param   hDbgAs          The address space handle.
 * @param   hDbgMod         The module handle of the module to be unlinked.
 */
RTDECL(int) RTDbgAsModuleUnlink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod);

/**
 * Unlinks the mapping at the specified address.
 *
 * @returns IPRT status code.
 * @retval  VERR_NOT_FOUND if no module or segment is mapped at that address.
 *
 * @param   hDbgAs          The address space handle.
 * @param   Addr            The address within the mapping to be unlinked.
 */
RTDECL(int) RTDbgAsModuleUnlinkByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr);

/**
 * Get a the handle of a module in the address space by is index.
 *
 * @returns A retained handle to the specified module. The caller must release
 *          the returned reference.
 *          NIL_RTDBGMOD if invalid index or handle.
 *
 * @param   hDbgAs          The address space handle.
 * @param   iModule         The index of the module to get.
 *
 * @remarks The module indexes may change after calls to RTDbgAsModuleLink,
 *          RTDbgAsModuleLinkSeg, RTDbgAsModuleUnlink and
 *          RTDbgAsModuleUnlinkByAddr.
 */
RTDECL(RTDBGMOD) RTDbgAsModuleByIndex(RTDBGAS hDbgAs, uint32_t iModule);

/**
 * Queries mapping module information by handle.
 *
 * @returns IPRT status code.
 * @retval  VERR_NOT_FOUND if no mapping was found at the specified address.
 *
 * @param   hDbgAs          The address space handle.
 * @param   Addr            Address within the mapping of the module or segment.
 * @param   phMod           Where to the return the retained module handle.
 *                          Optional.
 * @param   pAddr           Where to return the base address of the mapping.
 *                          Optional.
 * @param   piSeg           Where to return the segment index. This is set to
 *                          NIL if the entire module is mapped as a single
 *                          mapping. Optional.
 */
RTDECL(int) RTDbgAsModuleByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTDBGMOD phMod, PRTUINTPTR pAddr, PRTDBGSEGIDX piSeg);

/**
 * Queries mapping module information by name.
 *
 * @returns IPRT status code.
 * @retval  VERR_NOT_FOUND if no mapping was found at the specified address.
 * @retval  VERR_OUT_OF_RANGE if the name index was out of range.
 *
 * @param   hDbgAs          The address space handle.
 * @param   pszName         The module name.
 * @param   iName           There can be more than one module by the same name
 *                          in an address space. This argument indicates which
 *                          is meant. (0 based)
 * @param   phMod           Where to the return the retained module handle.
 */
RTDECL(int) RTDbgAsModuleByName(RTDBGAS hDbgAs, const char *pszName, uint32_t iName, PRTDBGMOD phMod);

/**
 * Information about a mapping.
 *
 * This is used by RTDbgAsModuleGetMapByIndex.
 */
typedef struct RTDBGASMAPINFO
{
    /** The mapping address. */
    RTUINTPTR       Address;
    /** The segment mapped there.
     *  This is NIL_RTDBGSEGIDX if the entire module image is mapped here. */
    RTDBGSEGIDX     iSeg;
} RTDBGASMAPINFO;
/** Pointer to info about an address space mapping. */
typedef RTDBGASMAPINFO *PRTDBGASMAPINFO;
/** Pointer to const info about an address space mapping. */
typedef RTDBGASMAPINFO const *PCRTDBGASMAPINFO;

/**
 * Queries mapping information for a module given by index.
 *
 * @returns IRPT status code.
 * @retval  VERR_INVALID_HANDLE if hDbgAs is invalid.
 * @retval  VERR_OUT_OF_RANGE if the name index was out of range.
 * @retval  VINF_BUFFER_OVERFLOW if the array is too small and the returned
 *          information is incomplete.
 *
 * @param   hDbgAs          The address space handle.
 * @param   iModule         The index of the module to get.
 * @param   paMappings      Where to return the mapping information.  The buffer
 *                          size is given by *pcMappings.
 * @param   pcMappings      IN: Size of the paMappings array. OUT: The number of
 *                          entries returned.
 * @param   fFlags          Flags for reserved for future use. MBZ.
 *
 * @remarks See remarks for RTDbgAsModuleByIndex regarding the volatility of the
 *          iModule parameter.
 */
RTDECL(int) RTDbgAsModuleQueryMapByIndex(RTDBGAS hDbgAs, uint32_t iModule, PRTDBGASMAPINFO paMappings, uint32_t *pcMappings, uint32_t fFlags);

/**
 * Adds a symbol to a module in the address space.
 *
 * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones.
 * @retval  VERR_INVALID_HANDLE if hDbgAs is invalid.
 * @retval  VERR_NOT_FOUND if no module was found at the specified address.
 * @retval  VERR_NOT_SUPPORTED if the module interpret doesn't support adding
 *          custom symbols.
 *
 * @param   hDbgAs          The address space handle.
 * @param   pszSymbol       The symbol name.
 * @param   Addr            The address of the symbol.
 * @param   cb              The size of the symbol.
 * @param   fFlags          Symbol flags.
 * @param   piOrdinal       Where to return the symbol ordinal on success. If
 *                          the interpreter doesn't do ordinals, this will be set to
 *                          UINT32_MAX. Optional
 */
RTDECL(int) RTDbgAsSymbolAdd(RTDBGAS hDbgAs, const char *pszSymbol, RTUINTPTR Addr, RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal);

/**
 * Query a symbol by address.
 *
 * @returns IPRT status code. See RTDbgModSymbolAddr for more specific ones.
 * @retval  VERR_INVALID_HANDLE if hDbgAs is invalid.
 * @retval  VERR_NOT_FOUND if the address couldn't be mapped to a module.
 *
 * @param   hDbgAs          The address space handle.
 * @param   Addr            The address which closest symbol is requested.
 * @param   poffDisp        Where to return the distance between the symbol
 *                          and address. Optional.
 * @param   pSymbol         Where to return the symbol info.
 * @param   phMod           Where to return the module handle. Optional.
 */
RTDECL(int) RTDbgAsSymbolByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod);

/**
 * Query a symbol by address.
 *
 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
 * @retval  VERR_INVALID_HANDLE if hDbgAs is invalid.
 * @retval  VERR_NOT_FOUND if the address couldn't be mapped to a module.
 *
 * @param   hDbgAs          The address space handle.
 * @param   Addr            The address which closest symbol is requested.
 * @param   poffDisp        Where to return the distance between the symbol
 *                          and address. Optional.
 * @param   ppSymInfo       Where to return the pointer to the allocated symbol
 *                          info. Always set. Free with RTDbgSymbolFree.
 * @param   phMod           Where to return the module handle. Optional.
 */
RTDECL(int) RTDbgAsSymbolByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo, PRTDBGMOD phMod);

/**
 * Query a symbol by name.
 *
 * @returns IPRT status code.
 * @retval  VERR_SYMBOL_NOT_FOUND if not found.
 *
 * @param   hDbgAs          The address space handle.
 * @param   pszSymbol       The symbol name. It is possible to limit the scope
 *                          of the search by prefixing the symbol with a module
 *                          name pattern followed by a bang (!) character.
 *                          RTStrSimplePatternNMatch is used for the matching.
 * @param   pSymbol         Where to return the symbol info.
 * @param   phMod           Where to return the module handle. Optional.
 */
RTDECL(int) RTDbgAsSymbolByName(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod);

/**
 * Query a symbol by name, allocating the returned symbol structure.
 *
 * @returns IPRT status code.
 * @retval  VERR_SYMBOL_NOT_FOUND if not found.
 *
 * @param   hDbgAs          The address space handle.
 * @param   pszSymbol       The symbol name. See RTDbgAsSymbolByName for more.
 * @param   ppSymbol        Where to return the pointer to the allocated
 *                          symbol info. Always set. Free with RTDbgSymbolFree.
 * @param   phMod           Where to return the module handle. Optional.
 */
RTDECL(int) RTDbgAsSymbolByNameA(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL *ppSymbol, PRTDBGMOD phMod);

/**
 * Query a line number by address.
 *
 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
 * @retval  VERR_INVALID_HANDLE if hDbgAs is invalid.
 * @retval  VERR_NOT_FOUND if the address couldn't be mapped to a module.
 *
 * @param   hDbgAs          The address space handle.
 * @param   Addr            The address which closest symbol is requested.
 * @param   poffDisp        Where to return the distance between the line
 *                          number and address.
 * @param   pLine           Where to return the line number information.
 */
RTDECL(int) RTDbgAs(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine);

/**
 * Adds a line number to a module in the address space.
 *
 * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones.
 * @retval  VERR_INVALID_HANDLE if hDbgAs is invalid.
 * @retval  VERR_NOT_FOUND if no module was found at the specified address.
 * @retval  VERR_NOT_SUPPORTED if the module interpret doesn't support adding
 *          custom symbols.
 *
 * @param   hDbgAs          The address space handle.
 * @param   pszFile         The file name.
 * @param   uLineNo         The line number.
 * @param   Addr            The address of the symbol.
 * @param   piOrdinal       Where to return the line number ordinal on success.
 *                          If the interpreter doesn't do ordinals, this will be
 *                          set to UINT32_MAX. Optional.
 */
RTDECL(int) RTDbgAsLineAdd(RTDBGAS hDbgAs, const char *pszFile, uint32_t uLineNo, RTUINTPTR Addr, uint32_t *piOrdinal);


/**
 * Query a line number by address.
 *
 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
 * @retval  VERR_INVALID_HANDLE if hDbgAs is invalid.
 * @retval  VERR_NOT_FOUND if the address couldn't be mapped to a module.
 *
 * @param   hDbgAs          The address space handle.
 * @param   Addr            The address which closest symbol is requested.
 * @param   poffDisp        Where to return the distance between the line
 *                          number and address.
 * @param   pLine           Where to return the line number information.
 */
RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine);

/**
 * Query a line number by address.
 *
 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
 * @retval  VERR_INVALID_HANDLE if hDbgAs is invalid.
 * @retval  VERR_NOT_FOUND if the address couldn't be mapped to a module.
 *
 * @param   hDbgAs          The address space handle.
 * @param   Addr            The address which closest symbol is requested.
 * @param   poffDisp        Where to return the distance between the line
 *                          number and address.
 * @param   ppLine          Where to return the pointer to the allocated line
 *                          number info. Always set. Free with RTDbgLineFree.
 */
RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE *ppLine);

/** @todo Missing some bits here. */

/** @} */


/** @defgroup grp_rt_dbgmod     RTDbgMod - Debug Module Interpreter
 * @{
 */

/**
 * Creates a module based on the default debug info container.
 *
 * This can be used to manually load a module and its symbol. The primary user
 * group is the debug info interpreters, which use this API to create an
 * efficient debug info container behind the scenes and forward all queries to
 * it once the info has been loaded.
 *
 * @returns IPRT status code.
 *
 * @param   phDbgMod        Where to return the module handle.
 * @param   pszName         The name of the module (mandatory).
 * @param   cbSeg           The size of initial segment. If zero, segments will
 *                          have to be added manually using RTDbgModSegmentAdd.
 * @param   fFlags          Flags reserved for future extensions, MBZ for now.
 */
RTDECL(int)         RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cbSeg, uint32_t fFlags);

RTDECL(int)         RTDbgModCreateDeferred(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTUINTPTR cb, uint32_t fFlags);
RTDECL(int)         RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t fFlags);
RTDECL(int)         RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTUINTPTR uSubtrahend, uint32_t fFlags);


/**
 * Retains another reference to the module.
 *
 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
 *
 * @param   hDbgMod         The module handle.
 *
 * @remarks Will not take any locks.
 */
RTDECL(uint32_t)    RTDbgModRetain(RTDBGMOD hDbgMod);

/**
 * Release a reference to the module.
 *
 * When the reference count reaches zero, the module is destroyed.
 *
 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
 *
 * @param   hDbgMod         The module handle. The NIL handle is quietly ignored
 *                          and 0 is returned.
 *
 * @remarks Will not take any locks.
 */
RTDECL(uint32_t)    RTDbgModRelease(RTDBGMOD hDbgMod);

/**
 * Gets the module name.
 *
 * @returns Pointer to a read only string containing the name.
 *
 * @param   hDbgMod         The module handle.
 */
RTDECL(const char *) RTDbgModName(RTDBGMOD hDbgMod);

/**
 * Converts an image relative address to a segment:offset address.
 *
 * @returns Segment index on success.
 *          NIL_RTDBGSEGIDX is returned if the module handle or the RVA are
 *          invalid.
 *
 * @param   hDbgMod         The module handle.
 * @param   uRva            The image relative address to convert.
 * @param   poffSeg         Where to return the segment offset. Optional.
 */
RTDECL(RTDBGSEGIDX) RTDbgModRvaToSegOff(RTDBGMOD hDbgMod, RTUINTPTR uRva, PRTUINTPTR poffSeg);

/**
 * Image size when mapped if segments are mapped adjacently.
 *
 * For ELF, PE, and Mach-O images this is (usually) a natural query, for LX and
 * NE and such it's a bit odder and the answer may not make much sense for them.
 *
 * @returns Image mapped size.
 *          RTUINTPTR_MAX is returned if the handle is invalid.
 *
 * @param   hDbgMod         The module handle.
 */
RTDECL(RTUINTPTR)   RTDbgModImageSize(RTDBGMOD hDbgMod);

/**
 * Gets the module tag value if any.
 *
 * @returns The tag. 0 if hDbgMod is invalid.
 *
 * @param   hDbgMod         The module handle.
 */
RTDECL(uint64_t)    RTDbgModGetTag(RTDBGMOD hDbgMod);

/**
 * Tags or untags the module.
 *
 * @returns IPRT status code.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 *
 * @param   hDbgMod         The module handle.
 * @param   uTag            The tag value.  The convention is that 0 is no tag
 *                          and any other value means it's tagged.  It's adviced
 *                          to use some kind of unique number like an address
 *                          (global or string cache for instance) to avoid
 *                          collisions with other users
 */
RTDECL(int)         RTDbgModSetTag(RTDBGMOD hDbgMod, uint64_t uTag);


/**
 * Adds a segment to the module. Optional feature.
 *
 * This method is intended used for manually constructing debug info for a
 * module. The main usage is from other debug info interpreters that want to
 * avoid writing a debug info database and instead uses the standard container
 * behind the scenes.
 *
 * @returns IPRT status code.
 * @retval  VERR_NOT_SUPPORTED if this feature isn't support by the debug info
 *          interpreter. This is a common return code.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_DBG_ADDRESS_WRAP if uRva+cb wraps around.
 * @retval  VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE if pszName is too short or long.
 * @retval  VERR_INVALID_PARAMETER if fFlags contains undefined flags.
 * @retval  VERR_DBG_SPECIAL_SEGMENT if *piSeg is a special segment.
 * @retval  VERR_DBG_INVALID_SEGMENT_INDEX if *piSeg doesn't meet expectations.
 *
 * @param   hDbgMod             The module handle.
 * @param   uRva                The image relative address of the segment.
 * @param   cb                  The size of the segment.
 * @param   pszName             The segment name. Does not normally need to be
 *                              unique, although this is somewhat up to the
 *                              debug interpreter to decide.
 * @param   fFlags              Segment flags. Reserved for future used, MBZ.
 * @param   piSeg               The segment index or NIL_RTDBGSEGIDX on input.
 *                              The assigned segment index on successful return.
 *                              Optional.
 */
RTDECL(int)         RTDbgModSegmentAdd(RTDBGMOD hDbgMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
                                       uint32_t fFlags, PRTDBGSEGIDX piSeg);

/**
 * Gets the number of segments in the module.
 *
 * This is can be used to determine the range which can be passed to
 * RTDbgModSegmentByIndex and derivates.
 *
 * @returns The segment relative address.
 *          NIL_RTDBGSEGIDX if the handle is invalid.
 *
 * @param   hDbgMod         The module handle.
 */
RTDECL(RTDBGSEGIDX) RTDbgModSegmentCount(RTDBGMOD hDbgMod);

/**
 * Query information about a segment.
 *
 * This can be used together with RTDbgModSegmentCount to enumerate segments.
 * The index starts a 0 and stops one below RTDbgModSegmentCount.
 *
 * @returns IPRT status code.
 * @retval  VERR_DBG_INVALID_SEGMENT_INDEX if iSeg is too high.
 * @retval  VERR_DBG_SPECIAL_SEGMENT if iSeg indicates a special segment.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 *
 * @param   hDbgMod         The module handle.
 * @param   iSeg            The segment index. No special segments.
 * @param   pSegInfo        Where to return the segment info. The
 *                          RTDBGSEGMENT::Address member will be set to
 *                          RTUINTPTR_MAX or the load address used at link time.
 */
RTDECL(int)         RTDbgModSegmentByIndex(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo);

/**
 * Gets the size of a segment.
 *
 * This is a just a wrapper around RTDbgModSegmentByIndex.
 *
 * @returns The segment size.
 *          RTUINTPTR_MAX is returned if either the handle and segment index are
 *          invalid.
 *
 * @param   hDbgMod         The module handle.
 * @param   iSeg            The segment index. RTDBGSEGIDX_ABS is not allowed.
 *                          If RTDBGSEGIDX_RVA is used, the functions returns
 *                          the same value as RTDbgModImageSize.
 */
RTDECL(RTUINTPTR)   RTDbgModSegmentSize(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg);

/**
 * Gets the image relative address of a segment.
 *
 * This is a just a wrapper around RTDbgModSegmentByIndex.
 *
 * @returns The segment relative address.
 *          RTUINTPTR_MAX is returned if either the handle and segment index are
 *          invalid.
 *
 * @param   hDbgMod         The module handle.
 * @param   iSeg            The segment index. No special segment indexes
 *                          allowed (asserted).
 */
RTDECL(RTUINTPTR)   RTDbgModSegmentRva(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg);


/**
 * Adds a line number to the module.
 *
 * @returns IPRT status code.
 * @retval  VERR_NOT_SUPPORTED if the module interpret doesn't support adding
 *          custom symbols. This is a common place occurrence.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
 *          short.
 * @retval  VERR_DBG_INVALID_RVA if an image relative address is specified and
 *          it's not inside any of the segments defined by the module.
 * @retval  VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
 * @retval  VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
 *          end of the segment.
 * @retval  VERR_DBG_ADDRESS_WRAP if off+cb wraps around.
 * @retval  VERR_INVALID_PARAMETER if the symbol flags sets undefined bits.
 *
 * @param   hDbgMod         The module handle.
 * @param   pszSymbol       The symbol name.
 * @param   iSeg            The segment index.
 * @param   off             The segment offset.
 * @param   cb              The size of the symbol. Can be zero, although this
 *                          may depend somewhat on the debug interpreter.
 * @param   fFlags          Symbol flags. Reserved for the future, MBZ.
 * @param   piOrdinal       Where to return the symbol ordinal on success. If
 *                          the interpreter doesn't do ordinals, this will be set to
 *                          UINT32_MAX. Optional.
 */
RTDECL(int)         RTDbgModSymbolAdd(RTDBGMOD hDbgMod, const char *pszSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off,
                                      RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal);

/**
 * Gets the symbol count.
 *
 * This can be used together wtih RTDbgModSymbolByOrdinal or
 * RTDbgModSymbolByOrdinalA to enumerate all the symbols.
 *
 * @returns The number of symbols in the module.
 *          UINT32_MAX is returned if the module handle is invalid or some other
 *          error occurs.
 *
 * @param   hDbgMod             The module handle.
 */
RTDECL(uint32_t)    RTDbgModSymbolCount(RTDBGMOD hDbgMod);

/**
 * Queries symbol information by ordinal number.
 *
 * @returns IPRT status code.
 * @retval  VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number.
 * @retval  VERR_DBG_NO_SYMBOLS if there aren't any symbols.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_NOT_SUPPORTED if lookup by ordinal is not supported.
 *
 * @param   hDbgMod             The module handle.
 * @param   iOrdinal            The symbol ordinal number. 0-based. The highest
 *                              number is RTDbgModSymbolCount() - 1.
 * @param   pSymInfo            Where to store the symbol information.
 */
RTDECL(int)         RTDbgModSymbolByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo);

/**
 * Queries symbol information by ordinal number.
 *
 * @returns IPRT status code.
 * @retval  VERR_DBG_NO_SYMBOLS if there aren't any symbols.
 * @retval  VERR_NOT_SUPPORTED if lookup by ordinal is not supported.
 * @retval  VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number.
 * @retval  VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
 *
 * @param   hDbgMod             The module handle.
 * @param   iOrdinal            The symbol ordinal number. 0-based. The highest
 *                              number is RTDbgModSymbolCount() - 1.
 * @param   ppSymInfo           Where to store the pointer to the returned
 *                              symbol information. Always set. Free with
 *                              RTDbgSymbolFree.
 */
RTDECL(int)         RTDbgModSymbolByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL *ppSymInfo);

/**
 * Queries symbol information by address.
 *
 * The returned symbol is what the debug info interpreter considers the symbol
 * most applicable to the specified address. This usually means a symbol with an
 * address equal or lower than the requested.
 *
 * @returns IPRT status code.
 * @retval  VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
 * @retval  VERR_DBG_NO_SYMBOLS if there aren't any symbols.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_DBG_INVALID_RVA if an image relative address is specified and
 *          it's not inside any of the segments defined by the module.
 * @retval  VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
 * @retval  VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
 *          end of the segment.
 *
 * @param   hDbgMod             The module handle.
 * @param   iSeg                The segment number.
 * @param   off                 The offset into the segment.
 * @param   poffDisp            Where to store the distance between the
 *                              specified address and the returned symbol.
 *                              Optional.
 * @param   pSymInfo            Where to store the symbol information.
 */
RTDECL(int)         RTDbgModSymbolByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo);

/**
 * Queries symbol information by address.
 *
 * The returned symbol is what the debug info interpreter considers the symbol
 * most applicable to the specified address. This usually means a symbol with an
 * address equal or lower than the requested.
 *
 * @returns IPRT status code.
 * @retval  VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
 * @retval  VERR_DBG_NO_SYMBOLS if there aren't any symbols.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_DBG_INVALID_RVA if an image relative address is specified and
 *          it's not inside any of the segments defined by the module.
 * @retval  VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
 * @retval  VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
 *          end of the segment.
 * @retval  VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
 *
 * @param   hDbgMod             The module handle.
 * @param   iSeg                The segment index.
 * @param   off                 The offset into the segment.
 * @param   poffDisp            Where to store the distance between the
 *                              specified address and the returned symbol. Optional.
 * @param   ppSymInfo           Where to store the pointer to the returned
 *                              symbol information. Always set. Free with
 *                              RTDbgSymbolFree.
 */
RTDECL(int)         RTDbgModSymbolByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo);

/**
 * Queries symbol information by symbol name.
 *
 * @returns IPRT status code.
 * @retval  VERR_DBG_NO_SYMBOLS if there aren't any symbols.
 * @retval  VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
 * @retval  VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
 *          short.
 *
 * @param   hDbgMod             The module handle.
 * @param   pszSymbol           The symbol name.
 * @param   pSymInfo            Where to store the symbol information.
 */
RTDECL(int)         RTDbgModSymbolByName(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL pSymInfo);

/**
 * Queries symbol information by symbol name.
 *
 * @returns IPRT status code.
 * @retval  VERR_DBG_NO_SYMBOLS if there aren't any symbols.
 * @retval  VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
 * @retval  VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
 *          short.
 * @retval  VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
 *
 * @param   hDbgMod             The module handle.
 * @param   pszSymbol           The symbol name.
 * @param   ppSymInfo           Where to store the pointer to the returned
 *                              symbol information. Always set. Free with
 *                              RTDbgSymbolFree.
 */
RTDECL(int)         RTDbgModSymbolByNameA(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL *ppSymInfo);

/**
 * Adds a line number to the module.
 *
 * @returns IPRT status code.
 * @retval  VERR_NOT_SUPPORTED if the module interpret doesn't support adding
 *          custom symbols. This should be consider a normal response.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_DBG_FILE_NAME_OUT_OF_RANGE if the file name is too longer or
 *          empty.
 * @retval  VERR_DBG_INVALID_RVA if an image relative address is specified and
 *          it's not inside any of the segments defined by the module.
 * @retval  VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
 * @retval  VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
 *          end of the segment.
 * @retval  VERR_INVALID_PARAMETER if the line number flags sets undefined bits.
 *
 * @param   hDbgMod             The module handle.
 * @param   pszFile             The file name.
 * @param   uLineNo             The line number.
 * @param   iSeg                The segment index.
 * @param   off                 The segment offset.
 * @param   piOrdinal           Where to return the line number ordinal on
 *                              success. If  the interpreter doesn't do ordinals,
 *                              this will be set to UINT32_MAX. Optional.
 */
RTDECL(int)         RTDbgModLineAdd(RTDBGMOD hDbgMod, const char *pszFile, uint32_t uLineNo,
                                    RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t *piOrdinal);

/**
 * Gets the line number count.
 *
 * This can be used together wtih RTDbgModLineByOrdinal or RTDbgModSymbolByLineA
 * to enumerate all the line number information.
 *
 * @returns The number of line numbers in the module.
 *          UINT32_MAX is returned if the module handle is invalid or some other
 *          error occurs.
 *
 * @param   hDbgMod             The module handle.
 */
RTDECL(uint32_t)    RTDbgModLineCount(RTDBGMOD hDbgMod);

/**
 * Queries line number information by ordinal number.
 *
 * This can be used to enumerate the line numbers for the module. Use
 * RTDbgModLineCount() to figure the end of the ordinals.
 *
 * @returns IPRT status code.
 * @retval  VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
 * @retval  VERR_DBG_LINE_NOT_FOUND if there is no line number with that
 *          ordinal.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.

 * @param   hDbgMod             The module handle.
 * @param   iOrdinal            The line number ordinal number.
 * @param   pLineInfo           Where to store the information about the line
 *                              number.
 */
RTDECL(int)         RTDbgModLineByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo);

/**
 * Queries line number information by ordinal number.
 *
 * This can be used to enumerate the line numbers for the module. Use
 * RTDbgModLineCount() to figure the end of the ordinals.
 *
 * @returns IPRT status code.
 * @retval  VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
 * @retval  VERR_DBG_LINE_NOT_FOUND if there is no line number with that
 *          ordinal.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_NO_MEMORY if RTDbgLineAlloc fails.
 *
 * @param   hDbgMod             The module handle.
 * @param   iOrdinal            The line number ordinal number.
 * @param   ppLineInfo          Where to store the pointer to the returned line
 *                              number information. Always set. Free with
 *                              RTDbgLineFree.
 */
RTDECL(int)         RTDbgModLineByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE *ppLineInfo);

/**
 * Queries line number information by address.
 *
 * The returned line number is what the debug info interpreter considers the
 * one most applicable to the specified address. This usually means a line
 * number with an address equal or lower than the requested.
 *
 * @returns IPRT status code.
 * @retval  VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
 * @retval  VERR_DBG_LINE_NOT_FOUND if no suitable line number was found.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_DBG_INVALID_RVA if an image relative address is specified and
 *          it's not inside any of the segments defined by the module.
 * @retval  VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
 * @retval  VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
 *          end of the segment.
 *
 * @param   hDbgMod             The module handle.
 * @param   iSeg                The segment number.
 * @param   off                 The offset into the segment.
 * @param   poffDisp            Where to store the distance between the
 *                              specified address and the returned symbol.
 *                              Optional.
 * @param   pLineInfo           Where to store the line number information.
 */
RTDECL(int)         RTDbgModLineByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE pLineInfo);

/**
 * Queries line number information by address.
 *
 * The returned line number is what the debug info interpreter considers the
 * one most applicable to the specified address. This usually means a line
 * number with an address equal or lower than the requested.
 *
 * @returns IPRT status code.
 * @retval  VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
 * @retval  VERR_DBG_LINE_NOT_FOUND if no suitable line number was found.
 * @retval  VERR_INVALID_HANDLE if hDbgMod is invalid.
 * @retval  VERR_DBG_INVALID_RVA if an image relative address is specified and
 *          it's not inside any of the segments defined by the module.
 * @retval  VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
 * @retval  VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
 *          end of the segment.
 * @retval  VERR_NO_MEMORY if RTDbgLineAlloc fails.
 *
 * @param   hDbgMod             The module handle.
 * @param   iSeg                The segment number.
 * @param   off                 The offset into the segment.
 * @param   poffDisp            Where to store the distance between the
 *                              specified address and the returned symbol.
 *                              Optional.
 * @param   ppLineInfo          Where to store the pointer to the returned line
 *                              number information. Always set. Free with
 *                              RTDbgLineFree.
 */
RTDECL(int)         RTDbgModLineByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE *ppLineInfo);
/** @} */

/** @} */

RT_C_DECLS_END

#endif

