Files
sigmaker-ida/idasdk75/include/struct.hpp
2021-06-05 21:10:25 +03:00

652 lines
20 KiB
C++

/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
/*! \file struct.hpp
\brief Structure type management (assembly level types)
*/
#ifndef _STRUCT_HPP
#define _STRUCT_HPP
#include <bytes.hpp>
#define STRUC_SEPARATOR '.' ///< structname.fieldname
/// Describes a member of an assembly level structure
class member_t
{
public:
tid_t id; ///< name(), cmt, rptcmt
ea_t soff; ///< start offset (for unions - number of the member 0..n)
ea_t eoff; ///< end offset
flags_t flag; ///< type+representation bits
//private:
uint32 props; ///< \ref MF_
/// \defgroup MF_ Struct member properties
/// Used by member_t::props
//@{
#define MF_OK 0x00000001 ///< is the member ok? (always yes)
#define MF_UNIMEM 0x00000002 ///< is a member of a union?
#define MF_HASUNI 0x00000004 ///< has members of type "union"?
#define MF_BYTIL 0x00000008 ///< the member was created due to the type system
#define MF_HASTI 0x00000010 ///< has type information?
#define MF_BASECLASS 0x00000020 ///< a special member representing base class
#define MF_DTOR 0x00000040 ///< a special member representing destructor
#define MF_DUPNAME 0x00000080 ///< duplicate name resolved with _N suffix (N==soff)
//@}
/// Is a member of a union?
bool unimem(void) const { return (props & MF_UNIMEM) != 0; }
/// Has members of type "union"?
bool has_union(void) const { return (props & MF_HASUNI) != 0; }
/// Was the member created due to the type system?
bool by_til(void) const { return (props & MF_BYTIL) != 0; }
/// Has type information?
bool has_ti(void) const { return (props & MF_HASTI) != 0; }
/// Is a base class member?
bool is_baseclass(void) const { return (props & MF_BASECLASS) != 0; }
/// Duplicate name was resolved during import?
bool is_dupname(void) const { return (props & MF_DUPNAME) != 0; }
/// Is a virtual destructor?
bool is_destructor(void) const { return (props & MF_DTOR) != 0; }
/// Get start offset (for unions - returns 0)
ea_t get_soff(void) const { return unimem() ? 0 : soff; }
};
/// Information about a structure type (assembly level)
//-V:struc_t:730 not all members of a class are initialized inside the constructor
class struc_t
{
protected:
struc_t(void) {} ///< plugins may not create struc_t instances. they should
///< use add_struc() and get_struc()
public:
tid_t id; ///< struct id
uint32 memqty; ///< number of members
member_t *members; ///< only defined members are stored here.
///< there may be gaps between members.
ushort age; ///< not used
uint32 props; ///< \ref SF_
/// \defgroup SF_ Structure properties
/// Used by struc_t::props
//@{
#define SF_VAR 0x00000001 ///< is variable size structure (varstruct)?
///< a variable size structure is one with
///< the zero size last member.
///< if the last member is a varstruct, then the current
///< structure is a varstruct too.
#define SF_UNION 0x00000002 ///< is a union?
///< varunions are prohibited!
#define SF_HASUNI 0x00000004 ///< has members of type "union"?
#define SF_NOLIST 0x00000008 ///< don't include in the chooser list
#define SF_TYPLIB 0x00000010 ///< the structure comes from type library
#define SF_HIDDEN 0x00000020 ///< the structure is collapsed
#define SF_FRAME 0x00000040 ///< the structure is a function frame
#define SF_ALIGN 0x00000F80 ///< alignment (shift amount: 0..31)
#define SF_GHOST 0x00001000 ///< ghost copy of a local type
//@}
/// Is variable size structure?
bool is_varstr(void) const { return (props & SF_VAR) != 0; }
/// Is a union?
bool is_union(void) const { return (props & SF_UNION) != 0; }
/// Has members of type "union"?
bool has_union(void) const { return (props & SF_HASUNI) != 0; }
/// Is included in chooser list?
/// Use \ref set_struc_listed to change the listed status
bool is_choosable(void) const { return (props & SF_NOLIST) == 0; }
/// Does structure come from a type library?
bool from_til(void) const { return (props & SF_TYPLIB) != 0; }
/// Is the structure collapsed?
/// Use \ref set_struc_hidden to change the hidden status
bool is_hidden(void) const { return (props & SF_HIDDEN) != 0; }
/// Is this structure a function frame?
bool is_frame(void) const { return (props & SF_FRAME) != 0; }
/// See #SF_ALIGN
int get_alignment(void) const { return (props & SF_ALIGN) >> 7; }
/// Is a ghost copy of a local type?
bool is_ghost(void) const { return (props & SF_GHOST) != 0; }
/// Do not use; use set_struc_align()
void set_alignment(int shift)
{
props &= ~SF_ALIGN;
props |= (shift << 7) & SF_ALIGN;
}
void set_ghost(bool _is_ghost) { setflag(props, SF_GHOST, _is_ghost); }
mutable int32 ordinal; ///< corresponding local type ordinal number
};
/// \name Internal structures list
/// IDA maintains an internal vector of known structures.
/// Use these functions to work with this vector.
//@{
/// Get number of known structures
idaman size_t ida_export get_struc_qty(void);
/// Get index of first structure.
/// \return #BADADDR if no known structures, 0 otherwise
idaman uval_t ida_export get_first_struc_idx(void);
/// Get index of last structure.
/// \return #BADADDR if no known structures, get_struc_qty()-1 otherwise
idaman uval_t ida_export get_last_struc_idx(void);
/// Get previous struct index.
/// \return #BADADDR if resulting index is negative, otherwise idx - 1
inline THREAD_SAFE uval_t get_prev_struc_idx(uval_t idx) { return idx == BADNODE ? idx : idx - 1; }
/// Get next struct index.
/// \return #BADADDR if resulting index is out of bounds, otherwise idx++
idaman uval_t ida_export get_next_struc_idx(uval_t idx);
/// Get internal number of the structure
idaman uval_t ida_export get_struc_idx(tid_t id);
/// Get struct id by struct number
idaman tid_t ida_export get_struc_by_idx(uval_t idx);
/// Get pointer to struct type info
idaman struc_t *ida_export get_struc(tid_t id);
//@}
/// Get struct id by name
inline tid_t get_struc_id(const char *name)
{
tid_t id = node2ea(netnode(name));
return get_struc(id) == NULL ? BADADDR : id;
}
/// Get struct name by id
/// \param[out] out buffer to hold the name
/// \param id struct id
/// \param flags \ref STRNFL_
idaman ssize_t ida_export get_struc_name(qstring *out, tid_t id, int flags=0);
/// \defgroup STRNFL_ Struct name flags
/// Passed as 'flags' parameter to get_struc_name()
//@{
#define STRNFL_REGEX 0x0001 ///< apply regular expressions to beautify the name
//@}
inline qstring get_struc_name(tid_t id, int flags=0)
{
qstring name;
get_struc_name(&name, id, flags);
return name;
}
/// Get struct comment
inline ssize_t get_struc_cmt(qstring *buf, tid_t id, bool repeatable) { return getnode(id).supstr(buf, repeatable != 0); }
/// Get struct size (also see get_struc_size(tid_t))
idaman asize_t ida_export get_struc_size(const struc_t *sptr);
/// Get struct size (also see get_struc_size(const struc_t *))
inline asize_t get_struc_size(tid_t id) { return get_struc_size(get_struc(id)); }
/// \name Struct offsets
/// \note for unions, soff == number of the current member
//@{
/// Get offset of member with largest offset less than 'offset'.
/// \return #BADADDR if no prev offset
idaman ea_t ida_export get_struc_prev_offset(const struc_t *sptr, ea_t offset);
/// Get offset of member with smallest offset larger than 'offset'.
/// \return #BADADDR if no next offset
idaman ea_t ida_export get_struc_next_offset(const struc_t *sptr, ea_t offset);
/// Get offset of last member.
/// \return #BADADDR if memqty == 0
idaman ea_t ida_export get_struc_last_offset(const struc_t *sptr);
/// Get offset of first member.
/// \return #BADADDR if memqty == 0
idaman ea_t ida_export get_struc_first_offset(const struc_t *sptr);
/// For unions: returns number of members, for structs: returns size of structure
inline ea_t get_max_offset(struc_t *sptr)
{
if ( sptr == NULL )
return 0; // just to avoid GPF
return sptr->is_union()
? sptr->memqty
: get_struc_size(sptr);
}
//@}
/// Is variable size structure?
inline bool is_varstr(tid_t id)
{
struc_t *sptr = get_struc(id);
return sptr != NULL && sptr->is_varstr();
}
/// Is a union?
inline bool is_union(tid_t id)
{
struc_t *sptr = get_struc(id);
return sptr != NULL && sptr->is_union();
}
/// Get containing structure of member by its full name "struct.field"
idaman struc_t *ida_export get_member_struc(const char *fullname);
/// Get child struct if member is a struct
idaman struc_t *ida_export get_sptr(const member_t *mptr);
/// Get member at given offset
idaman member_t *ida_export get_member(const struc_t *sptr, asize_t offset);
/// Get member id at given offset
inline tid_t get_member_id(const struc_t *sptr, asize_t offset)
{
member_t *mptr = get_member(sptr, offset);
return mptr != NULL ? mptr->id : BADADDR;
}
/// Get a member by its name, like "field44"
idaman member_t *ida_export get_member_by_name(const struc_t *sptr, const char *membername);
/// Get a member by its fully qualified name, "struct.field"
idaman member_t *ida_export get_member_by_fullname(struc_t **sptr_place, const char *fullname);
/// Get a member's fully qualified name, "struct.field"
inline ssize_t idaapi get_member_fullname(qstring *out, tid_t mid) { return getnode(mid).get_name(out); }
/// Get name of structure member
idaman ssize_t ida_export get_member_name(qstring *out, tid_t mid);
inline qstring get_member_name(tid_t mid)
{
qstring name;
get_member_name(&name, mid);
return name;
}
/// Get comment of structure member
inline ssize_t idaapi get_member_cmt(qstring *buf, tid_t mid, bool repeatable) { return getnode(mid).supstr(buf, repeatable != 0); }
/// Get size of structure member.
/// May return 0 for the last member of varstruct.
/// For union members, returns member_t::eoff.
inline asize_t get_member_size(const member_t *NONNULL mptr) { return mptr->unimem() ? mptr->eoff : (mptr->eoff - mptr->soff); }
/// Is variable size member?
idaman bool ida_export is_varmember(const member_t *mptr);
/// Get member that is most likely referenced by the specified offset.
/// Useful for offsets > sizeof(struct).
idaman member_t *ida_export get_best_fit_member(const struc_t *sptr, asize_t offset);
/// Get the next member idx, if it does not exist, return -1
idaman ssize_t ida_export get_next_member_idx(const struc_t *sptr, asize_t off);
/// Get the prev member idx, if it does not exist, return -1
idaman ssize_t ida_export get_prev_member_idx(const struc_t *sptr, asize_t off);
//--------------------------------------------------------------------------
// manipulation
/// Create a structure type.
/// if idx==#BADADDR then add as the last idx.
/// if name==NULL then a name will be generated "struct_%d".
idaman tid_t ida_export add_struc(uval_t idx, const char *name, bool is_union=false);
/// Delete a structure type
idaman bool ida_export del_struc(struc_t *sptr);
/// Set internal number of struct.
/// Also see get_struc_idx(), get_struc_by_idx().
idaman bool ida_export set_struc_idx(const struc_t *sptr, uval_t idx);
/// Set structure alignment (#SF_ALIGN)
idaman bool ida_export set_struc_align(struc_t *sptr, int shift);
/// Set structure name
idaman bool ida_export set_struc_name(tid_t id, const char *name);
/// Set structure comment
idaman bool ida_export set_struc_cmt(tid_t id, const char *cmt, bool repeatable);
/// Return values for add_struc_member()
enum struc_error_t
{
STRUC_ERROR_MEMBER_OK = 0, ///< success
STRUC_ERROR_MEMBER_NAME = -1, ///< already has member with this name (bad name)
STRUC_ERROR_MEMBER_OFFSET = -2, ///< already has member at this offset
STRUC_ERROR_MEMBER_SIZE = -3, ///< bad number of bytes or bad sizeof(type)
STRUC_ERROR_MEMBER_TINFO = -4, ///< bad typeid parameter
STRUC_ERROR_MEMBER_STRUCT = -5, ///< bad struct id (the 1st argument)
STRUC_ERROR_MEMBER_UNIVAR = -6, ///< unions can't have variable sized members
STRUC_ERROR_MEMBER_VARLAST = -7, ///< variable sized member should be the last member in the structure
STRUC_ERROR_MEMBER_NESTED = -8, ///< recursive structure nesting is forbidden
};
/// Add member to existing structure.
/// \param sptr structure to modify
/// \param fieldname if NULL, then "anonymous_#" name will be generated
/// \param offset #BADADDR means add to the end of structure
/// \param flag type + representation bits
/// \param mt additional info about member type.
/// must be present for
/// structs, offsets, enums, strings,
/// struct offsets.
/// \param nbytes if == 0 then the structure
/// will be a varstruct.
/// in this case the member should be
/// the last member in the structure
idaman struc_error_t ida_export add_struc_member(
struc_t *sptr,
const char *fieldname,
ea_t offset,
flags_t flag,
const opinfo_t *mt,
asize_t nbytes);
/// Delete member at given offset
idaman bool ida_export del_struc_member(struc_t *sptr, ea_t offset);
/// Delete members which occupy range of offsets (off1..off2).
/// \return number of deleted members or -1 on error
idaman int ida_export del_struc_members(struc_t *sptr, ea_t off1, ea_t off2);
/// Set name of member at given offset
idaman bool ida_export set_member_name(struc_t *sptr, ea_t offset,const char *name);
/// Set type of member at given offset (also see add_struc_member())
idaman bool ida_export set_member_type(struc_t *sptr, ea_t offset, flags_t flag,const opinfo_t *mt, asize_t nbytes);
/// Set member comment
idaman bool ida_export set_member_cmt(member_t *mptr,const char *cmt, bool repeatable);
/// Expand/Shrink structure type
idaman bool ida_export expand_struc(struc_t *sptr, ea_t offset, adiff_t delta, bool recalc=true);
/// Update struct information in the database (internal function)
idaman void ida_export save_struc(struc_t *sptr, bool may_update_ltypes=true);
/// Hide/unhide a struct type
inline void idaapi set_struc_hidden(struc_t *sptr, bool is_hidden)
{
setflag(sptr->props, SF_HIDDEN, is_hidden);
save_struc(sptr, false);
}
/// Add/remove a struct type from the struct list
inline void idaapi set_struc_listed(struc_t *sptr, bool is_listed)
{
setflag(sptr->props, SF_NOLIST, !is_listed);
save_struc(sptr, false);
}
/// Member type information (return values for set_member_tinfo())
enum smt_code_t
{
SMT_BADARG = -6, ///< bad parameters
SMT_NOCOMPAT = -5, ///< the new type is not compatible with the old type
SMT_WORSE = -4, ///< the new type is worse than the old type
SMT_SIZE = -3, ///< the new type is incompatible with the member size
SMT_ARRAY = -2, ///< arrays are forbidden as function arguments
SMT_OVERLAP = -1, ///< member would overlap with members that cannot be deleted
SMT_FAILED = 0, ///< failed to set new member type
SMT_OK = 1, ///< success: changed the member type
SMT_KEEP = 2, ///< no need to change the member type, the old type is better
};
/// Get tinfo for given member
idaman bool ida_export get_member_tinfo(tinfo_t *tif, const member_t *mptr);
/// Delete tinfo for given member
idaman bool ida_export del_member_tinfo(struc_t *sptr, member_t *mptr);
/// Set tinfo for given member.
/// \param sptr containing struct
/// \param mptr target member
/// \param memoff offset within member
/// \param tif type info
/// \param flags \ref SET_MEMTI_
idaman smt_code_t ida_export set_member_tinfo(
struc_t *sptr,
member_t *mptr,
uval_t memoff,
const tinfo_t &tif,
int flags);
/// \defgroup SET_MEMTI_ Set member tinfo flags
/// Passed as 'flags' parameter to set_member_tinfo()
//@{
#define SET_MEMTI_MAY_DESTROY 0x0001 ///< may destroy other members
#define SET_MEMTI_COMPATIBLE 0x0002 ///< new type must be compatible with the old
#define SET_MEMTI_FUNCARG 0x0004 ///< mptr is function argument (cannot create arrays)
#define SET_MEMTI_BYTIL 0x0008 ///< new type was created by the type subsystem
#define SET_MEMTI_USERTI 0x0010 ///< user-specified type
//@}
/// Try to get tinfo for given member - if failed, generate a tinfo using information about the
/// member id from the disassembly
idaman bool ida_export get_or_guess_member_tinfo(tinfo_t *tif, const member_t *mptr);
/// Get operand type info for member
inline opinfo_t *retrieve_member_info(opinfo_t *buf, const member_t *mptr)
{
if ( mptr == NULL )
return NULL;
return get_opinfo(buf, mptr->id, 0, mptr->flag);
}
/// Is member name prefixed with "anonymous"?
inline THREAD_SAFE bool is_anonymous_member_name(const char *name)
{
return name == NULL
|| strncmp(name, "anonymous", 9) == 0;
}
/// Is member name an auto-generated name?
inline THREAD_SAFE bool is_dummy_member_name(const char *name)
{
return name == NULL
|| strncmp(name, "arg_", 4) == 0
|| strncmp(name, "var_", 4) == 0
|| is_anonymous_member_name(name);
}
/// Check if the specified member id points to a struct member
inline member_t *idaapi get_member_by_id(
qstring *out_mname, // note: id 'out_mname' is important for SWiG
tid_t mid,
struc_t **sptr_place)
{
if ( get_member_fullname(out_mname, mid) > 0 )
return get_member_by_fullname(sptr_place, out_mname->begin());
return NULL;
}
/// Check if the specified member id points to a struct member. convenience function
inline member_t *idaapi get_member_by_id(tid_t mid, struc_t **sptr_place=NULL)
{
qstring buf;
return get_member_by_id(&buf, mid, sptr_place);
}
/// Is a member id?
inline bool is_member_id(tid_t mid)
{
return get_member_by_id(mid) != NULL;
}
/// Is a special member with the name beginning with ' '?
idaman bool ida_export is_special_member(tid_t id);
/// Implements action to take when a field is visited with visit_stroff_fields()
struct ida_local struct_field_visitor_t
{
virtual int idaapi visit_field(struc_t *sptr, member_t *mptr) = 0;
};
//--------------------------------------------------------------------------
/// Visit structure fields in a stroff expression or in a reference to a struct data variable.
/// This function can be used to enumerate all components of an expression like 'a.b.c'.
/// \param sfv visitor object
/// \param path struct path (path[0] contains the initial struct id)
/// \param plen len
/// \param[in,out] disp offset into structure
/// \param appzero should visit field at offset zero?
idaman flags_t ida_export visit_stroff_fields(
struct_field_visitor_t &sfv,
const tid_t *path,
int plen,
adiff_t *disp,
bool appzero);
//--------------------------------------------------------------------------
/// Should display a structure offset expression as the structure size?
inline bool stroff_as_size(int plen, const struc_t *sptr, asize_t value)
{
return plen == 1
&& value > 0
&& sptr != NULL
&& !sptr->is_varstr()
&& value == get_struc_size(sptr);
}
//-------------------------------------------------------------------------
// F U N C T I O N S F O R T H E K E R N E L
//-------------------------------------------------------------------------
///-------------------------------------------------------------------\cond
inline void save_structs(void) {}
///----------------------------------------------------------------\endcond
#endif // _STRUCT_HPP