Files
sigmaker-ida/idasdk76/include/typeinf.hpp
2021-10-31 21:20:46 +02:00

4397 lines
179 KiB
C++

/*
* Interactive disassembler (IDA)
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
* Type Information.
*
*/
#ifndef _TYPEINF_HPP
#define _TYPEINF_HPP
#include <idp.hpp>
#include <name.hpp>
/*! \file typeinf.hpp
\brief Describes the type information records in IDA.
The recommended way of using type info is to use the ::tinfo_t class.
The type information is internally kept as an array of bytes terminated by 0.
Items in brackets [] are optional and sometimes are omitted.
::type_t... means a sequence of ::type_t bytes which defines a type.
\note to work with the types of instructions or data in the database,
use get_tinfo()/set_tinfo() and similar functions.
*/
/// byte sequence used to describe a type in IDA (see \ref tf)
typedef uchar type_t;
/// pascal-like string: dt length, characters
typedef uchar p_string;
/// several ::p_string's
typedef uchar p_list;
struct til_t; // type information library
class lexer_t; // lexical analyzer
class argloc_t; // argument location
class tinfo_t; // type info object
struct func_type_data_t;
struct til_bucket_t;
struct til_stream_t;
//------------------------------------------------------------------------
#define RESERVED_BYTE 0xFF ///< multifunctional purpose
//------------------------------------------------------------------------
/// \defgroup tf Type flags
/// Here we describe the byte arrays used to describe type information
//@{
/// \defgroup tf_mask Masks
//@{
const type_t TYPE_BASE_MASK = 0x0F; ///< the low 4 bits define the basic type
const type_t TYPE_FLAGS_MASK = 0x30; ///< type flags - they have different
///< meaning depending on the basic type
const type_t TYPE_MODIF_MASK = 0xC0; ///< modifiers.
///< - for ::BT_ARRAY see \ref tf_array
///< - ::BT_VOID can have them ONLY in 'void *'
const type_t TYPE_FULL_MASK = (TYPE_BASE_MASK | TYPE_FLAGS_MASK); ///< basic type with type flags
//@}
/*! \defgroup tf_unk Basic type: unknown & void
::BT_UNK and ::BT_VOID with non-zero type flags can be used in function
(and struct) declarations to describe the function arguments or structure
fields if only their size is known. They may be used in ida to describe
the user input.
For struct used also as 'single-field-alignment-suffix'
[__declspec(align(x))] with ::TYPE_MODIF_MASK == ::TYPE_FULL_MASK.
*/
//@{
const type_t BT_UNK = 0x00; ///< unknown
const type_t BT_VOID = 0x01; ///< void
const type_t BTMT_SIZE0 = 0x00; ///< ::BT_VOID - normal void; ::BT_UNK - don't use
const type_t BTMT_SIZE12 = 0x10; ///< size = 1 byte if ::BT_VOID; 2 if ::BT_UNK
const type_t BTMT_SIZE48 = 0x20; ///< size = 4 bytes if ::BT_VOID; 8 if ::BT_UNK
const type_t BTMT_SIZE128 = 0x30; ///< size = 16 bytes if ::BT_VOID; unknown if ::BT_UNK
///< (IN struct alignment - see below)
//@}
/// \defgroup tf_int Basic type: integer
//@{
const type_t BT_INT8 = 0x02; ///< __int8
const type_t BT_INT16 = 0x03; ///< __int16
const type_t BT_INT32 = 0x04; ///< __int32
const type_t BT_INT64 = 0x05; ///< __int64
const type_t BT_INT128 = 0x06; ///< __int128 (for alpha & future use)
const type_t BT_INT = 0x07; ///< natural int. (size provided by idp module)
const type_t BTMT_UNKSIGN = 0x00; ///< unknown signedness
const type_t BTMT_SIGNED = 0x10; ///< signed
const type_t BTMT_USIGNED = 0x20; ///< unsigned
const type_t BTMT_UNSIGNED = BTMT_USIGNED;
const type_t BTMT_CHAR = 0x30; ///< specify char or segment register
///< - ::BT_INT8 - char
///< - ::BT_INT - segment register
///< - other BT_INT... - don't use
//@}
/// \defgroup tf_bool Basic type: bool
//@{
const type_t BT_BOOL = 0x08; ///< bool
const type_t BTMT_DEFBOOL = 0x00; ///< size is model specific or unknown(?)
const type_t BTMT_BOOL1 = 0x10; ///< size 1byte
const type_t BTMT_BOOL2 = 0x20; ///< size 2bytes - !inf_is_64bit()
const type_t BTMT_BOOL8 = 0x20; ///< size 8bytes - inf_is_64bit()
const type_t BTMT_BOOL4 = 0x30; ///< size 4bytes
//@}
/// \defgroup tf_float Basic type: float
//@{
const type_t BT_FLOAT = 0x09; ///< float
const type_t BTMT_FLOAT = 0x00; ///< float (4 bytes)
const type_t BTMT_DOUBLE = 0x10; ///< double (8 bytes)
const type_t BTMT_LNGDBL = 0x20; ///< long double (compiler specific)
const type_t BTMT_SPECFLT = 0x30; ///< float (variable size).
///< if \ph{use_tbyte()} then use \ph{tbyte_size},
///< otherwise 2 bytes
//@}
/// \defgroup tf_last_basic Basic type: last
//@{
const type_t _BT_LAST_BASIC = BT_FLOAT; ///< the last basic type,
///< all basic types may be followed by
///< [tah-typeattrs]
//@}
/*! \defgroup tf_ptr Derived type: pointer
Pointers to undeclared yet ::BT_COMPLEX types are prohibited
*/
//@{
const type_t BT_PTR = 0x0A; ///< pointer.
///< has the following format:
///< [db sizeof(ptr)]; [tah-typeattrs]; type_t...
const type_t BTMT_DEFPTR = 0x00; ///< default for model
const type_t BTMT_NEAR = 0x10; ///< near
const type_t BTMT_FAR = 0x20; ///< far
const type_t BTMT_CLOSURE = 0x30; ///< closure.
///< - if ptr to ::BT_FUNC - __closure.
///< in this case next byte MUST be
///< #RESERVED_BYTE, and after it ::BT_FUNC
///< - else the next byte contains sizeof(ptr)
///< allowed values are 1 - \varmem{ph,processor_t,max_ptr_size}
///< - if value is bigger than \varmem{ph,processor_t,max_ptr_size},
///< based_ptr_name_and_size() is called to
///< find out the typeinfo
//@}
/*! \defgroup tf_array Derived type: array
For ::BT_ARRAY, the BTMT_... flags must be equivalent to the BTMT_... flags of its elements
*/
//@{
const type_t BT_ARRAY = 0x0B; ///< array
const type_t BTMT_NONBASED = 0x10; ///< \code
/// if set
/// array base==0
/// format: dt num_elem; [tah-typeattrs]; type_t...
/// if num_elem==0 then the array size is unknown
/// else
/// format: da num_elem, base; [tah-typeattrs]; type_t... \endcode
/// used only for serialization
const type_t BTMT_ARRESERV = 0x20; ///< reserved bit
//@}
/*! \defgroup tf_func Derived type: function
Ellipsis is not taken into account in the number of parameters
The return type cannot be ::BT_ARRAY or ::BT_FUNC.
*/
//@{
const type_t BT_FUNC = 0x0C; ///< function.
///< format: <pre>
/// optional: ::CM_CC_SPOILED | num_of_spoiled_regs
/// if num_of_spoiled_reg == BFA_FUNC_MARKER:
/// ::bfa_byte
/// if (bfa_byte & BFA_FUNC_EXT_FORMAT) != 0
/// ::fti_bits (only low bits: FTI_SPOILED,...,FTI_VIRTUAL)
/// num_of_spoiled_reg times: spoiled reg info (see extract_spoiledreg)
/// else
/// bfa_byte is function attribute byte (see \ref BFA_...)
/// else:
/// num_of_spoiled_reg times: spoiled reg info (see extract_spoiledreg)
/// ::cm_t ... calling convention and memory model
/// [tah-typeattrs];
/// ::type_t ... return type;
/// [serialized argloc_t of returned value (if ::CM_CC_SPECIAL{PE} && !return void);
/// if !::CM_CC_VOIDARG:
/// dt N (N=number of parameters)
/// if ( N == 0 )
/// if ::CM_CC_ELLIPSIS or ::CM_CC_SPECIALE
/// func(...)
/// else
/// parameters are unknown
/// else
/// N records:
/// ::type_t ... (i.e. type of each parameter)
/// [serialized argloc_t (if ::CM_CC_SPECIAL{PE})] (i.e. place of each parameter)
/// [#FAH_BYTE + de( \ref funcarg_t::flags )] </pre>
const type_t BTMT_DEFCALL = 0x00; ///< call method - default for model or unknown
const type_t BTMT_NEARCALL = 0x10; ///< function returns by retn
const type_t BTMT_FARCALL = 0x20; ///< function returns by retf
const type_t BTMT_INTCALL = 0x30; ///< function returns by iret
///< in this case cc MUST be 'unknown'
//@}
/// \defgroup tf_complex Derived type: complex
//@{
const type_t BT_COMPLEX = 0x0D; ///< struct/union/enum/typedef.
///< format: <pre>
/// [dt N (N=field count) if !::BTMT_TYPEDEF]
/// if N == 0:
/// p_string name (unnamed types have names "anon_...")
/// [sdacl-typeattrs];
/// else, for struct & union:
/// if N == 0x7FFE // Support for high (i.e., > 4095) members count
/// N = deserialize_de()
/// ALPOW = N & 0x7
/// MCNT = N >> 3
/// if MCNT == 0
/// empty struct
/// if ALPOW == 0
/// ALIGN = get_default_align()
/// else
/// ALIGN = (1 << (ALPOW - 1))
/// [sdacl-typeattrs];
/// else, for enums:
/// if N == 0x7FFE // Support for high enum entries count.
/// N = deserialize_de()
/// [tah-typeattrs]; </pre>
///
const type_t BTMT_STRUCT = 0x00; ///< struct:
///< MCNT records: type_t; [sdacl-typeattrs];
const type_t BTMT_UNION = 0x10; ///< union:
///< MCNT records: type_t...
const type_t BTMT_ENUM = 0x20; ///< enum:
///< next byte bte_t (see below)
///< N records: de delta(s)
///< OR
///< blocks (see below)
const type_t BTMT_TYPEDEF = 0x30; ///< named reference
///< always p_string name
const type_t BT_BITFIELD = 0x0E; ///< bitfield (only in struct)
///< ['bitmasked' enum see below]
///< next byte is dt
///< ((size in bits << 1) | (unsigned ? 1 : 0))
const type_t BTMT_BFLDI8 = 0x00; ///< __int8
const type_t BTMT_BFLDI16 = 0x10; ///< __int16
const type_t BTMT_BFLDI32 = 0x20; ///< __int32
const type_t BTMT_BFLDI64 = 0x30; ///< __int64
//@}
const type_t BT_RESERVED = 0x0F; ///< RESERVED
//------------------------------------------------------------------------
/*! \defgroup tf_modifiers Type modifiers
"const volatile" types are forbidden
*/
//@{
const type_t BTM_CONST = 0x40; ///< const
const type_t BTM_VOLATILE = 0x80; ///< volatile
//@}
//------------------------------------------------------------------------
/// \defgroup tf_enum Special enum definitions
//@{
typedef uchar bte_t; ///< Enum type flags
const bte_t BTE_SIZE_MASK = 0x07; ///< storage size.
///< - if == 0 then inf_get_cc_size_e()
///< - else 1 << (n -1) = 1,2,4...64
const bte_t BTE_RESERVED = 0x08; ///< must be 0, in order to distinguish
///< from a tah-byte
const bte_t BTE_BITFIELD = 0x10; ///< 'subarrays'. In this case ANY record
///< has the following format:
///< - 'de' mask (has name)
///< - 'dt' cnt
///< - cnt records of 'de' values
///< (cnt CAN be 0)
///< \note delta for ALL subsegment is ONE
const bte_t BTE_OUT_MASK = 0x60; ///< output style mask
const bte_t BTE_HEX = 0x00; ///< hex
const bte_t BTE_CHAR = 0x20; ///< char or hex
const bte_t BTE_SDEC = 0x40; ///< signed decimal
const bte_t BTE_UDEC = 0x60; ///< unsigned decimal
const bte_t BTE_ALWAYS = 0x80; ///< this bit MUST be present
//@}
/// \defgroup tf_conv_segreg Convenience definitions: segment register
//@{
const type_t BT_SEGREG = (BT_INT | BTMT_CHAR); ///< segment register
//@}
/// \defgroup tf_conv_unk Convenience definitions: unknown types
//@{
const type_t BT_UNK_BYTE = (BT_VOID | BTMT_SIZE12); ///< 1 byte
const type_t BT_UNK_WORD = (BT_UNK | BTMT_SIZE12); ///< 2 bytes
const type_t BT_UNK_DWORD = (BT_VOID | BTMT_SIZE48); ///< 4 bytes
const type_t BT_UNK_QWORD = (BT_UNK | BTMT_SIZE48); ///< 8 bytes
const type_t BT_UNK_OWORD = (BT_VOID | BTMT_SIZE128); ///< 16 bytes
const type_t BT_UNKNOWN = (BT_UNK | BTMT_SIZE128); ///< unknown size - for parameters
//@}
//------------------------------------------------------------------------
/// \defgroup tf_shortcuts Convenience definitions: shortcuts
//@{
const type_t BTF_BYTE = BT_UNK_BYTE; ///< byte
const type_t BTF_UNK = BT_UNKNOWN; ///< unknown
const type_t BTF_VOID = BT_VOID | BTMT_SIZE0; ///< void
const type_t BTF_INT8 = BT_INT8 | BTMT_SIGNED; ///< signed byte
const type_t BTF_CHAR = BT_INT8 | BTMT_CHAR; ///< signed char
const type_t BTF_UCHAR = BT_INT8 | BTMT_USIGNED; ///< unsigned char
const type_t BTF_UINT8 = BT_INT8 | BTMT_USIGNED; ///< unsigned byte
const type_t BTF_INT16 = BT_INT16 | BTMT_SIGNED; ///< signed short
const type_t BTF_UINT16 = BT_INT16 | BTMT_USIGNED; ///< unsigned short
const type_t BTF_INT32 = BT_INT32 | BTMT_SIGNED; ///< signed int
const type_t BTF_UINT32 = BT_INT32 | BTMT_USIGNED; ///< unsigned int
const type_t BTF_INT64 = BT_INT64 | BTMT_SIGNED; ///< signed long
const type_t BTF_UINT64 = BT_INT64 | BTMT_USIGNED; ///< unsigned long
const type_t BTF_INT128 = BT_INT128 | BTMT_SIGNED; ///< signed 128-bit value
const type_t BTF_UINT128 = BT_INT128 | BTMT_USIGNED; ///< unsigned 128-bit value
const type_t BTF_INT = BT_INT | BTMT_UNKSIGN; ///< int, unknown signedness
const type_t BTF_UINT = BT_INT | BTMT_USIGNED; ///< unsigned int
const type_t BTF_SINT = BT_INT | BTMT_SIGNED; ///< singed int
const type_t BTF_BOOL = BT_BOOL; ///< boolean
const type_t BTF_FLOAT = BT_FLOAT | BTMT_FLOAT; ///< float
const type_t BTF_DOUBLE = BT_FLOAT | BTMT_DOUBLE; ///< double
const type_t BTF_LDOUBLE = BT_FLOAT | BTMT_LNGDBL; ///< long double
const type_t BTF_TBYTE = BT_FLOAT | BTMT_SPECFLT; ///< see ::BTMT_SPECFLT
const type_t BTF_STRUCT = BT_COMPLEX | BTMT_STRUCT; ///< struct
const type_t BTF_UNION = BT_COMPLEX | BTMT_UNION; ///< union
const type_t BTF_ENUM = BT_COMPLEX | BTMT_ENUM; ///< enum
const type_t BTF_TYPEDEF = BT_COMPLEX | BTMT_TYPEDEF; ///< typedef
//@}
//@} tf
//------------------------------------------------------------------------
// convenience functions:
inline THREAD_SAFE bool is_type_const(type_t t) { return (t & BTM_CONST) != 0; } ///< See ::BTM_CONST
inline THREAD_SAFE bool is_type_volatile(type_t t) { return (t & BTM_VOLATILE) != 0; } ///< See ::BTM_VOLATILE
inline THREAD_SAFE type_t get_base_type(type_t t) { return (t & TYPE_BASE_MASK); } ///< Get get basic type bits (::TYPE_BASE_MASK)
inline THREAD_SAFE type_t get_type_flags(type_t t) { return (t & TYPE_FLAGS_MASK); } ///< Get type flags (::TYPE_FLAGS_MASK)
inline THREAD_SAFE type_t get_full_type(type_t t) { return (t & TYPE_FULL_MASK); } ///< Get basic type bits + type flags (::TYPE_FULL_MASK)
/// Is the type_t the last byte of type declaration?
/// (there are no additional bytes after a basic type, see ::_BT_LAST_BASIC)
inline THREAD_SAFE bool is_typeid_last(type_t t) { return(get_base_type(t) <= _BT_LAST_BASIC); }
/// Identifies an unknown or void type with a known size (see \ref tf_unk)
inline THREAD_SAFE bool is_type_partial(type_t t) { return(get_base_type(t) <= BT_VOID) && get_type_flags(t) != 0; }
inline THREAD_SAFE bool is_type_void(type_t t) { return(get_full_type(t) == BTF_VOID); } ///< See ::BTF_VOID
inline THREAD_SAFE bool is_type_unknown(type_t t) { return(get_full_type(t) == BT_UNKNOWN); } ///< See ::BT_UNKNOWN
inline THREAD_SAFE bool is_type_ptr(type_t t) { return(get_base_type(t) == BT_PTR); } ///< See ::BT_PTR
inline THREAD_SAFE bool is_type_complex(type_t t) { return(get_base_type(t) == BT_COMPLEX); } ///< See ::BT_COMPLEX
inline THREAD_SAFE bool is_type_func(type_t t) { return(get_base_type(t) == BT_FUNC); } ///< See ::BT_FUNC
inline THREAD_SAFE bool is_type_array(type_t t) { return(get_base_type(t) == BT_ARRAY); } ///< See ::BT_ARRAY
inline THREAD_SAFE bool is_type_typedef(type_t t) { return(get_full_type(t) == BTF_TYPEDEF); } ///< See ::BTF_TYPEDEF
inline THREAD_SAFE bool is_type_sue(type_t t) { return is_type_complex(t) && !is_type_typedef(t); } ///< Is the type a struct/union/enum?
inline THREAD_SAFE bool is_type_struct(type_t t) { return(get_full_type(t) == BTF_STRUCT); } ///< See ::BTF_STRUCT
inline THREAD_SAFE bool is_type_union(type_t t) { return(get_full_type(t) == BTF_UNION); } ///< See ::BTF_UNION
inline THREAD_SAFE bool is_type_struni(type_t t) { return(is_type_struct(t) || is_type_union(t)); } ///< Is the type a struct or union?
inline THREAD_SAFE bool is_type_enum(type_t t) { return(get_full_type(t) == BTF_ENUM); } ///< See ::BTF_ENUM
inline THREAD_SAFE bool is_type_bitfld(type_t t) { return(get_base_type(t) == BT_BITFIELD); } ///< See ::BT_BITFIELD
/// Does the type_t specify one of the basic types in \ref tf_int?
inline THREAD_SAFE bool is_type_int(type_t bt) { bt = get_base_type(bt); return bt >= BT_INT8 && bt <= BT_INT; }
/// Does the type specify a 128-bit value? (signed or unsigned, see \ref tf_int)
inline THREAD_SAFE bool is_type_int128(type_t t)
{
return get_full_type(t) == (BT_INT128|BTMT_UNKSIGN)
|| get_full_type(t) == (BT_INT128|BTMT_SIGNED);
}
/// Does the type specify a 64-bit value? (signed or unsigned, see \ref tf_int)
inline THREAD_SAFE bool is_type_int64(type_t t)
{
return get_full_type(t) == (BT_INT64|BTMT_UNKSIGN)
|| get_full_type(t) == (BT_INT64|BTMT_SIGNED);
}
/// Does the type specify a 32-bit value? (signed or unsigned, see \ref tf_int)
inline THREAD_SAFE bool is_type_int32(type_t t)
{
return get_full_type(t) == (BT_INT32|BTMT_UNKSIGN)
|| get_full_type(t) == (BT_INT32|BTMT_SIGNED);
}
/// Does the type specify a 16-bit value? (signed or unsigned, see \ref tf_int)
inline THREAD_SAFE bool is_type_int16(type_t t)
{
return get_full_type(t) == (BT_INT16|BTMT_UNKSIGN)
|| get_full_type(t) == (BT_INT16|BTMT_SIGNED);
}
/// Does the type specify a char value? (signed or unsigned, see \ref tf_int)
inline THREAD_SAFE bool is_type_char(type_t t) // chars are signed by default(?)
{
return get_full_type(t) == (BT_INT8|BTMT_CHAR)
|| get_full_type(t) == (BT_INT8|BTMT_SIGNED);
}
/// Is the type a pointer, array, or function type?
inline THREAD_SAFE bool is_type_paf(type_t t)
{
t = get_base_type(t);
return t >= BT_PTR && t <= BT_FUNC;
}
/// Is the type a pointer or array type?
inline THREAD_SAFE bool is_type_ptr_or_array(type_t t) { t = get_base_type(t); return t == BT_PTR || t == BT_ARRAY; }
/// Is the type a floating point type?
inline THREAD_SAFE bool is_type_floating(type_t t) { return get_base_type(t) == BT_FLOAT; } // any floating type
/// Is the type an integral type (char/short/int/long/bool)?
inline THREAD_SAFE bool is_type_integral(type_t t) { return get_full_type(t) > BT_VOID && get_base_type(t) <= BT_BOOL; }
/// Is the type an extended integral type? (integral or enum)
inline THREAD_SAFE bool is_type_ext_integral(type_t t) { return is_type_integral(t) || is_type_enum(t); }
/// Is the type an arithmetic type? (floating or integral)
inline THREAD_SAFE bool is_type_arithmetic(type_t t) { return get_full_type(t) > BT_VOID && get_base_type(t) <= BT_FLOAT; }
/// Is the type an extended arithmetic type? (arithmetic or enum)
inline THREAD_SAFE bool is_type_ext_arithmetic(type_t t) { return is_type_arithmetic(t) || is_type_enum(t); }
inline THREAD_SAFE bool is_type_uint(type_t t) { return get_full_type(t) == BTF_UINT; } ///< See ::BTF_UINT
inline THREAD_SAFE bool is_type_uchar(type_t t) { return get_full_type(t) == BTF_UCHAR; } ///< See ::BTF_UCHAR
inline THREAD_SAFE bool is_type_uint16(type_t t) { return get_full_type(t) == BTF_UINT16; } ///< See ::BTF_UINT16
inline THREAD_SAFE bool is_type_uint32(type_t t) { return get_full_type(t) == BTF_UINT32; } ///< See ::BTF_UINT32
inline THREAD_SAFE bool is_type_uint64(type_t t) { return get_full_type(t) == BTF_UINT64; } ///< See ::BTF_UINT64
inline THREAD_SAFE bool is_type_uint128(type_t t) { return get_full_type(t) == BTF_UINT128; } ///< See ::BTF_UINT128
inline THREAD_SAFE bool is_type_ldouble(type_t t) { return get_full_type(t) == BTF_LDOUBLE; } ///< See ::BTF_LDOUBLE
inline THREAD_SAFE bool is_type_double(type_t t) { return get_full_type(t) == BTF_DOUBLE; } ///< See ::BTF_DOUBLE
inline THREAD_SAFE bool is_type_float(type_t t) { return get_full_type(t) == BTF_FLOAT; } ///< See ::BTF_FLOAT
inline THREAD_SAFE bool is_type_tbyte(type_t t) { return get_full_type(t) == BTF_TBYTE; } ///< See ::BTF_FLOAT
inline THREAD_SAFE bool is_type_bool(type_t t) { return get_base_type(t) == BT_BOOL; } ///< See ::BTF_BOOL
/*! \defgroup tattr Type attributes
\ingroup tf
The type attributes start with the type attribute header byte (::TAH_BYTE),
followed by attribute bytes
*/
//@{
#define TAH_BYTE 0xFE ///< type attribute header byte
#define FAH_BYTE 0xFF ///< function argument attribute header byte
#define MAX_DECL_ALIGN 0x000F
/// \defgroup tattr_ext Extended type attributes
//@{
#define TAH_HASATTRS 0x0010 ///< has extended attributes
//@}
/// \defgroup tattr_udt Type attributes for udts
//@{
#define TAUDT_UNALIGNED 0x0040 ///< struct: unaligned struct
#define TAUDT_MSSTRUCT 0x0020 ///< struct: gcc msstruct attribute
#define TAUDT_CPPOBJ 0x0080 ///< struct: a c++ object, not simple pod type
#define TAUDT_VFTABLE 0x0100 ///< struct: is virtual function table
//@}
/// \defgroup tattr_field Type attributes for udt fields
//@{
#define TAFLD_BASECLASS 0x0020 ///< field: do not include but inherit from the current field
#define TAFLD_UNALIGNED 0x0040 ///< field: unaligned field
#define TAFLD_VIRTBASE 0x0080 ///< field: virtual base (not supported yet)
#define TAFLD_VFTABLE 0x0100 ///< field: ptr to virtual function table
//@}
/// \defgroup tattr_ptr Type attributes for pointers
//@{
#define TAPTR_PTR32 0x0020 ///< ptr: __ptr32
#define TAPTR_PTR64 0x0040 ///< ptr: __ptr64
#define TAPTR_RESTRICT 0x0060 ///< ptr: __restrict
#define TAPTR_SHIFTED 0x0080 ///< ptr: __shifted(parent_struct, delta)
//@}
/// \defgroup tattr_enum Type attributes for enums
//@{
#define TAENUM_64BIT 0x0020 ///< enum: store 64-bit values
#define TAENUM_UNSIGNED 0x0040 ///< enum: unsigned
#define TAENUM_SIGNED 0x0080 ///< enum: signed
//@}
#define TAH_ALL 0x01F0 ///< all defined bits
//@} tattr
/// The TAH byte (type attribute header byte) denotes the start of type attributes.
/// (see "tah-typeattrs" in the type bit definitions)
inline THREAD_SAFE bool is_tah_byte(type_t t)
{
return t == TAH_BYTE;
}
/// Identify an sdacl byte.
/// The first sdacl byte has the following format: 11xx000x.
/// The sdacl bytes are appended to udt fields. They indicate the start of type
/// attributes (as the tah-bytes do). The sdacl bytes are used in the udt
/// headers instead of the tah-byte. This is done for compatibility with old
/// databases, they were already using sdacl bytes in udt headers and as udt
/// field postfixes.
/// (see "sdacl-typeattrs" in the type bit definitions)
inline THREAD_SAFE bool is_sdacl_byte(type_t t)
{
return ((t & ~TYPE_FLAGS_MASK) ^ TYPE_MODIF_MASK) <= BT_VOID;
}
#ifndef SWIG
/// Compare two bytevecs with '<'.
/// v1 is considered less than v2 if either:
/// - v1.size() < v2.size()
/// - there is some i such that v1[i] < v2[i]
inline THREAD_SAFE bool operator <(const bytevec_t &v1, const bytevec_t &v2)
{
size_t n = qmin(v1.size(), v2.size());
for ( size_t i=0; i < n; i++ )
{
uchar k1 = v1[i];
uchar k2 = v2[i];
if ( k1 < k2 )
return true;
if ( k1 > k2 )
return false;
}
return v1.size() < v2.size();
}
#endif
/// \addtogroup tattr_ext Extended type attributes
//@{
/// Extended type attributes.
struct type_attr_t
{
qstring key; ///< one symbol keys are reserved to be used by the kernel
///< the ones starting with an underscore are reserved too
bytevec_t value; ///< attribute bytes
bool operator < (const type_attr_t &r) const { return key < r.key; }
bool operator >= (const type_attr_t &r) const { return !(*this < r); }
};
DECLARE_TYPE_AS_MOVABLE(type_attr_t);
/// this vector must be sorted by keys
typedef qvector<type_attr_t> type_attrs_t;
typedef int type_sign_t; ///< type signedness
const type_sign_t
no_sign = 0, ///< no sign, or unknown
type_signed = 1, ///< signed type
type_unsigned = 2; ///< unsigned type
//@}
//---------------------------------------------------------------------------
idaman bool ida_export append_argloc(qtype *out, const argloc_t &vloc); ///< Serialize argument location
idaman bool ida_export extract_argloc(argloc_t *vloc, const type_t **ptype, bool is_retval); ///< Deserialize argument location
idaman const type_t *ida_export resolve_typedef(const til_t *til, const type_t *type);
// low level functions to be used in predicate_t::should_display()
// in other places please use tinfo_t
inline bool is_restype_void(const til_t *til, const type_t *type)
{
type = resolve_typedef(til, type);
return type != NULL && is_type_void(*type);
}
inline bool is_restype_enum(const til_t *til, const type_t *type)
{
type = resolve_typedef(til, type);
return type != NULL && is_type_enum(*type);
}
inline bool is_restype_struni(const til_t *til, const type_t *type)
{
type = resolve_typedef(til, type);
return type != NULL && is_type_struni(*type);
}
inline bool is_restype_struct(const til_t *til, const type_t *type)
{
type = resolve_typedef(til, type);
return type != NULL && is_type_struct(*type);
}
// Get a base type for the specified size.
// This function prefers to return integer types
// \param size size in bytes; should be 1,2,4,8,16 or sizeof(floating point)
// \return BT_INT.. or BT_FLOAT... or BT_UNK
idaman type_t ida_export get_scalar_bt(int size);
//------------------------------------------------------------------------
/// Type Information Library
//------------------------------------------------------------------------
struct til_t
{
char *name = nullptr; ///< short file name (without path and extension)
char *desc = nullptr; ///< human readable til description
int nbases = 0; ///< number of base tils
til_t **base = nullptr; ///< tils that our til is based on
uint32 flags = 0; ///< \ref TIL_
/// \defgroup TIL_ Type info library property bits
/// used by til_t::flags
//@{
#define TIL_ZIP 0x0001 ///< pack buckets using zip
#define TIL_MAC 0x0002 ///< til has macro table
#define TIL_ESI 0x0004 ///< extended sizeof info (short, long, longlong)
#define TIL_UNI 0x0008 ///< universal til for any compiler
#define TIL_ORD 0x0010 ///< type ordinal numbers are present
#define TIL_ALI 0x0020 ///< type aliases are present (this bit is used only on the disk)
#define TIL_MOD 0x0040 ///< til has been modified, should be saved
#define TIL_STM 0x0080 ///< til has extra streams
#define TIL_SLD 0x0100 ///< sizeof(long double)
//@}
/// Has the til been modified? (#TIL_MOD)
inline bool is_dirty(void) const { return (flags & TIL_MOD) != 0; }
/// Mark the til as modified (#TIL_MOD)
inline void set_dirty(void) { flags |= TIL_MOD; }
compiler_info_t cc; ///< information about the target compiler
til_bucket_t *syms = nullptr; ///< symbols
til_bucket_t *types = nullptr; ///< types
til_bucket_t *macros = nullptr; ///< macros
int nrefs = 0; ///< number of references to the til
int nstreams = 0; ///< number of extra streams
til_stream_t **streams = nullptr; ///< symbol stream storage
};
/// Initialize a til
idaman til_t *ida_export new_til(const char *name, const char *desc);
/// Add multiple base tils.
/// \param[out] errbuf error message
/// \param ti target til
/// \param tildir directory where specified tils can be found.
/// NULL means all default til subdirectories.
/// \param bases comma separated list of til names
/// \param gen_events generate corresponding IDB events
/// \return one of \ref TIL_ADD_
idaman int ida_export add_base_tils(qstring *errbuf, til_t *ti, const char *tildir, const char *bases, bool gen_events);
/// \defgroup TIL_ADD_ Add TIL result codes
/// returned by add_base_tils()
//@{
#define TIL_ADD_FAILED 0 ///< see errbuf
#define TIL_ADD_OK 1 ///< some tils were added
#define TIL_ADD_ALREADY 2 ///< the base til was already added
//@}
/// Load til from a file.
/// Failure to load base tils are reported into 'errbuf'. They do not prevent
/// loading of the main til.
/// \param name filename of the til. If it's an absolute path, tildir is ignored.
/// - NB: the file extension is forced to .til
/// \param[out] errbuf error message
/// \param tildir directory where to load the til from.
/// NULL means default til subdirectories.
/// \return pointer to resulting til, NULL if failed and error message is in errbuf
idaman til_t *ida_export load_til(const char *name, qstring *errbuf, const char *tildir=NULL);
/// Sort til (use after modifying it).
/// \return false if no memory or bad parameter
idaman bool ida_export sort_til(til_t *ti);
/// Collect garbage in til.
/// Must be called before storing the til.
/// \return true if any memory was freed
idaman bool ida_export compact_til(til_t *ti);
/// Store til to a file.
/// If the til contains garbage, it will be collected before storing the til.
/// Your plugin should call compact_til() before calling store_til().
/// \param ti type library to store
/// \param tildir directory where to store the til. NULL means current directory.
/// \param name filename of the til. If it's an absolute path, tildir is ignored.
/// - NB: the file extension is forced to .til
/// \return success
idaman bool ida_export store_til(til_t *ti, const char *tildir, const char *name);
/// Free memory allocated by til
idaman void ida_export free_til(til_t *ti);
/// Get human-readable til description
idaman til_t *ida_export load_til_header(const char *tildir, const char *name, qstring *errbuf);
//------------------------------------------------------------------------
/// \defgroup CM_ CM
/// Calling convention & Model
//@{
/// \defgroup CM_ptr Default pointer size
//@{
const cm_t CM_MASK = 0x03;
const cm_t CM_UNKNOWN = 0x00; ///< unknown
const cm_t CM_N8_F16 = 0x01; ///< if sizeof(int)<=2: near 1 byte, far 2 bytes
const cm_t CM_N64 = 0x01; ///< if sizeof(int)>2: near 8 bytes, far 8 bytes
const cm_t CM_N16_F32 = 0x02; ///< near 2 bytes, far 4 bytes
const cm_t CM_N32_F48 = 0x03; ///< near 4 bytes, far 6 bytes
//@}
/// \defgroup CM_M_ Model
//@{
const cm_t CM_M_MASK = 0x0C;
const cm_t CM_M_NN = 0x00; ///< small: code=near, data=near (or unknown if CM_UNKNOWN)
const cm_t CM_M_FF = 0x04; ///< large: code=far, data=far
const cm_t CM_M_NF = 0x08; ///< compact: code=near, data=far
const cm_t CM_M_FN = 0x0C; ///< medium: code=far, data=near
/// Does the given model specify far code?.
inline THREAD_SAFE bool is_code_far(cm_t cm) { return((cm & 4) != 0); }
/// Does the given model specify far data?.
inline THREAD_SAFE bool is_data_far(cm_t cm) { return((cm &= CM_M_MASK) && cm != CM_M_FN); }
//@}
/// \defgroup CM_CC_ Calling convention
//@{
const cm_t CM_CC_MASK = 0xF0;
const cm_t CM_CC_INVALID = 0x00; ///< this value is invalid
const cm_t CM_CC_UNKNOWN = 0x10; ///< unknown calling convention
const cm_t CM_CC_VOIDARG = 0x20; ///< function without arguments
///< if has other cc and argnum == 0,
///< represent as f() - unknown list
const cm_t CM_CC_CDECL = 0x30; ///< stack
const cm_t CM_CC_ELLIPSIS = 0x40; ///< cdecl + ellipsis
const cm_t CM_CC_STDCALL = 0x50; ///< stack, purged
const cm_t CM_CC_PASCAL = 0x60; ///< stack, purged, reverse order of args
const cm_t CM_CC_FASTCALL = 0x70; ///< stack, purged (x86), first args are in regs (compiler-dependent)
const cm_t CM_CC_THISCALL = 0x80; ///< stack, purged (x86), first arg is in reg (compiler-dependent)
const cm_t CM_CC_MANUAL = 0x90; ///< special case for compiler specific (not used)
const cm_t CM_CC_SPOILED = 0xA0; ///< This is NOT a cc! Mark of __spoil record
///< the low nibble is count and after n {spoilreg_t}
///< present real cm_t byte. if n == BFA_FUNC_MARKER,
///< the next byte is the function attribute byte.
const cm_t CM_CC_RESERVE4 = 0xB0;
const cm_t CM_CC_RESERVE3 = 0xC0;
const cm_t CM_CC_SPECIALE = 0xD0; ///< ::CM_CC_SPECIAL with ellipsis
const cm_t CM_CC_SPECIALP = 0xE0; ///< Equal to ::CM_CC_SPECIAL, but with purged stack
const cm_t CM_CC_SPECIAL = 0xF0; ///< usercall: locations of all arguments
///< and the return value are explicitly specified
//@} CM_CC_
//@} CM_
/*! \defgroup BFA_ Function attribute byte
\ingroup tf_func
Zero attribute byte is forbidden.
*/
//@{
const type_t BFA_NORET = 0x01; ///< __noreturn
const type_t BFA_PURE = 0x02; ///< __pure
const type_t BFA_HIGH = 0x04; ///< high level prototype (with possibly hidden args)
const type_t BFA_STATIC = 0x08; ///< static
const type_t BFA_VIRTUAL = 0x10; ///< virtual
const cm_t BFA_FUNC_MARKER = 0x0F; ///< This is NOT a cc! (used internally as a marker)
const type_t BFA_FUNC_EXT_FORMAT = 0x80; ///< This is NOT a real attribute (used internally as marker for extended format)
//@}
#ifndef SWIG
/// Helper to declare common ::argloc_t related functions
#define ARGLOC_HELPER_DEFINITIONS(decl) \
decl void ida_export copy_argloc(argloc_t *dst, const argloc_t *src); \
decl void ida_export cleanup_argloc(argloc_t *vloc);\
decl int ida_export compare_arglocs(const argloc_t &a, const argloc_t &b);
#else
#define ARGLOC_HELPER_DEFINITIONS(decl)
#endif // SWIG
ARGLOC_HELPER_DEFINITIONS(idaman)
/// \defgroup argloc Argument locations
/// \ingroup CM_
//@{
/// Specifies the location type of a function argument - see \ref ALOC_
typedef int argloc_type_t;
/// \defgroup ALOC_ Argument location types
//@{
const argloc_type_t
ALOC_NONE = 0, ///< none
ALOC_STACK = 1, ///< stack offset
ALOC_DIST = 2, ///< distributed (scattered)
ALOC_REG1 = 3, ///< one register (and offset within it)
ALOC_REG2 = 4, ///< register pair
ALOC_RREL = 5, ///< register relative
ALOC_STATIC = 6, ///< global address
ALOC_CUSTOM = 7; ///< custom argloc (7 or higher)
//@}
/// Register-relative argument location
struct rrel_t
{
sval_t off; ///< displacement from the address pointed by the register
int reg; ///< register index (into \varmem{ph,processor_t,reg_names})
};
class scattered_aloc_t;
/// Description of a custom argloc. Custom arglocs can be added by plugins in order
/// to describe the locations unsupported by the ida kernel.
struct custloc_desc_t
{
size_t cbsize; ///< size of this structure
const char *name; ///< name of the custom argloc type. must be unique
/// Copy src into empty_dst
void (idaapi *copy)(argloc_t *empty_dst, const argloc_t &src);
/// Clear contents of loc before it is modified (may be NULL)
void (idaapi *cleanup)(argloc_t *loc);
/// May be NULL
bool (idaapi *verify)(
const argloc_t &loc,
int size,
const rangeset_t *gaps,
bool part_of_scattered);
/// Lexical comparison of two arglocs
int (idaapi *compare)(const argloc_t &a, const argloc_t &b);
/// Get textual description of the location (not the value at the location!)
size_t (idaapi *print)(
char *buf,
size_t bufsize,
const argloc_t &loc,
asize_t size,
int praloc_flags); // PRALOC_...
/// Dereference the struct/union pointed by 'strloc': take member at offset 'off'
/// (or use the field name), improve member 'tif' if necessary
bool (idaapi *deref_field)(
argloc_t *out,
tinfo_t *tif,
const argloc_t &strloc,
const tinfo_t &struct_tif,
asize_t off,
const qstring &name);
/// Dereference the array pointed by 'arrloc': take member number 'n'
/// (element size is 'elsize'), improve member 'tif' if necessary
bool (idaapi *deref_array)(
argloc_t *out,
tinfo_t *tif,
const argloc_t &arrloc,
const tinfo_t &array_tif,
asize_t n,
asize_t elsize);
/// Dereference the pointer at 'loc': retrieve location of the pointed object,
/// improve 'tif' of the pointed object if necessary
bool (idaapi *deref_ptr)(
argloc_t *out,
tinfo_t *tif,
const argloc_t &ptrloc);
/// Read the pointer at 'loc': retrieve value of a simple object.
/// the object value must fit value_u.
bool (idaapi *read_value)(
value_u *value,
const argloc_t &loc,
int size,
const tinfo_t &tif);
/// Update value at 'loc'. if idcv is VT_LONG/VT_INT64/VT_FLOAT, the value
/// in native format is copied to 'scalar_value' for your convenience. otherwise
/// please use 'idcv' and not 'scalar_value'.
bool (idaapi *write_value)(
const argloc_t &loc,
const idc_value_t &idcv,
const value_u &scalar_value,
int size,
qstring *errbuf);
/// Calc max natural string length at 'loc' in the debugged process memory
asize_t (idaapi *calc_string_length)(
const argloc_t &loc,
const tinfo_t &string_tif);
/// Retrieve string at 'loc' from the debugged process memory,
/// returns quoted string value
bool (idaapi *get_string)(
qstring *out,
tinfo_t *elem_tif,
const argloc_t &loc,
const tinfo_t &string_tif,
size_t len);
/// Retrieve size of array at 'loc' (number of elements)
asize_t (idaapi *guess_array_size)(
const argloc_t &loc,
const tinfo_t &array_tif);
/// Retrieve type of the object at 'loc'
bool (idaapi *get_tinfo)(
tinfo_t *out,
const argloc_t &loc);
/// Calculate the number of children for the given location.
/// (arrays, structs, ptrs may have children and therefore be expanded)
int (idaapi *calc_number_of_children)(const argloc_t &loc, const tinfo_t &tif);
/// Get string containing a printable representation of the pointer at 'loc'.
/// Returns the number of characters printed.
/// May be NULL.
size_t (idaapi *print_ptr_value)(
char *buf,
size_t bufsize,
bool *is_valid_ptr,
const argloc_t &loc,
const tinfo_t &tif);
};
/// Save a custom argloc
idaman int ida_export install_custom_argloc(const custloc_desc_t *custloc);
/// Delete the custom argloc at the given index
idaman bool ida_export remove_custom_argloc(int idx);
/// Retrieve the custom argloc at the given index
idaman const custloc_desc_t *ida_export retrieve_custom_argloc(int idx);
/// Describes an argument location.
/// A typical argument is stored in one location, either a register or a stack slot. \n
/// However, some arguments can be stored in multiple locations, for example in a pair \n
/// of registers. In some really complex cases an argument can be located in multiple \n
/// registers and some stack slots. This class can describe all these cases.
class argloc_t // #argloc
{
public:
typedef size_t biggest_t;
private:
argloc_type_t type;
union
{
sval_t sval; // ::ALOC_STACK, ::ALOC_STATIC
uint32 reginfo; // ::ALOC_REG1, ::ALOC_REG2
rrel_t *rrel; // ::ALOC_RREL
scattered_aloc_t *dist; // ::ALOC_DIST
void *custom; // ::ALOC_CUSTOM
biggest_t biggest; // to facilitate manipulation of this union
};
ARGLOC_HELPER_DEFINITIONS(friend)
public:
argloc_t(void) : type(ALOC_NONE), biggest(0) {} ///< Constructor
argloc_t(const argloc_t &r) : type(ALOC_NONE) { copy_argloc(this, &r); } ///< Constructor
~argloc_t(void) { cleanup_argloc(this); } ///< Destructor
argloc_t &operator=(const argloc_t &r) { copy_argloc(this, &r); return *this; } ///< Constructor
DEFINE_MEMORY_ALLOCATION_FUNCS()
/// Assign this == r and r == this
void swap(argloc_t &r)
{
biggest_t tmp = biggest; biggest = r.biggest; r.biggest = tmp;
argloc_type_t t = type; type = r.type; r.type = t;
}
const char *dstr(void) const;
argloc_type_t atype(void) const { return type; } ///< Get type (\ref ALOC_)
bool is_reg1(void) const { return type == ALOC_REG1; } ///< See ::ALOC_REG1
bool is_reg2(void) const { return type == ALOC_REG2; } ///< See ::ALOC_REG2
bool is_reg(void) const { return type == ALOC_REG1 || type == ALOC_REG2; } ///< is_reg1() || is_reg2()
bool is_rrel(void) const { return type == ALOC_RREL; } ///< See ::ALOC_RREL
bool is_ea(void) const { return type == ALOC_STATIC; } ///< See ::ALOC_STATIC
bool is_stkoff(void) const { return type == ALOC_STACK; } ///< See ::ALOC_STACK
bool is_scattered(void) const { return type == ALOC_DIST; } ///< See ::ALOC_DIST
inline bool has_reg() const; ///< TRUE if argloc has a register part
inline bool has_stkoff() const; ///< TRUE if argloc has a stack part
inline bool is_mixed_scattered() const; ///< mixed scattered: consists of register and stack parts
bool is_fragmented(void) const { return type == ALOC_DIST || type == ALOC_REG2; } ///< is_scattered() || is_reg2()
bool is_custom(void) const { return type >= ALOC_CUSTOM; } ///< See ::ALOC_CUSTOM
bool is_badloc(void) const { return type == ALOC_NONE; } ///< See ::ALOC_NONE
/// Get the register info.
/// Use when atype() == ::ALOC_REG1 or ::ALOC_REG2
int reg1(void) const { return uint16(reginfo); }
/// Get offset from the beginning of the register in bytes.
/// Use when atype() == ::ALOC_REG1
int regoff(void) const { return uint16(reginfo >> 16); }
/// Get info for the second register.
/// Use when atype() == ::ALOC_REG2
int reg2(void) const { return uint16(reginfo >> 16); }
/// Get all register info.
/// Use when atype() == ::ALOC_REG1 or ::ALOC_REG2
uint32 get_reginfo(void) const { return reginfo; }
/// Get the stack offset.
/// Use if atype() == ::ALOC_STACK
sval_t stkoff(void) const { return sval; }
/// Get the global address.
/// Use when atype() == ::ALOC_STATIC
ea_t get_ea(void) const { return sval; }
/// Get scattered argument info.
/// Use when atype() == ::ALOC_DIST
scattered_aloc_t &scattered(void) { return *dist; }
const scattered_aloc_t &scattered(void) const { return *dist; } ///< copydoc scattered()
/// Get register-relative info.
/// Use when atype() == ::ALOC_RREL
rrel_t &get_rrel(void) { return *rrel; }
const rrel_t &get_rrel(void) const { return *rrel; } ///< copydoc get_rrel()
/// Get custom argloc info.
/// Use if atype() == ::ALOC_CUSTOM
void *get_custom(void) const { return custom; }
/// Get largest element in internal union
biggest_t get_biggest(void) const { return biggest; }
// be careful with these functions, they do not cleanup!
void _set_badloc(void) { type = ALOC_NONE; } ///< Use set_badloc()
void _set_reg1(int reg, int off=0) { type = ALOC_REG1; reginfo = reg | (off << 16); } ///< Use set_reg1()
void _set_reg2(int _reg1, int _reg2) { type = ALOC_REG2; reginfo = _reg1 | (_reg2 << 16); } ///< Use set_reg2()
void _set_stkoff(sval_t off) { type = ALOC_STACK; sval = off; } ///< Use set_stkoff()
void _set_ea(ea_t _ea) { type = ALOC_STATIC; sval = _ea; } ///< Use set_ea
/// Use consume_rrel()
bool _consume_rrel(rrel_t *p) //lint -sem(argloc_t::_consume_rrel, custodial(1))
{
if ( p == NULL )
return false;
type = ALOC_RREL;
rrel = p;
return true;
}
/// Use consume_scattered()
bool _consume_scattered(scattered_aloc_t *p)
{
if ( p == NULL )
return false;
type = ALOC_DIST;
dist = p;
return true;
}
/// Set custom argument location (careful - this function does not clean up!)
void _set_custom(argloc_type_t ct, void *pdata) { type = ct; custom = pdata; }
/// Set biggest element in internal union (careful - this function does not clean up!)
void _set_biggest(argloc_type_t ct, biggest_t data) { type = ct; biggest = data; }
/// Set register location
void set_reg1(int reg, int off=0) { cleanup_argloc(this); _set_reg1(reg, off); }
/// Set secondary register location
void set_reg2(int _reg1, int _reg2) { cleanup_argloc(this); _set_reg2(_reg1, _reg2); }
/// Set stack offset location
void set_stkoff(sval_t off) { cleanup_argloc(this); _set_stkoff(off); }
/// Set static ea location
void set_ea(ea_t _ea) { cleanup_argloc(this); _set_ea(_ea); }
/// Set register-relative location - can't be NULL
void consume_rrel(rrel_t *p) { cleanup_argloc(this); _consume_rrel(p); }
/// Set distributed argument location
void consume_scattered(scattered_aloc_t *p) { cleanup_argloc(this); _consume_scattered(p); }
/// Set to invalid location
void set_badloc(void) { cleanup_argloc(this); }
/// Calculate offset that can be used to compare 2 similar arglocs
sval_t calc_offset(void) const
{
switch ( type )
{
default:
case ALOC_NONE:
case ALOC_DIST:
case ALOC_REG2:
return -1;
case ALOC_RREL:
return rrel->off;
case ALOC_STACK:
case ALOC_STATIC:
return sval;
case ALOC_REG1:
return reg1();
}
}
/// Move the location to point 'delta' bytes further
bool advance(int delta)
{
switch ( type )
{
case ALOC_REG1:
_set_reg1(reg1()+delta, regoff());
break;
case ALOC_STACK:
case ALOC_STATIC:
sval += delta;
break;
case ALOC_RREL:
rrel->off += delta;
break;
default:
return false;
}
return true;
}
/// Set register offset to justify it to the upper part of _SLOTSIZE
void justify_reg_high(size_t size, size_t _slotsize)
{
if ( is_reg1() )
_set_reg1(reg1(), size < _slotsize ? _slotsize - size : 0);
}
/// Set stack offset to right-justify it in _SLOTSIZE
void justify_stkoff_right(size_t size, size_t _slotsize)
{
if ( is_stkoff() )
{
sval_t off = align_down(stkoff(), _slotsize);
if ( size < _slotsize )
off += _slotsize - size;
_set_stkoff(off);
}
}
DECLARE_COMPARISONS(argloc_t)
{
return compare_arglocs(*this, r);
}
};
DECLARE_TYPE_AS_MOVABLE(argloc_t);
typedef qvector<argloc_t> arglocs_t; ///< vector of argument locations
/// Subsection of an argument location
struct argpart_t : public argloc_t
{
ushort off; ///< offset from the beginning of the argument
ushort size; ///< the number of bytes
DEFINE_MEMORY_ALLOCATION_FUNCS()
argpart_t(const argloc_t &a) : argloc_t(a), off(0xFFFF), size(0) {} ///< Constructor
argpart_t(void) : off(0xFFFF), size(0) {} ///< Constructor
argpart_t &copy_from(const argloc_t &a) { *(argloc_t*)this = a; return *this; }
/// Does this argpart have a valid offset?
bool bad_offset(void) const { return off == 0xFFFF; }
/// Does this argpart have a valid size?
bool bad_size(void) const { return size == 0; }
/// Compare two argparts, based on their offset
bool operator < (const argpart_t &r) const { return off < r.off; }
/// Assign this = r and r = this
void swap(argpart_t &r)
{
argloc_t::swap(r);
qswap(off, r.off);
qswap(size, r.size);
}
};
DECLARE_TYPE_AS_MOVABLE(argpart_t);
typedef qvector<argpart_t> argpartvec_t;
/// Used to manage arguments that are described by multiple locations (also see ::ALOC_DIST)
class scattered_aloc_t : public argpartvec_t
{
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
};
DECLARE_TYPE_AS_MOVABLE(scattered_aloc_t);
/// Verify argloc_t.
/// \param size total size of the variable
/// \param gaps if not NULL, specifies gaps in structure definition.
/// these gaps should not map to any argloc, but everything else must be covered
/// \return 0 if ok, otherwise an interr code.
idaman int ida_export verify_argloc(const argloc_t &vloc, int size, const rangeset_t *gaps);
/// Verify and optimize scattered argloc into simple form.
/// All new arglocs must be processed by this function.
/// \retval true success
/// \retval false the input argloc was illegal
idaman bool ida_export optimize_argloc(argloc_t *vloc, int size, const rangeset_t *gaps);
/// Convert an argloc to human readable form
idaman size_t ida_export print_argloc(
char *buf,
size_t bufsize,
const argloc_t &vloc,
int size=0,
int vflags=0);
#define PRALOC_VERIFY 0x01 ///< interr if illegal argloc
#define PRALOC_STKOFF 0x02 ///< print stack offsets
/// Visit all argument locations. The callback will not receive ::ALOC_DIST/::ALOC_REG2 types,
/// they will be converted into smaller argloc types (::ALOC_REG1 or other)
struct aloc_visitor_t
{
virtual int idaapi visit_location(argloc_t &v, int off, int size) = 0;
virtual ~aloc_visitor_t() {}
};
/// Compress larger argloc types and initiate the aloc visitor
idaman int ida_export for_all_arglocs(aloc_visitor_t &vv, argloc_t &vloc, int size, int off=0);
/// Same as ::aloc_visitor_t, but may not modify the argloc
struct const_aloc_visitor_t
{
virtual int idaapi visit_location(const argloc_t &v, int off, int size) = 0;
virtual ~const_aloc_visitor_t() {}
};
/// See for_all_arglocs()
inline int idaapi for_all_const_arglocs(const_aloc_visitor_t &vv, const argloc_t &vloc, int size, int off=0)
{
return for_all_arglocs(*(aloc_visitor_t*)(&vv),
CONST_CAST(argloc_t&)(vloc),
size,
off);
}
//--------------------------------------------------------------------------
/// \defgroup C_PC_ Standard C-language models for x86
/// \ingroup CM_
//@{
const cm_t C_PC_TINY = (CM_N16_F32 | CM_M_NN);
const cm_t C_PC_SMALL = (CM_N16_F32 | CM_M_NN);
const cm_t C_PC_COMPACT = (CM_N16_F32 | CM_M_NF);
const cm_t C_PC_MEDIUM = (CM_N16_F32 | CM_M_FN);
const cm_t C_PC_LARGE = (CM_N16_F32 | CM_M_FF);
const cm_t C_PC_HUGE = (CM_N16_F32 | CM_M_FF);
const cm_t C_PC_FLAT = (CM_N32_F48 | CM_M_NN);
//@}
/// Get the calling convention
inline THREAD_SAFE cm_t get_cc(cm_t cm) { return(cm & CM_CC_MASK); }
/// Does the calling convention specify argument locations explicitly?
inline THREAD_SAFE bool is_user_cc(cm_t cm)
{
cm_t cc = get_cc(cm);
return cc >= CM_CC_SPECIALE;
}
/// Does the calling convention use ellipsis?
inline THREAD_SAFE bool is_vararg_cc(cm_t cm)
{
cm_t cc = get_cc(cm);
return cc == CM_CC_ELLIPSIS || cc == CM_CC_SPECIALE;
}
/// Does the calling convention clean the stack arguments upon return?.
/// \note this function is valid only for x86 code
inline THREAD_SAFE bool is_purging_cc(cm_t cm)
{
cm_t cc = get_cc(cm);
return cc == CM_CC_STDCALL || cc == CM_CC_PASCAL || cc == CM_CC_SPECIALP || cc == CM_CC_FASTCALL || cc == CM_CC_THISCALL;
}
//--------------------------------------------------------------------------
/// Function argument passing: how GP & FP registers cooperate with each other
enum argreg_policy_t
{
ARGREGS_POLICY_UNDEFINED,
ARGREGS_GP_ONLY, ///< GP registers used for all arguments
ARGREGS_INDEPENDENT, ///< FP/GP registers used separately (like gcc64)
ARGREGS_BY_SLOTS, ///< fixed FP/GP register per each slot (like vc64)
ARGREGS_FP_CONSUME_GP, ///< FP register also consumes one or more GP regs but not vice versa (aix ppc ABI)
ARGREGS_MIPS_O32, ///< MIPS ABI o32
};
//@} argloc
class callregs_t;
/// Register allocation calling convention.
/// (allocation policy, arrays of GP and FP registers)
class callregs_t
{
bool set_inds(int *p_ind1, int *p_ind2, int ind) const
{
if ( ind == -1 )
return false;
*p_ind1 = ind;
*p_ind2 = by_slots() ? ind : -1;
return true;
}
// copy -1-terminated array to a vector
static void set_regarray(intvec_t *regvec, const int *regarray)
{
regvec->clear();
if ( regarray != NULL )
while ( *regarray != -1 )
regvec->push_back(*regarray++);
}
void calc_nregs()
{
nregs = gpregs.size();
if ( policy == ARGREGS_INDEPENDENT || policy == ARGREGS_FP_CONSUME_GP )
nregs += int(fpregs.size());
}
public:
argreg_policy_t policy; ///< argument policy
int nregs; ///< max number of registers that can be used in a call
intvec_t gpregs; ///< array of gp registers
intvec_t fpregs; ///< array of fp registers
/// Constructor
callregs_t(): policy(ARGREGS_POLICY_UNDEFINED), nregs(0) {}
/// Constructor - initialize with the given request (see init_regs())
callregs_t(cm_t cc): policy(ARGREGS_POLICY_UNDEFINED), nregs(0)
{
init_regs(cc);
}
/// Init policy & registers for given CC.
void init_regs(cm_t cc)
{
processor_t::get_cc_regs(this, get_cc(cc));
}
// policy-specific options
bool by_slots() const { return policy == ARGREGS_BY_SLOTS; }
/// Init policy & registers (arrays are -1-terminated)
void set(argreg_policy_t _policy, const int *gprs, const int *fprs)
{
policy = _policy;
set_regarray(&gpregs, gprs);
set_regarray(&fpregs, fprs);
calc_nregs();
}
/// Set policy and registers to invalid values
void reset()
{
set(ARGREGS_POLICY_UNDEFINED, NULL, NULL);
}
/// Get max number of registers may be used in a function call.
static int regcount(cm_t cc)
{
callregs_t vr(cc); return vr.nregs;
}
// return index of register, -1 else
static int findreg(const intvec_t &regs, int r)
{
intvec_t::const_iterator p = regs.find(r);
return p == regs.end() ? -1 : (p-regs.begin());
}
/// Get register indexes within GP/FP arrays.
/// (-1 -> is not present in the corresponding array)
bool reginds(int *gp_ind, int *fp_ind, int r) const
{
return findregs(gp_ind, fp_ind, r, gpregs, fpregs);
}
protected:
/// Search for register r in gprs and fprs.
/// If found, fill gp_ind and fp_ind based on #policy
bool findregs(int *gp_ind, int *fp_ind, int r, const intvec_t &gprs, const intvec_t &fprs) const
{
*gp_ind = *fp_ind = -1;
return set_inds(gp_ind, fp_ind, findreg(gprs, r))
|| set_inds(fp_ind, gp_ind, findreg(fprs, r));
}
};
//--------------------------------------------------------------------------
/// \defgroup CC
/// Target compiler
//@{
/// \defgroup COMP_ Compiler IDs
//@{
const comp_t COMP_MASK = 0x0F;
const comp_t COMP_UNK = 0x00; ///< Unknown
const comp_t COMP_MS = 0x01; ///< Visual C++
const comp_t COMP_BC = 0x02; ///< Borland C++
const comp_t COMP_WATCOM = 0x03; ///< Watcom C++
// const comp_t COMP_ = 0x04
// const comp_t COMP_ = 0x05
const comp_t COMP_GNU = 0x06; ///< GNU C++
const comp_t COMP_VISAGE = 0x07; ///< Visual Age C++
const comp_t COMP_BP = 0x08; ///< Delphi
//----
const comp_t COMP_UNSURE = 0x80; ///< uncertain compiler id
//@}
/// \defgroup CC_funcs Functions: work with compiler IDs
//@{
/// Get compiler bits
inline THREAD_SAFE comp_t get_comp(comp_t comp) { return(comp & COMP_MASK); }
/// Get full compiler name
idaman const char *ida_export get_compiler_name(comp_t id);
/// Get abbreviated compiler name
idaman const char *ida_export get_compiler_abbr(comp_t id);
/// Collection of compiler descriptions
typedef qvector<comp_t> compvec_t;
/// Get names of all built-in compilers
idaman void ida_export get_compilers(compvec_t *ids, qstrvec_t *names, qstrvec_t *abbrs);
/// See ::COMP_UNSURE
inline THREAD_SAFE comp_t is_comp_unsure(comp_t comp) { return (comp & COMP_UNSURE); }
/// Get compiler specified by \varmem{inf,idainfo,cc}
inline comp_t default_compiler(void) { return get_comp(inf_get_cc_id()); }
/// Is the target compiler ::COMP_GNU?
inline bool is_gcc(void) { return default_compiler() == COMP_GNU; }
/// Is the target compiler 32 bit gcc?
inline bool is_gcc32(void) { return is_gcc() && !inf_is_64bit(); }
/// Is the target compiler 64 bit gcc?
inline bool is_gcc64(void) { return is_gcc() && inf_is_64bit(); }
/// Should use the struct/union layout as done by gcc?
inline bool gcc_layout(void) { return is_gcc() || (inf_get_abibits() & ABI_GCC_LAYOUT) != 0; }
/// Change current compiler.
/// \param cc compiler to switch to
/// \param flags \ref SETCOMP_
/// \param abiname ABI name
/// \return success
idaman bool ida_export set_compiler(
const compiler_info_t &cc,
int flags,
const char *abiname=NULL);
/// \defgroup SETCOMP_ Set compiler flags
//@{
#define SETCOMP_OVERRIDE 0x0001 ///< may override old compiler info
#define SETCOMP_ONLY_ID 0x0002 ///< cc has only 'id' field
///< the rest will be set to defaults
///< corresponding to the program bitness
#define SETCOMP_ONLY_ABI 0x0004 ///< ignore cc field complete, use only abiname
#define SETCOMP_BY_USER 0x0008 ///< invoked by user, cannot be replaced by module/loader
//@}
/// Set the compiler id (see \ref COMP_)
inline bool idaapi set_compiler_id(comp_t id, const char *abiname=NULL)
{
compiler_info_t cc;
cc.id = id;
return set_compiler(cc, SETCOMP_ONLY_ID, abiname);
}
/// Set abi name (see \ref COMP_)
inline bool idaapi set_abi_name(const char *abiname, bool user_level = false)
{
compiler_info_t cc;
cc.id = 0;
int flags = SETCOMP_ONLY_ABI | (user_level ? SETCOMP_BY_USER : 0);
return set_compiler(cc, flags, abiname);
}
/// Get ABI name.
/// \return length of the name (>=0)
idaman ssize_t ida_export get_abi_name(qstring *out);
/// Add/remove/check ABI option
/// General form of full abi name: abiname-opt1-opt2-... or -opt1-opt2-...
/// \param abi_opts - ABI options to add/remove in form opt1-opt2-...
/// \param user_level - initiated by user if TRUE (==SETCOMP_BY_USER)
/// \return success
idaman bool ida_export append_abi_opts(const char *abi_opts, bool user_level = false);
idaman bool ida_export remove_abi_opts(const char *abi_opts, bool user_level = false);
/// \param compstr - compiler description in form <abbr>:<abiname>
/// \param user_level - initiated by user if TRUE
/// \return success
idaman bool ida_export set_compiler_string(const char *compstr, bool user_level);
//-------------------------------------------------------------------------
inline bool is_golang_abi(void)
{
if ( !is_gcc() )
return false; // "golang" abi can be defined only for GCC
qstring abiname;
get_abi_name(&abiname);
return abiname == "golang";
}
//-------------------------------------------------------------------------
inline bool use_golang_abi(cm_t cm)
{
cm_t cc = get_cc(cm);
return (cc == CM_CC_FASTCALL || cc == CM_CC_VOIDARG) && is_golang_abi();
}
//@} CC_funcs
//@} CC
//--------------------------------------------------------------------------
const size_t BADSIZE = size_t(-1); ///< bad type size
#define MAX_FUNC_ARGS 256 ///< max number of function arguments
//--------------------------------------------------------------------------
/// abstractness of declaration (see h2ti())
enum abs_t { abs_unk, abs_no, abs_yes };
enum sclass_t ///< storage class
{
sc_unk, ///< unknown
sc_type, ///< typedef
sc_ext, ///< extern
sc_stat, ///< static
sc_reg, ///< register
sc_auto, ///< auto
sc_friend, ///< friend
sc_virt ///< virtual
};
/// \defgroup parse_tinfo Type parsing
/// Format/Parse/Print type information
//@{
/// \defgroup HTI_ Type formatting flags
//@{
#define HTI_CPP 0x00000001 ///< C++ mode (not implemented)
#define HTI_INT 0x00000002 ///< debug: print internal representation of types
#define HTI_EXT 0x00000004 ///< debug: print external representation of types
#define HTI_LEX 0x00000008 ///< debug: print tokens
#define HTI_UNP 0x00000010 ///< debug: check the result by unpacking it
#define HTI_TST 0x00000020 ///< test mode: discard the result
#define HTI_FIL 0x00000040 ///< "input" is file name,
///< otherwise "input" contains a C declaration
#define HTI_MAC 0x00000080 ///< define macros from the base tils
#define HTI_NWR 0x00000100 ///< no warning messages
#define HTI_NER 0x00000200 ///< ignore all errors but display them
#define HTI_DCL 0x00000400 ///< don't complain about redeclarations
#define HTI_NDC 0x00000800 ///< don't decorate names
#define HTI_PAK 0x00007000 ///< explicit structure pack value (#pragma pack)
#define HTI_PAK_SHIFT 12 ///< shift for #HTI_PAK. This field should
///< be used if you want to remember an explicit
///< pack value for each structure/union type.
///< See #HTI_PAK... definitions
#define HTI_PAKDEF 0x00000000 ///< default pack value
#define HTI_PAK1 0x00001000 ///< #pragma pack(1)
#define HTI_PAK2 0x00002000 ///< #pragma pack(2)
#define HTI_PAK4 0x00003000 ///< #pragma pack(4)
#define HTI_PAK8 0x00004000 ///< #pragma pack(8)
#define HTI_PAK16 0x00005000 ///< #pragma pack(16)
#define HTI_HIGH 0x00008000 ///< assume high level prototypes
///< (with hidden args, etc)
#define HTI_LOWER 0x00010000 ///< lower the function prototypes
#define HTI_RAWARGS 0x00020000 ///< leave argument names unchanged (do not remove underscores)
//@}
/// This callback will be called for each type/variable declaration.
/// \param name var/func/type name
/// \param tif type info
/// \param cmt main comment
/// \param value symbol value
/// \param cb_data data passed to callback
/// \retval T_CBBRKDEF the type declaration won't be saved in the til
typedef int idaapi h2ti_type_cb(
const char *name,
const tinfo_t &tif,
const char *cmt,
const uint64 *value,
void *cb_data);
/// Specify a printing callback when parsing types.
/// See h2ti() and parse_decls().
typedef AS_PRINTF(1, 2) int printer_t(const char *format, ...);
/// Convert declarations to type_t*.
/// This is a low level function - use parse_decls() or parse_decl()
/// \param ti type info library
/// \param lx input lexer. may be NULL. always destroyed by h2ti()
/// \param input file name or C declaration
/// \param flags combination of \ref HTI_
/// \param type_cb callback - for each type
/// \param var_cb callback - for each var
/// \param print_cb may pass msg() here
/// \param _cb_data data passed to callbacks
/// \param _isabs the expected abstracness of the type declaration(s)
/// \return number of errors (they are displayed using print_cb). zero means ok
idaman int ida_export h2ti(
til_t *ti,
lexer_t *lx,
const char *input,
int flags=HTI_HIGH,
h2ti_type_cb *type_cb=NULL,
h2ti_type_cb *var_cb=NULL,
printer_t *print_cb=NULL,
void *_cb_data=NULL,
abs_t _isabs=abs_unk);
/// Parse ONE declaration.
/// If the input string contains more than one declaration, the first complete
/// type declaration (#PT_TYP) or the last variable declaration (#PT_VAR) will be used.
/// \note name & tif may be empty after the call!
/// \param[out] tif type info
/// \param[out] out declared name
/// \param til type library to use. may be NULL
/// \param decl C declaration to parse
/// \param flags combination of \ref PT_ bits
/// \retval true ok
/// \retval false declaration is bad, the error message is displayed if !PT_SIL
idaman bool ida_export parse_decl(
tinfo_t *tif,
qstring *out,
til_t *til,
const char *decl,
int flags);
/// \defgroup PT_ Type parsing flags
//@{
#define PT_SIL 0x0001 ///< silent, no messages
#define PT_NDC 0x0002 ///< don't decorate names
#define PT_TYP 0x0004 ///< return declared type information
#define PT_VAR 0x0008 ///< return declared object information
#define PT_PACKMASK 0x0070 ///< mask for pack alignment values
#define PT_HIGH 0x0080 ///< assume high level prototypes
///< (with hidden args, etc)
#define PT_LOWER 0x0100 ///< lower the function prototypes
#define PT_REPLACE 0x0200 ///< replace the old type (used in idc)
#define PT_RAWARGS 0x0400 ///< leave argument names unchanged (do not remove underscores)
//@}
/// Convert \ref PT_ to \ref HTI_.
/// Type parsing flags lesser than 0x10 don't have stable meaning and will be ignored
/// (more on these flags can be seen in idc.idc)
inline THREAD_SAFE int convert_pt_flags_to_hti(int pt_flags)
{
return ((pt_flags >> 4) & 0x1f) << HTI_PAK_SHIFT;
}
/// Parse many declarations and store them in a til.
/// If there are any errors, they will be printed using 'printer'.
/// This function uses default include path and predefined macros from the
/// database settings. It always uses the #HTI_DCL bit.
/// \param til type library to store the result
/// \param input input string or file name (see hti_flags)
/// \param printer function to output error messages (use msg or NULL or your own callback)
/// \param hti_flags combination of \ref HTI_
/// \return number of errors, 0 means ok.
idaman int ida_export parse_decls(
til_t *til,
const char *input,
printer_t *printer,
int hti_flags);
/// Get type declaration for the specified address.
/// \param out output buffer
/// \param ea address
/// \param prtype_flags combination of \ref PRTYPE_
/// \return success
idaman bool ida_export print_type(qstring *out, ea_t ea, int prtype_flags);
/// \defgroup PRTYPE_ Type printing flags
//@{
#define PRTYPE_1LINE 0x0000 ///< print to one line
#define PRTYPE_MULTI 0x0001 ///< print to many lines
#define PRTYPE_TYPE 0x0002 ///< print type declaration (not variable declaration)
#define PRTYPE_PRAGMA 0x0004 ///< print pragmas for alignment
#define PRTYPE_SEMI 0x0008 ///< append ; to the end
#define PRTYPE_CPP 0x0010 ///< use c++ name (only for print_type())
#define PRTYPE_DEF 0x0020 ///< tinfo_t: print definition, if available
#define PRTYPE_NOARGS 0x0040 ///< tinfo_t: do not print function argument names
#define PRTYPE_NOARRS 0x0080 ///< tinfo_t: print arguments with #FAI_ARRAY as pointers
#define PRTYPE_NORES 0x0100 ///< tinfo_t: never resolve types (meaningful with PRTYPE_DEF)
#define PRTYPE_RESTORE 0x0200 ///< tinfo_t: print restored types for #FAI_ARRAY and #FAI_STRUCT
#define PRTYPE_NOREGEX 0x0400 ///< do not apply regular expressions to beautify name
#define PRTYPE_COLORED 0x0800 ///< add color tag COLOR_SYMBOL for any parentheses, commas and colons
//@}
//@} parse_tinfo
/// \defgroup named_types Named types
/// functions to work with named types
//@{
/// Get named typeinfo.
/// The returned pointers are pointers to static storage. \n
/// They are valid until free_til(), set_named_type(), del_named_type(), \n
/// rename_named_type(), set_numbered_type(), del_numbered_type(), \n
/// and idb structure/enum manipulation (in other words, until ::til_t is changed).
/// \param ti pointer to type information library
/// \param name name of type
/// \param ntf_flags combination of \ref NTF_
/// \param type ptr to ptr to output buffer for the type info
/// \param fields ptr to ptr to the field/args names. may be NULL
/// \param cmt ptr to ptr to the main comment. may be NULL
/// \param fieldcmts ptr to ptr to the field/args comments. may be NULL
/// \param sclass ptr to storage class
/// \param value ptr to symbol value. for types, ptr to the ordinal number
/// \retval 0 can't find the named type (or name==NULL)
/// \retval 1 ok, the buffers are filled with information (if not NULL)
/// \retval 2 ok, found it in a base til
idaman int ida_export get_named_type(
const til_t *ti,
const char *name,
int ntf_flags,
const type_t **type=NULL,
const p_list **fields=NULL,
const char **cmt=NULL,
const p_list **fieldcmts=NULL,
sclass_t *sclass=NULL,
uint32 *value=NULL);
/// \defgroup NTF_ Flags for named types
//@{
#define NTF_TYPE 0x0001 ///< type name
#define NTF_SYMU 0x0008 ///< symbol, name is unmangled ('func')
#define NTF_SYMM 0x0000 ///< symbol, name is mangled ('_func')
///< only one of #NTF_TYPE and #NTF_SYMU, #NTF_SYMM can be used
#define NTF_NOBASE 0x0002 ///< don't inspect base tils (for get_named_type)
#define NTF_REPLACE 0x0004 ///< replace original type (for set_named_type)
#define NTF_UMANGLED 0x0008 ///< name is unmangled (don't use this flag)
#define NTF_NOCUR 0x0020 ///< don't inspect current til file (for get_named_type)
#define NTF_64BIT 0x0040 ///< value is 64bit
#define NTF_FIXNAME 0x0080 ///< force-validate the name of the type when setting
///< (set_named_type, set_numbered_type only)
#define NTF_IDBENC 0x0100 ///< the name is given in the IDB encoding;
///< non-ASCII bytes will be decoded accordingly
///< (set_named_type, set_numbered_type only)
#define NTF_CHKSYNC 0x0200 ///< check that synchronization to IDB passed OK
///< (set_numbered_type, set_named_type)
//@}
/// See get_named_type() above.
/// \note If the value in the 'ti' library is 32-bit, it will
/// be sign-extended before being stored in the 'value' pointer.
inline int idaapi get_named_type64(
const til_t *ti,
const char *name,
int ntf_flags,
const type_t **type=NULL,
const p_list **fields=NULL,
const char **cmt=NULL,
const p_list **fieldcmts=NULL,
sclass_t *sclass=NULL,
uint64 *value=NULL)
{
return get_named_type(ti, name, ntf_flags | NTF_64BIT,
type, fields, cmt, fieldcmts, sclass, (uint32 *)value);
}
/// Error codes for save_tinfo functions:
enum tinfo_code_t
{
TERR_OK = 0, ///< ok
TERR_SAVE = -1, ///< failed to save
TERR_SERIALIZE = -2, ///< failed to serialize
TERR_WRONGNAME = -3, ///< name is not acceptable
TERR_BADSYNC = -4, ///< failed to synchronize with IDB
};
/// Delete information about a symbol.
/// \param ti type library
/// \param name name of symbol
/// \param ntf_flags combination of \ref NTF_
/// \return success
idaman bool ida_export del_named_type(til_t *ti, const char *name, int ntf_flags);
/// Enumerate types.
/// Returns mangled names.
/// Never returns anonymous types. To include it, enumerate types by ordinals.
idaman const char *ida_export first_named_type(const til_t *ti, int ntf_flags);
/// \copydoc first_named_type()
idaman const char *ida_export next_named_type(const til_t *ti, const char *name, int ntf_flags);
/// Copy a named type from one til to another.
/// This function will copy the specified type and all dependent types
/// from the source type library to the destination library.
/// \param dsttil Destination til. It must have orginal types enabled
/// \param srctil Source til.
/// \param name name of the type to copy
/// \return ordinal number of the copied type. 0 means error
idaman uint32 ida_export copy_named_type(
til_t *dsttil,
const til_t *srctil,
const char *name);
/// Decorate/undecorate a C symbol name.
/// \param out output buffer
/// \param name name of symbol
/// \param mangle true-mangle, false-unmangle
/// \param cc calling convention
/// \param type name type (NULL-unknown)
/// \return success
idaman bool ida_export decorate_name(
qstring *out,
const char *name,
bool mangle,
cm_t cc=CM_CC_UNKNOWN,
const tinfo_t *type = NULL);
/// Generic function for decorate_name() (may be used in IDP modules)
idaman bool ida_export gen_decorate_name(
qstring *out,
const char *name,
bool mangle,
cm_t cc,
const tinfo_t *type);
/// Get C or C++ form of the name.
/// \param out output buffer
/// \param name original (mangled or decorated) name
/// \param type name type if known, otherwise NULL
/// \param ccn_flags one of \ref CCN_
idaman ssize_t ida_export calc_c_cpp_name(
qstring *out,
const char *name,
const tinfo_t *type,
int ccn_flags);
/// \defgroup CCN_ C/C++ naming flags
//@{
#define CCN_C 0x00 // prepare C name
#define CCN_CPP 0x01 // prepare C++ name
//@}
//@} named_types
//--------------------------------------------------------------------------
/// \defgroup numbered_types Numbered types
/// Functions to work with numbered (ordinal) types.
/// Numbered types may be named or anonymous.
/// They are referenced by their ordinal number. Access to them is faster because
/// there is no need to resolve their names. Also, they can stay anonymous
/// and be aliased. They can be used only in the local type library
/// created by IDA (in idati).
//@{
/// Enable the use of numbered types in til.
/// Currently it is impossible to disable numbered types once they are enabled
idaman bool ida_export enable_numbered_types(til_t *ti, bool enable);
/// Retrieve a type by its ordinal number
idaman bool ida_export get_numbered_type(
const til_t *ti,
uint32 ordinal,
const type_t **type=NULL,
const p_list **fields=NULL,
const char **cmt=NULL,
const p_list **fieldcmts=NULL,
sclass_t *sclass=NULL);
/// Allocate a range of ordinal numbers for new types.
/// \param ti type library
/// \param qty number of ordinals to allocate
/// \return the first ordinal. 0 means failure.
idaman uint32 ida_export alloc_type_ordinals(til_t *ti, int qty);
/// \call2{alloc_type_ordinals,ti,1}
inline uint32 alloc_type_ordinal(til_t *ti) { return alloc_type_ordinals(ti, 1); }
/// Get number of allocated ordinals.
/// \return uint32(-1) if failed
idaman uint32 ida_export get_ordinal_qty(const til_t *ti);
/// Store a type in the til.
/// 'name' may be NULL for anonymous types.
/// The specified ordinal must be free (no other type is using it).
/// For ntf_flags, only #NTF_REPLACE is consulted.
idaman tinfo_code_t ida_export set_numbered_type(
til_t *ti,
uint32 ordinal,
int ntf_flags,
const char *name,
const type_t *type,
const p_list *fields=NULL,
const char *cmt=NULL,
const p_list *fldcmts=NULL,
const sclass_t *sclass=NULL);
/// Delete a numbered type
idaman bool ida_export del_numbered_type(til_t *ti, uint32 ordinal);
/// Create a type alias.
/// Redirects all references to source type to the destination type.
/// This is equivalent to instantaneous replacement all reference to srctype by dsttype.
idaman bool ida_export set_type_alias(til_t *ti, uint32 src_ordinal, uint32 dst_ordinal);
/// Find the final alias destination.
/// If the ordinal has not been aliased, return the specified ordinal itself
/// If failed, returns 0.
idaman uint32 ida_export get_alias_target(const til_t *ti, uint32 ordinal);
/// Get type ordinal by its name
inline int32 get_type_ordinal(const til_t *ti, const char *name)
{
uint32 ordinal = 0;
get_named_type(ti, name, NTF_TYPE|NTF_NOBASE, NULL, NULL, NULL, NULL, NULL, &ordinal);
return ordinal;
}
/// Get type name (if exists) by its ordinal.
/// If the type is anonymous, returns "". If failed, returns NULL
idaman const char *ida_export get_numbered_type_name(const til_t *ti, uint32 ordinal);
/// Create anonymous name for numbered type. This name can be used
/// to reference a numbered type by its ordinal
/// Ordinal names have the following format: '#' + set_de(ord)
/// Returns: -1 if error, otherwise the name length
idaman ssize_t ida_export create_numbered_type_name(qstring *buf, int32 ord);
/// Check if the name is an ordinal name.
/// Ordinal names have the following format: '#' + set_de(ord)
idaman bool ida_export is_ordinal_name(const char *name, uint32 *ord=NULL);
/// Get ordinal number of an idb type (struct/enum).
/// The 'type' parameter is used only to determine the kind of the type (struct or enum)
/// Use this function to find out the correspondence between idb types and til types
idaman int ida_export get_ordinal_from_idb_type(const char *name, const type_t *type);
/// Is the specified idb type automatically synchronized?
inline bool idaapi is_autosync(const char *name, const type_t *type)
{
return get_ordinal_from_idb_type(name, type) != -1;
}
inline bool idaapi is_autosync(const char *name, const tinfo_t &tif); ///< copydoc is_autosync(const char*, const type_t *)
/// Generate a name like $hex_numbers based on the field types and names
idaman void ida_export build_anon_type_name(
qstring *buf,
const type_t *type,
const p_list *fields);
const uint32 BADORD = uint32(-1); ///< invalid type ordinal
/// Compact numbered types to get rid of empty slots.
/// \param ti type library to compact
/// \param min_ord minimal ordinal number to start to compact. lower
/// ordinals are not modified
/// \param p_ordmap the resulting mapping
/// (for example, the new ordinal of min_ord will be in ordmap[0])
/// \param flags reserved
/// \return number of freed type slots
idaman int ida_export compact_numbered_types(
til_t *ti,
uint32 min_ord=0,
intvec_t *p_ordmap=NULL,
int flags=0);
//@} numbered_types
//--------------------------------------------------------------------------
/// \defgroup vftable_types Link between vftable types and addresses
//@{
/// Get address of a virtual function table.
/// \param ordinal ordinal number of a vftable type.
/// \return address of the corresponding virtual function table in the current database.
idaman ea_t ida_export get_vftable_ea(uint32 ordinal);
/// Get ordinal number of the virtual function table.
/// \param vftable_ea address of a virtual function table.
/// \return ordinal number of the corresponding vftable type. 0 - failure.
idaman uint32 ida_export get_vftable_ordinal(ea_t vftable_ea);
/// Set the address of a vftable instance for a vftable type.
/// \param vftable_ea address of a virtual function table.
/// \param ordinal ordinal number of the corresponding vftable type.
/// \return success
idaman bool ida_export set_vftable_ea(uint32 ordinal, ea_t vftable_ea);
/// Delete the address of a vftable instance for a vftable type.
/// \param ordinal ordinal number of a vftable type.
/// \return success
inline bool del_vftable_ea(uint32 ordinal) { return set_vftable_ea(ordinal, BADADDR); }
//@} vftable_types
//--------------------------------------------------------------------------
// ALIGNMENT
/// Get default alignment for structure fields.
/// \return one of 1,2,4,8,...
inline size_t get_default_align(void) { return inf_get_cc_defalign(); }
/// Get alignment delta for the a structure field.
/// \param cur_tot_size the structure size calculated so far
/// \param elem_size size of the current field.
/// the whole structure should be calculated
/// \param algn the structure alignment (0,1,2,4,8...)
inline THREAD_SAFE void align_size(size_t &cur_tot_size, size_t elem_size, size_t algn)
{
size_t al = elem_size;
if ( algn != 0 && algn < al )
al = algn;
cur_tot_size = align_up(cur_tot_size, al);
}
/// Dereference a pointer.
/// \param[out] ptr_ea in/out parameter
/// - in: address of the pointer
/// - out: the pointed address
/// \param tif type of the pointer
/// \param[out] closure_obj closure object (not used yet)
/// \return success
idaman bool ida_export deref_ptr(
ea_t *ptr_ea,
const tinfo_t &tif,
ea_t *closure_obj=NULL);
/// Remove pointer of a type.
/// (i.e. convert "char *" into "char").
/// Optionally remove the "lp" (or similar) prefix of the input name.
/// If the input type is not a pointer, then fail.
idaman bool ida_export remove_tinfo_pointer(tinfo_t *tif, const char **pname, const til_t *til=NULL);
/// Copy a named type from til to idb.
/// \param til type library
/// \param idx the position of the new type in the list of types (structures or enums).
/// -1 means at the end of the list
/// \param name the type name
/// \param flags combination of \ref IMPTYPE_
/// \return #BADNODE on error
idaman tid_t ida_export import_type(const til_t *til, int idx, const char *name, int flags=0);
/// \defgroup IMPTYPE_ Import type flags
/// passed as 'flags' parameter to import_type()
//@{
#define IMPTYPE_VERBOSE 0x0001 ///< more verbose output (dialog boxes may appear)
#define IMPTYPE_OVERRIDE 0x0002 ///< override existing type
#define IMPTYPE_LOCAL 0x0004 ///< the type is local, the struct/enum won't be marked as til type.
///< there is no need to specify this bit if til==idati,
///< the kernel will set it automatically
//@}
/// Load a til file.
/// \param name til name
/// \param flags combination of \ref ADDTIL_F
/// \return one of \ref ADDTIL_R
idaman int ida_export add_til(const char *name, int flags);
/// \defgroup ADDTIL_F Load TIL flags
/// passed as 'flags' parameter to add_til()
//@{
#define ADDTIL_DEFAULT 0x0000 ///< default behavior
#define ADDTIL_INCOMP 0x0001 ///< load incompatible tils
#define ADDTIL_SILENT 0x0002 ///< do not ask any questions
//@}
/// \defgroup ADDTIL_R Load TIL result codes
/// return values for add_til()
//@{
#define ADDTIL_FAILED 0 ///< something bad, the warning is displayed
#define ADDTIL_OK 1 ///< ok, til is loaded
#define ADDTIL_COMP 2 ///< ok, but til is not compatible with the current compiler
#define ADDTIL_ABORTED 3 ///< til was not loaded (incompatible til rejected by user)
//@}
/// Unload a til file
idaman bool ida_export del_til(const char *name);
/// Apply the specified named type to the address.
/// \param ea linear address
/// \param name the type name, e.g. "FILE"
/// \return success
idaman bool ida_export apply_named_type(ea_t ea, const char *name);
/// Apply the specified type to the specified address.
/// This function sets the type and tries to convert the item at the specified
/// address to conform the type.
/// \param ea linear address
/// \param tif type string in internal format
/// \param flags combination of \ref TINFO_
/// \returns success
idaman bool ida_export apply_tinfo(
ea_t ea,
const tinfo_t &tif,
uint32 flags);
/// \defgroup TINFO_ Apply tinfo flags
/// passed as 'flags' parameter to apply_tinfo()
//@{
#define TINFO_GUESSED 0x0000 ///< this is a guessed type
#define TINFO_DEFINITE 0x0001 ///< this is a definite type
#define TINFO_DELAYFUNC 0x0002 ///< if type is a function and no function exists at ea,
///< schedule its creation and argument renaming to auto-analysis
///< otherwise try to create it immediately
#define TINFO_STRICT 0x0004 ///< never convert given type to another one before applying
//@}
/// Apply the specified type to the address.
/// This function parses the declaration and calls apply_tinfo()
/// \param til type library
/// \param ea linear address
/// \param decl type declaration in C form
/// \param flags flags to pass to apply_tinfo (#TINFO_DEFINITE is always passed)
/// \return success
idaman bool ida_export apply_cdecl(til_t *til, ea_t ea, const char *decl, int flags=0);
/// Apply the type of the called function to the calling instruction.
/// This function will append parameter comments and rename the local
/// variables of the calling function. It also stores information about
/// the instructions that initialize call arguments in the database.
/// Use get_arg_addrs() to retrieve it if necessary. Alternatively it is
/// possible to hook to processor_t::arg_addrs_ready event.
/// \param caller linear address of the calling instruction.
/// must belong to a function.
/// \param tif type info
/// \return success
idaman bool ida_export apply_callee_tinfo(ea_t caller, const tinfo_t &tif);
/// Retrieve argument initialization addresses.
/// This function retrieves information about argument addresses.
/// This information is stored in the database by apply_callee_tinfo().
/// \param out linear addresses of the instructions that load call arguments
/// \param caller address of the call instruction
/// \return success
idaman bool ida_export get_arg_addrs(eavec_t *out, ea_t caller);
/// Apply the specified type and name to the address.
/// This function checks if the address already has a type. If the old type \n
/// does not exist or the new type is 'better' than the old type, then the \n
/// new type will be applied. A type is considered better if it has more \n
/// information (e.g. ::BTMT_STRUCT is better than ::BT_INT). \n
/// The same logic is with the name: if the address already have a meaningful \n
/// name, it will be preserved. Only if the old name does not exist or it \n
/// is a dummy name like byte_123, it will be replaced by the new name.
/// \param dea linear address
/// \param tif type string in the internal format
/// \param name new name for the address
/// \return success
idaman bool ida_export apply_once_tinfo_and_name(
ea_t dea,
const tinfo_t &tif,
const char *name);
// To retrieve the type information attach to an address, use get_tinfo() function
// (see nalt.hpp)
/// Generate a type information about the id from the disassembly.
/// id can be a structure/union/enum id or an address.
/// \return one of \ref GUESS_
idaman int ida_export guess_tinfo(tinfo_t *tif, tid_t id);
/// \defgroup GUESS_ Guess tinfo codes
/// return values for guess_tinfo()
//@{
#define GUESS_FUNC_FAILED 0 ///< couldn't guess the function type
#define GUESS_FUNC_TRIVIAL 1 ///< the function type doesn't have interesting info
#define GUESS_FUNC_OK 2 ///< ok, some non-trivial information is gathered
//@}
// The following functions should eventually be replaced by exported functions
#ifndef __KERNEL__
/// Set include directory path the target compiler
inline void set_c_header_path(const char *incdir) { setinf_buf(INF_H_PATH, incdir); }
/// Get the include directory path of the target compiler
inline ssize_t get_c_header_path(qstring *buf) { return getinf_str(buf, INF_H_PATH); }
/// Set predefined macros for the target compiler
inline void set_c_macros(const char *macros) { setinf_buf(INF_C_MACROS, macros); }
/// Get predefined macros for the target compiler
inline ssize_t get_c_macros(qstring *buf) { return getinf_str(buf, INF_C_MACROS); }
#endif
//------------------------------------------------------------------------
// HIGH LEVEL FUNCTIONS TO SUPPORT TILS IN THE IDA KERNEL
/// Pointer to the local type library - this til is private for each IDB file
/// Function that accepts til_t* uses local type library instead of NULL.
idaman const til_t *ida_export get_idati(void);
/// Extract information from a tinfo_t.
/// \param[out] psize size of tif
/// \param[out] pflags description of type using flags_t
/// \param[out] mt info for non-scalar types
/// \param tif the type to inspect
/// \param[out] alsize alignment
idaman bool ida_export get_idainfo_by_type(
size_t *out_size,
flags_t *out_flags,
opinfo_t *out_mt,
const tinfo_t &tif,
size_t *out_alsize=NULL);
//------------------------------------------------------------------------
// Type information object: tinfo_t
struct ptr_type_data_t;
struct udt_type_data_t;
struct enum_type_data_t;
struct array_type_data_t;
struct typedef_type_data_t;
struct bitfield_type_data_t;
/// IDs for common types
enum stock_type_id_t
{
STI_PCHAR, ///< char *
STI_PUCHAR, ///< uint8 *
STI_PCCHAR, ///< const char *
STI_PCUCHAR, ///< const uint8 *
STI_PBYTE, ///< _BYTE *
STI_PINT, ///< int *
STI_PUINT, ///< unsigned int *
STI_PVOID, ///< void *
STI_PPVOID, ///< void **
STI_PCVOID, ///< const void *
STI_ACHAR, ///< char[]
STI_AUCHAR, ///< uint8[]
STI_ACCHAR, ///< const char[]
STI_ACUCHAR, ///< const uint8[]
STI_FPURGING, ///< void __userpurge(int)
STI_FDELOP, ///< void __cdecl(void *)
STI_MSGSEND, ///< void *(void *, const char *, ...)
STI_AEABI_LCMP, ///< int __fastcall(int64 x, int64 y)
STI_AEABI_ULCMP, ///< int __fastcall(uint64 x, uint64 y)
STI_DONT_USE, ///< unused stock type id; should not be used
STI_SIZE_T, ///< size_t
STI_SSIZE_T, ///< ssize_t
STI_AEABI_MEMCPY, ///< void __fastcall(void *, const void *, size_t)
STI_AEABI_MEMSET, ///< void __fastcall(void *, size_t, int)
STI_AEABI_MEMCLR, ///< void __fastcall(void *, size_t)
STI_RTC_CHECK_2, ///< int16 __fastcall(int16 x)
STI_RTC_CHECK_4, ///< int32 __fastcall(int32 x)
STI_RTC_CHECK_8, ///< int64 __fastcall(int64 x)
STI_LAST
};
/// Constants to be used with get_udt_details()
enum gtd_udt_t
{
GTD_CALC_LAYOUT = 0, ///< calculate udt layout
GTD_NO_LAYOUT = BTM_VOLATILE, ///< don't calculate udt layout
///< please note that udt layout may have been
///< calculated earlier
GTD_DEL_BITFLDS = BTM_CONST, ///< delete udt bitfields
};
/// Constants to be used with get_func_details()
enum gtd_func_t
{
GTD_CALC_ARGLOCS = 0, ///< calculate func arg locations
GTD_NO_ARGLOCS = BTM_VOLATILE, ///< don't calculate func arg locations
///< please note that the locations may have been
///< calculated earlier
};
/// Constants to be used with get_size()
enum gts_code_t
{
GTS_NESTED = 0x01, ///< nested type (embedded into a udt)
GTS_BASECLASS = 0x02, ///< is baseclass of a udt
};
/// \defgroup SUDT_ UDT serialization flags
/// passed as 'sudt_flags' parameter of helpers declared in #DECLARE_TINFO_HELPERS
//@{
#define SUDT_SORT 0x0001 ///< fields are not sorted by offset, sort them first
#define SUDT_ALIGN 0x0002 ///< recalculate field alignments, struct packing, etc
///< to match the offsets and size info
#define SUDT_GAPS 0x0004 ///< allow to fill gaps with additional members (_BYTE[])
#define SUDT_UNEX 0x0008 ///< references to nonexistent member types are acceptable
///< in this case it is better to set the corresponding
///< udt_member_t::fda field to the type alignment. if this
///< field is not set, ida will try to guess the alignment.
#define SUDT_FAST 0x0010 ///< serialize without verifying offsets and alignments
#define SUDT_CONST 0x0040 ///< only for serialize_udt: make type const
#define SUDT_VOLATILE 0x0080 ///< only for serialize_udt: make type volatile
#define SUDT_TRUNC 0x0100 ///< serialize: truncate useless strings from fields, fldcmts
//@}
/// Macro to declare common tinfo_t related functions
#define DECLARE_TINFO_HELPERS(decl)\
decl void ida_export copy_tinfo_t(tinfo_t *_this, const tinfo_t &r); \
decl void ida_export clear_tinfo_t(tinfo_t *_this);\
decl bool ida_export create_tinfo(tinfo_t *_this, type_t bt, type_t bt2, void *ptr);\
decl int ida_export verify_tinfo(uint32 typid);\
decl bool ida_export get_tinfo_details(uint32 typid, type_t bt2, void *buf);\
decl size_t ida_export get_tinfo_size(uint32 *p_effalign, uint32 typid, int gts_code);\
decl size_t ida_export get_tinfo_pdata(void *outptr, uint32 typid, int what);\
decl size_t ida_export get_tinfo_property(uint32 typid, int gta_prop);\
decl size_t ida_export set_tinfo_property(tinfo_t *tif, int sta_prop, size_t x);\
decl bool ida_export serialize_tinfo(qtype *type, qtype *fields, qtype *fldcmts, const tinfo_t *tif, int sudt_flags);\
decl bool ida_export deserialize_tinfo(tinfo_t *tif, const til_t *til, const type_t **ptype, const p_list **pfields, const p_list **pfldcmts);\
decl int ida_export find_tinfo_udt_member(struct udt_member_t *udm, uint32 typid, int strmem_flags);\
decl bool ida_export print_tinfo(qstring *result, const char *prefix, int indent, int cmtindent, int flags, const tinfo_t *tif, const char *name, const char *cmt);\
decl const char *ida_export dstr_tinfo(const tinfo_t *tif);\
decl int ida_export visit_subtypes(struct tinfo_visitor_t *visitor, struct type_mods_t *out, const tinfo_t &tif, const char *name, const char *cmt);\
decl bool ida_export compare_tinfo(uint32 t1, uint32 t2, int tcflags);\
decl int ida_export lexcompare_tinfo(uint32 t1, uint32 t2, int);\
decl bool ida_export get_stock_tinfo(tinfo_t *tif, stock_type_id_t id);\
decl uint64 ida_export read_tinfo_bitfield_value(uint32 typid, uint64 v, int bitoff);\
decl uint64 ida_export write_tinfo_bitfield_value(uint32 typid, uint64 dst, uint64 v, int bitoff);\
decl bool ida_export get_tinfo_attr(uint32 typid, const qstring &key, bytevec_t *bv, bool all_attrs);\
decl bool ida_export set_tinfo_attr(tinfo_t *tif, const type_attr_t &ta, bool may_overwrite);\
decl bool ida_export del_tinfo_attr(tinfo_t *tif, const qstring &key, bool make_copy);\
decl bool ida_export get_tinfo_attrs(uint32 typid, type_attrs_t *tav, bool include_ref_attrs);\
decl bool ida_export set_tinfo_attrs(tinfo_t *tif, type_attrs_t *ta);\
decl uint32 ida_export score_tinfo(const tinfo_t *tif);\
decl tinfo_code_t ida_export save_tinfo(tinfo_t *tif, til_t *til, size_t ord, const char *name, int ntf_flags);\
decl bool ida_export append_tinfo_covered(rangeset_t *out, uint32 typid, uint64 offset);\
decl bool ida_export calc_tinfo_gaps(rangeset_t *out, uint32 typid);\
decl bool ida_export name_requires_qualifier(qstring *out, uint32 typid, const char *name, uint64 offset);\
DECLARE_TINFO_HELPERS(idaman)
/*! \defgroup tf_nontrivial Nontrivial types
\ingroup tf
bits 0..5: base type \n
bits 6..7: const & volatile bits \n
bit 8: 'is_typeref' bit \n
bits 9..31: type detail idx
*/
//@{
const int FIRST_NONTRIVIAL_TYPID = 0x100; ///< Denotes the first bit describing a nontrivial type
const int TYPID_ISREF = 0x100; ///< Identifies that a type that is a typeref
const int TYPID_SHIFT = 9; ///< First type detail bit
//@}
//-V:create_array:678 An object is used as an argument to its own method.
//-V:create_ptr:678
/// Primary mechanism for managing type information
class tinfo_t // #tinfo_t #tif
{
uint32 typid; /// byte sequence describing the type
bool create_type(type_t decl_type, type_t bt2, void *details)
{
return create_tinfo(this, decl_type, bt2, details);
}
/// Get the type details.
/// The information is copied to the user-supplied buffer.
/// Also check out convenience functions below (get_ptr_details, etc), they work faster because
/// they do not copy the entire type info but only the desired part of it.
bool get_type_details(type_t bt2, void *buf) const { return get_tinfo_details(typid, bt2, buf); }
void copy(const tinfo_t &r) { copy_tinfo_t(this, r); }
DECLARE_TINFO_HELPERS(friend)
friend struct type_detail_t;
friend tinfo_t remove_pointer(const tinfo_t &tif);
/// Various type properties (properties are a 32-bit scalar values)
enum gta_prop_t
{
GTA_DECLALIGN, ///< declared alignment
GTA_RESOLVE, ///< real type (fully resolve eventual type references)
GTA_REALTYPE, ///< real type (do not fully resolve type refs)
GTA_TYPE_SIGN, ///< get type sign
GTA_FROM_SUBTIL, ///< is from a subtil (not from main til)
GTA_IS_FORWARD, ///< is forward declaration?
GTA_IS_FUNCPTR, ///< is a pointer to a function?
GTA_ORDINAL, ///< get initial type ordinal
GTA_FINAL_ORDINAL, ///< get final (resolved) type ordinal
GTA_PTR_OBJ, ///< ptr: pointed type
GTA_SAFE_PTR_OBJ, ///< ptr: pointed type or type itself
GTA_ARRAY_ELEM, ///< array: array element
GTA_ARRAY_NELEMS, ///< array: number of elements
GTA_PTRARR_SUBTIF, ///< ptr&array: pointed object or array element (nb: deletes current tif)
GTA_PTRARR_SIZE, ///< ptr&array: get size of subtype
GTA_UNPADDED_SIZE, ///< udt: sizeof baseclass when embedded into a derived class
GTA_UDT_NMEMBERS, ///< udt: get number of udt members
GTA_IS_SMALL_UDT, ///< udt: is small udt (can be passed in regs)
GTA_ONEMEM_TYPE, ///< udt&array: object consisting of one member: type of the member
GTA_ENUM_BASE_TYPE, ///< enum: get enum base type
GTA_FUNC_CC, ///< func: calling convention
GTA_PURGED_BYTES, ///< func: number of purged bytes
GTA_IS_HIGH_TYPE, ///< func: is high type
GTA_FUNC_NARGS, ///< func: number of arguments
GTA_FUNC_RET, ///< func: get function return type
GTA_FUNC_ARG, ///< func: get type of function arg
GTA_LAST_FUNC_ARG = GTA_FUNC_ARG + 255,
GTA_IS_SSE_TYPE, ///< is a SSE vector type?
GTA_IS_ANON_UDT, ///< is anonymous struct/union?
GTA_IS_VFTABLE, ///< is vftable?
GTA_HAS_VFTABLE, ///< has vftable?
GTA_IS_SHIFTED_PTR, ///< is a shifted pointer?
GTA_IS_VARSTRUCT, ///< is a variable-size structure?
};
enum sta_prop_t ///< set type property
{
STA_DECLALIGN, ///< set declared alignment
STA_TYPE_SIGN, ///< set type sign
STA_UDT_ALIGN, ///< calculate udt field alignments
};
enum gta_pdata_t ///< get info returned by pointer
{
GTP_NAME, ///< get referenced name
GTP_NEXT_NAME, ///< get immediately next referenced name
GTP_FINAL_NAME, ///< get final referenced name
GTP_TIL, ///< get type library
};
public:
/// Constructor
tinfo_t(): typid(BT_UNK) {}
/// Constructor - can only be used to initialize simple types!
explicit tinfo_t(type_t decl_type) : typid(decl_type) {}
/// Constructor
tinfo_t(const tinfo_t &r) : typid(0) { copy(r); }
/// Copy contents of given tinfo into this one
tinfo_t &operator=(const tinfo_t &r) { copy(r); return *this; }
/// Destructor
~tinfo_t(void) { clear(); }
/// Clear contents of this tinfo, and remove from the type system
void clear(void) { clear_tinfo_t(this); }
/// Assign this = r and r = this
void swap(tinfo_t &r) { uint32 tmp = typid; typid = r.typid; r.typid = tmp; }
DEFINE_MEMORY_ALLOCATION_FUNCS()
/// Create a tinfo_t object for an existing named type.
/// \param til type library to use
/// \param name name of the type to link to
/// \param decl_type if the reference was explicitly specified with the type tag \n
/// (::BTF_STRUCT/::BTF_UNION/::BTF_ENUM) you may specify it. \n
/// the kernel will accept only the specified tag after resolving \n
/// the type. If the resolved type does not correspond to the \n
/// explicitly specified tag, the type will be considered as undefined \n
/// \param resolve true: immediately resolve the type and return success code.
/// false: return true but do not immediately resolve the type
/// \param try_ordinal true: try to replace name reference by an ordinal reference
inline bool get_named_type(
const til_t *til,
const char *name,
type_t decl_type=BTF_TYPEDEF,
bool resolve=true,
bool try_ordinal=true);
/// Create a tinfo_t object for an existing ordinal type.
/// \param til type library to use
/// \param ordinal number of the type to link to
/// \param decl_type if the reference was explicitly specified with the type tag
/// (BTF_STRUCT/BTF_UNION/BTF_ENUM) you may specify it.
/// the kernel will accept only the specified tag after resolving
/// the type. If the resolved type does not correspond to the
/// explicitly specified tag, the type will be considered as undefined
/// \param resolve true: immediately resolve the type and return success code
/// false: return true but do not immediately resolve the type
inline bool get_numbered_type(
const til_t *til,
uint32 ordinal,
type_t decl_type=BTF_TYPEDEF,
bool resolve=true);
/// Serialize tinfo_t object into a type string.
bool serialize(
qtype *type,
qtype *fields=NULL,
qtype *fldcmts=NULL,
int sudt_flags=SUDT_FAST|SUDT_TRUNC) const
{
return serialize_tinfo(type, fields, fldcmts, this, sudt_flags);
}
/// Deserialize a type string into a tinfo_t object
bool deserialize(
const til_t *til,
const type_t **ptype,
const p_list **pfields=NULL,
const p_list **pfldcmts=NULL)
{
return deserialize_tinfo(this, til, ptype, pfields, pfldcmts);
}
/// \copydoc deserialize()
bool deserialize(
const til_t *til,
const qtype *ptype,
const qtype *pfields=NULL,
const qtype *pfldcmts=NULL)
{
const type_t *tp = ptype->begin();
const p_list *fp = pfields == NULL ? NULL : pfields->begin();
const p_list *cp = pfldcmts == NULL ? NULL : pfldcmts->begin();
return deserialize(til, &tp, fp == NULL ? NULL : &fp, cp == NULL ? NULL : &cp);
}
/// Is the type object correct?.
/// It is possible to create incorrect types. For example, we can define a
/// function that returns a enum and then delete the enum type.
/// If this function returns false, the type should not be used in
/// disassembly. Please note that this function does not verify all
/// involved types: for example, pointers to undefined types are permitted.
bool is_correct(void) const { return verify_tinfo(typid) == 0; }
/// Get the resolved base type.
/// Deserialization options:
/// - if full=true, the referenced type will be deserialized fully,
/// this may not always be desirable (slows down things)
/// - if full=false, we just return the base type, the referenced type will be
/// resolved again later if necessary
/// (this may lead to multiple resolvings of the same type)
/// imho full=false is a better approach because it does not perform
/// unnecessary actions just in case. however, in some cases the caller knows
/// that it is very likely that full type info will be required. in those cases
/// full=true makes sense
type_t get_realtype(bool full=false) const { return (type_t)get_tinfo_property(typid, full ? GTA_RESOLVE : GTA_REALTYPE); }
/// Get declared type (without resolving type references; they are returned as is).
/// Obviously this is a very fast function and should be used instead of get_realtype()
/// if possible.
THREAD_SAFE type_t get_decltype(void) const { return type_t(typid); }
/// Was tinfo_t initialized with some type info or not?
THREAD_SAFE bool empty(void) const { return get_decltype() == BT_UNK; }
/// Is the type really present? (not a reference to a missing type, for example)
bool present(void) const { return get_realtype() != BT_UNK; }
/// Get the type size in bytes.
/// \param p_effalign buffer for the alignment value
/// \param gts_code combination of GTS_... constants
/// \return ::BADSIZE in case of problems
size_t get_size(uint32 *p_effalign=NULL, int gts_code=0) const { return get_tinfo_size(p_effalign, typid, gts_code); }
/// Get the type size in bytes without the final padding, in bytes.
/// For some UDTs get_unpadded_size() != get_size()
size_t get_unpadded_size(void) const { return get_tinfo_property(typid, GTA_UNPADDED_SIZE); }
/// Get type sign
type_sign_t get_sign(void) const { return get_tinfo_property(typid, GTA_TYPE_SIGN); }
/// Is this a signed type?
bool is_signed(void) const { return get_sign() == type_signed; }
/// Is this an unsigned type?
bool is_unsigned(void) const { return get_sign() == type_unsigned; }
/// Get declared alignment of the type
uchar get_declalign(void) const { return uchar(get_tinfo_property(typid, GTA_DECLALIGN)); }
/// Set declared alignment of the type
bool set_declalign(uchar declalign) { return set_tinfo_property(this, STA_DECLALIGN, declalign) != 0; }
/// Is this type a type reference?.
/// Type references cannot be modified. Once created, they do not change.
/// Because of this, the set_... functions applied to typerefs create
/// a new type id. Other types are modified directly.
THREAD_SAFE bool is_typeref(void) const { return (typid & TYPID_ISREF) != 0; }
/// Does this type refer to a nontrivial type?
THREAD_SAFE bool has_details(void) const { return typid >= FIRST_NONTRIVIAL_TYPID; }
/// Does a type refer to a name?.
/// If yes, fill the provided buffer with the type name and return true.
/// Names are returned for numbered types too: either a user-defined nice name
/// or, if a user-provided name does not exist, an ordinal name
/// (like #xx, see create_numbered_type_name()).
bool get_type_name(qstring *out) const { return is_typeref() && get_tinfo_pdata(out, typid, GTP_NAME); }
/// Use in the case of typedef chain (TYPE1 -> TYPE2 -> TYPE3...TYPEn).
/// \return the name of the last type in the chain (TYPEn).
/// if there is no chain, returns TYPE1
bool get_final_type_name(qstring *out) const { return is_typeref() && get_tinfo_pdata(out, typid, GTP_FINAL_NAME); }
/// Use In the case of typedef chain (TYPE1 -> TYPE2 -> TYPE3...TYPEn).
/// \return the name of the next type in the chain (TYPE2).
/// if there is no chain, returns failure
bool get_next_type_name(qstring *out) const { return is_typeref() && get_tinfo_pdata(out, typid, GTP_NEXT_NAME); }
/// Get type ordinal (only if the type was created as a numbered type, 0 if none)
uint32 get_ordinal(void) const { return get_tinfo_property(typid, GTA_ORDINAL); }
/// Get final type ordinal (0 is none)
uint32 get_final_ordinal(void) const { return get_tinfo_property(typid, GTA_FINAL_ORDINAL); }
/// Get the type library for tinfo_t
const til_t *get_til(void) const { const til_t *til; get_tinfo_pdata(&til, typid, GTP_TIL); return til; }
/// Was the named type found in some base type library (not the top level type library)?.
/// If yes, it usually means that the type comes from some loaded type library,
/// not the local type library for the database
bool is_from_subtil(void) const { return is_typeref() && get_tinfo_property(typid, GTA_FROM_SUBTIL); }
/// Is this a forward declaration?.
/// Forward declarations are placeholders: the type definition does not exist
bool is_forward_decl(void) const { return get_tinfo_property(typid, GTA_IS_FORWARD) != 0; }
THREAD_SAFE bool is_decl_const(void) const { return is_type_const(get_decltype()); } ///< \isdecl{is_type_const}
THREAD_SAFE bool is_decl_volatile(void) const { return is_type_volatile(get_decltype()); } ///< \isdecl{is_type_volatile}
THREAD_SAFE bool is_decl_void(void) const { return is_type_void(get_decltype()); } ///< \isdecl{is_type_void}
THREAD_SAFE bool is_decl_partial(void) const { return is_type_partial(get_decltype()); } ///< \isdecl{is_type_partial}
THREAD_SAFE bool is_decl_unknown(void) const { return is_type_unknown(get_decltype()); } ///< \isdecl{is_type_unknown}
THREAD_SAFE bool is_decl_last(void) const { return is_typeid_last(get_decltype()); } ///< \isdecl{is_typeid_last}
THREAD_SAFE bool is_decl_ptr(void) const { return is_type_ptr(get_decltype()); } ///< \isdecl{is_type_ptr}
THREAD_SAFE bool is_decl_array(void) const { return is_type_array(get_decltype()); } ///< \isdecl{is_type_array}
THREAD_SAFE bool is_decl_func(void) const { return is_type_func(get_decltype()); } ///< \isdecl{is_type_func}
THREAD_SAFE bool is_decl_complex(void) const { return is_type_complex(get_decltype()); } ///< \isdecl{is_type_complex}
THREAD_SAFE bool is_decl_typedef(void) const { return is_type_typedef(get_decltype()); } ///< \isdecl{is_type_typedef}
THREAD_SAFE bool is_decl_sue(void) const { return is_type_sue(get_decltype()); } ///< \isdecl{is_type_sue}
THREAD_SAFE bool is_decl_struct(void) const { return is_type_struct(get_decltype()); } ///< \isdecl{is_type_struct}
THREAD_SAFE bool is_decl_union(void) const { return is_type_union(get_decltype()); } ///< \isdecl{is_type_union}
THREAD_SAFE bool is_decl_udt(void) const { return is_type_struni(get_decltype()); } ///< \isdecl{is_type_struni}
THREAD_SAFE bool is_decl_enum(void) const { return is_type_enum(get_decltype()); } ///< \isdecl{is_type_enum}
THREAD_SAFE bool is_decl_bitfield(void) const { return is_type_bitfld(get_decltype()); } ///< \isdecl{is_type_bitfld}
THREAD_SAFE bool is_decl_int128(void) const { return is_type_int128(get_decltype()); } ///< \isdecl{is_type_int128}
THREAD_SAFE bool is_decl_int64(void) const { return is_type_int64(get_decltype()); } ///< \isdecl{is_type_int64}
THREAD_SAFE bool is_decl_int32(void) const { return is_type_int32(get_decltype()); } ///< \isdecl{is_type_int32}
THREAD_SAFE bool is_decl_int16(void) const { return is_type_int16(get_decltype()); } ///< \isdecl{is_type_int16}
THREAD_SAFE bool is_decl_int(void) const { return is_type_int(get_decltype()); } ///< \isdecl{is_type_int}
THREAD_SAFE bool is_decl_char(void) const { return is_type_char(get_decltype()); } ///< \isdecl{is_type_char}
THREAD_SAFE bool is_decl_uint(void) const { return is_type_uint(get_decltype()); } ///< \isdecl{is_type_uint}
THREAD_SAFE bool is_decl_uchar(void) const { return is_type_uchar(get_decltype()); } ///< \isdecl{is_type_uchar}
THREAD_SAFE bool is_decl_uint16(void) const { return is_type_uint16(get_decltype()); } ///< \isdecl{is_type_uint16}
THREAD_SAFE bool is_decl_uint32(void) const { return is_type_uint32(get_decltype()); } ///< \isdecl{is_type_uint32}
THREAD_SAFE bool is_decl_uint64(void) const { return is_type_uint64(get_decltype()); } ///< \isdecl{is_type_uint64}
THREAD_SAFE bool is_decl_uint128(void) const { return is_type_uint128(get_decltype()); } ///< \isdecl{is_type_uint128}
THREAD_SAFE bool is_decl_ldouble(void) const { return is_type_ldouble(get_decltype()); } ///< \isdecl{is_type_ldouble}
THREAD_SAFE bool is_decl_double(void) const { return is_type_double(get_decltype()); } ///< \isdecl{is_type_double}
THREAD_SAFE bool is_decl_float(void) const { return is_type_float(get_decltype()); } ///< \isdecl{is_type_float}
THREAD_SAFE bool is_decl_tbyte(void) const { return is_type_tbyte(get_decltype()); } ///< \isdecl{is_type_tbyte}
THREAD_SAFE bool is_decl_floating(void) const { return is_type_floating(get_decltype()); } ///< \isdecl{is_type_floating}
THREAD_SAFE bool is_decl_bool(void) const { return is_type_bool(get_decltype()); } ///< \isdecl{is_type_bool}
THREAD_SAFE bool is_decl_paf(void) const { return is_type_paf(get_decltype()); } ///< \isdecl{is_type_paf}
THREAD_SAFE bool is_well_defined(void) const { return !empty() && !is_decl_partial(); } ///< !(empty()) && !(is_decl_partial())
// Probe the resolved type for various attributes:
bool is_const(void) const { return is_type_const(get_realtype()); } ///< \isreal{is_type_const}
bool is_volatile(void) const { return is_type_volatile(get_realtype()); } ///< \isreal{is_type_volatile}
bool is_void(void) const { return is_type_void(get_realtype()); } ///< \isreal{is_type_void}
bool is_partial(void) const { return is_type_partial(get_realtype()); } ///< \isreal{is_type_partial}
bool is_unknown(void) const { return is_type_unknown(get_realtype()); } ///< \isreal{is_type_unknown}
bool is_ptr(void) const { return is_type_ptr(get_realtype()); } ///< \isreal{is_type_ptr}
bool is_array(void) const { return is_type_array(get_realtype()); } ///< \isreal{is_type_array}
bool is_func(void) const { return is_type_func(get_realtype()); } ///< \isreal{is_type_func}
bool is_complex(void) const { return is_type_complex(get_realtype()); } ///< \isreal{is_type_complex}
bool is_struct(void) const { return is_type_struct(get_realtype()); } ///< \isreal{is_type_struct}
bool is_union(void) const { return is_type_union(get_realtype()); } ///< \isreal{is_type_union}
bool is_udt(void) const { return is_type_struni(get_realtype()); } ///< \isreal{is_type_struni}
bool is_enum(void) const { return is_type_enum(get_realtype()); } ///< \isreal{is_type_enum}
bool is_sue(void) const { return is_type_sue(get_realtype()); } ///< \isreal{is_type_sue}
bool is_bitfield(void) const { return is_type_bitfld(get_realtype()); } ///< \isreal{is_type_bitfld}
bool is_int128(void) const { return is_type_int128(get_realtype()); } ///< \isreal{is_type_int128}
bool is_int64(void) const { return is_type_int64(get_realtype()); } ///< \isreal{is_type_int64}
bool is_int32(void) const { return is_type_int32(get_realtype()); } ///< \isreal{is_type_int32}
bool is_int16(void) const { return is_type_int16(get_realtype()); } ///< \isreal{is_type_int16}
bool is_int(void) const { return is_type_int(get_realtype()); } ///< \isreal{is_type_int}
bool is_char(void) const { return is_type_char(get_realtype()); } ///< \isreal{is_type_char}
bool is_uint(void) const { return is_type_uint(get_realtype()); } ///< \isreal{is_type_uint}
bool is_uchar(void) const { return is_type_uchar(get_realtype()); } ///< \isreal{is_type_uchar}
bool is_uint16(void) const { return is_type_uint16(get_realtype()); } ///< \isreal{is_type_uint16}
bool is_uint32(void) const { return is_type_uint32(get_realtype()); } ///< \isreal{is_type_uint32}
bool is_uint64(void) const { return is_type_uint64(get_realtype()); } ///< \isreal{is_type_uint64}
bool is_uint128(void) const { return is_type_uint128(get_realtype()); } ///< \isreal{is_type_uint128}
bool is_ldouble(void) const { return is_type_ldouble(get_realtype()); } ///< \isreal{is_type_ldouble}
bool is_double(void) const { return is_type_double(get_realtype()); } ///< \isreal{is_type_double}
bool is_float(void) const { return is_type_float(get_realtype()); } ///< \isreal{is_type_float}
bool is_tbyte(void) const { return is_type_tbyte(get_realtype()); } ///< \isreal{is_type_tbyte}
bool is_bool(void) const { return is_type_bool(get_realtype()); } ///< \isreal{is_type_bool}
bool is_paf(void) const { return is_type_paf(get_realtype()); } ///< \isreal{is_type_paf}
bool is_ptr_or_array(void) const { return is_type_ptr_or_array(get_realtype()); } ///< \isreal{is_type_ptr_or_array}
bool is_integral(void) const { return is_type_integral(get_realtype()); } ///< \isreal{is_type_integral}
bool is_ext_integral(void) const { return is_type_ext_integral(get_realtype()); } ///< \isreal{is_type_ext_integral}
bool is_floating(void) const { return is_type_floating(get_realtype()); } ///< \isreal{is_type_floating}
bool is_arithmetic(void) const { return is_type_arithmetic(get_realtype()); } ///< \isreal{is_type_arithmetic}
bool is_ext_arithmetic(void) const { return is_type_ext_arithmetic(get_realtype()); } ///< \isreal{is_type_ext_arithmetic}
/// Does the type represent a single number?
bool is_scalar(void) const { type_t bt = get_realtype(); return get_base_type(bt) <= BT_PTR || is_type_enum(bt); }
/// Get the pointer info.
bool get_ptr_details(ptr_type_data_t *pi) const
{
return get_type_details(BT_PTR|BTM_VOLATILE, pi);
}
/// Get the array specific info
bool get_array_details(array_type_data_t *ai) const
{
return get_type_details(BT_ARRAY, ai);
}
/// Get the enum specific info
bool get_enum_details(enum_type_data_t *ei) const
{
return get_type_details(BTF_ENUM, ei);
}
/// Get the bitfield specific info
bool get_bitfield_details(bitfield_type_data_t *bi) const
{
return get_type_details(BT_BITFIELD, bi);
}
/// Get the udt specific info
bool get_udt_details(udt_type_data_t *udt, gtd_udt_t gtd=GTD_CALC_LAYOUT) const
{
return get_type_details(BTF_STRUCT|gtd, udt);
}
/// Get only the function specific info for this tinfo_t
bool get_func_details(func_type_data_t *fi, gtd_func_t gtd=GTD_CALC_ARGLOCS) const
{
return get_type_details(BT_FUNC|gtd, fi);
}
/// Is this pointer to a function?
bool is_funcptr(void) const { return get_tinfo_property(typid, GTA_IS_FUNCPTR) != 0; }
/// Is a shifted pointer?
bool is_shifted_ptr(void) const { return get_tinfo_property(typid, GTA_IS_SHIFTED_PTR) != 0; }
/// Is a variable-size structure?
bool is_varstruct(void) const { return get_tinfo_property(typid, GTA_IS_VARSTRUCT) != 0; }
/// ::BT_PTR & ::BT_ARRAY: get size of pointed object or array element. On error returns -1
int get_ptrarr_objsize(void) const { return get_tinfo_property(typid, GTA_PTRARR_SIZE); }
/// ::BT_PTR & ::BT_ARRAY: get the pointed object or array element.
/// If the current type is not a pointer or array, return empty type info.
tinfo_t get_ptrarr_object(void) const { tinfo_t r; r.typid = get_tinfo_property(typid, GTA_PTRARR_SUBTIF); return r; }
/// ::BT_PTR: get type of pointed object.
/// If the current type is not a pointer, return empty type info.
/// See also get_ptrarr_object() and remove_pointer()
tinfo_t get_pointed_object(void) const { tinfo_t r; r.typid = get_tinfo_property(typid, GTA_PTR_OBJ); return r; }
/// Is "void *"?. This function does not check the pointer attributes and type modifiers
bool is_pvoid(void) const { return get_pointed_object().is_void(); }
/// ::BT_ARRAY: get type of array element. See also get_ptrarr_object()
tinfo_t get_array_element(void) const { tinfo_t r; r.typid = get_tinfo_property(typid, GTA_ARRAY_ELEM); return r; }
/// ::BT_ARRAY: get number of elements (-1 means error)
int get_array_nelems(void) const { return get_tinfo_property(typid, GTA_ARRAY_NELEMS); }
/// ::BT_FUNC or ::BT_PTR ::BT_FUNC: Get type of n-th arg (-1 means return type, see get_rettype())
tinfo_t get_nth_arg(int n) const
{
tinfo_t r;
if ( n >= -1 && n < MAX_FUNC_ARGS )
r.typid = get_tinfo_property(typid, GTA_FUNC_ARG+n);
return r;
}
/// ::BT_FUNC or ::BT_PTR ::BT_FUNC: Get the function's return type
tinfo_t get_rettype(void) const { return get_nth_arg(-1); }
/// ::BT_FUNC or ::BT_PTR ::BT_FUNC: Calculate number of arguments (-1 - error)
int get_nargs(void) const { return get_tinfo_property(typid, GTA_FUNC_NARGS); }
/// ::BT_FUNC or ::BT_PTR ::BT_FUNC: Get calling convention
cm_t get_cc(void) const { return (cm_t)get_tinfo_property(typid, GTA_FUNC_CC); }
bool is_user_cc(void) const { return ::is_user_cc(get_cc()); } ///< \tinfocc{is_user_cc}
bool is_vararg_cc(void) const { return ::is_vararg_cc(get_cc()); } ///< \tinfocc{is_vararg_cc}
bool is_purging_cc(void) const { return ::is_purging_cc(get_cc()); } ///< \tinfocc{is_purging_cc}
/// ::BT_FUNC: Calculate number of purged bytes
int calc_purged_bytes(void) const { return get_tinfo_property(typid, GTA_PURGED_BYTES); }
/// ::BT_FUNC: Is high level type?
bool is_high_func(void) const { return get_tinfo_property(typid, GTA_IS_HIGH_TYPE) != 0; }
/// ::BTF_STRUCT,::BTF_UNION: Find a udt member.
/// - at the specified offset (#STRMEM_OFFSET)
/// - with the specified index (#STRMEM_INDEX)
/// - with the specified type (#STRMEM_TYPE)
/// - with the specified name (#STRMEM_NAME)
/// \return the index of the found member or -1
int find_udt_member(struct udt_member_t *udm, int strmem_flags) const { return find_tinfo_udt_member(udm, typid, strmem_flags); }
/// \defgroup STRMEM_ Find UDT member flags
/// used by 'strmem_flags' parameter to find_udt_member()
//@{
#define STRMEM_MASK 0x0007
#define STRMEM_OFFSET 0x0000 ///< get member by offset
///< - in: udm->offset - is a member offset in bits
#define STRMEM_INDEX 0x0001 ///< get member by number
///< - in: udm->offset - is a member number
#define STRMEM_AUTO 0x0002 ///< get member by offset if struct, or get member by index if union
///< - nb: union: index is stored in the udm->offset field!
///< - nb: struct: offset is in bytes (not in bits)!
#define STRMEM_NAME 0x0003 ///< get member by name
///< - in: udm->name - the desired member name.
#define STRMEM_TYPE 0x0004 ///< get member by type.
///< - in: udm->type - the desired member type.
///< member types are compared with tinfo_t::equals_to()
#define STRMEM_SIZE 0x0005 ///< get member by size.
///< - in: udm->size - the desired member size.
#define STRMEM_MINS 0x0006 ///< get smallest member by size.
#define STRMEM_MAXS 0x0007 ///< get biggest member by size.
#define STRMEM_VFTABLE 0x10000000
///< can be combined with #STRMEM_OFFSET, #STRMEM_AUTO
///< get vftable instead of the base class
#define STRMEM_SKIP_EMPTY 0x20000000
///< can be combined with #STRMEM_OFFSET, #STRMEM_AUTO
///< skip empty members (i.e. having zero size)
///< only last empty member can be returned
#define STRMEM_CASTABLE_TO 0x40000000
///< can be combined with #STRMEM_TYPE:
///< member type must be castable to the specified type
#define STRMEM_ANON 0x80000000
///< can be combined with #STRMEM_NAME:
///< look inside anonymous members too.
//@}
/// Get number of udt members. -1-error
int get_udt_nmembers(void) const { return get_tinfo_property(typid, GTA_UDT_NMEMBERS); }
/// Is an empty struct/union? (has no fields)
bool is_empty_udt(void) const { return get_udt_nmembers() == 0; }
/// Is a small udt? (can fit a register or a pair of registers)
bool is_small_udt(void) const { return get_tinfo_property(typid, GTA_IS_SMALL_UDT) != 0; }
/// Requires full qualifier? (name is not unique)
/// \param out qualifier. may be NULL
/// \param name field name
/// \param off field offset in bits
/// \return if the name is not unique, returns true
bool requires_qualifier(qstring *out, const char *name, uint64 offset) const { return name_requires_qualifier(out, typid, name, offset); }
/// Calculate set of covered bytes for the type
/// \param out pointer to the output buffer. covered bytes will be appended to it.
bool append_covered(rangeset_t *out, uint64 offset=0) const { return append_tinfo_covered(out, typid, offset); }
/// Calculate set of padding bytes for the type
/// \param out pointer to the output buffer; old buffer contents will be lost.
bool calc_gaps(rangeset_t *out) const { return calc_tinfo_gaps(out, typid); }
/// Floating value or an object consisting of one floating member entirely
bool is_one_fpval(void) const { return get_onemember_type().is_floating(); }
/// Is a SSE vector type?
bool is_sse_type(void) const { return get_tinfo_property(typid, GTA_IS_SSE_TYPE) != 0; }
/// Is an anonymous struct/union?
/// We assume that types with names are anonymous if the name starts with $
bool is_anonymous_udt(void) const { return get_tinfo_property(typid, GTA_IS_ANON_UDT) != 0; }
/// Is a vftable type?
bool is_vftable(void) const { return get_tinfo_property(typid, GTA_IS_VFTABLE) != 0; }
/// Has a vftable?
bool has_vftable(void) const { return get_tinfo_property(typid, GTA_HAS_VFTABLE) != 0; }
/// Get enum base type (convert enum to integer type)
/// Returns ::BT_UNK if failed to convert
type_t get_enum_base_type(void) const { return (type_t)get_tinfo_property(typid, GTA_ENUM_BASE_TYPE); }
/// For objects consisting of one member entirely: return type of the member
tinfo_t get_onemember_type(void) const { tinfo_t r; r.typid = get_tinfo_property(typid, GTA_ONEMEM_TYPE); return r; }
/// Calculate the type score (the higher - the nicer is the type)
uint32 calc_score(void) const { return score_tinfo(this); }
/// Get a C-like string representation of the type.
/// \param out output string
/// \param name name of type
/// \param prtype_flags \ref PRTYPE_
/// \param indent structure level indent
/// \param cmtindent comment indent
/// \param prefix string prepended to each line
/// \param cmt comment text
/// \return success
bool print(
qstring *out,
const char *name=NULL,
int prtype_flags=PRTYPE_1LINE,
int indent=0,
int cmtindent=0,
const char *prefix=NULL,
const char *cmt=NULL) const
{
return print_tinfo(out, prefix, indent, cmtindent, prtype_flags, this, name, cmt);
}
/// Function to facilitate debugging
const char *dstr(void) const { return dstr_tinfo(this); }
/// Get type attributes (all_attrs: include attributes of referenced types, if any)
bool get_attrs(type_attrs_t *tav, bool all_attrs=false) const { return get_tinfo_attrs(typid, tav, all_attrs); }
/// Get a type attribute
bool get_attr(const qstring &key, bytevec_t *bv, bool all_attrs=true) const { return get_tinfo_attr(typid, key, bv, all_attrs); }
/// Set type attributes. If necessary, a new typid will be created.
/// this function modifies tav! (returns old attributes, if any)
/// \return false: bad attributes
bool set_attrs(type_attrs_t *tav) { return set_tinfo_attrs(this, tav); }
/// Set a type attribute. If necessary, a new typid will be created.
bool set_attr(const type_attr_t &ta, bool may_overwrite=true) { return set_tinfo_attr(this, ta, may_overwrite); }
/// Del all type attributes. typerefs cannot be modified by this function.
void del_attrs(void) { set_tinfo_attrs(this, NULL); }
/// Del a type attribute. typerefs cannot be modified by this function.
bool del_attr(const qstring &key, bool make_copy=true) { return del_tinfo_attr(this, key, make_copy); }
bool create_simple_type(type_t decl_type) { return create_type(decl_type, BT_INT, NULL); }
bool create_ptr(const ptr_type_data_t &p, type_t decl_type=BT_PTR) { return create_type(decl_type, BT_PTR|BTM_VOLATILE, (void*)&p); }
bool create_array(const array_type_data_t &p, type_t decl_type=BT_ARRAY) { return create_type(decl_type, BT_ARRAY, (void*)&p); }
bool create_bitfield(const bitfield_type_data_t &p, type_t decl_type=BT_BITFIELD) { return create_type(decl_type, BT_BITFIELD, (void*)&p); }
bool create_typedef(const typedef_type_data_t &p, type_t decl_type=BTF_TYPEDEF, bool try_ordinal=true)
{
type_t bt2 = try_ordinal ? BTF_TYPEDEF : BTF_TYPEDEF|BTM_VOLATILE;
return create_type(decl_type, bt2, (void *)&p);
}
/// \name Convenience functions
//@{
inline bool create_ptr(const tinfo_t &tif, uchar bps=0, type_t decl_type=BT_PTR);
inline bool create_array(const tinfo_t &tif, uint32 nelems=0, uint32 base=0, type_t decl_type=BT_ARRAY);
inline void create_typedef(const til_t *til, const char *name, type_t decl_type=BTF_TYPEDEF, bool try_ordinal=true) { get_named_type(til, name, decl_type, false, try_ordinal); }
inline void create_typedef(const til_t *til, uint ord, type_t decl_type=BTF_TYPEDEF) { get_numbered_type(til, ord, decl_type, false); }
inline bool create_bitfield(uchar nbytes, uchar width, bool is_unsigned=false, type_t decl_type=BT_BITFIELD);
//@}
/// \name Warning
/// These functions consume 'p' (make it empty)
//@{
bool create_udt(udt_type_data_t &p, type_t decl_type) { return create_type(decl_type, BTF_STRUCT, &p); }
bool create_enum(enum_type_data_t &p, type_t decl_type=BTF_ENUM) { return create_type(decl_type, BTF_ENUM, &p); }
bool create_func(func_type_data_t &p, type_t decl_type=BT_FUNC) { return create_type(decl_type, BT_FUNC, &p); }
//@}
/// \name Store type
/// Store the type info in the type library as a named or numbered type.
/// The tinfo_t object will be replaced by a reference to the created type.
/// Allowed bits for ntf_flags: #NTF_NOBASE, #NTF_REPLACE
//@{
tinfo_code_t set_named_type(til_t *til, const char *name, int ntf_flags=0) { return save_tinfo(this, til, 0, name, ntf_flags|NTF_TYPE); }
tinfo_code_t set_symbol_type(til_t *til, const char *name, int ntf_flags=0) { return save_tinfo(this, til, 0, name, ntf_flags); } // NTF_SYMM and NTF_SYMU are permitted
tinfo_code_t set_numbered_type(til_t *til, uint32 ord, int ntf_flags=0, const char *name=NULL) { return save_tinfo(this, til, ord, name, ntf_flags); }
//@}
/// Create a forward declaration.
/// decl_type: ::BTF_STRUCT, ::BTF_UNION, or ::BTF_ENUM
tinfo_code_t create_forward_decl(til_t *til, type_t decl_type, const char *name, int ntf_flags=0)
{
create_typedef(til, "", decl_type, false);
return set_named_type(til, name, ntf_flags);
}
/// Get stock type information.
/// This function can be used to get tinfo_t for some common types.
/// The same tinfo_t will be returned for the same id, thus saving memory
/// and increasing the speed
/// Please note that retrieving the STI_SIZE_T or STI_SSIZE_T stock type,
/// will also have the side-effect of adding that type to the 'idati' TIL,
/// under the well-known name 'size_t' or 'ssize_t' (respectively).
static tinfo_t get_stock(stock_type_id_t id) { tinfo_t t; get_stock_tinfo(&t, id); return t; }
/// Convert an array into a pointer.
/// type[] => type *
inline bool convert_array_to_ptr(void);
/// Replace the current type with the ptr obj or array element.
/// This function performs one of the following conversions:
/// - type[] => type
/// - type* => type
/// If the conversion is performed successfully, return true
inline bool remove_ptr_or_array(void)
{
tinfo_t tif = get_ptrarr_object();
if ( tif.empty() )
return false;
swap(tif);
return true;
}
/// Change the type sign. Works only for the types that may have sign
bool change_sign(type_sign_t sign) { return set_tinfo_property(this, STA_TYPE_SIGN, sign) != 0; }
/// Calculate the udt alignments using the field offsets/sizes and the total udt size
/// This function does not work on typerefs
bool calc_udt_aligns(int sudt_flags=SUDT_GAPS)
{ return set_tinfo_property(this, STA_UDT_ALIGN, sudt_flags) != 0; }
/// \name Bitfields
/// Helper functions to store/extract bitfield values
//@{
uint64 read_bitfield_value(uint64 v, int bitoff) const { return read_tinfo_bitfield_value(typid, v, bitoff); }
uint64 write_bitfield_value(uint64 dst, uint64 v, int bitoff) const { return write_tinfo_bitfield_value(typid, dst, v, bitoff); }
//@}
/// \name Modifiers
/// Work with type modifiers: const and volatile
//@{
type_t get_modifiers(void) const { return typid & TYPE_MODIF_MASK; }
void set_modifiers(type_t mod) { if ( !empty() ) typid = (typid & ~TYPE_MODIF_MASK) | (mod & TYPE_MODIF_MASK); }
void set_const(void) { if ( !empty() ) typid |= BTM_CONST; }
void set_volatile(void) { if ( !empty() ) typid |= BTM_VOLATILE; }
void clr_const(void) { typid &= ~BTM_CONST; }
void clr_volatile(void) { typid &= ~BTM_VOLATILE; }
void clr_const_volatile(void) { typid &= ~TYPE_MODIF_MASK; }
//@}
DECLARE_COMPARISONS(tinfo_t)
{ // simple comparison: good enough to organize std::map, etc
// for this function "unsigned char" and "uchar" are different
// for deeper comparison see compare_with()
return lexcompare_tinfo(typid, r.typid, 0);
}
/// \defgroup TCMP_ tinfo_t comparison flags
/// passed as 'tcflags' parameter to tinfo_t::compare_with()
//@{
#define TCMP_EQUAL 0x0000 ///< are types equal?
#define TCMP_IGNMODS 0x0001 ///< ignore const/volatile modifiers
#define TCMP_AUTOCAST 0x0002 ///< can t1 be cast into t2 automatically?
#define TCMP_MANCAST 0x0004 ///< can t1 be cast into t2 manually?
#define TCMP_CALL 0x0008 ///< can t1 be called with t2 type?
#define TCMP_DELPTR 0x0010 ///< remove pointer from types before comparing
#define TCMP_DECL 0x0020 ///< compare declarations without resolving them
#define TCMP_ANYBASE 0x0040 ///< accept any base class when casting
#define TCMP_SKIPTHIS 0x0080 ///< skip the first function argument in comparison
//@}
/// Compare two types, based on given flags (see \ref TCMP_)
bool compare_with(const tinfo_t &r, int tcflags=0) const { return compare_tinfo(typid, r.typid, tcflags); }
bool equals_to(const tinfo_t &r) const { return compare_with(r, 0); }
bool is_castable_to(const tinfo_t &target) const { return compare_with(target, TCMP_AUTOCAST); }
bool is_manually_castable_to(const tinfo_t &target) const { return compare_with(target, TCMP_MANCAST); }
};
DECLARE_TYPE_AS_MOVABLE(tinfo_t);
typedef qvector<tinfo_t> tinfovec_t; ///< vector of tinfo objects
//------------------------------------------------------------------------
/// SIMD type info
struct simd_info_t
{
const char *name; ///< name of SIMD type (NULL-undefined)
tinfo_t tif; ///< SIMD type (empty-undefined)
uint16 size; ///< SIMD type size in bytes (0-undefined)
type_t memtype; ///< member type
///< BTF_INT8/16/32/64/128, BTF_UINT8/16/32/64/128
///< BTF_INT - integrals of any size/sign
///< BTF_FLOAT, BTF_DOUBLE
///< BTF_TBYTE - floatings of any size
///< BTF_UNION - union of integral and floating types
///< BTF_UNK - undefined
simd_info_t(const char *nm = NULL, uint16 sz = 0, type_t memt = BTF_UNK)
: name(nm), size(sz), memtype(memt) {}
bool match_pattern(const simd_info_t *pattern)
{
if ( pattern == NULL )
return true;
if ( pattern->size != 0 && pattern->size != size
|| pattern->name != NULL && !streq(pattern->name, name)
|| !pattern->tif.empty() && !pattern->tif.compare_with(tif) )
{
return false;
}
if ( pattern->memtype == BTF_UNK || pattern->memtype == memtype )
return true;
return pattern->memtype == BTF_TBYTE && is_type_float(memtype)
|| pattern->memtype == BTF_INT && is_type_int(memtype);
}
};
DECLARE_TYPE_AS_MOVABLE(simd_info_t);
typedef qvector<simd_info_t> simd_info_vec_t;
//------------------------------------------------------------------------
/// Use func_type_data_t::guess_cc()
idaman cm_t ida_export guess_func_cc(
const func_type_data_t &fti,
int npurged,
int cc_flags);
/// Use func_type_data_t::dump()
idaman bool ida_export dump_func_type_data(
qstring *out,
const func_type_data_t &fti,
int praloc_bits);
//------------------------------------------------------------------------
/// Pointer type information (see tinfo_t::get_ptr_details())
struct ptr_type_data_t // #ptr
{
tinfo_t obj_type; ///< pointed object type
tinfo_t closure; ///< cannot have both closure and based_ptr_size
uchar based_ptr_size;
uchar taptr_bits; ///< TAH bits
tinfo_t parent; ///< Parent struct
int32 delta; ///< Offset from the beginning of the parent struct
ptr_type_data_t(
tinfo_t c=tinfo_t(),
uchar bps=0,
tinfo_t p=tinfo_t(),
int32 d=0)
: closure(c), based_ptr_size(bps), taptr_bits(0), parent(p), delta(d) {}
DEFINE_MEMORY_ALLOCATION_FUNCS()
void swap(ptr_type_data_t &r) { qswap(*this, r); } ///< Set this = r and r = this
bool operator == (const ptr_type_data_t &r) const
{
return obj_type == r.obj_type
&& closure == r.closure
&& based_ptr_size == r.based_ptr_size;
}
bool operator != (const ptr_type_data_t &r) const { return !(*this == r); }
bool is_code_ptr(void) const { return obj_type.is_func(); } ///< Are we pointing to code?
bool is_shifted() const { return delta != 0; }
};
DECLARE_TYPE_AS_MOVABLE(ptr_type_data_t);
//------------------------------------------------------------------------
/// Array type information (see tinfo_t::get_array_details())
struct array_type_data_t // #array
{
tinfo_t elem_type; ///< element type
uint32 base; ///< array base
uint32 nelems; ///< number of elements
array_type_data_t(size_t b=0, size_t n=0) : base(b), nelems(n) {} ///< Constructor
DEFINE_MEMORY_ALLOCATION_FUNCS()
void swap(array_type_data_t &r) { qswap(*this, r); } ///< set this = r and r = this
};
DECLARE_TYPE_AS_MOVABLE(array_type_data_t);
//-------------------------------------------------------------------------
/// Information about a single function argument
struct funcarg_t
{
argloc_t argloc; ///< argument location
qstring name; ///< argument name (may be empty)
qstring cmt; ///< argument comment (may be empty)
tinfo_t type; ///< argument type
uint32 flags = 0; ///< \ref FAI_
/// \defgroup FAI_ Function argument property bits
/// used by funcarg_t::flags
//@{
#define FAI_HIDDEN 0x0001 ///< hidden argument
#define FAI_RETPTR 0x0002 ///< pointer to return value. implies hidden
#define FAI_STRUCT 0x0004 ///< was initially a structure
#define FAI_ARRAY 0x0008 ///< was initially an array
///< see "__org_typedef" or "__org_arrdim" type attributes
///< to determine the original type
#define FAI_UNUSED 0x0010 ///< argument is not used by the function
#define TA_ORG_TYPEDEF "__org_typedef" ///< the original typedef name (simple string)
#define TA_ORG_ARRDIM "__org_arrdim" ///< the original array dimension (pack_dd)
#define TA_FORMAT "format" ///< info about the 'format' argument
///< 3 times pack_dd:
///< \ref format_functype_t,
///< argument number of 'format',
///< argument number of '...'
//@}
bool operator == (const funcarg_t &r) const
{
return argloc == r.argloc
&& name == r.name
// && cmt == r.cmt
&& type == r.type;
}
bool operator != (const funcarg_t &r) const { return !(*this == r); }
};
DECLARE_TYPE_AS_MOVABLE(funcarg_t);
typedef qvector<funcarg_t> funcargvec_t; ///< vector of function argument objects
/// Function type information (see tinfo_t::get_func_details())
struct func_type_data_t : public funcargvec_t // #func
{
int flags = 0; ///< \ref FTI_
/// \defgroup FTI_ Function type data property bits
/// used by func_type_data_t::flags
//@{
#define FTI_SPOILED 0x0001 ///< information about spoiled registers is present
#define FTI_NORET 0x0002 ///< noreturn
#define FTI_PURE 0x0004 ///< __pure
#define FTI_HIGH 0x0008 ///< high level prototype (with possibly hidden args)
#define FTI_STATIC 0x0010 ///< static
#define FTI_VIRTUAL 0x0020 ///< virtual
#define FTI_CALLTYPE 0x00C0 ///< mask for FTI_*CALL
#define FTI_DEFCALL 0x0000 ///< default call
#define FTI_NEARCALL 0x0040 ///< near call
#define FTI_FARCALL 0x0080 ///< far call
#define FTI_INTCALL 0x00C0 ///< interrupt call
#define FTI_ARGLOCS 0x0100 ///< info about argument locations has been calculated
///< (stkargs and retloc too)
#define FTI_ALL 0x01FF ///< all defined bits
//@}
tinfo_t rettype; ///< return type
argloc_t retloc; ///< return location
uval_t stkargs = 0; ///< size of stack arguments (not used in build_func_type)
reginfovec_t spoiled; ///< spoiled register information.
///< if spoiled register info is present, it overrides
///< the standard spoil info (eax, edx, ecx for x86)
cm_t cc = 0; ///< calling convention
void swap(func_type_data_t &r) { qswap(*this, r); }
bool is_high(void) const { return (flags & FTI_HIGH) != 0; }
bool is_noret(void) const { return (flags & FTI_NORET) != 0; }
bool is_pure(void) const { return (flags & FTI_PURE) != 0; }
int get_call_method(void) const { return flags & FTI_CALLTYPE; }
cm_t get_cc(void) const
{
cm_t ret = ::get_cc(cc);
// if the calling convention is not specified, use the default one
if ( ret <= CM_CC_UNKNOWN )
ret = ::get_cc(inf_get_cc_cm());
return ret;
}
bool is_vararg_cc() const { return ::is_vararg_cc(cc); }
/// Guess function calling convention
/// use the following info: argument locations and 'stkargs'
cm_t guess_cc(int purged, int cc_flags) const
{
return guess_func_cc(*this, purged, cc_flags);
}
#define CC_CDECL_OK 0x01 ///< can use __cdecl calling convention?
#define CC_ALLOW_ARGPERM 0x02 ///< disregard argument order?
#define CC_ALLOW_REGHOLES 0x04 ///< allow holes in register argument list?
#define CC_HAS_ELLIPSIS 0x08 ///< function has a variable list of arguments?
/// Dump information that is not always visible in the function prototype.
/// (argument locations, return location, total stkarg size)
bool dump(qstring *out, int praloc_bits=PRALOC_STKOFF) const
{
return dump_func_type_data(out, *this, praloc_bits);
}
bool use_golang_abi() const { return ::use_golang_abi(get_cc()); }
};
/// Function index for the 'format' attribute.
enum format_functype_t
{
FMTFUNC_PRINTF,
FMTFUNC_SCANF,
FMTFUNC_STRFTIME,
FMTFUNC_STRFMON,
};
//-------------------------------------------------------------------------
/// Describes an enum value
struct enum_member_t
{
qstring name;
qstring cmt;
uint64 value;
DEFINE_MEMORY_ALLOCATION_FUNCS()
bool operator == (const enum_member_t &r) const
{
return name == r.name
// && cmt == r.cmt
&& value == r.value;
}
bool operator != (const enum_member_t &r) const { return !(*this == r); }
void swap(enum_member_t &r) { qswap(*this, r); }
};
DECLARE_TYPE_AS_MOVABLE(enum_member_t);
typedef qvector<enum_member_t> enum_member_vec_t; ///< vector of enum values
/// Enum type information (see tinfo_t::get_enum_details())
struct enum_type_data_t : public enum_member_vec_t // #enum
{
intvec_t group_sizes; ///< if present, specifies bitfield group sizes
///< each group starts with a mask member
uint32 taenum_bits; ///< \ref tattr_enum
bte_t bte; ///< enum member sizes (shift amount) and style
enum_type_data_t(bte_t _bte=BTE_ALWAYS|BTE_HEX) : taenum_bits(0), bte(_bte) {}
DEFINE_MEMORY_ALLOCATION_FUNCS()
bool is_64bit(void) const { return (taenum_bits & TAENUM_64BIT) != 0; }
bool is_hex(void) const { return (bte & BTE_OUT_MASK) == BTE_HEX; }
bool is_char(void) const { return (bte & BTE_OUT_MASK) == BTE_CHAR; }
bool is_sdec(void) const { return (bte & BTE_OUT_MASK) == BTE_SDEC; }
bool is_udec(void) const { return (bte & BTE_OUT_MASK) == BTE_UDEC; }
int calc_nbytes(void) const
{
int emsize = bte & BTE_SIZE_MASK;
return emsize != 0 ? 1 << (emsize-1) : inf_get_cc_size_e();
}
uint64 calc_mask(void) const { return make_mask<uint64>(calc_nbytes()*8); }
void swap(enum_type_data_t &r) { qswap(*this, r); } ///< swap two instances
};
DECLARE_TYPE_AS_MOVABLE(enum_type_data_t);
//-------------------------------------------------------------------------
/// Type information for typedefs
struct typedef_type_data_t // #typedef
{
const til_t *til; ///< type library to use when resolving
union
{
const char *name; ///< is_ordref=false: target type name. we do not own this pointer!
uint32 ordinal; ///< is_ordref=true: type ordinal number
};
bool is_ordref; ///< is reference by ordinal?
bool resolve; ///< should resolve immediately?
typedef_type_data_t(const til_t *_til, const char *_name, bool _resolve=false)
: name(_name), is_ordref(false), resolve(_resolve) { til = _til == NULL ? get_idati() : _til; }
typedef_type_data_t(const til_t *_til, uint32 ord, bool _resolve=false)
: ordinal(ord), is_ordref(true), resolve(_resolve) { til = _til == NULL ? get_idati() : _til; }
DEFINE_MEMORY_ALLOCATION_FUNCS()
void swap(typedef_type_data_t &r) { qswap(*this, r); }
};
DECLARE_TYPE_AS_MOVABLE(typedef_type_data_t);
//-------------------------------------------------------------------------
/// An object to represent struct or union members
struct udt_member_t // #udm
{
uint64 offset; ///< member offset in bits
uint64 size; ///< size in bits
qstring name; ///< member name
qstring cmt; ///< member comment
tinfo_t type; ///< member type
int effalign; ///< effective field alignment (in bytes)
uint32 tafld_bits; ///< TAH bits
uchar fda; ///< field alignment (shift amount)
udt_member_t(void)
: offset(0), size(0), effalign(0), tafld_bits(0), fda(0)
{
}
bool is_bitfield(void) const { return type.is_decl_bitfield(); }
bool is_zero_bitfield(void) const { return size == 0 && is_bitfield(); }
bool is_unaligned(void) const { return (tafld_bits & TAFLD_UNALIGNED) != 0; }
bool is_baseclass(void) const { return (tafld_bits & TAFLD_BASECLASS) != 0; }
bool is_virtbase(void) const { return (tafld_bits & TAFLD_VIRTBASE) != 0; }
bool is_vftable(void) const { return (tafld_bits & TAFLD_VFTABLE) != 0; }
void set_unaligned(void) { tafld_bits |= TAFLD_UNALIGNED; }
void set_baseclass(void) { tafld_bits |= TAFLD_BASECLASS; }
void set_virtbase(void) { tafld_bits |= TAFLD_VIRTBASE; }
void set_vftable(void) { tafld_bits |= TAFLD_VFTABLE; }
void clr_unaligned(void) { tafld_bits &= ~TAFLD_UNALIGNED; }
void clr_baseclass(void) { tafld_bits &= ~TAFLD_BASECLASS; }
void clr_virtbase(void) { tafld_bits &= ~TAFLD_VIRTBASE; }
void clr_vftable(void) { tafld_bits &= ~TAFLD_VFTABLE; }
uint64 begin(void) const { return offset; }
uint64 end(void) const { return offset + size; }
bool operator < (const udt_member_t &r) const
{
return offset < r.offset;
}
bool operator == (const udt_member_t &r) const
{
return offset == r.offset
&& size == r.size
&& name == r.name
// && cmt == r.cmt
&& type == r.type
&& fda == r.fda
&& tafld_bits == r.tafld_bits
&& effalign == r.effalign;
}
bool operator != (const udt_member_t &r) const { return !(*this == r); }
DEFINE_MEMORY_ALLOCATION_FUNCS()
void swap(udt_member_t &r) { qswap(*this, r); }
// the user cannot enter anonymous fields in ida (they can come only from tils),
// so we use the following trick: if the field type starts with $ and the name
// with __, then we consider the field as anonymous
bool is_anonymous_udm() const
{
return name[0] == '_' && name[1] == '_' && type.is_anonymous_udt();
}
};
DECLARE_TYPE_AS_MOVABLE(udt_member_t);
typedef qvector<udt_member_t> udtmembervec_t; ///< vector of udt member objects
/// An object to represent struct or union types (see tinfo_t::get_udt_details())
struct udt_type_data_t : public udtmembervec_t // #udt
{
size_t total_size; ///< total structure size in bytes
size_t unpadded_size; ///< unpadded structure size in bytes
uint32 effalign; ///< effective structure alignment (in bytes)
uint32 taudt_bits; ///< TA... and TAUDT... bits
uchar sda; ///< declared structure alignment (shift amount+1). 0 - unspecified
uchar pack; ///< #pragma pack() alignment (shift amount)
bool is_union; ///< is union or struct?
udt_type_data_t(void)
: total_size(0), unpadded_size(0), effalign(0),
taudt_bits(0), sda(0), pack(0),
is_union(false)
{
}
void swap(udt_type_data_t &r) { qswap(*this, r); }
DEFINE_MEMORY_ALLOCATION_FUNCS()
bool is_unaligned(void) const { return (taudt_bits & TAUDT_UNALIGNED) != 0; }
bool is_msstruct(void) const { return (taudt_bits & TAUDT_MSSTRUCT) != 0; }
bool is_cppobj(void) const { return (taudt_bits & TAUDT_CPPOBJ) != 0; }
bool is_vftable(void) const { return (taudt_bits & TAUDT_VFTABLE) != 0; }
void set_vftable(void) { taudt_bits |= TAUDT_VFTABLE; }
bool is_last_baseclass(size_t idx) // we assume idx is valid
{
return at(idx).is_baseclass()
&& (idx+1 == size() || !at(idx+1).is_baseclass());
}
};
DECLARE_TYPE_AS_MOVABLE(udt_type_data_t);
// The type name of a virtual function table (__vftable) of a class is
// constructed by appending the following suffix to the class name.
// In the case of multiple inheritance we append the vft offset
// to the class name (with format %04X)
// Example: CLS_0024_vtbl is used for the vft located at the offset 0x24 of CLS
#define VTBL_SUFFIX "_vtbl"
// The member name of a virtual function table
// Complex cases are not handled yet.
#define VTBL_MEMNAME "__vftable"
//-------------------------------------------------------------------------
/// Bitfield type information (see tinfo_t::get_bitfield_details())
struct bitfield_type_data_t // #bitfield
{
uchar nbytes; ///< enclosing type size (1,2,4,8 bytes)
uchar width; ///< number of bits
bool is_unsigned; ///< is bitfield unsigned?
bitfield_type_data_t(uchar _nbytes=0, uchar _width=0, bool _is_unsigned=false)
: nbytes(_nbytes), width(_width), is_unsigned(_is_unsigned)
{
}
bool serialize(qtype *type, type_t mods) const;
DECLARE_COMPARISONS(bitfield_type_data_t)
{
if ( nbytes != r.nbytes )
return nbytes > r.nbytes ? 1 : -1;
if ( width != r.width )
return width > r.width ? 1 : -1;
if ( is_unsigned )
{
if ( !r.is_unsigned )
return 1;
}
else
{
if ( r.is_unsigned )
return -1;
}
return 0;
}
void swap(bitfield_type_data_t &r) { qswap(*this, r); }
};
DECLARE_TYPE_AS_MOVABLE(bitfield_type_data_t);
//--------------------------------------------------------------------------
// This tag can be used at the beginning of
// udt_member_t::cmt
// funcarg_t::cmt
// enum_member_t::cmt
// to specify the line number where it is defined.
// Example: "\x05123." means the line number 123
#define TPOS_LNNUM "\x05"
//-------------------------------------------------------------------------
// return argument alignment (which depends on ABI and natural type alignment)
inline int get_arg_align(int type_align, int slotsize)
{
if ( type_align > slotsize*2 && !inf_huge_arg_align() )
type_align = slotsize*2;
return type_align < slotsize
? inf_pack_stkargs() ? type_align : slotsize
: inf_big_arg_align() ? type_align : slotsize;
}
inline int get_arg_align(const tinfo_t &tif, int slotsize)
{
uint32 align = 0;
tif.get_size(&align);
return get_arg_align(align, slotsize);
}
inline sval_t align_stkarg_up(sval_t spoff, int type_align, int slotsize)
{
uint32 align = get_arg_align(type_align, slotsize);
return align_up(spoff, align);
}
inline sval_t align_stkarg_up(sval_t spoff, const tinfo_t &tif, int slotsize)
{
uint32 align = get_arg_align(tif, slotsize);
return align_up(spoff, align);
}
inline bool argloc_t::has_reg() const
{
if ( !is_scattered() )
return is_reg();
for ( const auto &part : scattered() )
if ( part.is_reg() )
return true;
return false;
};
inline bool argloc_t::has_stkoff() const
{
if ( !is_scattered() )
return is_stkoff();
for ( const auto &part : scattered() )
if ( part.is_stkoff() )
return true;
return false;
};
inline bool argloc_t::is_mixed_scattered() const
{
if ( !is_scattered() )
return false;
bool reg_found = false;
bool stkoff_found = false;
for ( const auto &part : scattered() )
{
if ( part.is_reg() )
reg_found = true;
if ( part.is_stkoff() )
stkoff_found = true;
}
return reg_found && stkoff_found;
};
inline bool tinfo_t::get_named_type(
const til_t *til,
const char *name,
type_t decl_type,
bool resolve,
bool try_ordinal)
{
typedef_type_data_t tp(til, name, resolve);
return create_typedef(tp, decl_type, try_ordinal);
}
inline bool tinfo_t::get_numbered_type(
const til_t *til,
uint32 ordinal,
type_t decl_type,
bool resolve)
{
typedef_type_data_t tp(til, ordinal, resolve);
return create_typedef(tp, decl_type, false);
}
inline bool tinfo_t::create_ptr(
const tinfo_t &tif,
uchar bps,
type_t decl_type)
{
ptr_type_data_t pi(tinfo_t(), bps);
pi.obj_type = tif;
return create_ptr(pi, decl_type);
}
inline bool tinfo_t::create_array(
const tinfo_t &tif,
uint32 nelems,
uint32 base,
type_t decl_type)
{
array_type_data_t ai(base, nelems);
ai.elem_type = tif;
return create_array(ai, decl_type);
}
inline bool tinfo_t::create_bitfield(
uchar nbytes,
uchar width,
bool _is_unsigned,
type_t decl_type)
{
bitfield_type_data_t bi(nbytes, width, _is_unsigned);
return create_bitfield(bi, decl_type);
}
inline bool tinfo_t::convert_array_to_ptr(void)
{
bool ok = false;
array_type_data_t ai;
if ( get_array_details(&ai) )
{
ptr_type_data_t pi;
pi.obj_type.swap(ai.elem_type);
create_ptr(pi);
ok = true;
}
return ok;
}
/// ::BT_PTR: If the current type is a pointer, return the pointed object.
/// If the current type is not a pointer, return the current type.
/// See also get_ptrarr_object() and get_pointed_object()
inline tinfo_t remove_pointer(const tinfo_t &tif)
{
tinfo_t r;
r.typid = get_tinfo_property(tif.typid, tinfo_t::GTA_SAFE_PTR_OBJ);
return r;
}
/// Information about how to modify the current type, used by ::tinfo_visitor_t.
struct type_mods_t
{
tinfo_t type; ///< current type
qstring name; ///< current type name
qstring cmt; ///< comment for current type
int flags; ///< \ref TVIS_
/// \defgroup TVIS_ Type modification bits
/// used by type_mods_t::flags
//@{
#define TVIS_TYPE 0x0001 ///< new type info is present
#define TVIS_NAME 0x0002 ///< new name is present
#define TVIS_CMT 0x0004 ///< new comment is present
//@}
type_mods_t(void) : flags(0) {}
void clear(void) { flags = 0; }
/// The visit_type() function may optionally save the modified type info.
/// Use the following functions for that. The new name and comment will be applied
/// only if the current tinfo element has storage for them.
void set_new_type(const tinfo_t &t) { type = t; flags |= TVIS_TYPE; }
void set_new_name(const qstring &n) { name = n; flags |= TVIS_NAME; }
void set_new_cmt(const qstring &c) { cmt = c; flags |= TVIS_CMT; }
bool has_type(void) const { return (flags & TVIS_TYPE) != 0; }
bool has_name(void) const { return (flags & TVIS_NAME) != 0; }
bool has_cmt(void) const { return (flags & TVIS_CMT) != 0; }
bool has_info(void) const { return flags != 0; }
};
/// Visit all subtypes of a type. Derive your visitor from this class and use apply_to()
struct tinfo_visitor_t
{
int state; ///< \ref TVST_
/// \defgroup TVST_ tinfo visitor states
/// used by tinfo_visitor_t::state
//@{
#define TVST_PRUNE 0x01 ///< don't visit children of current type
#define TVST_DEF 0x02 ///< visit type definition (meaningful for typerefs)
#define TVST_LEVEL 0x04 // has level member (internal use)
//@}
int level; // recursion level (internal use)
tinfo_visitor_t(int s=0) : state(s|TVST_LEVEL), level(0) {}
virtual ~tinfo_visitor_t() {}
/// Visit a subtype.
/// this function must be implemented in the derived class.
/// it may optionally fill out with the new type info. this can be used to
/// modify types (in this case the 'out' argument of apply_to() may not be NULL)
/// return 0 to continue the traversal.
/// return !=0 to stop the traversal.
virtual int idaapi visit_type(
type_mods_t *out,
const tinfo_t &tif,
const char *name,
const char *cmt) = 0;
/// To refuse to visit children of the current type, use this:
void prune_now(void) { state |= TVST_PRUNE; }
/// Call this function to initiate the traversal
int apply_to(const tinfo_t &tif, type_mods_t *out=NULL, const char *name=NULL, const char *cmt=NULL)
{
return visit_subtypes(this, out, tif, name, cmt);
}
};
//------------------------------------------------------------------------
// Definitions for packing/unpacking idc objects
/// Object that represents a register
struct regobj_t
{
int regidx; ///< index into dbg->registers
int relocate; ///< 0-plain num, 1-must relocate
bytevec_t value;
size_t size(void) const { return value.size(); }
};
DECLARE_TYPE_AS_MOVABLE(regobj_t);
typedef qvector<regobj_t> regobjvec_t;
struct regobjs_t : public regobjvec_t {}; /// Collection of register objects
/// Read a typed idc object from the database
idaman error_t ida_export unpack_idcobj_from_idb(
idc_value_t *obj,
const tinfo_t &tif,
ea_t ea,
const bytevec_t *off0, // if !NULL: bytevec that represents object at 'ea'
int pio_flags=0);
#define PIO_NOATTR_FAIL 0x0004 ///< missing attributes are not ok
#define PIO_IGNORE_PTRS 0x0008 ///< do not follow pointers
/// Read a typed idc object from the byte vector
idaman error_t ida_export unpack_idcobj_from_bv(
idc_value_t *obj,
const tinfo_t &tif,
const bytevec_t &bytes,
int pio_flags=0);
/// Write a typed idc object to the database
idaman error_t ida_export pack_idcobj_to_idb(
const idc_value_t *obj,
const tinfo_t &tif,
ea_t ea,
int pio_flags=0);
/// Write a typed idc object to the byte vector.
/// Byte vector may be non-empty, this function will append data to it
idaman error_t ida_export pack_idcobj_to_bv(
const idc_value_t *obj,
const tinfo_t &tif,
relobj_t *bytes,
void *objoff, // NULL - append object to 'bytes'
// if not NULL:
// in: int32*: offset in 'bytes' for the object
// -1 means 'do not store the object itself in bytes
// store only pointed objects'
// out: data for object (if *(int32*)objoff == -1)
int pio_flags=0);
/// Helper function for the processor modules.
/// to be called from \ph{use_stkarg_type}
idaman bool ida_export apply_tinfo_to_stkarg(
const insn_t &insn,
const op_t &x,
uval_t v,
const tinfo_t &tif,
const char *name);
//------------------------------------------------------------------------
// Helper struct for the processor modules: process call arguments
struct argtinfo_helper_t
{
size_t reserved = 0;
virtual ~argtinfo_helper_t() {}
/// Set the operand type as specified
virtual bool idaapi set_op_tinfo(
const insn_t &insn,
const op_t &x,
const tinfo_t &tif,
const char *name) = 0;
/// Is the current insn a stkarg load?.
/// if yes:
/// - src: index of the source operand in \insn_t{ops}
/// - dst: index of the destination operand in \insn_t{ops}
/// \insn_t{ops}[dst].addr is expected to have the stack offset
virtual bool idaapi is_stkarg_load(const insn_t &insn, int *src, int *dst) = 0;
/// The call instruction with a delay slot?.
virtual bool idaapi has_delay_slot(ea_t /*caller*/) { return false; }
/// This function is to be called by the processor module in response
/// to ev_use_arg_types.
inline void use_arg_tinfos(ea_t caller, func_type_data_t *fti, funcargvec_t *rargs);
};
/// Do not call this function directly, use argtinfo_helper_t
idaman void ida_export gen_use_arg_tinfos2(
struct argtinfo_helper_t *_this,
ea_t caller,
func_type_data_t *fti,
funcargvec_t *rargs);
inline void argtinfo_helper_t::use_arg_tinfos(
ea_t caller,
func_type_data_t *fti,
funcargvec_t *rargs)
{
gen_use_arg_tinfos2(this, caller, fti, rargs);
}
//-------------------------------------------------------------------------
/// Looks for a hole at the beginning of the stack arguments. Will make use
/// of the IDB's func_t function at that place (if present) to help determine
/// the presence of such a hole.
idaman bool ida_export func_has_stkframe_hole(ea_t ea, const func_type_data_t &fti);
//-------------------------------------------------------------------------
/// Interface class - see ::ida_lowertype_helper_t
class lowertype_helper_t
{
public:
virtual bool idaapi func_has_stkframe_hole(
const tinfo_t &candidate,
const func_type_data_t &candidate_data) = 0;
virtual int idaapi get_func_purged_bytes(
const tinfo_t &candidate,
const func_type_data_t &candidate_data) = 0;
};
//-------------------------------------------------------------------------
/// An implementation of ::lowertype_helper_t that has access to the
/// IDB, and thus can help spot holes in the stack arguments.
class ida_lowertype_helper_t : public lowertype_helper_t
{
const tinfo_t &tif;
ea_t ea;
int purged_bytes;
public:
ida_lowertype_helper_t(const tinfo_t &_tif, ea_t _ea, int _pb)
: tif(_tif), ea(_ea), purged_bytes(_pb) {}
virtual bool idaapi func_has_stkframe_hole(
const tinfo_t &candidate,
const func_type_data_t &candidate_data) override
{
return candidate == tif
? ::func_has_stkframe_hole(ea, candidate_data)
: false;
}
virtual int idaapi get_func_purged_bytes(
const tinfo_t &candidate,
const func_type_data_t &) override
{
return candidate == tif
? purged_bytes
: -1;
}
};
//-------------------------------------------------------------------------
/// Lower type.
/// Inspect the type and lower all function subtypes using lower_func_type(). \n
/// We call the prototypes usually encountered in source files "high level" \n
/// They may have implicit arguments, array arguments, big structure retvals, etc \n
/// We introduce explicit arguments (i.e. 'this' pointer) and call the result \n
/// "low level prototype". See #FTI_HIGH.
///
/// In order to improve heuristics for recognition of big structure retvals, \n
/// it is recommended to pass a helper that will be used to make decisions. \n
/// That helper will be used only for lowering 'tif', and not for the children \n
/// types walked through by recursion.
/// \retval 1 removed #FTI_HIGH,
/// \retval 2 made substantial changes
/// \retval -1 failure
idaman int ida_export lower_type(
til_t *til,
tinfo_t *tif,
const char *name=NULL,
lowertype_helper_t *_helper=NULL);
/// Replace references to ordinal types by name references.
/// This function 'unties' the type from the current local type library
/// and makes it easier to export it.
/// \param til type library to use. may be NULL.
/// \param tif type to modify (in/out)
/// \retval number of replaced subtypes, -1 on failure
idaman int ida_export replace_ordinal_typerefs(til_t *til, tinfo_t *tif);
/// See begin_type_updating()
enum update_type_t
{
UTP_ENUM,
UTP_STRUCT,
};
/// Mark the beginning of a large update operation on the types.
/// Can be used with add_enum_member(), add_struc_member, etc...
/// Also see end_type_updating()
idaman void ida_export begin_type_updating(update_type_t utp);
/// Mark the end of a large update operation on the types (see begin_type_updating())
idaman void ida_export end_type_updating(update_type_t utp);
//--------------------------------------------------------------------------
/// See format_cdata()
struct format_data_info_t
{
int ptvf; /// \ref PTV_
/// \defgroup PTV_ C data formatting properties
/// used by format_data_info_t::ptvf
//@{
#define PTV_DEREF 0x0001 ///< take value to print from the debugged process.
///< #VT_LONG: the address is specified by idc_value_t::num
///< #VT_PVOID: argloc_t is pointed by idc_value_t::pvoid
#define PTV_QUEST 0x0002 ///< print '?' for uninited data
#define PTV_EMPTY 0x0004 ///< return empty string for uninited data
///< should not specify PTV_QUEST and PTV_EMPTY together
#define PTV_CSTR 0x0008 ///< print constant strings inline
#define PTV_EXPAND 0x0010 ///< print only top level on separate lines
///< max_length applies to separate lines
///< margin is ignored
#define PTV_LZHEX 0x0020 ///< print hex numbers with leading zeroes
#define PTV_STPFLT 0x0040 ///< fail on bad floating point numbers
///< (if not set, just print ?flt for them)
#define PTV_SPACE 0x0080 ///< add spaces after commas and around braces
#define PTV_DEBUG 0x0100 ///< format output for debugger
#define PTV_NOPTR 0x0200 ///< prevent pointer values from appearing in the output
#define PTV_NTOP 0x40000000 ///< internal flag, do not use
#define PTV_KEEP 0x80000000 ///< internal flag, do not use
//@}
int radix; ///< number representation (8,10,16)
int max_length; ///< max length of the formatted text (0 means no limit)
///< should be used to format huge arrays for the screen,
///< we cannot display the whole array anyway
///< if this limit is hit, the function returns false
///< and qerrno is set to eMaxLengthExceeded
int arrbase; ///< for arrays: the first element of array to print
int arrnelems; ///< for arrays: number of elements to print
int margin; ///< length of one line (0 means to print everything on one line)
///< if an item cannot be printed in a shorter way,
///< some output lines can be considerably longer
///< 1 means each item on its own line
int indent; ///< how many spaces to use to indent nested structures/arrays
format_data_info_t(void)
: ptvf(PTV_EMPTY|PTV_CSTR|PTV_SPACE), radix(10), max_length(0),
arrbase(0), arrnelems(0),
margin(80), indent(2) {}
};
/// Additional information about the output lines
struct valinfo_t
{
argloc_t loc;
qstring label;
tinfo_t type;
valinfo_t(argloc_t l=argloc_t(), const char *name=NULL, const tinfo_t &tif=tinfo_t())
: loc(l), label(name), type(tif) {}
void swap(valinfo_t &r)
{
loc.swap(r.loc);
label.swap(r.label);
type.swap(r.type);
}
DEFINE_MEMORY_ALLOCATION_FUNCS()
};
DECLARE_TYPE_AS_MOVABLE(valinfo_t);
/// Text representation of a data value (value string).
/// This structure is used before we decide how to represent it,
/// on one line or on many lines
class valstr_t
{
public:
qstring oneline; ///< result if printed on one line in UTF-8 encoding
size_t length; ///< length if printed on one line
struct valstrs_t *members; ///< strings for members, each member separately
valinfo_t *info; ///< additional info
int props; ///< temporary properties, used internally
#define VALSTR_OPEN 0x01 ///< printed opening curly brace '{'
valstr_t(void) : length(0), members(NULL), info(NULL), props(0) {}
~valstr_t(void);
DEFINE_MEMORY_ALLOCATION_FUNCS()
private:
struct flatten_args_t
{
const valstr_t *may_not_collapse;
int ptvf;
int max_length;
int margin;
int indent;
};
friend struct valstr_sink_t;
void update_length(int ptvf);
void set_oneline(const char *line, int len)
{
oneline.append(line, len);
length = oneline.length();
}
void consume_oneline(const qstring &line)
{
oneline.append(line);
length = oneline.length();
}
bool append_char(char c, int max_length);
bool convert_to_one_line(int ptvf, int max_length);
bool flatten(const flatten_args_t &flargs, int level);
};
DECLARE_TYPE_AS_MOVABLE(valstr_t);
typedef qvector<valstr_t> valstrvec_t;
struct valstrs_t : public valstrvec_t {}; ///< Collection of value strings
inline valstr_t::~valstr_t(void)
{
delete members;
delete info;
}
/// Format a data value as a C initializer.
/// \param outvec buffer for the formatted string(s). may be NULL
/// \param idc_value value to format
/// \param tif type of the data to format.
/// if NULL and #PTV_DEREF is specified, take tinfo from idb
/// \param vtree more detailed output info
/// \param fdi formatting options
/// \return success. if failed, see qerrno for more info
idaman bool ida_export format_cdata(
qstrvec_t *outvec,
const idc_value_t &idc_value,
const tinfo_t *tif,
valstr_t *vtree=NULL,
const format_data_info_t *fdi=NULL);
/// Flush formatted text
struct text_sink_t
{
/// \return 0-ok, otherwise print_cdata will stop
virtual int idaapi print(const char *str) = 0;
};
/// The same as format_cdata(), but instead of returning the answer in a vector, print it.
/// This function can handle very huge data volume without using too much memory.
/// As soon as the output text becomes too long, the function prints it and
/// flushes its internal buffers.
/// \retval 0 ok
/// \retval -1 printing failed, check qerrno
/// \retval else code returned by text_sink_t::print()
idaman int ida_export print_cdata(
text_sink_t &printer,
const idc_value_t &idc_value,
const tinfo_t *tif,
const format_data_info_t *fdi=NULL);
//-------------------------------------------------------------------------
#define PDF_INCL_DEPS 0x1 ///< Include all type dependencies
#define PDF_DEF_FWD 0x2 ///< Allow forward declarations
#define PDF_DEF_BASE 0x4 ///< Include base types: __int8, __int16, etc..
#define PDF_HEADER_CMT 0x8 ///< Prepend output with a descriptive comment
typedef qvector<uint32> ordvec_t;
/// Print types (and possibly their dependencies) in a format suitable
/// for use in a header file. This is the reverse parse_decls().
/// \param printer a handler for printing text
/// \param til the type library holding the ordinals
/// \param ordinals ordinals of types to export. NULL means: all ordinals in til
/// \param flags flags for the algorithm. A combination of PDF_* constants
/// \retval >0 the number of types exported
/// \retval 0 an error occurred
/// \retval <0 the negated number of types exported. There were minor errors
/// and the resulting output might not be compilable.
idaman int ida_export print_decls(
text_sink_t &printer,
til_t *til,
const ordvec_t *ordinals,
uint32 flags);
/// Calculate max number of lines of a formatted c data, when expanded (#PTV_EXPAND).
/// \param loc location of the data (::ALOC_STATIC or ::ALOC_CUSTOM)
/// \param tif type info
/// \param dont_deref_ptr consider 'ea' as the ptr value
/// \retval 0 data is not expandable
/// \retval -1 error, see qerrno
/// \retval else the max number of lines
idaman int ida_export calc_number_of_children(
const argloc_t &loc,
const tinfo_t &tif,
bool dont_deref_ptr=false);
/// Format a C number.
/// \param buf output buffer
/// \param bufsize size of the output buffer
/// \param value number to format
/// \param size size of the number in bytes (1,2,4,8,16)
/// \param pcn combination of \ref PCN_
idaman size_t ida_export format_c_number(
char *buf,
size_t bufsize,
uint128 value,
int size,
int pcn=0);
/// \defgroup PCN_ C Number formatting flags
/// passed as 'pcn' parameter to format_c_number()
//@{
#define PCN_RADIX 0x07 ///< number base to use
#define PCN_DEC 0x00 ///< decimal
#define PCN_HEX 0x01 ///< hexadecimal
#define PCN_OCT 0x02 ///< octal
#define PCN_CHR 0x03 ///< character
#define PCN_UNSIGNED 0x08 ///< add 'u' suffix
#define PCN_LZHEX 0x10 ///< print leading zeroes for hexdecimal number
#define PCN_NEGSIGN 0x20 ///< print negated value (-N) for negative numbers
#define PCN_DECSEXT 0x40 ///< automatically extend sign of signed decimal numbers
//@}
/// Return a C expression that can be used to represent an enum member.
/// If the value does not correspond to any single enum member, this function tries
/// to find a bitwise combination of enum members that correspond to it.
/// If more than half of value bits do not match any enum members, it fails.
/// \param buf output buffer
/// \param tif enumeration type
/// \param serial which enumeration member to use (0 means the first with the given value)
/// \param value value to search in the enumeration type. only 32-bit number can be handled yet
/// \return success
idaman bool ida_export get_enum_member_expr(
qstring *buf,
const tinfo_t &tif,
int serial,
uint64 value);
inline bool idaapi is_autosync(const char *name, const tinfo_t &tif)
{
type_t decl_type = tif.get_decltype();
return get_ordinal_from_idb_type(name, &decl_type) != -1;
}
//-------------------------------------------------------------------------
// Dialogs to choose a symbol from a type library
//------------------------------------------------------------------------
/// A symbol in a type library
struct til_symbol_t
{
const char *name; ///< symbol name
const til_t *til; ///< pointer to til
til_symbol_t(const char *n = NULL, const til_t *t = NULL): name(n), til(t) {}
};
DECLARE_TYPE_AS_MOVABLE(til_symbol_t);
/// Helper class for choose_named_type().
/// Controls which types are displayed when choosing types.
struct predicate_t
{
virtual bool idaapi should_display(
const til_t *til,
const char *name,
const type_t *type,
const p_list *fields) = 0;
virtual ~predicate_t() {}
};
/// Choose a type from a type library.
/// \param out_sym pointer to be filled with the chosen type
/// \param root_til pointer to starting til (the function will inspect the base tils if allowed by flags)
/// \param title title of listbox to display
/// \param ntf_flags combination of \ref NTF_
/// \param predicate predicate to select types to display (maybe NULL)
/// \return false if nothing is chosen, otherwise true
idaman bool ida_export choose_named_type(
til_symbol_t *out_sym,
const til_t *root_til,
const char *title,
int ntf_flags,
predicate_t *predicate=NULL);
/// Controls which types are displayed/selected when choosing local types.
/// \retval 0 skip type
/// \retval 1 include
typedef int idaapi local_tinfo_predicate_t(uint32 ord, const tinfo_t &type, void *ud);
/// Choose a type from the local type library.
/// \param ti pointer to til
/// \param title title of listbox to display
/// \param func predicate to select types to display (maybe NULL)
/// \param def_ord ordinal to position cursor before choose
/// \param ud user data
/// \return == 0 means nothing is chosen, otherwise an ordinal number
idaman uint32 ida_export choose_local_tinfo(
const til_t *ti,
const char *title,
local_tinfo_predicate_t *func = NULL,
uint32 def_ord = 0,
void *ud = NULL);
/// Choose a type from the local type library and specify the pointer shift value.
/// \param delta pointer shift value
/// \param ti pointer to til
/// \param title title of listbox to display
/// \param func predicate to select types to display (maybe NULL)
/// \param def_ord ordinal to position cursor before choose
/// \param ud user data
/// \return == 0 means nothing is chosen, otherwise an ordinal number
idaman uint32 ida_export choose_local_tinfo_and_delta(
int32 *delta,
const til_t *ti,
const char *title,
local_tinfo_predicate_t *func = NULL,
uint32 def_ord = 0,
void *ud = NULL);
#ifndef NO_OBSOLETE_FUNCS
typedef bool idaapi set_op_tinfo_t(const insn_t &insn, const op_t &x, const tinfo_t &type, const char *name);
typedef bool idaapi is_stkarg_load_t(const insn_t &insn, int *src, int *dst);
typedef bool idaapi has_delay_slot_t(ea_t caller);
idaman DEPRECATED void ida_export gen_use_arg_tinfos(ea_t caller, func_type_data_t *fti, funcargvec_t *rargs, set_op_tinfo_t *set_optype, is_stkarg_load_t *is_stkarg_load, has_delay_slot_t *has_delay_slot); // gen_use_arg_tinfos2
#endif
#endif // _TYPEINF_HPP