update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

21420
idasdk76/include/allins.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
// this file should be included before calling deprecated functions
// it should be included at the point where the definitions of deprecated
// functions begin in the source file. this way a deprecated function may call
// another deprecated function without raising a warning.
// deprecated functions may call each other
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

289
idasdk76/include/auto.hpp Normal file
View File

@@ -0,0 +1,289 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _AUTO_HPP
#define _AUTO_HPP
#include <ida.hpp>
/*! \file auto.hpp
\brief Functions that work with the autoanalyzer queue.
The autoanalyzer works when IDA is not busy processing
the user keystrokes. It has several queues, each queue having
its own priority. The analyzer stops when all queues are empty.
A queue contains addresses or address ranges.
The addresses are kept sorted by their values.
The analyzer will process all addresses from the first queue, then
switch to the second queue and so on.
There are no limitations on the size of the queues.
This file also contains functions that deal with the IDA status
indicator and the autoanalysis indicator.
You may use these functions to change the indicator value.
*/
typedef int atype_t; ///< identifies an autoanalysis queue - see \ref AU_
/// \defgroup AU_ Autoanalysis queues
/// Names and priorities of the analyzer queues
//@{
const atype_t
AU_NONE = 00, ///< placeholder, not used
AU_UNK = 10, ///< 0: convert to unexplored
AU_CODE = 20, ///< 1: convert to instruction
AU_WEAK = 25, ///< 2: convert to instruction (ida decision)
AU_PROC = 30, ///< 3: convert to procedure start
AU_TAIL = 35, ///< 4: add a procedure tail
AU_FCHUNK=38, ///< 5: find func chunks
AU_USED = 40, ///< 6: reanalyze
AU_TYPE = 50, ///< 7: apply type information
AU_LIBF = 60, ///< 8: apply signature to address
AU_LBF2 = 70, ///< 9: the same, second pass
AU_LBF3 = 80, ///< 10: the same, third pass
AU_CHLB = 90, ///< 11: load signature file (file name is kept separately)
AU_FINAL=200; ///< 12: final pass
//@}
typedef int idastate_t; ///< IDA status indicator - see \ref st_
/// \defgroup st_ Status indicator states
//@{
const idastate_t
// meaning
st_Ready = 0, ///< READY: IDA is doing nothing
st_Think = 1, ///< THINKING: Autoanalysis on, the user may press keys
st_Waiting = 2, ///< WAITING: Waiting for the user input
st_Work = 3; ///< BUSY: IDA is busy
//@}
/// Get current state of autoanalyzer.
/// If auto_state == ::AU_NONE, IDA is currently not running the analysis
/// (it could be temporarily interrupted to perform the user's requests, for example).
idaman atype_t ida_export get_auto_state(void);
/// Set current state of autoanalyzer.
/// \param new_state new state of autoanalyzer
/// \return previous state
idaman atype_t ida_export set_auto_state(atype_t new_state);
/// See ::get_auto_display
struct auto_display_t
{
atype_t type = AU_NONE;
ea_t ea = BADADDR;
idastate_t state = st_Ready;
};
/// Get structure which holds the autoanalysis indicator contents
idaman bool ida_export get_auto_display(auto_display_t *auto_display);
/// Change autoanalysis indicator value.
/// \param ea linear address being analyzed
/// \param type autoanalysis type (see \ref AU_)
idaman void ida_export show_auto(ea_t ea, atype_t type=AU_NONE);
/// Show an address on the autoanalysis indicator.
/// The address is displayed in the form " @:12345678".
/// \param ea - linear address to display
inline void show_addr(ea_t ea) { show_auto(ea); }
/// Change IDA status indicator value
/// \param st - new indicator status
/// \return old indicator status
idaman idastate_t ida_export set_ida_state(idastate_t st);
/// Is it allowed to create stack variables automatically?.
/// This function should be used by IDP modules before creating stack vars.
inline bool may_create_stkvars(void)
{
return inf_should_create_stkvars() && get_auto_state() == AU_USED;
}
/// Is it allowed to trace stack pointer automatically?.
/// This function should be used by IDP modules before tracing sp.
inline bool may_trace_sp(void)
{
if ( inf_should_trace_sp() )
{
atype_t auto_state = get_auto_state();
return auto_state == AU_USED;
}
return false;
}
/// Put range of addresses into a queue.
/// 'start' may be higher than 'end', the kernel will swap them in this case.
/// 'end' doesn't belong to the range.
idaman void ida_export auto_mark_range(ea_t start,ea_t end,atype_t type);
/// Put single address into a queue. Queues keep addresses sorted.
inline void auto_mark(ea_t ea, atype_t type)
{
auto_mark_range(ea, ea+1, type);
}
/// Remove range of addresses from a queue.
/// 'start' may be higher than 'end', the kernel will swap them in this case.
/// 'end' doesn't belong to the range.
idaman void ida_export auto_unmark(ea_t start, ea_t end, atype_t type);
// Convenience functions
/// Plan to perform reanalysis
inline void plan_ea(ea_t ea)
{
auto_mark(ea, AU_USED);
}
/// Plan to perform reanalysis
inline void plan_range(ea_t sEA, ea_t eEA)
{
auto_mark_range(sEA, eEA, AU_USED);
}
/// Plan to make code
inline void auto_make_code(ea_t ea)
{
auto_mark(ea, AU_CODE);
}
/// Plan to make code&function
inline void auto_make_proc(ea_t ea)
{
auto_make_code(ea);
auto_mark(ea, AU_PROC);
}
/// Plan to reanalyze callers of the specified address.
/// This function will add to ::AU_USED queue all instructions that
/// call (not jump to) the specified address.
/// \param ea linear address of callee
/// \param noret !=0: the callee doesn't return, mark to undefine subsequent
/// instructions in the caller. 0: do nothing.
idaman void ida_export reanalyze_callers(ea_t ea, bool noret);
/// Delete all analysis info that IDA generated for for the given range
idaman void ida_export revert_ida_decisions(ea_t ea1, ea_t ea2);
/// Plan to apply the callee's type to the calling point
idaman void ida_export auto_apply_type(ea_t caller, ea_t callee);
/// Plan to apply the tail_ea chunk to the parent
/// \param tail_ea linear address of start of tail
/// \param parent_ea linear address within parent. If BADADDR, automatically
/// try to find parent via xrefs.
idaman void ida_export auto_apply_tail(ea_t tail_ea, ea_t parent_ea);
/// Analyze the specified range.
/// Try to create instructions where possible.
/// Make the final pass over the specified range if specified.
/// This function doesn't return until the range is analyzed.
/// \retval 1 ok
/// \retval 0 Ctrl-Break was pressed
idaman int ida_export plan_and_wait(ea_t ea1, ea_t ea2, bool final_pass=true);
/// Process everything in the queues and return true.
/// \return false if the user clicked cancel.
/// (the wait box must be displayed by the caller if desired)
idaman bool ida_export auto_wait(void);
/// Process everything in the specified range and return true.
/// \return number of autoanalysis steps made. -1 if the user clicked cancel.
/// (the wait box must be displayed by the caller if desired)
idaman ssize_t ida_export auto_wait_range(ea_t ea1, ea_t ea2);
/// Analyze one address in the specified range and return true.
/// \return if processed anything. false means that there is nothing to
/// process in the specified range.
idaman bool ida_export auto_make_step(ea_t ea1, ea_t ea2);
/// Remove an address range (ea1..ea2) from queues ::AU_CODE, ::AU_PROC, ::AU_USED.
/// To remove an address range from other queues use auto_unmark() function.
/// 'ea1' may be higher than 'ea2', the kernel will swap them in this case.
/// 'ea2' doesn't belong to the range.
idaman void ida_export auto_cancel(ea_t ea1, ea_t ea2);
/// Are all queues empty?
/// (i.e. has autoanalysis finished?).
idaman bool ida_export auto_is_ok(void);
/// Peek into a queue 'type' for an address not lower than 'low_ea'.
/// Do not remove address from the queue.
/// \return the address or #BADADDR
idaman ea_t ida_export peek_auto_queue(ea_t low_ea, atype_t type);
/// Retrieve an address from queues regarding their priority.
/// Returns #BADADDR if no addresses not lower than 'lowEA' and less than
/// 'highEA' are found in the queues.
/// Otherwise *type will have queue type.
idaman ea_t ida_export auto_get(atype_t *type, ea_t lowEA, ea_t highEA);
/// Try to create instruction
/// \param ea linear address of callee
/// \return the length of the instruction or 0
idaman int ida_export auto_recreate_insn(ea_t ea);
/// Get autoanalyzer state
idaman bool ida_export is_auto_enabled(void);
/// Temporarily enable/disable autoanalyzer. Not user-facing, but rather because
/// IDA sometimes need to turn AA on/off regardless of inf.s_genflags:INFFL_AUTO
/// \return old state
idaman bool ida_export enable_auto(bool enable);
#endif // _AUTO_HPP

View File

@@ -0,0 +1,350 @@
#ifndef _BITMASK_HPP
#define _BITMASK_HPP
/*! \file bitrange.hpp
\brief Definition of the ::bitrange_t class
*/
//---------------------------------------------------------------------------
/// This class manages the offset and size of a value that occupies
/// a number of contiguous bits within some container - generally a byte array.
/// A special state - empty range (both offset and size are zeroes) - determines
/// the value as all bits of the container.
class bitrange_t
{
public:
/// Constructor
explicit bitrange_t(uint16 bit_ofs = 0, uint16 size_in_bits = 0);
/// Initialize offset and size to given values
inline void init(uint16 bit_ofs, uint16 size_in_bits);
/// Make the bitrange empty
inline void reset();
/// Is the bitrange empty?
inline bool empty() const;
/// Get offset of 1st bit
inline uint bitoff() const;
/// Get size of the value in bits
inline uint bitsize() const;
/// Size of the value in bytes
inline uint bytesize() const;
/// Convert to mask of 64 bits
inline uint64 mask64() const;
/// Does have common bits with another bitrange?
inline bool has_common(const bitrange_t &r) const;
/// Apply mask to a bitrange
/// \param subrange range *inside* the main bitrange to keep
/// After this operation the main bitrange will be truncated
/// to have only the bits that are specified by subrange.
/// Example: [off=8,nbits=4], subrange[off=1,nbits=2] => [off=9,nbits=2]
/// \return success
inline bool apply_mask(const bitrange_t &subrange);
/// Intersect two ranges
inline void intersect(const bitrange_t &r);
/// Create union of 2 ranges including the hole between them
inline void create_union(const bitrange_t &r);
/// Subtract a bitrange
inline bool sub(const bitrange_t &r);
/// Shift range down (left)
inline void shift_down(uint cnt);
/// Shift range up (right)
inline void shift_up(uint cnt);
/// Initialize bitrange_t with offset/size defined by given mask
template <class T> inline void assign_max_nonzero(T mask);
/// \name Extract
/// Extract a value from 'src' according to the bitrange
/// \param dst vector the extracted value will be stored to
/// \param src source buffer
/// \param src_size size of source buffer
/// \param is_mf is Msb First? (TRUE-big endian, FALSE-little endian)
//@{
inline bool extract(
bytevec_t *dst,
const void *src,
size_t src_size,
bool is_mf) const;
inline bool extract(
void *dst,
size_t dst_size,
const void *src,
size_t src_size,
bool is_mf) const;
//@}
/// \name Inject
/// Inject a value into 'dst' according to the bitrange
/// \param dst a buffer the value will be injected into
/// \param dst_size size of buffer
/// \param src source value
/// \param is_mf is Msb First? (TRUE-big endian, FALSE-little endian)
//@{
inline bool inject(
void *dst,
size_t dst_size,
const void *src,
size_t src_size,
bool is_mf) const;
inline bool inject(
void *dst,
size_t dst_size,
const bytevec_t &src,
bool is_mf) const;
//@}
DECLARE_COMPARISONS(bitrange_t);
private:
uint16 offset; ///< offset of 1st bit starting with the lowest bit
uint16 nbits; ///< size of the value in bits
};
//---------------------------------------------------------------------------
inline bitrange_t::bitrange_t(uint16 bit_ofs, uint16 size_in_bits)
: offset(bit_ofs), nbits(size_in_bits)
{
}
//---------------------------------------------------------------------------
inline void bitrange_t::init(uint16 bit_ofs, uint16 size_in_bits)
{
offset = bit_ofs;
nbits = size_in_bits;
}
//---------------------------------------------------------------------------
inline void bitrange_t::reset()
{
init(0, 0);
}
//---------------------------------------------------------------------------
inline bool bitrange_t::empty() const
{
return nbits == 0;
}
//---------------------------------------------------------------------------
inline uint bitrange_t::bitoff() const
{
return offset;
}
//---------------------------------------------------------------------------
inline uint bitrange_t::bitsize() const
{
return nbits;
}
//---------------------------------------------------------------------------
inline uint bitrange_t::bytesize() const
{
return (nbits + 8-1) / 8;
}
//--------------------------------------------------------------------------
inline uint64 bitrange_t::mask64() const
{
return empty() ? 0 : (left_shift(uint64(1), nbits)-1) << offset;
}
//--------------------------------------------------------------------------
inline bool bitrange_t::apply_mask(const bitrange_t &submask)
{
if ( submask.bitoff() + submask.bitsize() > bitsize() )
return false;
init(bitoff() + submask.bitoff(), submask.bitsize());
return true;
}
//--------------------------------------------------------------------------
inline void bitrange_t::intersect(const bitrange_t &r)
{
uint16 e1 = offset + nbits;
uint16 e2 = r.offset + r.nbits;
uint16 e = qmin(e1, e2);
uint16 s = qmax(offset, r.offset);
if ( s > e )
{
s = 0;
e = 0;
}
init(s, e-s);
}
//--------------------------------------------------------------------------
inline bool bitrange_t::has_common(const bitrange_t &r) const
{
return interval::overlap(offset, nbits, r.offset, r.nbits);
}
//--------------------------------------------------------------------------
inline void bitrange_t::create_union(const bitrange_t &r)
{
uint16 e1 = offset + nbits;
uint16 e2 = r.offset + r.nbits;
uint16 e = qmax(e1, e2);
uint16 s = qmin(offset, r.offset);
init(s, e-s);
}
//--------------------------------------------------------------------------
inline bool bitrange_t::sub(const bitrange_t &r)
{
// r is in the middle of our bitrange, cannot handle this case
// because it would require 2 bitranges :/
uint16 end = offset + nbits;
uint16 rend = r.offset + r.nbits;
if ( r.offset > offset && rend < end )
return false;
if ( r.offset <= offset )
{
if ( rend > end )
{
reset();
}
else if ( rend > offset )
{
offset = rend;
nbits = end - offset;
}
}
else if ( r.offset < end )
{
nbits = r.offset - offset;
}
return true;
}
//--------------------------------------------------------------------------
inline int bitrange_t::compare(const bitrange_t &r) const
{
if ( offset != r.offset )
return offset < r.offset ? -1 : 1;
if ( nbits != r.nbits )
return nbits < r.nbits ? -1 : 1;
return 0;
}
//--------------------------------------------------------------------------
inline void bitrange_t::shift_down(uint cnt)
{
if ( cnt > offset )
{
cnt -= offset;
offset = 0;
if ( cnt > nbits )
nbits = 0;
else
nbits -= cnt;
}
else
{
offset -= cnt;
}
}
//--------------------------------------------------------------------------
inline void bitrange_t::shift_up(uint cnt)
{
offset += cnt;
}
//--------------------------------------------------------------------------
template <class T> inline void bitrange_t::assign_max_nonzero(T mask)
{
if ( mask == T(0) )
{
reset();
return;
}
int i = 0;
T bit = T(1);
for ( i=0; i < sizeof(T)*8; ++i, bit <<= 1 )
if ( (mask & bit) != 0 )
break;
offset = i;
i = sizeof(T)*8 - 1;
bit = left_shift(T(1), i);
while ( i >= offset )
{
if ( (mask & bit) != 0 )
break;
--i;
bit >>= 1;
}
nbits = i - offset + 1;
}
//--------------------------------------------------------------------------
#ifndef SWIG
/// \name Helper functions
/// Should not be called directly!
//@{
idaman bool ida_export bitrange_t_extract_using_bitrange(const bitrange_t *bm, void *dst, size_t dst_size, const void *src, size_t src_size, bool is_mf);
idaman bool ida_export bitrange_t_inject_using_bitrange(const bitrange_t *bm, void *dst, size_t dst_size, const void *src, size_t src_size, bool is_mf);
//@}
#else
#endif // SWIG
//--------------------------------------------------------------------------
inline bool bitrange_t::extract(
void *dst,
size_t dst_size,
const void *src,
size_t src_size,
bool is_mf) const
{
return bitrange_t_extract_using_bitrange(this, dst, dst_size, src, src_size, is_mf);
}
//--------------------------------------------------------------------------
inline bool bitrange_t::extract(
bytevec_t *dst,
const void *src,
size_t src_size,
bool is_mf) const
{
size_t dst_size = empty() ? src_size : bytesize();
dst->resize(dst_size);
return bitrange_t_extract_using_bitrange(this,
dst->begin(), dst_size,
src, src_size,
is_mf);
}
//--------------------------------------------------------------------------
inline bool bitrange_t::inject(
void *dst,
size_t dst_size,
const void *src,
size_t src_size,
bool is_mf) const
{
return bitrange_t_inject_using_bitrange(this, dst, dst_size, src, src_size, is_mf);
}
//--------------------------------------------------------------------------
inline bool bitrange_t::inject(
void *dst,
size_t dst_size,
const bytevec_t &src,
bool is_mf) const
{
return bitrange_t_inject_using_bitrange(this,
dst, dst_size,
src.begin(), src.size(),
is_mf);
}
#endif // define _BITMASK_HPP

2556
idasdk76/include/bytes.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,173 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef COMPRESS_HPP
#define COMPRESS_HPP
#include <diskio.hpp>
/*! \file compress.hpp
\brief Data compression functions
*/
/// Compress data.
/// This function depends on the value of legacy_idb, so it is not completely
/// thread safe. However, legacy_idb does not change its value.
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export zip_deflate(
void *ud,
ssize_t (idaapi *file_reader)(void *ud, void *buf, size_t size),
ssize_t (idaapi *file_writer)(void *ud, const void *buf, size_t size));
/// Uncompress data.
/// This function depends on the value of legacy_idb, so it is not completely
/// thread safe. However, legacy_idb does not change its value.
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export zip_inflate(
void *ud,
ssize_t (idaapi *file_reader)(void *ud, void *buf, size_t size),
ssize_t (idaapi *file_writer)(void *ud, const void *buf, size_t size));
/// Process zip file and enumerate all files stored in it
/// \param zipfile name of zip file
/// \param callback callback for each file. params:
/// - ud: user data
/// - offset: offset in the zip file
/// - method: compression method (\ref compression_methods)
/// - csize: compressed size
/// - ucsize: uncompressed size
/// - attributes: file attributes
/// \param ud user data
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export process_zipfile(
const char *zipfile,
int (idaapi *callback)(
void *ud,
qoff64_t offset,
int method,
uint64 csize,
uint64 ucsize,
uint32 attributes,
const char *filename),
void *ud = NULL);
/// Process zip file and enumerate all files stored in it
/// \param li input file
/// \param callback callback for each file. params:
/// - ud: user data
/// - offset: offset in the zip file
/// - method: compression method (\ref compression_methods)
/// - csize: compressed size
/// - ucsize: uncompressed size
/// - attributes: file attributes
/// \param ud user data
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export process_zip_linput(
linput_t *li,
int (idaapi *callback)(
void *ud,
qoff64_t offset,
int method,
uint64 csize,
uint64 ucsize,
uint32 attributes,
const char *filename),
void *ud = NULL);
/// Search for specified entry in zip file, and calls the
/// callback with it, if found.
/// \param zipfile name of zip file
/// \param entry entry in zip file. E.g., "path/to/entry.dat"
/// \param callback callback for each file. params:
/// - ud: user data
/// - offset: offset in the zip file
/// - method: compression method (\ref compression_methods)
/// - csize: compressed size
/// - ucsize: uncompressed size
/// - attributes: file attributes
/// \param ud user data
/// \param case_sensitive should the search be case sensitive?
/// \return \ref PKZ_
idaman THREAD_SAFE int ida_export process_zipfile_entry(
const char *zipfile,
const char *entry,
int (idaapi *callback)(
void *ud,
qoff64_t offset,
int method,
uint64 csize,
uint64 ucsize,
uint32 attributes,
const char *filename),
void *ud = NULL,
bool case_sensitive = true);
/// \defgroup PKZ_ Compression error codes
/// Returned by functions in compress.hpp
//@{
#define PKZ_OK 0
#define PKZ_ERRNO 1
#define PKZ_STREAM_ERROR 2
#define PKZ_DATA_ERROR 3
#define PKZ_MEM_ERROR 4
#define PKZ_BUF_ERROR 5
#define PKZ_VERSION_ERROR 6
#define PKZ_RERR 777 // read error
#define PKZ_WERR 778 // write error
//@}
/// \defgroup compression_methods Compression methods
/// passed as 'method' parameter to callback functions in compress.hpp
//@{
#define STORED 0
#define SHRUNK 1
#define REDUCED1 2
#define REDUCED2 3
#define REDUCED3 4
#define REDUCED4 5
#define IMPLODED 6
#define TOKENIZED 7
#define DEFLATED 8
#define NUM_METHODS 9 /* index of last method + 1 */
//@}
extern bool legacy_idb; ///< for old idb files
/// Upon closing outer linput, perform one of these actions
enum linput_close_code_t
{
LOC_CLOSE, ///< close the inner linput
LOC_UNMAKE, ///< unmake the inner linput
LOC_KEEP, ///< do nothing
};
/// Create a linput to read a compressed input stream
/// \param in linput with compressed data, seeked to the stream beginning
/// \param insize size of compressed data. -1 - unknown
/// \param loc what to do upon closing the resulting linput
/// \return linput that can be used to read uncompressed data.
/// NULL if any error (no more linput descriptors).
idaman THREAD_SAFE linput_t *ida_export create_zip_linput(
linput_t *in,
ssize_t insize=-1,
linput_close_code_t loc=LOC_CLOSE);
#endif

543
idasdk76/include/config.hpp Normal file
View File

@@ -0,0 +1,543 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _CONFIG_HPP
#define _CONFIG_HPP
//-----------------------------------------------------------------------
/// \defgroup IDPOPT_T Option value types
/// Passed as 'value_type' parameter to ::set_options_t callbacks
//@{
#define IDPOPT_STR 1 ///< string constant (char *)
#define IDPOPT_NUM 2 ///< number (uval_t *)
#define IDPOPT_BIT 3 ///< bit, yes/no (int *)
#define IDPOPT_I64 5 ///< 64bit number (int64 *)
#define IDPOPT_CST 6 ///< lexer (lexer_t*)
///< Custom type, starting with a '{'
///< Values of this type should be handled by
///< ::set_options_t callbacks. E.g.,:
///< \code
///< ERROR_STRINGS =
///< {
///< {0, "Unknown error"},
///< {1, "Missing filename"},
///< {5, "Out-of-memory"}
///< }
///< \endcode
///< For values of this type, the data that will
///< be passed as the callback's 'value' parameter
///< is the lexer instance that is being used
///< to parse the configuration file.
///< You can use \ref parse_json() (see parsejson.hpp)
///< to parse JSON-format data
///< NB: the '{' is already consumed by the parser,
///< so you need to push it again if it's a part of the JSON object
//@}
/// \defgroup IDPOPT_RET Option result codes
/// Predefined return values for ::set_options_t callbacks
//@{
#define IDPOPT_OK NULL ///< ok
#define IDPOPT_BADKEY ((char*)1) ///< illegal keyword
#define IDPOPT_BADTYPE ((char*)2) ///< illegal type of value
#define IDPOPT_BADVALUE ((char*)3) ///< illegal value (bad range, for example)
//@}
/// Callback - called when a config directive is processed in IDA.
/// Also see read_config_file() and processor_t::set_idp_options
/// \param keyword keyword encountered in IDA.CFG/user config file.
/// if NULL, then an interactive dialog form should be displayed
/// \param value_type type of value of the keyword - one of \ref IDPOPT_T
/// \param value pointer to value
/// \param idb_loaded true if the ev_oldfile/ev_newfile events have been generated?
/// \return one of \ref IDPOPT_RET, otherwise a pointer to an error message
typedef const char *(idaapi set_options_t)(
const char *keyword,
int value_type,
const void *value,
bool idb_loaded);
/// \defgroup IDAOPT_PRIO Option priority
/// Specifies the priority of a configuration option. Since options may
/// be specified in different way, and applied in various orders, we need
/// option priorities.
/// Normally the default priority option does not overwrite the existing value
/// whereas the high priority one does.
/// High priority options may be stored in the database to be available
/// in the next session.
//@{
#define IDPOPT_PRI_DEFAULT 1 ///< default priority - taken from config file
#define IDPOPT_PRI_HIGH 2 ///< high priority - received from UI or a script function
//@}
//-------------------------------------------------------------------------
/// Parse the value type for the value token 'value'.
/// This is mostly used for converting from values that a cfgopt_handler_t
/// receives, into data that callbacks
/// - processor_t::set_idp_options
/// - debugger_t::set_dbg_options
/// expect.
///
/// Plugins that wish to use options shouldn't rely on this,
/// and use the cfgopt_t utility instead.
///
/// \param out parsed data
/// \param lx the lexer in use
/// \param value the value token
/// \return true if guessing didn't lead to an error, false otherwise.
/// note that even if 'true' is returned, it doesn't mean the
/// type could be guessed: merely that no syntax error occurred.
class lexer_t;
struct token_t;
idaman bool ida_export parse_config_value(
idc_value_t *out,
lexer_t *lx,
const token_t &value);
//-------------------------------------------------------------------------
typedef const char *(idaapi cfgopt_handler_t)(
lexer_t *lx,
const token_t &keyword,
const token_t &value);
//-------------------------------------------------------------------------
typedef const char *(idaapi cfgopt_handler2_t)(
lexer_t *lx,
const token_t &keyword,
const token_t &value,
int64 param1,
int64 param2);
//-------------------------------------------------------------------------
typedef const char *(idaapi cfgopt_handler3_t)(
lexer_t *lx,
const token_t &keyword,
const token_t &value,
int64 param1,
int64 param2,
void *obj);
//-----------------------------------------------------------------------
/// used by cfgopt_t. You shouldn't have to deal with those directly.
#define IDPOPT_NUM_INT (0)
#define IDPOPT_NUM_CHAR (1 << 24)
#define IDPOPT_NUM_SHORT (2 << 24)
#define IDPOPT_NUM_RANGE (1 << 26)
#define IDPOPT_NUM_UNS (1 << 27)
#define IDPOPT_BIT_UINT 0
#define IDPOPT_BIT_UCHAR (1 << 24)
#define IDPOPT_BIT_USHORT (2 << 24)
#define IDPOPT_BIT_BOOL (3 << 24)
#define IDPOPT_STR_QSTRING (1 << 24)
#define IDPOPT_STR_LONG (1 << 25)
#define IDPOPT_I64_RANGES (1 << 24)
#define IDPOPT_I64_UNS (1 << 25)
#define IDPOPT_CST_PARAMS (1 << 24)
#define IDPOPT_MBROFF (1 << 18)
//-------------------------------------------------------------------------
struct cfgopt_t;
idaman const char *ida_export cfgopt_t__apply(
const cfgopt_t *_this,
int vtype,
const void *vdata);
idaman const char *ida_export cfgopt_t__apply2(
const cfgopt_t *_this,
int vtype,
const void *vdata,
void *obj);
//-------------------------------------------------------------------------
// cfgopt_t objects are suitable for being statically initialized, and
// passed to 'read_config_file'.
//
// E.g.,
// ---
// static const cfgopt_t g_opts[] =
// {
// cfgopt_t("AUTO_UNDEFINE", &auto_undefine, -1, 1),
// cfgopt_t("NOVICE", &novice, true),
// cfgopt_t("EDITOR", editor_buf, sizeof(editor_buf)),
// cfgopt_t("SCREEN_PALETTE", set_screen_palette), // specific handler for SCREEN_PALETTE
// };
//
// ...
//
// read_config_file("myfile", g_opts, qnumber(g_opts), other_handler)
// ---
//
// NOTES:
// * so-called 'long' strings (the default) can span on multiple lines,
// and are terminated by a ';'
struct cfgopt_t
{
const char *name;
union
{
void *ptr;
size_t mbroff; // offset of a structure member
cfgopt_handler_t *hnd; // to avoid reinterpret_cast and gcc's error:
cfgopt_handler2_t *hnd2; // "a reinterpret_cast is not a constant expression"
cfgopt_handler3_t *hnd3; //
};
int flags;
struct num_range_t
{
constexpr num_range_t(int64 _min, int64 _max) : minval(_min), maxval(_max) {}
int64 minval;
int64 maxval;
};
struct params_t
{
constexpr params_t(int64 _p1, int64 _p2) : p1(_p1), p2(_p2) {}
int64 p1;
int64 p2;
};
union
{
size_t buf_size;
num_range_t num_range;
uint32 bit_flags;
params_t params;
void *mbroff_obj;
};
// IDPOPT_STR
constexpr cfgopt_t(const char *_n, char *_p, size_t _sz, bool _long = true)
: name(_n), ptr(_p), flags(IDPOPT_STR | (_long ? IDPOPT_STR_LONG : 0)), buf_size(_sz)
{}
constexpr cfgopt_t(const char *_n, qstring *_p, bool _long = true)
: name(_n), ptr(_p), flags(IDPOPT_STR | IDPOPT_STR_QSTRING | (_long ? IDPOPT_STR_LONG : 0)), buf_size(0)
{}
// IDPOPT_NUM
constexpr cfgopt_t(const char *_n, int *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM), buf_size(0) {}
constexpr cfgopt_t(const char *_n, uint *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS), buf_size(0) {}
constexpr cfgopt_t(const char *_n, char *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_CHAR), buf_size(0) {}
constexpr cfgopt_t(const char *_n, uchar *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_CHAR), buf_size(0) {}
constexpr cfgopt_t(const char *_n, short *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_SHORT), buf_size(0) {}
constexpr cfgopt_t(const char *_n, ushort *_p)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_SHORT), buf_size(0) {}
// IDPOPT_NUM + ranges
constexpr cfgopt_t(const char *_n, int *_p, int _min, int _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_RANGE), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, uint *_p, uint _min, uint _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_RANGE), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, char *_p, char _min, char _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_CHAR | IDPOPT_NUM_RANGE), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, uchar *_p, uchar _min, uchar _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_CHAR | IDPOPT_NUM_RANGE), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, short *_p, short _min, short _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_RANGE | IDPOPT_NUM_SHORT), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, ushort *_p, ushort _min, ushort _max)
: name(_n), ptr(_p), flags(IDPOPT_NUM | IDPOPT_NUM_UNS | IDPOPT_NUM_RANGE | IDPOPT_NUM_SHORT), num_range(_min, _max) {}
// IDPOPT_BIT
constexpr cfgopt_t(const char *_n, bool *_p, bool _flags) : name(_n), ptr(_p), flags(IDPOPT_BIT | IDPOPT_BIT_BOOL), bit_flags(_flags) {}
constexpr cfgopt_t(const char *_n, uchar *_p, uchar _flags) : name(_n), ptr(_p), flags(IDPOPT_BIT | IDPOPT_BIT_UCHAR), bit_flags(_flags) {}
constexpr cfgopt_t(const char *_n, ushort *_p, ushort _flags) : name(_n), ptr(_p), flags(IDPOPT_BIT | IDPOPT_BIT_USHORT), bit_flags(_flags) {}
constexpr cfgopt_t(const char *_n, uint32 *_p, uint32 _flags) : name(_n), ptr(_p), flags(IDPOPT_BIT), bit_flags(_flags) {}
// IDPOPT_I64
constexpr cfgopt_t(const char *_n, int64 *_p) : name(_n), ptr(_p), flags(IDPOPT_I64), buf_size(0) {}
constexpr cfgopt_t(const char *_n, uint64 *_p) : name(_n), ptr(_p), flags(IDPOPT_I64 | IDPOPT_NUM_UNS), buf_size(0) {}
// IDPOPT_I64 + ranges
constexpr cfgopt_t(const char *_n, int64 *_p, int64 _min, int64 _max)
: name(_n), ptr(_p), flags(IDPOPT_I64 | IDPOPT_I64_RANGES), num_range(_min, _max) {}
constexpr cfgopt_t(const char *_n, uint64 *_p, uint64 _min, uint64 _max)
: name(_n), ptr(_p), flags(IDPOPT_I64 | IDPOPT_I64_UNS | IDPOPT_I64_RANGES), num_range(int64(_min), int64(_max)) {}
// IDPOPT_CST
constexpr cfgopt_t(const char *_n, cfgopt_handler_t *_p)
: name(_n), hnd(_p), flags(IDPOPT_CST), buf_size(0) {}
// IDPOPT_CST + params
constexpr cfgopt_t(const char *_n, cfgopt_handler2_t *_p, int64 _p1=0, int64 _p2=0)
: name(_n), hnd2(_p), flags(IDPOPT_CST | IDPOPT_CST_PARAMS), params(_p1, _p2) {}
// configuration option based on the offset of a structure member
// IDPOPT_STR
template<class T>
constexpr cfgopt_t(const char *_n, qstring T:: *, size_t _mbroff, bool _long = true)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF | IDPOPT_STR | IDPOPT_STR_QSTRING | (_long ? IDPOPT_STR_LONG : 0)),
buf_size(0)
{}
#define CFGOPT_QS(nm, cfgt, cfgm, _long) \
cfgopt_t(nm, &cfgt::cfgm, qoffsetof(cfgt, cfgm), _long)
#define CFGOPT_INNER_QS(nm, cfgt, cfgm, mt, mf, _long) \
cfgopt_t(nm, &mt::mf, qoffsetof(cfgt, cfgm) + qoffsetof(mt, mf), _long)
// IDPOPT_NUM
#define CTR_CFGOPT(ctrtype, ctrflags) \
template<class T> \
constexpr cfgopt_t(const char *_n, ctrtype T:: *, size_t _mbroff) \
: name(_n), \
mbroff(_mbroff), \
flags(IDPOPT_MBROFF|IDPOPT_NUM|ctrflags), \
buf_size(0) \
{}
CTR_CFGOPT(int, 0)
CTR_CFGOPT(uint, IDPOPT_NUM_UNS)
CTR_CFGOPT(char, IDPOPT_NUM_CHAR)
CTR_CFGOPT(uchar, IDPOPT_NUM_UNS|IDPOPT_NUM_CHAR)
CTR_CFGOPT(short, IDPOPT_NUM_SHORT)
CTR_CFGOPT(ushort, IDPOPT_NUM_SHORT|IDPOPT_NUM_UNS)
#undef CTR_CFGOPT
#define CFGOPT_N(nm, cfgt, cfgm) \
cfgopt_t(nm, &cfgt::cfgm, qoffsetof(cfgt, cfgm))
#define CFGOPT_INNER_N(nm, cfgt, cfgm, mt, mf) \
cfgopt_t(nm, &mt::mf, qoffsetof(cfgt, cfgm) + qoffsetof(mt, mf))
// IDPOPT_NUM + ranges
#define CTR_CFGOPT(ctrtype, ctrflags) \
template<class T> \
constexpr cfgopt_t(const char *_n, ctrtype T:: *, size_t _mbroff, int64 _min, int64 _max) \
: name(_n), \
mbroff(_mbroff), \
flags(IDPOPT_MBROFF|IDPOPT_NUM|IDPOPT_NUM_RANGE|ctrflags), \
num_range(_min, _max) \
{}
CTR_CFGOPT(int, 0)
CTR_CFGOPT(uint, IDPOPT_NUM_UNS)
CTR_CFGOPT(char, IDPOPT_NUM_CHAR)
CTR_CFGOPT(uchar, IDPOPT_NUM_UNS|IDPOPT_NUM_CHAR)
CTR_CFGOPT(short, IDPOPT_NUM_SHORT)
CTR_CFGOPT(ushort, IDPOPT_NUM_SHORT|IDPOPT_NUM_UNS)
#undef CTR_CFGOPT
#define CFGOPT_R(nm, cfgt, cfgm, min, max) \
cfgopt_t(nm, &cfgt::cfgm, qoffsetof(cfgt, cfgm), min, max)
#define CFGOPT_INNER_R(nm, cfgt, cfgm, mt, mf, min, max) \
cfgopt_t(nm, &mt::mf, qoffsetof(cfgt, cfgm) + qoffsetof(mt, mf), min, max)
// IDPOPT_BIT
#define CTR_CFGOPT(ctrtype, ctrflags) \
template<class T> \
constexpr cfgopt_t(const char *_n, ctrtype T:: *, size_t _mbroff, ctrtype _flags) \
: name(_n), \
mbroff(_mbroff), \
flags(IDPOPT_MBROFF|IDPOPT_BIT|ctrflags), \
bit_flags(_flags) \
{}
CTR_CFGOPT(bool, IDPOPT_BIT_BOOL);
CTR_CFGOPT(uchar, IDPOPT_BIT_UCHAR);
CTR_CFGOPT(ushort, IDPOPT_BIT_USHORT);
CTR_CFGOPT(uint32, 0);
#undef CTR_CFGOPT
#define CFGOPT_B(nm, cfgt, cfgm, _flags) \
cfgopt_t(nm, &cfgt::cfgm, qoffsetof(cfgt, cfgm), _flags)
#define CFGOPT_INNER_B(nm, cfgt, cfgm, mt, mf, _flags) \
cfgopt_t(nm, &mt::mf, qoffsetof(cfgt, cfgm) + qoffsetof(mt, mf), _flags)
// IDPOPT_I64
template<class T>
constexpr cfgopt_t(const char *_n, int64 T:: *, size_t _mbroff)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF|IDPOPT_I64),
buf_size(0)
{}
template<class T>
constexpr cfgopt_t(const char *_n, uint64 T:: *, size_t _mbroff)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF|IDPOPT_I64|IDPOPT_NUM_UNS),
buf_size(0)
{}
// IDPOPT_I64 + ranges
template<class T>
constexpr cfgopt_t(const char *_n, int64 T:: *, size_t _mbroff, int64 _min, int64 _max)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF|IDPOPT_I64|IDPOPT_I64_RANGES),
num_range(_min, _max)
{}
template<class T>
constexpr cfgopt_t(const char *_n, uint64 T:: *, size_t _mbroff, uint64 _min, uint64 _max)
: name(_n),
mbroff(_mbroff),
flags(IDPOPT_MBROFF|IDPOPT_I64|IDPOPT_I64_UNS|IDPOPT_I64_RANGES),
num_range(int64(_min), int64(_max))
{}
// IDPOPT_CST + params
constexpr cfgopt_t(const char *_n, cfgopt_handler3_t *_p, int64 _p1=0, int64 _p2=0)
: name(_n), hnd3(_p), flags(IDPOPT_MBROFF|IDPOPT_CST), params(_p1, _p2) {}
int type() const { return flags & 0xf; }
int qualifier() const { return flags & 0xf000000; }
const char *apply(int vtype, const void *vdata, void *obj=nullptr) const
{
return cfgopt_t__apply2(this, vtype, vdata, obj);
}
};
/// Parse the input, and apply options.
///
/// \param input input file name, or string
/// \param is_file is input a string, or a file name
/// \param opts options destcriptions
/// \param nopts the number of entries present in the 'opts' array
/// \param defhdlr a handler to be called, if a directive couldn't be found in 'opts'
/// \param defines a list of preprocessor identifiers to define (so it is
/// possible to use #ifdef checks in the file.)
/// NB: the actual identifier defined by the parser will be
/// surrounded with double underscores (e.g., passing 'FOO'
/// will result in '__FOO__' being defined)
/// Additionally, the parser will also define a similar macro
/// with the current processor name (e.g., __ARM__)
/// \param ndefines the number of defines in the list
/// \param obj see cfgopt_t constructor based on the offset of a structure member
/// \return true if parsing finished without errors, false if there was a
/// syntax error, callback returned an error, or no file was found
/// at all.
idaman bool ida_export read_config(
const char *input,
bool is_file,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = NULL,
const char *const *defines = NULL,
size_t ndefines = 0);
idaman bool ida_export read_config2(
const char *input,
bool is_file,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = nullptr,
const char *const *defines = nullptr,
size_t ndefines = 0,
void *obj = nullptr);
inline bool read_config_file2(
const char *filename,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = nullptr,
const char *const *defines = nullptr,
size_t ndefines = 0,
void *obj = nullptr)
{
return read_config2(filename, true, opts, nopts, defhdlr, defines, ndefines, obj);
}
/// Search for all IDA system files with the given name.
/// This function will search, in that order, for the following files:
/// -# %IDADIR%/cfg/<file>
/// -# for each directory 'ONEDIR' in %IDAUSR%: %ONEDIR%/cfg/<file>
///
/// For each directive in each of those files, the same processing as
/// that of read_config will be performed.
inline bool read_config_file(
const char *filename,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = NULL,
const char *const *defines = NULL,
size_t ndefines = 0)
{
return read_config(filename, true, opts, nopts, defhdlr, defines, ndefines);
}
/// For each directive in 'string', the same processing as that of
/// read_config will be performed.
inline bool read_config_string(
const char *string,
const cfgopt_t opts[],
size_t nopts,
cfgopt_handler_t *defhdlr = NULL,
const char *const *defines = NULL,
size_t ndefines = 0)
{
return read_config(string, false, opts, nopts, defhdlr, defines, ndefines);
}
/// Process one or more config directive(s).
/// \param directive the directives to process
/// \param priority priority \ref IDPOPT_RET
/// In the case of errors this function displays a message and exits.
idaman void ida_export process_config_directive(
const char *directive,
int priority=IDPOPT_PRI_HIGH);
/// Register array of config options.
/// This function can be used by a plugin to register the config options.
/// After registering an option, it becomes usable by the
/// process_config_directive() function.
/// \param opts array of config options
/// \param nopts number of options to install. 0 means uninstall
/// \param cb callback that will be invoked upon changing a config option
/// \param obj see cfgopt_t constructor based on the offset of a structure member
/// \return success
typedef void idaapi config_changed_cb_t(const cfgopt_t &opt, int vtype, const void *vdata);
idaman bool ida_export register_cfgopts(
const cfgopt_t opts[],
size_t nopts,
config_changed_cb_t cb=nullptr,
void *obj=nullptr);
/// Get one of config parameters defined by CC_PARMS in ida.cfg.
/// All parameters for all compilers are stored in local map during last read
/// of ida.cfg - this function just returns previously stored parameter value for
/// given compiler (NULL if no such parameter)
idaman const char *ida_export cfg_get_cc_parm(comp_t compid, const char *name);
/// Get header path config parameter from ida.cfg.
/// Also see cfg_get_cc_parm()
inline const char *cfg_get_cc_header_path(comp_t compid)
{
return cfg_get_cc_parm(compid, "HEADER_PATH");
}
/// Get predefined macros config parameter from ida.cfg.
/// Also see cfg_get_cc_parm()
inline const char *cfg_get_cc_predefined_macros(comp_t compid)
{
return cfg_get_cc_parm(compid, "PREDEFINED_MACROS");
}
#endif // _CONFIG_HPP

2625
idasdk76/include/dbg.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,269 @@
/*
* CPP/D/Swift Demangler.
* Copyright (c) 2000-2018 by Iouri Kharon.
* E-mail: yjh@styx.cabel.net
*
* ALL RIGHTS RESERVED.
*
*/
#ifndef _DEMANGLE_HPP
#define _DEMANGLE_HPP
// int32 result code
#define ME_INTERR -1 // Internal error
#define ME_PARAMERR -2 // Input parameters are wrong
#define ME_ILLSTR -3 // Incorrectly mangled name
#define ME_SMALLANS -4 // Output buffer is too small
// This code is possible only with the 'old' calling
// form. With the new calling form the output buffer
// will have '...' as the last characters and the
// result code or'ed with the sign bit
#define ME_FRAME -5 // Partial demanging is possible (the input name has
// unrecognized suffix)
#define ME_NOCOMP -6 // Could not determine the compiler
#define ME_ERRAUTO -7 // Specified compiler is impossible for the input name
#define ME_NOHASHMEM -8 // Out of internal indexes-most likely bad input name
#define ME_NOSTRMEM -9 // Out of internal buffers (can't be!:)
#define ME_NOERROR_LIMIT -10 // Lowest error number. Lower values
// signal about the truncated output name
// (the output buffer is too small)
#define M_PRCMSK 0x0000000F // If = 0, then data
#define MT_DEFAULT 0x00000001 // 1 - default (for watcom/gnu only this)
#define MT_CDECL 0x00000002 // 2 - __cdecl
#define MT_PASCAL 0x00000003 // 3 - __pascal
#define MT_STDCALL 0x00000004 // 4 - __stdcall
#define MT_FASTCALL 0x00000005 // 5 - __fastcall
#define MT_THISCALL 0x00000006 // 6 - __thiscall [ms & bc => pragma only]
#define MT_FORTRAN 0x00000007 // 7 - __fortran
#define MT_SYSCALL 0x00000008 // 8 - __syscall [without ms]
#define MT_INTERRUPT 0x00000009 // 9 - __interrupt (only with __cdecl!)
#define MT_MSFASTCALL 0x0000000A // A - __msfastcall (bc)
#define MT_CLRCALL 0x0000000B // B - __clrcall (vc7)
#define MT_DMDCALL 0x0000000C // C - __dcall (dm D language abi)
#define MT_VECTORCALL 0x0000000D // D - __vectorcall (vc13)
#define MT_REGCALL 0x0000000E // E - __regcall (icl, clang)
// reserved
#define MT_LOCALNAME 0x0000000F // f - might be function or data. Currently
// is used only for bc - as the
// identifier for local pascal labels
#define M_SAVEREGS 0x00000010 // For functions with "__saveregs"
#define M_CLASS 0x000000E0 // 0 - no keyword (not a member field)
#define MT_PUBLIC 0x00000020 // 1 - public
#define MT_PRIVATE 0x00000040 // 2 - private
#define MT_PROTECT 0x00000060 // 3 - protected
#define MT_MEMBER 0x00000080 // 4 - undetermined (bc/wat/gcc)
#define MT_VTABLE 0x000000A0 // 5 - vtable (bc/gnu)
#define MT_RTTI 0x000000C0 // 6 - typeinfo table (gcc3), witness table (Swift)
// reserved
#define M_PARMSK 0x0000FF00 // Parameter number mask (excluding ellipsis)
// 255 - >= 255
#define MT_PARSHF 8 // shift to PARMSK
#define MT_PARMAX 0xFF // Number limiter
// ATT: when CC is __vectorcall and mode is 'C'
// real argscount is unknown. This number is
// total sizeof of all arguments divided to
// sizeof of defptr
#define M_ELLIPSIS 0x00010000 // The function _certainly_ has '...'
#define MT_VOIDARG 0x0001FF00 // If = 0, the func(void), i.e. no parameters
#define M_STATIC 0x00020000 // static
// gcc3 - static data in a function
// might be encountered in object files and
// (possibly) in binaries with debug info
#define M_VIRTUAL 0x00040000 // virtual
// NOTE: for (D) not virtual -- this (counted!)
#define M_AUTOCRT 0x00080000 // Most likely "autogenerated" function (data)
// NOTE: +M_STATIC => "__linkproc__" (bc)
#define M_TYPMASK 0x00700000 // Special functions (0-regular function)
#define MT_OPERAT 0x00100000 // 1 - operator
#define MT_CONSTR 0x00200000 // 2 - constructor
#define MT_DESTR 0x00300000 // 3 - destructor
#define MT_CASTING 0x00400000 // 4 - type conversion
#define MT_CLRCDTOR 0x00500000 // 5 - delphi2010 CLR ctor/dtor for packages
// reserved
#define M_TRUNCATE 0x00800000 // Name was truncated by the compiler (bc/va)
#define M_THUNK 0x01000000 // [thunk]:
#define M_ANONNSP 0x02000000 // ms => Anonymous Namespace for field
// gc3 => Item placed in Anonymous namespace
// wat => anonymous_enum
// bc => + TMPLNAM = PascalTemplate (for DCC)
// If separate - "automatic" except_t
// from CBuilder for "external" variables
// or a template for global object
// constructor/destructor tables (for CBuilder
// as well)
#define M_TMPLNAM 0x04000000 // ms => template name (?)
// wat =>
// bc => template name => its description table
// gc3 => any template funciton/data
#define M_DBGNAME 0x08000000 // ms => CV:
// wat => xxxx: (T?xxxx-form)
// bc => old pascal format (capitalized)
// gc3 => unicode symbols or 'vendor-extension'
// qualifiers are present
#define M_COMPILER 0x70000000 // Compiler mask (0-unknown)
#define MT_MSCOMP 0x10000000 // 1 - microsoft/symantec
#define MT_BORLAN 0x20000000 // 2 - borland
#define MT_WATCOM 0x30000000 // 3 - watcom
#define MT_OTHER 0x40000000 // 4 - digital mars D language (start: _D)
// - apple Swift language (start: [_]_T)
// !!! The following definitions must be last and in this order!
#define MT_GNU 0x50000000 // 5 - GNU - (over VA for autodetection)
#define MT_GCC3 0x60000000 // 6 - gcc-v3
// In the short form this answer is possible
// for GNU/VA as well, but gcc3 can be
// explicitly requested only with it.
// Autodetection works but not very reliable.
#define MT_VISAGE 0x70000000 // 7 - Visual Age - never autodetected
// In the short form this answer means VA
// or GNU. In the automatic mode GNU will
// be used!
//---------------------------------------------------------------------------
// Flags to inhibit different parts of the demangled name
#define MNG_PTRMSK 0x7 // Memory model mask
// DO NOT change order in this group (PtrType)
#define MNG_DEFNEAR 0x0 // inhibit near, display everything else
#define MNG_DEFNEARANY 0x1 // inhibit near/__ptr64, display everything else
#define MNG_DEFFAR 0x2 // inhibit far, display everything else
#define MNG_NOPTRTYP16 0x3 // inhibit everything (disables vc7-extensions)
#define MNG_DEFHUGE 0x4 // inhibit huge, display everything else
#define MNG_DEFPTR64 0x5 // inhibit __pt64, display everything else
// ATT: in 64bit must be + MNG_NOTYPE|MNG_NOCALLC
#define MNG_DEFNONE 0x6 // display everything
#define MNG_NOPTRTYP 0x7 // inhibit everything
//
#define MNG_NODEFINIT 0x00000008 // Inhibit everything except the main name
// This flag is not recommended
// for __fastcall/__stdcall GCC3 names
// because there is a high probablity of
// incorrect demangling. Use it only when
// you are sure that the input is a
// cygwin/mingw function name
//
#define MNG_NOUNDERSCORE 0x00000010 // Inhibit underscores in __ccall, __pascal... +
#define MNG_NOTYPE 0x00000020 // Inhibit callc&based
#define MNG_NORETTYPE 0x00000040 // Inhibit return type of functions
#define MNG_NOBASEDT 0x00000080 // Inhibit base types
// NOTE: also inhibits "__linkproc__"
// NOTE: -"- 'implicit self types' (Swift)
#define MNG_NOCALLC 0x00000100 // Inhibit __pascal/__ccall/etc
// NOTE: also inhibits "extern (cc)" (D)
#define MNG_NOPOSTFC 0x00000200 // Inhibit postfix const
#define MNG_NOSCTYP 0x00000400 // Inhibit public/private/protected
// NOTE: also inhibits in/out/lazy for args (D)
// NOTE: -"- dynamic/super/override/... (Swift)
#define MNG_NOTHROW 0x00000800 // Inhibit throw description
// NOTE: also inhibits all funcattr (D)
#define MNG_NOSTVIR 0x00001000 // Inhibit "static" & "virtual"
// NOTE: also inhibits (D) top-level procs (<=)
#define MNG_NOECSU 0x00002000 // Inhibit class/struct/union/enum[/D:typedef]
#define MNG_NOCSVOL 0x00004000 // Inhibit const/volatile/restrict
// NOTE: also inhibits __unaligned (vc)
// NOTE: also inhibits transaction_safe(gcc)
// NOTE: also inhibits shared/immutable (D)
// NOTE: also inhibits prefix/postfix/infix/inout (Swift)
#define MNG_NOCLOSUR 0x00008000 // Inhibit __closure for borland
// 'reabstract thunk' description (Swift)
#define MNG_NOUNALG 0x00010000 // Inhibit __unaligned (see NOCSVOL)
// NOTE: also inhibit transaction_safe (see NOCSVOL)
#define MNG_NOMANAGE 0x00020000 // Inhibit __pin/__box/__gc for ms(.net)
// NOTE: also inhibit archetype/witness (Swift)
// NOTE: also ingibit [abi:xxxx] (gcc3)
#define MNG_NOMODULE 0x00040000 // Inhibit module names (Swift)
// 0x00080000
//
#define MNG_SHORT_S 0x00100000 // signed (int) is displayed as s(int)
#define MNG_SHORT_U 0x00200000 // unsigned (int) is displayed as u(int)
#define MNG_ZPT_SPACE 0x00400000 // Display space after comma in the arglist
// NOTE: also spaces in name:type pair (Swift)
// and around Swift return clause ->
#define MNG_DROP_IMP 0x00800000 // Inhibit __declspec(dllimport)
//
// 0x01000000
#define MNG_IGN_ANYWAY 0x02000000 // Ingore '_nn' at the end of name
#define MNG_IGN_JMP 0x04000000 // Ingore 'j_' at the beginning of name
#define MNG_MOVE_JMP 0x08000000 // Move 'j_' prefix to the demangled name
// If both MNG_IGN_JMP and MNG_MOVE_JMP
// are set then move the prefix only if
// the name was not truncated
//
#define MNG_COMPILER_MSK 0x70000000 // Compiler mask (0-autodetect)
#define MNG_SHORT_FORM (MNG_NOTYPE|MNG_NORETTYPE|MNG_NOPOSTFC|MNG_NOPTRTYP \
| MNG_NOSCTYP|MNG_NOTHROW|MNG_NOSTVIR|MNG_NOECSU|MNG_NOCLOSUR \
| MNG_SHORT_U|MNG_DROP_IMP|MNG_NOUNALG|MNG_NOMANAGE \
| MNG_IGN_JMP|MNG_MOVE_JMP|MNG_IGN_ANYWAY)
#define MNG_LONG_FORM (MNG_ZPT_SPACE | MNG_IGN_JMP | MNG_IGN_ANYWAY | MNG_NOPTRTYP)
// The description of the following symbol is in the notes
#define MNG_CALC_VALID (MNG_COMPILER_MSK|MNG_IGN_JMP|MNG_IGN_ANYWAY)
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#ifndef H2ASH
#if !defined(NO_OBSOLETE_FUNCS) || defined(__DEFINE_DEMANGLE__)
typedef int32 ida_export demangler_t(
char *answer,
uint answer_length,
const char *str,
uint32 disable_mask);
idaman demangler_t demangle;
#endif
// If answer_length == 0 then no demangling is performed neither. The function
// will check if demangling is possible and what compiler is used to mangle
// the name. If the name cannot be demangled then the function will return 0.
// NOTE: the answer MT_MSCOMP+1 means __msfastcall
// (or borland class name with "_4" suffix) and the demangling is possible
// either as MS (__fastcall) or as bc (__msfastcall)
// NOTE: the answer MT_GCC3+1 means POSSIBLE mingw/cygwin with
// __stdcall/__fastcall but it might also mean ms-stdcall.
// In essense it means that the demangler cannot determine the compiler
// precisely.
// It also means that the demangling is possible in the gcc3 mode
// ONLY when the compiler is explicitly set to gcc3 and MNG_NODEFINIT
// bit is not set.
// If answer == NULL then the demangler will return check if the demangling
// is possible and only return the flags.
// In this case answer_length should be enough to hold the demangled name.
// NOTE: If int32(answer_length) < 0 then the demangler will calcuate the
// the number of purged bytes for the given name. In this case
// disable_mask may contain only bits included in MNG_CALC_VALID,
// and -answer_length must be equal to the register size (e.g.
// sizeof(uint16/uint32/uint64)). The value of the register size
// is used to check the numeric value in the ms stdcall/fastcall
// encoding (it is used in the gcc mode too).
// if return value <= 0 - no purged bytes or valid information.
// If (value & 1) != 0 - ms stdcall (definite npurged is value-1.
// If (value & 1) == 0 - 'encoded' counter (not implemented yet).
// If answer != NULL (and answer_length != 0) - perform demangling and fill out.
// NOTE: if int32(answer_length) < 0 then the buffer size will be -answer_length
// but 'answer' is interpreted not as a pointer to the output buffer but
// as a pointer to pointer to the output buffer (char**).
// In this case if the function succeeds,a pointer to the answer end
// will be returned in the pointer (like stpcpy). In this form 'answer'
// cannot be NULL and *(char**)answer cannot be NULL.
// answer_length must be greater than 9 for the 'truncated' answer.
typedef int mangled_name_type_t;
const mangled_name_type_t MANGLED_CODE = 0;
const mangled_name_type_t MANGLED_DATA = 1;
const mangled_name_type_t MANGLED_UNKNOWN = 2;
idaman mangled_name_type_t ida_export get_mangled_name_type(const char *name);
#endif // H2ASH
#endif // _DEMANGLE_HPP

View File

@@ -0,0 +1,468 @@
/*
This class is used to organize a directory tree on top of any
collection that allows for accessing its elements by an id (inode).
No requirements are imposed on the inodes apart from the forbidden
value -1 (it is used ot denote a bad inode).
The dirspec_t class is used to specialize the dirtree.
It can be used to introduce a directory structure for:
- local types
- structs
- enums
- functions
- names
- etc
*/
#ifndef DIRTREE_HPP
#define DIRTREE_HPP
//------------------------------------------------------------------------
typedef qvector<inode_t> inodevec_t; // sequence of inodes
/// Directory indexes are simple numbers like 0,1,2,3...
/// They are independent of inode numbers.
/// The root directory always exists and has the index 0 (\ref direntry_t::ROOTIDX).
typedef uval_t diridx_t;
typedef qvector<diridx_t> dirvec_t; // sequence of directory indexes
// Directory entry: either a file or directory
// We use PACKED to save memory, without it we would spend 64 bits instead of
// 8 bits to store a 1-bit value on ida64.
#pragma pack(push, 1)
struct PACKED direntry_t
{
uval_t idx; // diridx_t or inode_t
bool isdir;
static const uval_t BADIDX = uval_t(-1);
static const uval_t ROOTIDX = 0;
direntry_t(uval_t i=BADIDX, bool d=false) : idx(i), isdir(d) {}
bool valid() const { return idx != BADIDX; }
bool operator==(const direntry_t &r) const
{
return idx == r.idx && isdir == r.isdir;
}
bool operator!=(const direntry_t &r) const
{
return !(*this == r);
}
bool operator<(const direntry_t &r) const
{
if ( !isdir && r.isdir )
return true;
if ( isdir && !r.isdir )
return false;
return idx < r.idx;
}
};
#pragma pack(pop)
DECLARE_TYPE_AS_MOVABLE(direntry_t);
typedef qvector<direntry_t> direntry_vec_t;
//------------------------------------------------------------------------
/// Directory tree specialization. This is an abstract base class that
/// represents 'file items' of our directory structure.
struct dirspec_t
{
uint32 flags;
enum
{
DSF_INODE_EA = 0x01, // inode is EA, will be handled during segment moving
DSF_PRIVRANGE = 0x02, // inode is tid_t, structure or enum id, will be handled during segment moving
};
// netnode name to load/save directory tree
// if not specified the loading/storing operations are not supported
qstring nodename;
dirspec_t(const char *nm=nullptr, uint32 f=0) : flags(f), nodename(nm) {}
virtual ~dirspec_t() {}
// get the entry name. for example, the structure name
// out may be nullptr; in this case get_name can be used to validate an inode.
// return false if the entry does not exist.
virtual bool get_name(qstring *out, inode_t inode) = 0;
// get the entry inode. for example, the structure id
virtual inode_t get_inode(diridx_t diridx, const char *name) = 0;
// print additional attributes of the entry. for example, is union? is mapped?
virtual qstring get_attrs(inode_t inode) const = 0;
// rename the entry
virtual bool rename_inode(inode_t inode, const char *newname) = 0;
// event: unlinked an inode
virtual void unlink_inode(inode_t) {}
};
//------------------------------------------------------------------------
/// Position in the directory tree
struct dirtree_cursor_t
{
diridx_t parent;
size_t rank; // item rank: index into parent.subdirs or parent.inodes
// if the index value is greated than parent.subdirs.size()
// then it points to parent.inodes (after -= parent.subdirs.size())
dirtree_cursor_t(diridx_t _parent=direntry_t::BADIDX, size_t _rank=size_t(-1))
: parent(_parent), rank(_rank) {}
bool valid() const { return parent != direntry_t::BADIDX || rank == 0; }
bool is_root_cursor() const { return parent == direntry_t::BADIDX && rank == 0; }
void set_root_cursor(void) { parent = direntry_t::BADIDX; rank = 0; }
static dirtree_cursor_t root_cursor()
{
dirtree_cursor_t c;
c.set_root_cursor();
return c;
}
DECLARE_COMPARISONS(dirtree_cursor_t)
{
if ( parent < r.parent ) return -1;
if ( parent > r.parent ) return 1;
if ( rank < r.rank ) return -1;
if ( rank > r.rank ) return 1;
return 0;
}
};
DECLARE_TYPE_AS_MOVABLE(dirtree_cursor_t);
typedef qvector<dirtree_cursor_t> dirtree_cursor_vec_t;
//-------------------------------------------------------------------------
struct dirtree_selection_t : public dirtree_cursor_vec_t {};
//------------------------------------------------------------------------
/// Helper class to iterate over files
struct dirtree_iterator_t
{
qstring pattern;
dirtree_cursor_t cursor;
};
//------------------------------------------------------------------------
// Directory tree: error codes
enum dterr_t
{
DTE_OK, // ok
DTE_ALREADY_EXISTS, // item already exists
DTE_NOT_FOUND, // item not found
DTE_NOT_DIRECTORY, // item is not a directory
DTE_NOT_EMPTY, // directory is not empty
DTE_BAD_PATH, // invalid path
DTE_CANT_RENAME, // failed to rename an item
DTE_OWN_CHILD, // moving inside subdirectory of itself
DTE_MAX_DIR, // maximum directory count achieved
DTE_LAST,
};
class dirtree_t;
class dirtree_impl_t;
struct segm_move_infos_t;
//------------------------------------------------------------------------
// internal functions; use dirtree_t members instead
#ifndef SWIG
idaman dirtree_impl_t *ida_export create_dirtree(dirtree_t *dt, dirspec_t *ds);
idaman void ida_export delete_dirtree(dirtree_impl_t *d);
idaman bool ida_export load_dirtree(dirtree_impl_t *d);
idaman bool ida_export save_dirtree(dirtree_impl_t *d);
void reset_dirtree(dirtree_impl_t *d);
idaman const char *ida_export dirtree_errstr(dterr_t err);
idaman dterr_t ida_export dirtree_chdir(dirtree_impl_t *d, const char *path);
idaman void ida_export dirtree_getcwd(qstring *out, const dirtree_impl_t *d);
idaman void ida_export dirtree_resolve_path(direntry_t *de, const dirtree_impl_t *d, const char *path);
idaman void ida_export dirtree_resolve_cursor(direntry_t *de, const dirtree_impl_t *d, const dirtree_cursor_t &cursor);
idaman bool ida_export dirtree_get_entry_name(qstring *out, const dirtree_impl_t *d, const direntry_t &de);
idaman void ida_export dirtree_get_entry_attrs(qstring *out, const dirtree_impl_t *d, const direntry_t &de);
idaman ssize_t ida_export dirtree_get_dir_size(dirtree_impl_t *d, diridx_t diridx);
idaman bool ida_export dirtree_findfirst(dirtree_impl_t *d, dirtree_iterator_t *ff, const char *pattern);
idaman bool ida_export dirtree_findnext(dirtree_impl_t *d, dirtree_iterator_t *ff);
idaman bool ida_export dirtree_get_abspath_by_cursor(qstring *out, const dirtree_impl_t *d, const dirtree_cursor_t &cursor);
idaman bool ida_export dirtree_get_abspath_by_relpath(qstring *out, const dirtree_impl_t *d, const char *relpath);
idaman dterr_t ida_export dirtree_mkdir(dirtree_impl_t *d, const char *path);
idaman dterr_t ida_export dirtree_rmdir(dirtree_impl_t *d, const char *path);
idaman dterr_t ida_export dirtree_link(dirtree_impl_t *d, const char *path, bool do_link);
idaman dterr_t ida_export dirtree_link_inode(dirtree_impl_t *d, inode_t inode, bool do_link);
idaman dterr_t ida_export dirtree_rename(dirtree_impl_t *d, const char *from, const char *to);
idaman ssize_t ida_export dirtree_get_rank(const dirtree_impl_t *d, diridx_t diridx, const direntry_t &de);
idaman dterr_t ida_export dirtree_change_rank(dirtree_impl_t *d, const char *path, ssize_t rank_delta);
idaman void ida_export dirtree_get_parent_cursor(dirtree_cursor_t *out, const dirtree_impl_t *d, const dirtree_cursor_t &cursor);
idaman void ida_export notify_dirtree(dirtree_impl_t *d, bool added, inode_t inode);
idaman const char *ida_export dirtree_get_nodename(const dirtree_impl_t *d);
idaman void ida_export dirtree_set_nodename(dirtree_impl_t *d, const char *nm);
#endif // SWIG
//------------------------------------------------------------------------
/// Directory tree.
/// This class organizes a virtual directory tree over items that
/// are represented by dirspec_t.
class dirtree_t
{
dirtree_impl_t *d;
public:
//lint -sem(dirtree_t::dirtree_t, custodial(1))
dirtree_t(dirspec_t *ds) { d = create_dirtree(this, ds); }
~dirtree_t() { delete_dirtree(d); }
/// Get textual representation of the error code
static const char *errstr(dterr_t err) { return dirtree_errstr(err); }
/// Change current directory
/// \param path new current directory
/// \return \ref dterr_t error code
dterr_t chdir(const char *path) { return dirtree_chdir(d, path); }
/// Get current directory
/// \return the current working directory
qstring getcwd() const
{
qstring out;
dirtree_getcwd(&out, d);
return out;
}
/// Get absolute path pointed by the cursor
/// \param cursor
/// \return path; empty string if error
/// \note see also resolve_cursor()
qstring get_abspath(const dirtree_cursor_t &cursor) const
{
qstring out;
dirtree_get_abspath_by_cursor(&out, d, cursor);
return out;
}
/// Construct an absolute path from the specified relative path.
/// This function verifies the directory part of the specified path.
/// The last component of the specified path is not verified.
/// \param relpath relative path
/// \return path. empty path means wrong directory part of RELPATH
qstring get_abspath(const char *relpath) const
{
qstring out;
dirtree_get_abspath_by_relpath(&out, d, relpath);
return out;
}
/// Resolve cursor
/// \param cursor to analyze
/// \return directory entry;
/// if the cursor is bad, the resolved entry will be invalid.
/// \note see also get_abspath()
direntry_t resolve_cursor(const dirtree_cursor_t &cursor) const
{
direntry_t de;
dirtree_resolve_cursor(&de, d, cursor);
return de;
}
/// Resolve path
/// \param path to analyze
/// \return directory entry
direntry_t resolve_path(const char *path) const
{
direntry_t de;
dirtree_resolve_path(&de, d, path);
return de;
}
static bool isdir(const direntry_t &de) { return de.valid() && de.isdir; }
static bool isfile(const direntry_t &de) { return de.valid() && !de.isdir; }
/// Is a directory?
/// \param path to analyze
/// \return true if the specified path is a directory
bool isdir(const char *path) const
{
direntry_t de = resolve_path(path);
return isdir(de);
}
/// Is a file?
/// \param path to analyze
/// \return true if the specified path is a file
bool isfile(const char *path) const
{
direntry_t de = resolve_path(path);
return isfile(de);
}
/// Get entry name
/// \param de directory entry
/// \return name
qstring get_entry_name(const direntry_t &de) const
{
qstring out;
dirtree_get_entry_name(&out, d, de);
return out;
}
/// Get dir size
/// \param diridx directory index
/// \return number of entries under this directory;
/// if error, return -1
ssize_t get_dir_size(diridx_t diridx) const { return dirtree_get_dir_size(d, diridx); }
/// Get entry attributes
/// \param de directory entry
/// \return name
qstring get_entry_attrs(const direntry_t &de) const
{
qstring out;
dirtree_get_entry_attrs(&out, d, de);
return out;
}
/// Start iterating over files in a directory
/// \param ff directory iterator. it will be initialized by the function
/// \param pattern pattern to search for
/// \return success
bool findfirst(dirtree_iterator_t *ff, const char *pattern) const
{
return dirtree_findfirst(d, ff, pattern);
}
/// Continue iterating over files in a directory
/// \param ff directory iterator
/// \return success
bool findnext(dirtree_iterator_t *ff) const
{
return dirtree_findnext(d, ff);
}
/// Create a directory.
/// \param path directory to create
/// \return \ref dterr_t error code
dterr_t mkdir(const char *path) { return dirtree_mkdir(d, path); }
/// Remove a directory.
/// \param path directory to delete
/// \return \ref dterr_t error code
dterr_t rmdir(const char *path) { return dirtree_rmdir(d, path); }
/// Add a file item into a directory.
/// \param path path to item to add to a directory
/// \return \ref dterr_t error code
dterr_t link(const char *path) { return dirtree_link(d, path, true); }
/// Remove a file item from a directory.
/// \param path path to item remove from a directory
/// \return \ref dterr_t error code
dterr_t unlink(const char *path) { return dirtree_link(d, path, false); }
/// Add an inode into the current directory
/// \param inode
/// \return \ref dterr_t error code
dterr_t link(inode_t inode) { return dirtree_link_inode(d, inode, true); }
/// Remove an inode from the current directory
/// \param inode
/// \return \ref dterr_t error code
dterr_t unlink(inode_t inode) { return dirtree_link_inode(d, inode, false); }
/// Rename a directory entry.
/// \param from source path
/// \param to destination path
/// \return \ref dterr_t error code
/// \note This function can also rename the item
dterr_t rename(const char *from, const char *to)
{
return dirtree_rename(d, from, to);
}
/// Get ordering rank of an item.
/// \param diridx index of the parent directory
/// \param de directory entry
/// \return number in a range of [0..n) where n is the number of entries in
/// the parent directory. -1 if error
ssize_t get_rank(diridx_t diridx, const direntry_t &de) const
{
return dirtree_get_rank(d, diridx, de);
}
/// Change ordering rank of an item.
/// \param path path to the item
/// \param delta the amount of the change. positive numbers mean to move down
/// in the list; negative numbers mean to move up.
/// \return \ref dterr_t error code
/// \note All subdirectories go before all file entries.
dterr_t change_rank(const char *path, ssize_t rank_delta)
{
return dirtree_change_rank(d, path, rank_delta);
}
/// Get parent cursor.
/// \param cursor a valid ditree cursor
/// \return cursor's parent
dirtree_cursor_t get_parent_cursor(const dirtree_cursor_t &cursor) const
{
dirtree_cursor_t parent;
dirtree_get_parent_cursor(&parent, d, cursor);
return parent;
}
/// Load the tree structure from the netnode.
/// If dirspec_t::nodename is empty, the operation will be considered a success.
/// In addition, calling load() more than once will not do anything,
/// and will be considered a success.
/// \return success
/// \see dirspec_t::nodename.
bool load()
{
return load_dirtree(d);
}
/// Save the tree structure to the netnode.
/// \return success
/// \see dirspec_t::nodename.
bool save() const
{
return save_dirtree(d);
}
/// netnode name
const char *get_nodename() const
{
return dirtree_get_nodename(d);
}
void set_nodename(const char *nm)
{
return dirtree_set_nodename(d, nm);
}
/// Notify dirtree about a change of an inode.
/// \param add are we adding or deleting an inode?
/// \param inode inode in question
void notify_dirtree(bool added, inode_t inode)
{
::notify_dirtree(d, added, inode);
}
};
/// Built-in dirtree specializations:
enum dirtree_id_t
{
DIRTREE_LOCAL_TYPES,
DIRTREE_STRUCTS,
DIRTREE_ENUMS,
DIRTREE_FUNCS,
DIRTREE_NAMES,
DIRTREE_IMPORTS,
DIRTREE_IDAPLACE_BOOKMARKS,
DIRTREE_STRUCTS_BOOKMARKS,
DIRTREE_ENUMS_BOOKMARKS,
DIRTREE_END,
};
idaman dirtree_t *ida_export get_std_dirtree(dirtree_id_t id);
#endif // define DIRTREE_HPP

621
idasdk76/include/diskio.hpp Normal file
View File

@@ -0,0 +1,621 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _DISKIO_HPP
#define _DISKIO_HPP
#include <stdio.h>
/*! \file diskio.hpp
\brief File I/O functions for IDA
You should not use standard C file I/O functions in modules.
Use functions from this header, pro.h and fpro.h instead.
This file also declares a call_system() function.
*/
//-------------------------------------------------------------------------
// S E A R C H F O R F I L E S
//-------------------------------------------------------------------------
/// Get IDA directory (if subdir==NULL)
/// or the specified subdirectory (see \ref SUBDIR)
idaman THREAD_SAFE const char *ida_export idadir(const char *subdir);
/// Search for IDA system file.
/// This function searches for a file in:
/// -# each directory specified by %IDAUSR%
/// -# ida directory [+ subdir]
/// and returns the first match.
/// \param[out] buf buffer for file name
/// \param bufsize size of output buffer
/// \param filename name of file to search
/// \param subdir if specified, the file is looked for in the specified subdirectory
/// of the ida directory first (see \ref SUBDIR)
/// \return NULL if not found, otherwise a pointer to full file name.
idaman THREAD_SAFE char *ida_export getsysfile(
char *buf,
size_t bufsize,
const char *filename,
const char *subdir);
/// \defgroup SUBDIR IDA subdirectories
/// Passed as 'subdir' parameter to idadir(), getsysfile(), and others.
//@{
#define CFG_SUBDIR "cfg"
#define IDC_SUBDIR "idc"
#define IDS_SUBDIR "ids"
#define IDP_SUBDIR "procs"
#define LDR_SUBDIR "loaders"
#define SIG_SUBDIR "sig"
#define TIL_SUBDIR "til"
#define PLG_SUBDIR "plugins"
#define THM_SUBDIR "themes"
//@}
/// Get user ida related directory.
/// \code
/// - if $IDAUSR is defined:
/// - the first element in $IDAUSR
/// - else
/// - default user directory ($HOME/.idapro or %APPDATA%Hex-Rays/IDA Pro)
/// \endcode
idaman THREAD_SAFE const char *ida_export get_user_idadir(void);
/// Get list of directories in which to find a specific IDA resource
/// (see \ref SUBDIR). The order of the resulting list is as follows:
/// \code
/// - [$IDAUSR/subdir (0..N entries)]
/// - $IDADIR/subdir
/// \endcode
/// \param[out] dirs output vector for directory names
/// \param subdir name of the resource to list
/// \param flags \ref IDA_SUBDIR_ bits
/// \return number of directories appended to 'dirs'
idaman THREAD_SAFE int ida_export get_ida_subdirs(qstrvec_t *dirs, const char *subdir, int flags=0);
/// \defgroup IDA_SUBDIR_ Subdirectory modification flags
/// Passed as 'flags' parameter to get_ida_subdirs()
//@{
#define IDA_SUBDIR_IDP 0x0001 ///< append the processor name as a subdirectory
#define IDA_SUBDIR_IDADIR_FIRST 0x0002 ///< $IDADIR/subdir will be first, not last
#define IDA_SUBDIR_ONLY_EXISTING 0x0004 ///< only existing directories will be present
//@}
/// Get a folder location by CSIDL (see \ref CSIDL).
/// Path should be of at least MAX_PATH size
idaman THREAD_SAFE bool ida_export get_special_folder(char *buf, size_t bufsize, int csidl);
/// \defgroup CSIDL Common CSIDLs
/// Passed as 'csidl' parameter to get_special_folder()
//@{
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
#endif
#ifndef CSIDL_LOCAL_APPDATA
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
#ifndef CSIDL_PROGRAM_FILES
#define CSIDL_PROGRAM_FILES 0x0026
#endif
#ifndef CSIDL_PROGRAM_FILES_COMMON
#define CSIDL_PROGRAM_FILES_COMMON 0x002b
#endif
#ifndef CSIDL_PROGRAM_FILESX86
#define CSIDL_PROGRAM_FILESX86 0x002a
#endif
//@}
/// Enumerate files in the specified directory.
/// \param[out] answer buffer to contain the file name for which
/// file_enumerator_t::visit_file returns non-zero value
/// (may be NULL)
/// \param answer_size size of 'answer'
/// \param path directory to enumerate files in
/// \param fname mask of file names to enumerate
/// \param fv file_enumerator_t::visit_file function called for each file
/// - file: full file name (with path)
/// - if returns non-zero value, the enumeration
/// is stopped and the return code is
/// is returned to the caller.
/// the callback function
/// \return zero or the code returned by 'func'
struct file_enumerator_t
{
virtual int visit_file(const char *file) = 0;
virtual ~file_enumerator_t() {}
};
idaman THREAD_SAFE int ida_export enumerate_files2(
char *answer,
size_t answer_size,
const char *path,
const char *fname,
file_enumerator_t &fv);
//-------------------------------------------------------------------------
// O P E N / R E A D / W R I T E / C L O S E F I L E S
//-------------------------------------------------------------------------
/// \name Open/Read/Write/Close Files
/// There are two sets of "open file" functions.
/// The first set tries to open a file and returns success or failure.
/// The second set is "open or die": if the file cannot be opened
/// then the function will display an error message and exit.
//@{
/// Open a new file for write in text mode, deny write.
/// If a file exists, it will be removed.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenWT(const char *file);
/// Open a new file for write in binary mode, deny read/write.
/// If a file exists, it will be removed.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenWB(const char *file);
/// Open a file for read in text mode, deny none.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenRT(const char *file);
/// Open a file for read in binary mode, deny none.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenRB(const char *file);
/// Open a file for read/write in binary mode, deny write.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenM(const char *file);
/// Open a file for append in text mode, deny none.
/// \return NULL if failure
idaman THREAD_SAFE FILE *ida_export fopenA(const char *file);
/// Open a file for read in binary mode or die, deny none.
/// If a file cannot be opened, this function displays a message and exits.
idaman THREAD_SAFE FILE *ida_export openR(const char *file);
/// Open a file for read in text mode or die, deny none.
/// If a file cannot be opened, this function displays a message and exits.
idaman THREAD_SAFE FILE *ida_export openRT(const char *file);
/// Open a file for read/write in binary mode or die, deny write.
/// If a file cannot be opened, this function displays a message and exits.
idaman THREAD_SAFE FILE *ida_export openM(const char *file);
//@}
//-------------------------------------------------------------------------
// F I L E S I Z E / D I S K S P A C E
//-------------------------------------------------------------------------
/// Get length of file in bytes.
/// \param fp pointer to file
idaman THREAD_SAFE uint64 ida_export qfsize(FILE *fp);
/// Change size of file or die.
/// If an error occurs, this function displays a message and exits.
/// \param fp pointer to file
/// \param size new size of file
idaman THREAD_SAFE void ida_export echsize(FILE *fp, uint64 size);
/// Get free disk space in bytes.
/// \param path name of any directory on the disk to get information about
idaman THREAD_SAFE uint64 ida_export get_free_disk_space(const char *path);
//-------------------------------------------------------------------------
// I / O P O R T D E F I N I T I O N S F I L E
//-------------------------------------------------------------------------
/// Describes an I/O port bit
struct ioport_bit_t
{
qstring name; ///< name of the bit
qstring cmt; ///< comment
};
DECLARE_TYPE_AS_MOVABLE(ioport_bit_t);
typedef qvector<ioport_bit_t> ioport_bits_t;
/// Describes an I/O port
struct ioport_t
{
ea_t address; ///< address of the port
qstring name; ///< name of the port
qstring cmt; ///< comment
ioport_bits_t bits; ///< bit names
void *userdata; ///< arbitrary data. initialized to NULL.
ioport_t()
: address(0), userdata(NULL)
{
}
};
DECLARE_TYPE_AS_MOVABLE(ioport_t);
typedef qvector<ioport_t> ioports_t;
/// Read i/o port definitions from a config file.
///
/// Each device definition in the input file begins with a line like this:
///
/// \v{.devicename}
///
/// After it go the port definitions in this format:
///
/// \v{portname address}
///
/// The bit definitions (optional) are represented like this:
///
/// \v{portname.bitname bitnumber}
///
/// Lines beginning with a space are ignored.
/// comment lines should be started with ';' character.
///
/// The default device is specified at the start of the file:
///
/// \v{.default device_name}
///
/// \note It is permissible to have a symbol mapped to several addresses
/// but all addresses must be unique.
/// \param[out] ports output vector
/// \param device contains device name to load. If default_device[0] == 0
/// then the default device is determined by .default directive
/// in the config file.
/// \param file config file name
/// \param callback callback to call when the input line can't be parsed normally.
/// - line: input line to parse
/// - returns error message. if NULL, then the line is parsed ok.
/// \return -1 on error or size of vector
idaman THREAD_SAFE ssize_t ida_export read_ioports(
ioports_t *ports,
qstring *device,
const char *file,
const char *(idaapi *callback)(
const ioports_t &ports,
const char *line)=NULL);
struct ioports_fallback_t
{
// returns success or fills ERRBUF with an error message
virtual bool handle(qstring *errbuf, const ioports_t &ports, const char *line) = 0;
};
idaman THREAD_SAFE ssize_t ida_export read_ioports2(
ioports_t *ports,
qstring *device,
const char *file,
ioports_fallback_t *callback=nullptr);
/// Allow the user to choose the ioport device.
/// \param[in,out] device in: contains default device name. If default_device[0] == 0
/// then the default device is determined by .default directive
/// in the config file.
/// out: the selected device name
/// \param file config file name
/// \param parse_params if present (non NULL), then defines a callback which
/// will be called for all lines not starting with a dot (.)
/// This callback may parse these lines are prepare a simple
/// processor parameter string. This string will be displayed
/// along with the device name.
/// If it returns #IOPORT_SKIP_DEVICE, then the current
/// device will not be included in the list.
/// \retval true the user selected a device, its name is in 'device'
/// \retval false the selection was cancelled. if device=="NONE" upon return,
/// then no devices were found in the configuration file
idaman THREAD_SAFE bool ida_export choose_ioport_device(
qstring *_device,
const char *file,
const char *(idaapi *parse_params)(
qstring *buf,
const char *line)=NULL);
struct choose_ioport_parser_t
{
/// \retval true and fill PARAM with a displayed string
/// \retval false and empty PARAM to skip the current device
/// \retval false and fill PARAM with an error message
virtual bool parse(qstring *param, const char *line) = 0;
};
idaman THREAD_SAFE bool ida_export choose_ioport_device2(
qstring *_device,
const char *file,
choose_ioport_parser_t *parse_params);
/// See 'parse_params' parameter to choose_ioport_device()
#define IOPORT_SKIP_DEVICE ((const char *)(-1))
/// Find ioport in the array of ioports
idaman THREAD_SAFE const ioport_t *ida_export find_ioport(const ioports_t &ports, ea_t address);
/// Find ioport bit in the array of ioports
idaman THREAD_SAFE const ioport_bit_t *ida_export find_ioport_bit(const ioports_t &ports, ea_t address, size_t bit);
//-------------------------------------------------------------------------
// S Y S T E M S P E C I F I C C A L L S
//-------------------------------------------------------------------------
/// Execute a operating system command.
/// This function suspends the interface (Tvision), runs the command
/// and redraws the screen.
/// \param command command to execute. If NULL, an interactive shell is activated
/// \return the error code returned by system() call
idaman THREAD_SAFE int ida_export call_system(const char *command);
//-------------------------------------------------------------------------
// L O A D E R I N P U T S O U R C E F U N C T I O N S
//-------------------------------------------------------------------------
/// \name Loader Input Source
/// Starting with v4.8 IDA can load and run remote files.
/// In order to do that, we replace the FILE* in the loader modules
/// with an abstract input source (linput_t). The source might be linked to
/// a local or remote file.
//@{
class linput_t; ///< loader input source
/// linput types
enum linput_type_t
{
LINPUT_NONE, ///< invalid linput
LINPUT_LOCAL, ///< local file
LINPUT_RFILE, ///< remote file (\dbg{open_file}, \dbg{read_file})
LINPUT_PROCMEM, ///< debugged process memory (read_dbg_memory())
LINPUT_GENERIC ///< generic linput
};
/// Read the input source.
/// If failed, inform the user and ask him if he wants to continue.
/// If he does not, this function will not return (loader_failure() will be called).
/// This function may be called only from loaders!
idaman void ida_export lread(linput_t *li, void *buf, size_t size);
/// Read the input source.
/// \return number of read bytes or -1
idaman ssize_t ida_export qlread(linput_t *li, void *buf, size_t size);
/// Read one line from the input source.
/// \return NULL if failure, otherwise 's'
idaman char *ida_export qlgets(char *s, size_t len, linput_t *li);
/// Read one character from the input source.
/// \return EOF if failure, otherwise the read character
idaman int ida_export qlgetc(linput_t *li);
/// Read multiple bytes and swap if necessary.
/// \param li input file
/// \param buf pointer to output buffer
/// \param size number of bytes to read
/// \param mf big endian?
/// \retval 0 ok
/// \retval -1 failure
idaman int ida_export lreadbytes(linput_t *li, void *buf, size_t size, bool mf);
/// Helper to define lread2bytes(), lread4bytes(), etc
#define DEF_LREADBYTES(read, type, size) \
/*! \brief Read a value from linput - also see lreadbytes() */ \
inline int idaapi read(linput_t *li, type *res, bool mf) \
{ return lreadbytes(li, res, size, mf); }
DEF_LREADBYTES(lread2bytes, int16, 2)
DEF_LREADBYTES(lread2bytes, uint16, 2)
DEF_LREADBYTES(lread4bytes, int32, 4)
DEF_LREADBYTES(lread4bytes, uint32, 4)
DEF_LREADBYTES(lread8bytes, int64, 8)
DEF_LREADBYTES(lread8bytes, uint64, 8)
#undef DEF_LREADBYTES
/// Read a zero-terminated string from the input.
/// If fpos == -1 then no seek will be performed.
idaman char *ida_export qlgetz(
linput_t *li,
int64 fpos,
char *buf,
size_t bufsize);
/// Get the input source size
idaman int64 ida_export qlsize(linput_t *li);
/// Set input source position.
/// \return the new position (not 0 as fseek!)
idaman qoff64_t ida_export qlseek(linput_t *li, qoff64_t pos, int whence=SEEK_SET);
/// Get input source position
inline qoff64_t idaapi qltell(linput_t *li) { return qlseek(li, 0, SEEK_CUR); }
/// Open loader input
idaman linput_t *ida_export open_linput(const char *file, bool remote);
/// Close loader input
idaman THREAD_SAFE void ida_export close_linput(linput_t *li);
/// Get FILE* from the input source.
/// If the input source is linked to a remote file, then return NULL.
/// Otherwise return the underlying FILE*
/// Please do not use this function if possible.
idaman THREAD_SAFE FILE *ida_export qlfile(linput_t *li);
/// Convert FILE * to input source.
/// Used for temporary linput_t objects - call unmake_linput() to free
/// the slot after the use.
idaman THREAD_SAFE linput_t *ida_export make_linput(FILE *fp);
/// Free an linput_t object (also see make_linput())
idaman THREAD_SAFE void ida_export unmake_linput(linput_t *li);
/// Generic linput class - may be used to create a linput_t instance for
/// any data source
struct generic_linput_t
{
/// \name Warning
/// The following two fields must be filled before calling create_generic_linput()
//@{
uint64 filesize; ///< input file size
uint32 blocksize; ///< preferred block size to work with
///< read/write sizes will be in multiples of this number.
///< for example, 4096 is a nice value
///< blocksize 0 means that the filesize is unknown.
///< the internal cache will be disabled in this case.
///< also, seeks from the file end will fail.
///< blocksize=-1 means error.
//@}
virtual ssize_t idaapi read(qoff64_t off, void *buffer, size_t nbytes) = 0;
virtual ~generic_linput_t() {}
};
/// Create a generic linput
/// \param gl linput description.
/// this object will be destroyed by close_linput()
/// using "delete gl;"
idaman THREAD_SAFE linput_t *ida_export create_generic_linput(generic_linput_t *gl);
/// Trivial memory linput
idaman THREAD_SAFE linput_t *ida_export create_bytearray_linput(const uchar *start, size_t size);
/// Create a linput for process memory.
/// This linput will use read_dbg_memory() to read data.
/// \param start starting address of the input
/// \param size size of the memory area to represent as linput
/// if unknown, may be passed as 0
idaman linput_t *ida_export create_memory_linput(ea_t start, asize_t size);
/// Get linput type
inline THREAD_SAFE linput_type_t idaapi get_linput_type(linput_t *li)
{
return *(linput_type_t *)li;
}
/// Object that will free an linput_t at destruction-time
typedef janitor_t<linput_t*> linput_janitor_t;
/// Free the linput_t
template <> inline linput_janitor_t::~janitor_t()
{
close_linput(resource);
}
//---------------------------------------------------------------------------
/// Helper class - adapts linput to be used in extract_... functions
/// as a data supplier (see kernwin.hpp)
class linput_buffer_t
{
public:
linput_buffer_t(linput_t *linput, int64 size=0): li(linput), lsize(size) {}
ssize_t read(void *buf, size_t n)
{
return qlread(li, buf, n);
}
bool eof()
{
if ( lsize == 0 )
lsize = qlsize(li);
return qltell(li) >= lsize;
}
protected:
linput_t *li;
private:
int64 lsize;
};
//@}
// -------------------------------------------------------------------------
#ifndef NO_OBSOLETE_FUNCS
idaman DEPRECATED THREAD_SAFE FILE *ida_export ecreate(const char *file);
idaman DEPRECATED THREAD_SAFE void ida_export eclose(FILE *fp);
idaman DEPRECATED THREAD_SAFE void ida_export eread(FILE *fp, void *buf, size_t size);
idaman DEPRECATED THREAD_SAFE void ida_export ewrite(FILE *fp, const void *buf, size_t size);
idaman DEPRECATED THREAD_SAFE void ida_export eseek(FILE *fp, qoff64_t pos);
idaman DEPRECATED THREAD_SAFE int ida_export enumerate_files(
char *answer,
size_t answer_size,
const char *path,
const char *fname,
int (idaapi*func)(const char *file,void *ud),
void *ud=NULL);
#endif
#endif // _DISKIO_HPP

106
idasdk76/include/entry.hpp Normal file
View File

@@ -0,0 +1,106 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _ENTRY_HPP
#define _ENTRY_HPP
/*! \file entry.hpp
\brief Functions that deal with entry points
Exported functions are considered as entry points as well.
IDA maintains list of entry points to the program.
Each entry point:
- has an address
- has a name
- may have an ordinal number
*/
/// Get number of entry points
idaman size_t ida_export get_entry_qty(void);
/// \defgroup AEF_ entry flags
/// Passed as 'flags' parameter to add_entry(ea_t, const char *, int)
//@{
#define AEF_UTF8 0x0 ///< the name is given in UTF-8 (default)
#define AEF_IDBENC 0x1 ///< the name is given in the IDB encoding;
///< non-ASCII bytes will be decoded accordingly
///< Specifying AEF_IDBENC also implies AEF_NODUMMY
#define AEF_NODUMMY 0x2 ///< automatically prepend the name with '_' if
///< it begins with a dummy suffix. See also AEF_IDBENC
//@}
/// Add an entry point to the list of entry points.
/// \param ord ordinal number
/// if ordinal number is equal to 'ea' then ordinal is not used
/// \param ea linear address
/// \param name name of entry point. If the specified location already
/// has a name, the old name will be appended to the regular
/// comment. If name == NULL, then the old name will be retained.
/// \param makecode should the kernel convert bytes at the entry point
/// to instruction(s)
/// \param flags See AEF_*
/// \return success (currently always true)
idaman bool ida_export add_entry(uval_t ord, ea_t ea, const char *name, bool makecode, int flags=AEF_UTF8);
/// Get ordinal number of an entry point.
/// \param idx internal number of entry point. Should be
/// in the range 0..get_entry_qty()-1
/// \return ordinal number or 0.
idaman uval_t ida_export get_entry_ordinal(size_t idx);
/// Get entry point address by its ordinal
/// \param ord ordinal number of entry point
/// \return address or #BADADDR
idaman ea_t ida_export get_entry(uval_t ord);
/// Get name of the entry point by its ordinal.
/// \param buf output buffer, may be NULL
/// \param ord ordinal number of entry point
/// \return size of entry name or -1
idaman ssize_t ida_export get_entry_name(qstring *buf, uval_t ord);
/// Rename entry point.
/// \param ord ordinal number of the entry point
/// \param name name of entry point. If the specified location already
/// has a name, the old name will be appended to a repeatable
/// comment.
/// \param flags See AEF_*
/// \return success
idaman bool ida_export rename_entry(uval_t ord, const char *name, int flags=AEF_UTF8);
/// Set forwarder name for ordinal.
/// \param ord ordinal number of the entry point
/// \param name forwarder name for entry point.
/// \param flags See AEF_*
/// \return success
idaman bool ida_export set_entry_forwarder(uval_t ord, const char *name, int flags=AEF_UTF8);
/// Get forwarder name for the entry point by its ordinal.
/// \param buf output buffer, may be NULL
/// \param ord ordinal number of entry point
/// \return size of entry forwarder name or -1
idaman ssize_t ida_export get_entry_forwarder(qstring *buf, uval_t ord);
#endif // _ENTRY_HPP

371
idasdk76/include/enum.hpp Normal file
View File

@@ -0,0 +1,371 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
* Enums and bitfields
* Bitfields will be abbreviated as "bf".
*
*/
#ifndef _ENUM_HPP
#define _ENUM_HPP
#include <nalt.hpp>
/*! \file enum.hpp
\brief Assembly level enum management
Enums and bitfields are represented as ::enum_t.
*/
typedef tid_t enum_t; ///< Enums and bitfields
typedef uval_t bmask_t; ///< unsigned value that describes a bitmask
///< a bit mask is 32/64 bits.
#define DEFMASK (bmask_t(-1)) ///< default bitmask
typedef uval_t const_t; ///< members of enums
/// Max number of identical constants allowed for one enum type
const uchar MAX_ENUM_SERIAL = 255;
/// Get number of declared ::enum_t types
idaman size_t ida_export get_enum_qty(void);
/// Get enum by its index in the list of enums (0..get_enum_qty()-1).
idaman enum_t ida_export getn_enum(size_t idx);
/// Get the index in the list of enums
idaman uval_t ida_export get_enum_idx(enum_t id);
/// Get enum by name
idaman enum_t ida_export get_enum(const char *name);
/// Is enum a bitfield?
/// (otherwise - plain enum, no bitmasks except for #DEFMASK are allowed)
idaman bool ida_export is_bf(enum_t id);
/// Is enum collapsed?
idaman bool ida_export is_enum_hidden(enum_t id);
/// Collapse enum
idaman bool ida_export set_enum_hidden(enum_t id, bool hidden);
/// Does enum come from type library?
idaman bool ida_export is_enum_fromtil(enum_t id);
/// Specify that enum comes from a type library
idaman bool ida_export set_enum_fromtil(enum_t id, bool fromtil);
/// Is a ghost copy of a local type?
idaman bool ida_export is_ghost_enum(enum_t id);
/// Specify that enum is a ghost copy of a local type
idaman bool ida_export set_enum_ghost(enum_t id, bool ghost);
/// Get name of enum
idaman ssize_t ida_export get_enum_name(qstring *out, enum_t id);
/// Get name of enum
/// \param[out] out buffer to hold the name
/// \param id enum id
/// \param flags \ref ENFL_
idaman ssize_t ida_export get_enum_name2(qstring *out, enum_t id, int flags=0);
/// \defgroup ENFL_ Enum name flags
/// Passed as 'flags' parameter to get_enum_name()
//@{
#define ENFL_REGEX 0x0001 ///< apply regular expressions to beautify the name
//@}
inline qstring get_enum_name(tid_t id, int flags=0)
{
qstring name;
get_enum_name2(&name, id, flags);
return name;
}
/// Get the width of a enum element
/// allowed values: 0 (unspecified),1,2,4,8,16,32,64
idaman size_t ida_export get_enum_width(enum_t id);
/// See comment for get_enum_width()
idaman bool ida_export set_enum_width(enum_t id, int width);
/// Get enum comment
idaman ssize_t ida_export get_enum_cmt(qstring *buf, enum_t id, bool repeatable);
/// Get the number of the members of the enum
idaman size_t ida_export get_enum_size(enum_t id);
/// Get flags determining the representation of the enum.
/// (currently they define the numeric base: octal, decimal, hex, bin) and signness.
idaman flags_t ida_export get_enum_flag(enum_t id);
/// Get a reference to an enum member by its name
idaman const_t ida_export get_enum_member_by_name(const char *name);
/// Get value of an enum member
idaman uval_t ida_export get_enum_member_value(const_t id);
/// Get the parent enum of an enum member
idaman enum_t ida_export get_enum_member_enum(const_t id);
/// Get bitmask of an enum member
idaman bmask_t ida_export get_enum_member_bmask(const_t id);
/// Find an enum member by enum, value and bitmask
/// \note if serial -1, return a member with any serial
idaman const_t ida_export get_enum_member(enum_t id, uval_t value, int serial, bmask_t mask);
/// \name Access to all used bitmasks in an enum
//@{
/// Get first bitmask in the enum (bitfield)
///
/// \param enum_id id of enum (bitfield)
/// \return the smallest bitmask for enum, or DEFMASK
///
idaman bmask_t ida_export get_first_bmask(enum_t id);
/// Get last bitmask in the enum (bitfield)
///
/// \param enum_id id of enum
/// \return the biggest bitmask for enum, or DEFMASK
idaman bmask_t ida_export get_last_bmask(enum_t id);
/// Get next bitmask in the enum (bitfield)
///
/// \param enum_id id of enum
/// \param value the current bitmask
/// \return value of a bitmask with value higher than the specified value, or DEFMASK
idaman bmask_t ida_export get_next_bmask(enum_t id, bmask_t bmask);
/// Get prev bitmask in the enum (bitfield)
///
/// \param enum_id id of enum
/// \param value the current bitmask
/// \return value of a bitmask with value lower than the specified value, or DEFMASK
idaman bmask_t ida_export get_prev_bmask(enum_t id, bmask_t bmask);
//@}
/// \name Access to all enum members with specified bitmask
/// \note these functions return values, not ::const_t!
//@{
idaman uval_t ida_export get_first_enum_member(enum_t id, bmask_t bmask=DEFMASK);
idaman uval_t ida_export get_last_enum_member(enum_t id, bmask_t bmask=DEFMASK);
idaman uval_t ida_export get_next_enum_member(enum_t id, uval_t value, bmask_t bmask=DEFMASK);
idaman uval_t ida_export get_prev_enum_member(enum_t id, uval_t value, bmask_t bmask=DEFMASK);
//@}
/// Get name of an enum member by const_t
idaman ssize_t ida_export get_enum_member_name(qstring *out, const_t id);
/// Get enum member's comment
idaman ssize_t ida_export get_enum_member_cmt(qstring *buf, const_t id, bool repeatable);
/// \name Access to all enum members with specified value and mask
/// A sample loop looks like this:
/// \code
/// const_t main_cid;
/// uchar serial;
/// for ( const_t cid=main_cid=get_first_serial_enum_member(&serial, id, v, mask);
/// cid != BADNODE;
/// cid = get_next_serial_enum_member(&serial, main_cid) )
/// {
/// ...
/// }
/// \endcode
/// The 'out_serial' argument of get_first_serial_enum_member/get_last_serial_enum_member can be NULL.
/// The 'in_out_serial' is required for the other functions.
//@{
idaman const_t ida_export get_first_serial_enum_member(uchar *out_serial, enum_t id, uval_t value, bmask_t bmask);
idaman const_t ida_export get_last_serial_enum_member(uchar *out_serial, enum_t id, uval_t value, bmask_t bmask);
idaman const_t ida_export get_next_serial_enum_member(uchar *in_out_serial, const_t first_cid);
idaman const_t ida_export get_prev_serial_enum_member(uchar *in_out_serial, const_t first_cid);
//@}
/// Enum member visitor - see for_all_enum_members().
/// Derive your visitor from this class.
struct enum_member_visitor_t
{
/// Implements action to take when enum member is visited.
/// \return nonzero to stop the iteration
virtual int idaapi visit_enum_member(const_t cid, uval_t value) = 0;
};
/// Visit all members of a given enum
idaman int ida_export for_all_enum_members(enum_t id, enum_member_visitor_t &cv);
/// Get serial number of an enum member
idaman uchar ida_export get_enum_member_serial(const_t cid);
/// Get corresponding type ordinal number
idaman int32 ida_export get_enum_type_ordinal(enum_t id);
/// Set corresponding type ordinal number
idaman void ida_export set_enum_type_ordinal(enum_t id, int32 ord);
//--------------------------------------------------------------------------
// MANIPULATION
/// Add new enum type.
/// - if idx==#BADADDR then add as the last idx
/// - if name==NULL then generate a unique name "enum_%d"
idaman enum_t ida_export add_enum(size_t idx, const char *name, flags_t flag);
/// Delete an enum type
idaman void ida_export del_enum(enum_t id);
/// Set serial number of enum.
/// Also see get_enum_idx().
idaman bool ida_export set_enum_idx(enum_t id, size_t idx);
/// Set 'bitfield' bit of enum (i.e. convert it to a bitfield)
idaman bool ida_export set_enum_bf(enum_t id, bool bf);
/// Set name of enum type
idaman bool ida_export set_enum_name(enum_t id,const char *name);
/// Set comment for enum type
idaman bool ida_export set_enum_cmt(enum_t id,const char *cmt,bool repeatable);
/// Set data representation flags
idaman bool ida_export set_enum_flag(enum_t id, flags_t flag);
/// Add member to enum type.
/// \return 0 if ok, otherwise one of \ref ENUM_MEMBER_
idaman int ida_export add_enum_member(
enum_t id,
const char *name,
uval_t value,
bmask_t bmask=DEFMASK);
/// \defgroup ENUM_MEMBER_ Add enum member result codes
/// Return values for add_enum_member()
//@{
#define ENUM_MEMBER_ERROR_NAME 1 ///< already have member with this name (bad name)
#define ENUM_MEMBER_ERROR_VALUE 2 ///< already have 256 members with this value
#define ENUM_MEMBER_ERROR_ENUM 3 ///< bad enum id
#define ENUM_MEMBER_ERROR_MASK 4 ///< bad bmask
#define ENUM_MEMBER_ERROR_ILLV 5 ///< bad bmask and value combination (~bmask & value != 0)
//@}
/// Delete member of enum type
idaman bool ida_export del_enum_member(enum_t id, uval_t value, uchar serial, bmask_t bmask);
/// Set name of enum member
idaman bool ida_export set_enum_member_name(const_t id, const char *name);
/// Set comment for enum member
inline bool set_enum_member_cmt(const_t id, const char *cmt, bool repeatable)
{
return set_enum_cmt(id, cmt, repeatable);
}
/// Is bitmask one bit?
inline THREAD_SAFE bool is_one_bit_mask(bmask_t mask)
{
return (mask & (mask-1)) == 0;
}
/// \name Work with the bitmask name & comment
//@{
idaman bool ida_export set_bmask_name(enum_t id, bmask_t bmask, const char *name);
idaman ssize_t ida_export get_bmask_name(qstring *out, enum_t id, bmask_t bmask);
idaman bool ida_export set_bmask_cmt(enum_t id, bmask_t bmask, const char *cmt, bool repeatable);
idaman ssize_t ida_export get_bmask_cmt(qstring *buf, enum_t id, bmask_t bmask, bool repeatable);
//@}
#endif // _ENUM_HPP

96
idasdk76/include/err.h Normal file
View File

@@ -0,0 +1,96 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _ERR_H
#define _ERR_H
#include <errno.h>
/*! \file err.h
\brief Thread safe functions that deal with error codes
*/
/// Print error message to stderr (analog of perror)
idaman THREAD_SAFE AS_PRINTF(1, 0) void ida_export vqperror(const char *format, va_list va);
/// Get error description string.
/// if _qerrno=-1, get_qerrno() will be used
idaman THREAD_SAFE const char *ida_export qstrerror(error_t _qerrno);
/// A convenience function to generate error messages (returns "header: error message")
idaman THREAD_SAFE char *ida_export get_errdesc(const char *header, error_t _qerrno=-1);
/// Get error message for MS Windows error codes
idaman THREAD_SAFE char *ida_export winerr(int code);
/// errno or GetLastError() depending on the system.
idaman THREAD_SAFE int ida_export qerrcode(int new_code=-1);
/// Get error string corresponding to qerrcode().
/// if code == -1, then qerrcode() will be called.
idaman const char *ida_export qerrstr(int code=-1);
#ifdef __cplusplus
/// See vqperror()
THREAD_SAFE AS_PRINTF(1, 2) inline void qperror(const char *format, ...)
{
va_list va;
va_start(va, format);
vqperror(format, va);
va_end(va);
}
/// See set_qerrno()
THREAD_SAFE inline void set_errno(int code)
{
errno = code;
set_qerrno(eOS);
}
#endif
// Internal functions
/// \cond
// n=0..3
idaman THREAD_SAFE void ida_export set_error_data(int n, size_t data);
idaman THREAD_SAFE void ida_export set_error_string(int n, const char *str);
idaman THREAD_SAFE size_t ida_export get_error_data(int n);
idaman THREAD_SAFE const char *ida_export get_error_string(int n);
#define QPRM_TYPE(t,n,x) set_error_data(n-1, t(x))
#define QPRM_CHAR(n,x) QPRM_TYPE(char,n,x)
#define QPRM_SHORT(n,x) QPRM_TYPE(short,n,x)
#define QPRM_INT(n,x) QPRM_TYPE(int,n,x)
#define QPRM_INT32(n,x) QPRM_TYPE(int32,n,x)
#define QPRM_UCHAR(n,x) QPRM_TYPE(uchar,n,x)
#define QPRM_USHORT(n,x) QPRM_TYPE(ushort,n,x)
#define QPRM_UINT(n,x) QPRM_TYPE(uint,n,x)
#define QPRM_UINT32(n,x) QPRM_TYPE(uint32,n,x)
#define QPRM(n,x) set_error_string(n-1, x)
/// \endcond
#endif

67
idasdk76/include/exehdr.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
* EXE-file header layout
*
*/
#ifndef __EXEHDR_H
#define __EXEHDR_H
#pragma pack(push, 1)
struct exehdr
{
uint16 exe_ident;
#define EXE_ID 0x5A4D // 'MZ'
#define EXE_ID2 0x4D5A // 'ZM' (DOS works with this also)
uint16 PartPag;
uint16 PageCnt;
uint16 ReloCnt;
uint16 HdrSize;
uint16 MinMem;
uint16 MaxMem;
uint16 ReloSS;
uint16 ExeSP;
uint16 ChkSum;
uint16 ExeIP;
uint16 ReloCS;
uint16 TablOff;
uint16 Overlay;
/*
uint16 res[4]; // Reserved words
uint16 oemid; // OEM identifier (for e_oeminfo)
uint16 oeminfo; // OEM information; e_oemid specific
uint16 res2[10]; // Reserved words
uint32 lfanew; // File address of new exe header
*/
int32 CalcEXE_Length(void)
{
int32 len = PageCnt * 512L - HdrSize * 16;
if ( PartPag != 0 )
len -= 512 - PartPag;
return len;
}
void CalcEXE_Pages(int32 len)
{
PartPag = uint16(len % 512);
PageCnt = uint16(len / 512);
if ( PartPag != 0 )
PageCnt++;
}
};
struct exehdr_full: exehdr
{
uint16 res[4]; // Reserved words
uint16 oemid; // OEM identifier (for e_oeminfo)
uint16 oeminfo; // OEM information; e_oemid specific
uint16 res2[10]; // Reserved words
uint32 lfanew; // File address of new exe header
};
#define PSPsize 0x100
#define PE_PTROFF 0x3C
#pragma pack(pop)
#endif

1192
idasdk76/include/expr.hpp Normal file

File diff suppressed because it is too large Load Diff

572
idasdk76/include/fixup.hpp Normal file
View File

@@ -0,0 +1,572 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef FIXUP_HPP
#define FIXUP_HPP
#include <nalt.hpp>
#include <segment.hpp>
/*! \file fixup.hpp
\brief Functions that deal with fixup information
A loader should setup fixup information using set_fixup().
*/
//--------------------------------------------------------------------------
/// Fixup information structure
typedef uint16 fixup_type_t; ///< see \ref fixup_type_t
/// \defgroup fixup_type_t Types of fixups
/// Fixup may be of standard or custom type. Standard types fall into
/// range 1..FIXUP_CUSTOM-1 and custom types fall into range
/// FIXUP_CUSTOM..MAX_UINT16.
/// \note Fixup type 0 is unused.
/// \name Fixup standard types
//@{
#define FIXUP_OFF8 13 ///< 8-bit offset
#define FIXUP_OFF16 1 ///< 16-bit offset
#define FIXUP_SEG16 2 ///< 16-bit base--logical segment base (selector)
#define FIXUP_PTR16 3 ///< 32-bit long pointer (16-bit base:16-bit
///< offset)
#define FIXUP_OFF32 4 ///< 32-bit offset
#define FIXUP_PTR32 5 ///< 48-bit pointer (16-bit base:32-bit offset)
#define FIXUP_HI8 6 ///< high 8 bits of 16bit offset
#define FIXUP_HI16 7 ///< high 16 bits of 32bit offset
#define FIXUP_LOW8 8 ///< low 8 bits of 16bit offset
#define FIXUP_LOW16 9 ///< low 16 bits of 32bit offset
#define V695_FIXUP_VHIGH 10 ///< obsolete
#define V695_FIXUP_VLOW 11 ///< obsolete
#define FIXUP_OFF64 12 ///< 64-bit offset
#define FIXUP_OFF8S 14 ///< 8-bit signed offset
#define FIXUP_OFF16S 15 ///< 16-bit signed offset
#define FIXUP_OFF32S 16 ///< 32-bit signed offset
//#define FIXUP_ 0xE
#define FIXUP_CUSTOM 0x8000 ///< start of the custom types range
//@}
/// Is fixup processed by processor module?
inline THREAD_SAFE bool is_fixup_custom(fixup_type_t type)
{
return (type & FIXUP_CUSTOM) != 0;
}
/// \defgroup FIXUPF_ Fixup flags
/// Used by fixup_data_t
//@{
/// fixup is relative to the linear address `base'. Otherwise fixup is
/// relative to the start of the segment with `sel' selector.
#define FIXUPF_REL 0x0001
/// target is a location (otherwise - segment).
/// Use this bit if the target is a symbol rather than an offset from the
/// beginning of a segment.
#define FIXUPF_EXTDEF 0x0002
/// fixup is ignored by IDA
/// - disallows the kernel to convert operands
/// - this fixup is not used during output
#define FIXUPF_UNUSED 0x0004
/// fixup was not present in the input file
#define FIXUPF_CREATED 0x0008
/// additional flags. The bits from this mask are not stored in the database
/// and can be used by the loader at its discretion.
#define FIXUPF_LOADER_MASK 0xF0000000
//@}
struct fixup_handler_t;
struct fixup_data_t
{
protected:
fixup_type_t type; // fixup type
uint32 flags; // FIXUPF_... bits
uval_t base; // base for relative fixups
public:
sel_t sel; ///< selector of the target segment.
///< BADSEL means an absolute (zero based) target.
///< \sa FIXUPF_REL
ea_t off; ///< target offset
///< \note The target is calculated as
///< `get_base() + off`.
adiff_t displacement; ///< displacement (offset from the target)
public:
fixup_data_t()
: type(0),
flags(0),
base(0),
sel(BADSEL),
off(0),
displacement(0) {}
fixup_data_t(fixup_type_t type_, uint32 flags_ = 0)
: type(type_),
flags(flags_),
base(0),
sel(BADSEL),
off(0),
displacement(0) {}
/// Fixup type \ref fixup_type_t
fixup_type_t get_type(void) const { return type; }
void set_type(fixup_type_t type_) { type = type_; }
void set_type_and_flags(fixup_type_t type_, uint32 flags_ = 0)
{
type = type_;
flags = flags_;
}
bool is_custom(void) const; ///< \ref is_fixup_custom()
/// Fixup flags \ref FIXUPF_
uint32 get_flags() const { return flags; }
bool is_extdef(void) const { return (flags & FIXUPF_EXTDEF) != 0; }
void set_extdef(void) { flags |= FIXUPF_EXTDEF; }
void clr_extdef(void) { flags &= ~FIXUPF_EXTDEF; }
bool is_unused(void) const { return (flags & FIXUPF_UNUSED) != 0; }
void set_unused(void) { flags |= FIXUPF_UNUSED; }
void clr_unused(void) { flags &= ~FIXUPF_UNUSED; }
/// Is fixup relative?
bool has_base(void) const { return (flags & FIXUPF_REL) != 0; }
/// Is fixup artificial?
bool was_created(void) const { return (flags & FIXUPF_CREATED) != 0; }
/// Get base of fixup.
/// \note The target is calculated as `get_base() + off`.
/// \sa FIXUPF_REL
ea_t get_base() const
{
return has_base() ? base : sel != BADSEL ? sel2ea(sel) : 0;
}
/// Set base of fixup.
/// The target should be set before a call of this function.
void set_base(ea_t new_base)
{
ea_t target = get_base() + off;
flags |= FIXUPF_REL;
base = new_base;
off = target - base;
}
void set_sel(const segment_t *seg)
{
sel = seg == NULL ? BADSEL : seg->sel;
}
/// Set selector of fixup to the target.
/// The target should be set before a call of this function.
void set_target_sel()
{
ea_t target = get_base() + off;
set_sel(getseg(target));
flags &= ~FIXUPF_REL;
base = 0; // just in case
off = target - get_base();
}
void set(ea_t source) const; ///< \ref set_fixup()
bool get(ea_t source); ///< \ref get_fixup()
/// \ref get_fixup_handler()
const fixup_handler_t *get_handler() const;
/// \ref get_fixup_desc()
const char *get_desc(qstring *buf, ea_t source) const;
// TODO rewrite to the inline implementation which uses
// fixup_handler_t::size
int calc_size() const; ///< \ref calc_fixup_size()
uval_t get_value(ea_t ea) const; ///< \ref get_fixup_value()
bool patch_value(ea_t ea) const; ///< \ref patch_fixup_value()
};
/// Get fixup information
idaman bool ida_export get_fixup(fixup_data_t *fd, ea_t source);
/// Check that a fixup exists at the given address
inline bool exists_fixup(ea_t source)
{
return get_fixup(NULL, source);
}
/// Set fixup information. You should fill ::fixup_data_t and call this
/// function and the kernel will remember information in the database.
/// \param source the fixup source address, i.e. the address modified by
/// the fixup
/// \param fd fixup data
idaman void ida_export set_fixup(ea_t source, const fixup_data_t &fd);
/// Delete fixup information
idaman void ida_export del_fixup(ea_t source);
/// \name Enumerate addresses with fixup information:
//@{
/// Get the first address with fixup information
///
/// \return the first address with fixup information, or BADADDR
idaman ea_t ida_export get_first_fixup_ea(void);
/// Find next address with fixup information
///
/// \param ea current address
/// \return the next address with fixup information, or BADADDR
idaman ea_t ida_export get_next_fixup_ea(ea_t ea);
/// Find previous address with fixup information
///
/// \param ea current address
/// \return the previous address with fixup information, or BADADDR
idaman ea_t ida_export get_prev_fixup_ea(ea_t ea);
//@}
/// Get handler of standard or custom fixup
idaman const fixup_handler_t * ida_export get_fixup_handler(fixup_type_t type);
/// Use fixup information for an address.
/// This function converts item_ea flags to offsets/segments.
/// For undefined bytes, you may set item_ea == fixup_ea. In this case this
/// function will create an item (byte, word, dword) there.
/// \param item_ea start address of item to modify
/// \param fixup_ea address of fixup record
/// \param n number of operand. may be 0, 1, 2, or OPND_ALL
/// \param is_macro is the instruction at 'item_ea' a macro?
/// if yes, then partial fixups (HIGH, LOW) won't be applied
/// \retval false no fixup at fixup_ea or it has #FIXUPF_UNUSED flag
/// \retval true ok, the fixup information was applied
idaman bool ida_export apply_fixup(ea_t item_ea, ea_t fixup_ea, int n, bool is_macro);
/// Get the operand value.
/// This function get fixup bytes from data or an instruction at `ea' and
/// convert them to the operand value (maybe partially).
/// It is opposite in meaning to the `patch_fixup_value()`.
/// For example, FIXUP_HI8 read a byte at `ea' and shifts it left by 8 bits,
/// or AArch64's custom fixup BRANCH26 get low 26 bits of the insn at `ea'
/// and shifts it left by 2 bits.
/// This function is mainly used to get a relocation addend.
/// \param ea address to get fixup bytes from, the size of the fixup
/// bytes depends on the fixup type.
/// \sa fixup_handler_t::size
/// \param type fixup type
/// \retval operand value
idaman uval_t ida_export get_fixup_value(ea_t ea, fixup_type_t type);
/// Patch the fixup bytes.
/// This function updates data or an instruction at `ea' to the fixup bytes.
/// For example, FIXUP_HI8 updates a byte at `ea' to the high byte of
/// `fd->off', or AArch64's custom fixup BRANCH26 updates low 26 bits of the
/// insn at `ea' to the value of `fd->off' shifted right by 2.
/// \param ea address where data are changed, the size of the changed data
/// depends on the fixup type.
/// \sa fixup_handler_t::size
/// \param fd fixup data
/// \retval false the fixup bytes do not fit (e.g. `fd->off' is greater
/// than 0xFFFFFFC for BRANCH26). The database is changed
/// even in this case.
idaman bool ida_export patch_fixup_value(ea_t ea, const fixup_data_t &fd);
/// Get FIXUP description comment.
idaman const char *ida_export get_fixup_desc(
qstring *buf,
ea_t source,
const fixup_data_t &fd);
/// Calculate size of fixup in bytes (the number of bytes the fixup patches)
/// \retval -1 means error
idaman int ida_export calc_fixup_size(fixup_type_t type);
//--------------------------------------------------------------------------
// inline implementation
inline bool fixup_data_t::is_custom(void) const
{
return is_fixup_custom(type);
}
inline void fixup_data_t::set(ea_t source) const
{
set_fixup(source, *this);
}
inline bool fixup_data_t::get(ea_t source)
{
return get_fixup(this, source);
}
inline const char *fixup_data_t::get_desc(qstring *buf, ea_t source) const
{
return get_fixup_desc(buf, source, *this);
}
inline int fixup_data_t::calc_size() const
{
return calc_fixup_size(type);
}
inline uval_t fixup_data_t::get_value(ea_t ea) const
{
return get_fixup_value(ea, type);
}
inline bool fixup_data_t::patch_value(ea_t ea) const
{
return patch_fixup_value(ea, *this);
}
inline const fixup_handler_t *fixup_data_t::get_handler() const
{
return get_fixup_handler(type);
}
/// \name Custom fixups
/// Processor modules and plugins may register custom fixup handlers. File
/// loaders should use find_custom_fixup() function to find the handler
/// created by the processor module. The custom fixup handlers will be
/// unregistered automatically before the database gets closed.
//@{
//--------------------------------------------------------------------------
/// Implements the core behavior of a custom fixup
struct fixup_handler_t
{
int32 cbsize; ///< size of this structure
const char *name; ///< Format name, must be unique
uint32 props; ///< \ref FHF_
/// \defgroup FHF_ Fixup handler properties
/// Used by fixup_handler_t::props
//@{
#define FHF_VERIFY 0x0001 ///< verify that the value fits into WIDTH
///< bits. If this property is not set we
///< just truncate the value.
#define FHF_CODE 0x0002 ///< verify that ITEM_EA in std_apply() points
///< to an instruction.
#define FHF_FORCE_CODE 0x0004 ///< if ITEM_EA in std_apply() points to an
///< unknown item, then convert it to code.
///< this property is valid only with FHF_CODE.
#define FHF_ABS_OPVAL 0x0008 ///< create absolute refinfo in std_apply()
///< because the operand also has the absolute
///< value (usually for o_near operands)
#define FHF_SIGNED 0x0010 ///< the operand value is signed.
///< create a refinfo with REFINFO_SIGNEDOP in
///< std_apply()
//@}
/// Is the operand value signed?
bool is_signed() const { return (props & FHF_SIGNED) != 0; }
/// \defgroup fh_options Tuning options
//@{
/// The examples below show how these options work.
/// \sa std_patch_value() std_get_value()
uint8 size; ///< size in bytes
uint8 width; ///< number of significant bits before shifting
uint8 shift; ///< number of bits to shift right before patching.
///< The following should be true:
///< width - shift <= size * 8
uint8 rsrv4; // reserved
uint32 reftype; ///< reference info type and flags,
///< std_apply() produces an offset of this type
//@}
/// Apply a fixup: take it into account while analyzing the file.
/// Usually it consists of converting the operand into an offset expression.
/// \sa apply_fixup()
/// If this callback is not specified then std_apply() is used.
bool (idaapi *apply)(
const fixup_handler_t *fh,
ea_t item_ea,
ea_t fixup_ea,
int opnum,
bool is_macro,
const fixup_data_t &fd);
/// Get the operand value.
/// This callback is called from get_fixup_value().
/// \sa get_fixup_value()
/// If this callback is not specified then std_get_value() is used.
uval_t (idaapi *get_value)(const fixup_handler_t *fh, ea_t ea);
/// Patch the fixup bytes.
/// This callback is called from patch_fixup_value() or after changing the
/// fixup (e.g. after it was moved from one location to another).
/// If this callback is not specified then std_patch_value() is used.
/// \sa patch_fixup_value()
/// \retval false the fixup bytes do not fit. The database is changed
/// even in this case.
bool (idaapi *patch_value)(
const fixup_handler_t *fh,
ea_t ea,
const fixup_data_t &fd);
#ifndef SWIG
DECLARE_COMPARISONS(fixup_handler_t);
#endif
};
/// \name std_apply()
/// This internal function takes \ref fh_options and \ref FHF_ to convert
/// the fixup to an offset.
/// \name std_patch_value()
/// This internal function takes \ref fh_options and \ref FHF_ to determine
/// how to patch the bytes.
/// 1) it verifies that the fixup value fits to the fixup_handler_t::width
/// bits if the FHF_VERIFY property is specified,
/// 2) it discards bits that do not fit,
/// 3) it shifts the result right by fixup_handler_t::shift bits,
/// 4) it puts the result to the rightmost bits of fixup_handler_t::size
/// bytes at the given address.
/// For example, FIXUP_HI8 uses size = 1, and width = 16, and shift = 8, and
/// property FHF_VERIFY, or MIPS's custom fixup BRANCH26 uses size = 4,
/// and width = 28, and shift = 2.
/// In details:
/// a) size = 1, width = 16, shift = 8
/// - the value to patch is masked with 0xFFFF (width=16)
/// - then it is shifted right by 8 bits (shift=8)
/// - then the result is patched to the 8bit data at the fixup address
/// e.g.
/// 0xXX the original data
/// 0x1234 the value
/// 0x0012 the shifted value
/// 0x12 the patched data
/// b) size = 4, width = 28, shift = 2
/// - the value to patch is masked with 0xFFFFFFF (width=28)
/// - then it is shifted right by 2 bits (shift=2)
/// - then the result is patched in the low 26 bits of the 32bit
/// e.g.
/// 0x10000000 an instruction at the fixup address
/// 0x0000005C the value
/// 0x00000017 the shifted value
/// 0x10000017 the patched insn
/// \name std_get_value()
/// This internal function takes \ref fh_options to determine how to get the
/// operand value.
/// It is opposite in meaning to the std_patch_value().
/// 1) it gets the fixup_handler_t::size bytes at the given address,
/// 2) it shifts the result left by fixup_handler_t::shift bits,
/// 3) it returns the rightmost fixup_handler_t::width bits as a signed
/// value.
/// In details:
/// b) size = 4, width = 28, shift = 2
/// - it gets 4 bytes from the fixup address (the branch insn)
/// - then it shifts this dword left by 2 bits (shift=2)
/// - then the result is masked with 0xFFFFFFF (width=28)
/// e.g.
/// 0x10000017 the insn
/// 0x4000005C the unshifted value
/// 0x0000005C the masked result
/// Register a new custom fixup.
/// This function must be called by a processor module or plugin, but not
/// by a file loader. File loaders should use find_custom_fixup() function
/// to find the handler created by the processor module.
/// \return id of the new custom fixup handler with FIXUP_CUSTOM bit set or
/// 0 (e.g. when the custom fixup handler with the same name was
/// already registered).
idaman fixup_type_t ida_export register_custom_fixup(
const fixup_handler_t *cfh);
/// Unregister a new custom fixup format. Should be called by the processor
/// module before the database gets closed.
idaman bool ida_export unregister_custom_fixup(fixup_type_t type);
/// Get id of a custom fixup handler.
/// \param name name of the custom fixup handler
/// \return id with FIXUP_CUSTOM bit set or 0
idaman fixup_type_t ida_export find_custom_fixup(const char *name);
//@}
//--------------------------------------------------------------------------
/// Collect fixup records for the specified range.
/// Partially overlapping records will be reported too.
/// \return success (false means no fixup info have been found)
struct fixup_info_t
{
ea_t ea;
fixup_data_t fd;
};
DECLARE_TYPE_AS_MOVABLE(fixup_info_t);
typedef qvector<fixup_info_t> fixups_t;
idaman bool ida_export get_fixups(fixups_t *out, ea_t ea, asize_t size);
/// Does the specified address range contain any fixup information?
inline bool contains_fixups(ea_t ea, asize_t size)
{
return get_fixups(NULL, ea, size);
}
/// Relocate the bytes with fixup information once more (generic function).
/// This function may be called from loader_t::move_segm() if it suits the goal.
/// If loader_t::move_segm is not defined then this function will be called
/// automatically when moving segments or rebasing the entire program.
/// Special parameter values (from = BADADDR, size = 0, to = delta) are used
/// when the function is called from rebase_program(delta).
idaman void ida_export gen_fix_fixups(ea_t from, ea_t to, asize_t size);
/// Handle two fixups in a macro.
/// We often combine two instruction that load parts of a value into one
/// macro instruction. For example:
/// ARM: ADRP X0, #var@PAGE
/// ADD X0, X0, #var@PAGEOFF --> ADRL X0, var
/// MIPS: lui $v0, %hi(var)
/// addiu $v0, $v0, %lo(var) --> la $v0, var
/// When applying the fixups that fall inside such a macro, we should convert
/// them to one refinfo. This function does exactly that.
/// It should be called from the apply() callback of a custom fixup.
/// \return success ('false' means that RI was not changed)
idaman bool ida_export handle_fixups_in_macro(
refinfo_t *ri,
ea_t ea,
fixup_type_t other,
uint32 macro_reft_and_flags);
#endif // FIXUP_HPP

223
idasdk76/include/fpro.h Normal file
View File

@@ -0,0 +1,223 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __FPRO_H
#define __FPRO_H
#include <pro.h>
#include <stdio.h>
/*! \file fpro.h
\brief System independent counterparts of FILE* related functions from Clib
You should not use C standard I/O functions in your modules.
The reason: Each module compiled with Borland
(and statically linked to Borland's library) will host a copy of
the FILE * information.
So, if you open a file in the plugin and pass the handle to the
kernel, the kernel will not be able to use it.
If you really need to use the standard functions, define USE_STANDARD_FILE_FUNCTIONS.
In this case do not mix them with q... functions.
*/
#if !defined(USE_STANDARD_FILE_FUNCTIONS) && !defined(__CODE_CHECKER__)
#undef stdin
#undef stdout
#undef stderr
#undef fgetc
#undef fputc
#define stdin dont_use_stdin ///< use gets()
#define stdout dont_use_stdout ///< use qprintf()
#define stderr dont_use_stderr ///< use qeprintf()
#define fopen dont_use_fopen ///< use qfopen()
#define fread dont_use_fread ///< use qfread()
#define fwrite dont_use_fwrite ///< use qfwrite()
#define ftell dont_use_ftell ///< use qftell()
#define fseek dont_use_fseek ///< use qfseek()
#define fclose dont_use_fclose ///< use qfclose()
#define fflush dont_use_fflush ///< use qflush()
#define fputc dont_use_fputc ///< use qfputc()
#define fgetc dont_use_fgetc ///< use qfgetc()
#define fgets dont_use_fgets ///< use qfgets()
#define fputs dont_use_fputs ///< use qfputs()
#define vfprintf dont_use_vfprintf ///< use qvfprintf()
#define vfscanf dont_use_vfscanf ///< use qvfscanf()
#define fprintf dont_use_fprintf ///< use qfprintf()
#define fscanf dont_use_fscanf ///< use qfscanf()
#endif
/// \name File I/O
/// The following functions work just like their counterparts from Clib,
/// only they are safer, system independent, and they set qerrno (see get_qerrno()).
//@{
idaman THREAD_SAFE FILE *ida_export qfopen(const char *file, const char *mode);
idaman THREAD_SAFE ssize_t ida_export qfread(FILE *fp, void *buf, size_t n);
idaman THREAD_SAFE ssize_t ida_export qfwrite(FILE *fp, const void *buf, size_t n);
idaman THREAD_SAFE qoff64_t ida_export qftell(FILE *fp);
idaman THREAD_SAFE int ida_export qfseek(FILE *fp, qoff64_t offset, int whence);
idaman THREAD_SAFE int ida_export qfclose(FILE *fp);
idaman THREAD_SAFE int ida_export qflush(FILE *fp);
idaman THREAD_SAFE int ida_export qfputc(int chr, FILE *fp);
idaman THREAD_SAFE int ida_export qfgetc(FILE *fp);
idaman THREAD_SAFE char *ida_export qfgets(char *s, size_t len, FILE *fp);
idaman THREAD_SAFE int ida_export qfputs(const char *s, FILE *fp);
idaman FILE *ida_export qtmpfile(void);
idaman THREAD_SAFE int ida_export qunlink(const char *fname);
idaman THREAD_SAFE int ida_export qaccess(const char *fname, int mode);
idaman THREAD_SAFE char *ida_export qgets(char *line, size_t linesize);
idaman THREAD_SAFE AS_PRINTF(2, 0) int ida_export qvfprintf(FILE *fp, const char *format, va_list va);
idaman THREAD_SAFE AS_PRINTF(1, 0) int ida_export qvprintf(const char *format, va_list va);
idaman THREAD_SAFE AS_PRINTF(1, 0) int ida_export qveprintf(const char *format, va_list va);
idaman THREAD_SAFE AS_SCANF(2, 0) int ida_export qvfscanf(FILE *fp, const char *format, va_list va);
#ifdef __cplusplus
THREAD_SAFE AS_PRINTF(2, 3) inline int qfprintf(FILE *fp, const char *format, ...)
{
va_list va;
va_start(va, format);
int code = qvfprintf(fp, format, va);
va_end(va);
return code;
}
THREAD_SAFE AS_PRINTF(1, 2) inline int qprintf(const char *format, ...)
{
va_list va;
va_start(va, format);
int code = qvprintf(format, va);
va_end(va);
return code;
}
THREAD_SAFE AS_PRINTF(1, 2) inline int qeprintf(const char *format, ...)
{
va_list va;
va_start(va, format);
int code = qveprintf(format, va);
va_end(va);
return code;
}
THREAD_SAFE AS_SCANF(2, 3) inline int qfscanf(FILE *fp, const char *format, ...)
{
va_list va;
va_start(va, format);
int code = qvfscanf(fp, format, va);
va_end(va);
return code;
}
#endif
//@}
/// Read line from file (the newline is removed from the output buffer)
/// \param buf output buffer
/// \param fp pointer to file
/// \return -1 or length of line
idaman THREAD_SAFE ssize_t ida_export qgetline(qstring *buf, FILE *fp);
/// Rename a file: 'newname' may exist, and will be deleted
idaman THREAD_SAFE int ida_export qrename(const char *oldfname, const char *newfname);
/// Move a file - more powerful version of qrename
/// \retval 0 success
/// \retval -1 system error
/// \retval else a combination of flags to be given for successful move
idaman THREAD_SAFE int ida_export qmove(const char *oldfname, const char *newfname, uint32 flags);
enum
{
QMOVE_CROSS_FS = 0x01, // UNIX: allow moving between different filesystem
QMOVE_OVERWRITE = 0x02, // Overwrite existing file
QMOVE_OVR_RO = 0x04, // Overwrite file even if it is write-protected
};
/// Copy a file.
/// \param from source file name
/// \param to destination file name
/// \param overwrite overwrite output if it exists?
/// \param cb user callback. return false to abort the copy loop
/// \param ud user data passed back to cb
/// \param flags reserved (should be zero)
/// \retval -1 input file not found
/// \retval -2 output file not writable
/// \retval -3 output file already exists while overwrite is false
/// \retval -4 write failure
/// \retval -5 interrupted from the callback
idaman THREAD_SAFE int ida_export qcopyfile(
const char *from,
const char *to,
bool overwrite = true,
bool (idaapi *cb)(uint64 pos, uint64 total, void *ud)=NULL,
void *ud = NULL,
int flags = 0);
/// Get temporary file name.
/// Returns absolute path, includes directory, and uses TEMP/TMP vars.
idaman char *ida_export qtmpnam(char *buf, size_t bufsize);
/// File janitor: will close a file at destruction-time
typedef janitor_t<FILE*> file_janitor_t;
template <> inline file_janitor_t::~janitor_t()
{
qfclose(resource);
}
/// \name readbytes/writebytes
/// Add-ins for 2..32 byte read/writes.
/// \param fp pointer to file
/// \param res value read from file
/// \param size size of value in bytes (1..32)
/// \param mostfirst is MSB first? (0/1)
/// \retval 0 All these functions return 0 on success
//@{
idaman THREAD_SAFE int ida_export freadbytes(FILE *fp,void *res,int size,int mostfirst);
idaman THREAD_SAFE int ida_export fwritebytes(FILE *fp,const void *l,int size,int mostfirst);
#ifdef __cplusplus
#define DEF_FREADBYTES(read, write, type, size) \
inline THREAD_SAFE int read(FILE *fp, type *res, bool mostfirst) \
{ return freadbytes(fp, res, size, mostfirst); } \
inline THREAD_SAFE int write(FILE *fp, const type *res, bool mostfirst) \
{ return fwritebytes(fp, res, size, mostfirst); }
DEF_FREADBYTES(fread2bytes, fwrite2bytes, int16, 2)
DEF_FREADBYTES(fread2bytes, fwrite2bytes, uint16, 2)
DEF_FREADBYTES(fread4bytes, fwrite4bytes, int32, 4)
DEF_FREADBYTES(fread4bytes, fwrite4bytes, uint32, 4)
DEF_FREADBYTES(fread8bytes, fwrite8bytes, longlong, 8)
DEF_FREADBYTES(fread8bytes, fwrite8bytes, ulonglong, 8)
#else
#define fread2bytes(fp,v,mf) freadbytes(fp,v,2,mf)
#define fwrite2bytes(fp,v,mf) fwritebytes(fp,v,2,mf)
#define fread4bytes(fp,v,mf) freadbytes(fp,v,4,mf)
#define fwrite4bytes(fp,v,mf) fwritebytes(fp,v,4,mf)
#define fread8bytes(fp,v,mf) freadbytes(fp,v,8,mf)
#define fwrite8bytes(fp,v,mf) fwritebytes(fp,v,8,mf)
#endif
//@}
#if !defined(feof) || !defined(ferror)
// If feof() and ferror() are not macros, we cannot use them
// Fortunately, for borland and vc they are macros, so there is no problem
// GCC defines them as functions: I have no idea whether they will work or not
// Anyway we remove the error directive from this file
// so the plugins can be compiled with gcc
//#error feof or ferror are not macros!
#endif
#endif

609
idasdk76/include/frame.hpp Normal file
View File

@@ -0,0 +1,609 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _FRAME_HPP
#define _FRAME_HPP
#include <idp.hpp>
/*! \file frame.hpp
\brief Routines to manipulate function stack frames, stack
variables, register variables and local labels.
The frame is represented as a structure:
<pre>
+------------------------------------------------+
| function arguments |
+------------------------------------------------+
| return address (isn't stored in func_t) |
+------------------------------------------------+
| saved registers (SI, DI, etc - func_t::frregs) |
+------------------------------------------------+ <- typical BP
| | |
| | | func_t::fpd
| | |
| | <- real BP
| local variables (func_t::frsize) |
| |
| |
+------------------------------------------------+ <- SP
</pre>
To access the structure of a function frame, use:
- get_struc() (use func_t::frame as structure ID)
- get_frame(const func_t *pfn)
- get_frame(ea_t ea)
*/
class struc_t;
class member_t;
class op_t;
// We need to trace value of SP register. For this we introduce
// an array of SP register change points.
// SP register change point
//
// NOTE: To manipulate/modify stack points, please use the specialized
// functions provided below in this file (stack pointer change points)
struct stkpnt_t
{
ea_t ea; // linear address
sval_t spd; // here we keep a cumulative difference from [BP-frsize]
stkpnt_t &operator=(const stkpnt_t &) = default;
DECLARE_COMPARISONS(stkpnt_t)
{
if ( ea < r.ea )
return -1;
if ( ea > r.ea )
return 1;
return 0;
}
};
DECLARE_TYPE_AS_MOVABLE(stkpnt_t);
// we declare a struct to be able to forward declare it in other files
struct stkpnts_t : public qvector<stkpnt_t>
{
DECLARE_COMPARISONS(stkpnts_t) { return compare_containers(*this, r); }
};
//--------------------------------------------------------------------------
// F R A M E M A N I P U L A T I O N
//--------------------------------------------------------------------------
/// Add function frame.
/// \param pfn pointer to function structure
/// \param frsize size of function local variables
/// \param frregs size of saved registers
/// \param argsize size of function arguments range which will be purged upon return.
/// this parameter is used for __stdcall and __pascal calling conventions.
/// for other calling conventions please pass 0.
/// \retval 1 ok
/// \retval 0 failed (no function, frame already exists)
idaman bool ida_export add_frame(
func_t *pfn,
sval_t frsize,
ushort frregs,
asize_t argsize);
/// Delete a function frame.
/// \param pfn pointer to function structure
/// \return success
idaman bool ida_export del_frame(func_t *pfn);
/// Set size of function frame.
/// Note: The returned size may not include all stack arguments. It does so
/// only for __stdcall and __fastcall calling conventions. To get the entire
/// frame size for all cases use get_struc_size(get_frame(pfn)).
/// \param pfn pointer to function structure
/// \param frsize size of function local variables
/// \param frregs size of saved registers
/// \param argsize size of function arguments that will be purged
/// from the stack upon return
/// \return success
idaman bool ida_export set_frame_size(
func_t *pfn,
asize_t frsize,
ushort frregs,
asize_t argsize);
/// Get full size of a function frame.
/// This function takes into account size of local variables + size of
/// saved registers + size of return address + number of purged bytes.
/// The purged bytes correspond to the arguments of the functions with
/// __stdcall and __fastcall calling conventions.
/// \param pfn pointer to function structure, may be NULL
/// \return size of frame in bytes or zero
idaman asize_t ida_export get_frame_size(const func_t *pfn);
/// Get size of function return address.
/// \param pfn pointer to function structure, can't be NULL
idaman int ida_export get_frame_retsize(const func_t *pfn);
/// Parts of a frame
enum frame_part_t
{
FPC_ARGS,
FPC_RETADDR,
FPC_SAVREGS,
FPC_LVARS,
};
/// Get offsets of the frame part in the frame.
/// \param range pointer to the output buffer with the frame part
/// start/end(exclusive) offsets, can't be NULL
/// \param pfn pointer to function structure, can't be NULL
/// \param part frame part
idaman void ida_export get_frame_part(range_t *range, const func_t *pfn, frame_part_t part);
/// Get starting address of arguments section
inline ea_t frame_off_args(const func_t *pfn)
{
range_t range;
get_frame_part(&range, pfn, FPC_ARGS);
return range.start_ea;
}
/// Get starting address of return address section
inline ea_t frame_off_retaddr(const func_t *pfn)
{
range_t range;
get_frame_part(&range, pfn, FPC_RETADDR);
return range.start_ea;
}
/// Get starting address of saved registers section
inline ea_t frame_off_savregs(const func_t *pfn)
{
range_t range;
get_frame_part(&range, pfn, FPC_SAVREGS);
return range.start_ea;
}
/// Get start address of local variables section
inline ea_t frame_off_lvars(const func_t *pfn)
{
range_t range;
get_frame_part(&range, pfn, FPC_LVARS);
return range.start_ea;
}
/// Does the given offset lie within the arguments section?
inline bool processor_t::is_funcarg_off(const func_t *pfn, uval_t frameoff) const
{
range_t args;
get_frame_part(&args, pfn, FPC_ARGS);
return stkup()
? frameoff < args.end_ea
: frameoff >= args.start_ea;
}
/// Does the given offset lie within the local variables section?
inline sval_t processor_t::lvar_off(const func_t *pfn, uval_t frameoff) const
{
range_t lvars;
get_frame_part(&lvars, pfn, FPC_LVARS);
return stkup()
? frameoff - lvars.start_ea
: lvars.end_ea - frameoff;
}
/// Get pointer to function frame.
/// \param pfn pointer to function structure
idaman struc_t *ida_export get_frame(const func_t *pfn);
/// Get pointer to function frame.
/// \param ea any address in the function
inline struc_t *get_frame(ea_t ea) { return get_frame(get_func(ea)); }
/// Convert struct offsets into fp-relative offsets.
/// This function converts the offsets inside the struc_t object
/// into the frame pointer offsets (for example, EBP-relative).
inline sval_t soff_to_fpoff(func_t *pfn, uval_t soff)
{
return soff - pfn->frsize + pfn->fpd;
}
/// Update frame pointer delta.
/// \param pfn pointer to function structure
/// \param fpd new fpd value.
/// cannot be bigger than the local variable range size.
/// \return success
idaman bool ida_export update_fpd(func_t *pfn, asize_t fpd);
/// Set the number of purged bytes for a function or data item (funcptr).
/// This function will update the database and plan to reanalyze items
/// referencing the specified address. It works only for processors
/// with #PR_PURGING bit in 16 and 32 bit modes.
/// \param ea address of the function of item
/// \param nbytes number of purged bytes
/// \param override_old_value may overwrite old information about purged bytes
/// \return success
idaman bool ida_export set_purged(ea_t ea, int nbytes, bool override_old_value);
/// Get function by its frame id.
/// \warning this function works only with databases created by IDA > 5.6
/// \param frame_id id of the function frame
/// \return start address of the function or #BADADDR
idaman ea_t ida_export get_func_by_frame(tid_t frame_id);
//--------------------------------------------------------------------------
// S T A C K V A R I A B L E S
//--------------------------------------------------------------------------
/// Get pointer to stack variable.
/// \param actval actual value used to fetch stack variable
/// this pointer may point to 'v'
/// \param insn the instruction
/// \param x reference to instruction operand
/// \param v immediate value in the operand (usually x.addr)
/// \return NULL or ptr to stack variable
idaman member_t *ida_export get_stkvar(
sval_t *actval,
const insn_t &insn,
const op_t &x,
sval_t v);
/// Automatically add stack variable if doesn't exist.
/// Processor modules should use insn_t::create_stkvar().
/// \param insn the instruction
/// \param x reference to instruction operand
/// \param v immediate value in the operand (usually x.addr)
/// \param flags \ref STKVAR_1
/// \return success
idaman bool ida_export add_stkvar(const insn_t &insn, const op_t &x, sval_t v, int flags);
/// \defgroup STKVAR_1 Add stkvar flags
/// Passed as 'flags' parameter to add_stkvar()
//@{
#define STKVAR_VALID_SIZE 0x0001 ///< x.dtyp contains correct variable type
///< (for insns like 'lea' this bit must be off)
///< in general, dr_O references do not allow
///< to determine the variable size
//@}
/// Define/redefine a stack variable.
/// \param pfn pointer to function
/// \param name variable name, NULL means autogenerate a name
/// \param off offset of the stack variable in the frame.
/// negative values denote local variables, positive - function arguments.
/// \param flags variable type flags (byte_flag() for a byte variable, for example)
/// \param ti additional type information (like offsets, structs, etc)
/// \param nbytes number of bytes occupied by the variable
/// \return success
idaman bool ida_export define_stkvar(
func_t *pfn,
const char *name,
sval_t off,
flags_t flags,
const opinfo_t *ti,
asize_t nbytes);
/// Build automatic stack variable name.
/// \param buf pointer to buffer
/// \param pfn pointer to function (can't be NULL!)
/// \param v value of variable offset
/// \return length of stack variable name or -1
idaman ssize_t ida_export build_stkvar_name(
qstring *buf,
const func_t *pfn,
sval_t v);
/// Calculate offset of stack variable in the frame structure.
/// \param pfn pointer to function (can't be NULL!)
/// \param insn the instruction
/// \param n number of operand: (0..#UA_MAXOP-1)
/// -1 if error, return #BADADDR
/// \return #BADADDR if some error (issue a warning if stack frame is bad)
idaman ea_t ida_export calc_stkvar_struc_offset(
func_t *pfn,
const insn_t &insn,
int n);
/// Find and delete wrong frame info.
/// Namely, we delete:
/// - unreferenced stack variable definitions
/// - references to dead stack variables (i.e. operands displayed in red)
/// these operands will be untyped and most likely displayed in hex.
/// We also plan to reanalyze instruction with the stack frame references
/// \param pfn pointer to the function
/// \param should_reanalyze callback to determine which instructions to reanalyze
/// \return number of deleted definitions
idaman int ida_export delete_wrong_frame_info(
func_t *pfn,
bool idaapi should_reanalyze(const insn_t &insn));
//--------------------------------------------------------------------------
// R E G I S T E R V A R I A B L E S
//--------------------------------------------------------------------------
/// \defgroup regvar Register variables
/// Definition of ::regvar_t and related functions
//@{
idaman void ida_export free_regvar(struct regvar_t *v);
/// A register variable allows the user to rename a general processor register
/// to a meaningful name.
/// IDA doesn't check whether the target assembler supports the register renaming.
/// All register definitions will appear at the beginning of the function.
struct regvar_t : public range_t
{
char *canon = nullptr; ///< canonical register name (case-insensitive)
char *user = nullptr; ///< user-defined register name
char *cmt = nullptr; ///< comment to appear near definition
regvar_t() {}
regvar_t(const regvar_t &r) : range_t(r)
{
canon = ::qstrdup(r.canon);
user = ::qstrdup(r.user);
cmt = ::qstrdup(r.cmt);
}
~regvar_t() { free_regvar(this); }
regvar_t &operator=(const regvar_t &r)
{
if ( this != &r )
{
free_regvar(this);
new (this) regvar_t(r);
}
return *this;
}
void swap(regvar_t &r)
{
uchar buf[sizeof(*this)];
memcpy(buf, &r, sizeof(buf));
memcpy(&r, this, sizeof(buf));
memcpy(this, buf, sizeof(buf));
}
#ifndef SWIG
DECLARE_COMPARISONS(regvar_t);
#endif
};
DECLARE_TYPE_AS_MOVABLE(regvar_t);
/// Define a register variable.
/// \param pfn function in which the definition will be created
/// \param ea1,ea2 range of addresses within the function where the definition
/// will be used
/// \param canon name of a general register
/// \param user user-defined name for the register
/// \param cmt comment for the definition
/// \return \ref REGVAR_ERROR_
idaman int ida_export add_regvar(
func_t *pfn,
ea_t ea1,
ea_t ea2,
const char *canon,
const char *user,
const char *cmt);
/// \defgroup REGVAR_ERROR_ Register variable error codes
/// Return values for functions in described in \ref regvar
//@{
#define REGVAR_ERROR_OK 0 ///< all ok
#define REGVAR_ERROR_ARG (-1) ///< function arguments are bad
#define REGVAR_ERROR_RANGE (-2) ///< the definition range is bad
#define REGVAR_ERROR_NAME (-3) ///< the provided name(s) can't be accepted
//@}
/// Find a register variable definition (powerful version).
/// One of 'canon' and 'user' should be NULL.
/// If both 'canon' and 'user' are NULL it returns the first regvar
/// definition in the range.
/// \param pfn function in question
/// \param ea1,ea2 range of addresses to search.
/// ea1==BADADDR means the entire function
/// \param canon name of a general register
/// \param user user-defined name for the register
/// \return NULL-not found, otherwise ptr to regvar_t
idaman regvar_t *ida_export find_regvar(func_t *pfn, ea_t ea1, ea_t ea2, const char *canon, const char *user);
/// Find a register variable definition.
/// \param pfn function in question
/// \param ea current address
/// \param canon name of a general register
/// \return NULL-not found, otherwise ptr to regvar_t
inline regvar_t *find_regvar(func_t *pfn, ea_t ea, const char *canon)
{
return find_regvar(pfn, ea, ea+1, canon, NULL);
}
/// Is there a register variable definition?
/// \param pfn function in question
/// \param ea current address
inline bool has_regvar(func_t *pfn, ea_t ea)
{
return find_regvar(pfn, ea, ea+1, NULL, NULL) != NULL;
}
/// Rename a register variable.
/// \param pfn function in question
/// \param v variable to rename
/// \param user new user-defined name for the register
/// \return \ref REGVAR_ERROR_
idaman int ida_export rename_regvar(func_t *pfn, regvar_t *v, const char *user);
/// Set comment for a register variable.
/// \param pfn function in question
/// \param v variable to rename
/// \param cmt new comment
/// \return \ref REGVAR_ERROR_
idaman int ida_export set_regvar_cmt(func_t *pfn, regvar_t *v, const char *cmt);
/// Delete a register variable definition.
/// \param pfn function in question
/// \param ea1,ea2 range of addresses within the function where the definition holds
/// \param canon name of a general register
/// \return \ref REGVAR_ERROR_
idaman int ida_export del_regvar(func_t *pfn, ea_t ea1, ea_t ea2, const char *canon);
//@} regvar
//--------------------------------------------------------------------------
// S P R E G I S T E R C H A N G E P O I N T S
//--------------------------------------------------------------------------
/// Add automatic SP register change point.
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address where SP changes.
/// usually this is the end of the instruction which
/// modifies the stack pointer (\cmd{ea}+\cmd{size})
/// \param delta difference between old and new values of SP
/// \return success
idaman bool ida_export add_auto_stkpnt(func_t *pfn, ea_t ea, sval_t delta);
/// Add user-defined SP register change point.
/// \param ea linear address where SP changes
/// \param delta difference between old and new values of SP
/// \return success
idaman bool ida_export add_user_stkpnt(ea_t ea, sval_t delta);
/// Delete SP register change point.
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address
/// \return success
idaman bool ida_export del_stkpnt(func_t *pfn, ea_t ea);
/// Get difference between the initial and current values of ESP.
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address of an instruction
/// \return 0 or the difference, usually a negative number.
/// returns the sp-diff before executing the instruction.
idaman sval_t ida_export get_spd(func_t *pfn, ea_t ea);
/// Get effective difference between the initial and current values of ESP.
/// This function returns the sp-diff used by the instruction.
/// The difference between get_spd() and get_effective_spd() is present only
/// for instructions like "pop [esp+N]": they modify sp and use the modified value.
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address
/// \return 0 or the difference, usually a negative number
idaman sval_t ida_export get_effective_spd(func_t *pfn, ea_t ea);
/// Get modification of SP made at the specified location
/// \param pfn pointer to function. may be NULL.
/// \param ea linear address
/// \return 0 if the specified location doesn't contain a SP change point.
/// otherwise return delta of SP modification.
idaman sval_t ida_export get_sp_delta(func_t *pfn, ea_t ea);
/// Recalculate SP delta for an instruction that stops execution.
/// The next instruction is not reached from the current instruction.
/// We need to recalculate SP for the next instruction.
///
/// This function will create a new automatic SP register change
/// point if necessary. It should be called from the emulator (emu.cpp)
/// when auto_state == ::AU_USED if the current instruction doesn't pass
/// the execution flow to the next instruction.
/// \param cur_ea linear address of the current instruction
/// \retval 1 new stkpnt is added
/// \retval 0 nothing is changed
idaman bool ida_export recalc_spd(ea_t cur_ea);
/// An xref to an argument or variable located in a function's stack frame
struct xreflist_entry_t
{
ea_t ea; ///< Location of the insn referencing the stack frame member
uchar opnum; ///< Number of the operand of that instruction
uchar type; ///< The type of xref (::cref_t & ::dref_t)
DECLARE_COMPARISONS(xreflist_entry_t)
{
int code = ::compare(ea, r.ea);
if ( code == 0 )
{
code = ::compare(type, r.type);
if ( code == 0 )
code = ::compare(opnum, r.opnum);
}
return code;
}
};
DECLARE_TYPE_AS_MOVABLE(xreflist_entry_t);
typedef qvector<xreflist_entry_t> xreflist_t; ///< vector of xrefs to variables in a function's stack frame
/// Fill 'out' with a list of all the xrefs made from function 'pfn', to
/// the argument or variable 'mptr' in 'pfn's stack frame.
/// \param out the list of xrefs to fill.
/// \param pfn the function to scan.
/// \param mptr the argument/variable in pfn's stack frame.
idaman void ida_export build_stkvar_xrefs(xreflist_t *out, func_t *pfn, const member_t *mptr);
#ifndef NO_OBSOLETE_FUNCS
idaman DEPRECATED ea_t ida_export get_min_spd_ea(func_t *pfn);
idaman DEPRECATED int ida_export delete_unreferenced_stkvars(func_t *pfn);
idaman DEPRECATED int ida_export delete_wrong_stkvar_ops(func_t *pfn);
#endif
#endif // _FRAME_HPP

984
idasdk76/include/funcs.hpp Normal file
View File

@@ -0,0 +1,984 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef FUNCS_HPP
#define FUNCS_HPP
#include <range.hpp>
#include <bytes.hpp>
/*! \file funcs.hpp
\brief Routines for working with functions within the disassembled program.
This file also contains routines for working with library signatures
(e.g. FLIRT).
Each function consists of function chunks. At least one function chunk
must be present in the function definition - the function entry chunk.
Other chunks are called function tails. There may be several of them
for a function.
A function tail is a continuous range of addresses.
It can be used in the definition of one or more functions.
One function using the tail is singled out and called the tail owner.
This function is considered as 'possessing' the tail.
get_func() on a tail address will return the function possessing the tail.
You can enumerate the functions using the tail by using ::func_parent_iterator_t.
Each function chunk in the disassembly is represented as an "range" (a range
of addresses, see range.hpp for details) with characteristics.
A function entry must start with an instruction (code) byte.
*/
struct stkpnt_t; // #include <frame.hpp>
struct regvar_t; // #include <frame.hpp>
struct llabel_t; // #include <frame.hpp>
class insn_t; // #include <ua.hpp>
idaman void ida_export free_regarg(struct regarg_t *v);
/// Register argument description.
/// regargs are destroyed when the full function type is determined.
struct regarg_t
{
int reg = 0;
type_t *type = nullptr;
char *name = nullptr;
regarg_t() {}
regarg_t(const regarg_t &r) : reg(r.reg)
{
type = (type_t *)::qstrdup((char *)r.type);
name = ::qstrdup(r.name);
}
~regarg_t() { free_regarg(this); }
regarg_t &operator=(const regarg_t &r)
{
if ( this != &r )
{
free_regarg(this);
new (this) regarg_t(r);
}
return *this;
}
void swap(regarg_t &r)
{
std::swap(reg, r.reg);
std::swap(type, r.type);
std::swap(name, r.name);
}
#ifndef SWIG
DECLARE_COMPARISONS(regarg_t);
#endif
};
DECLARE_TYPE_AS_MOVABLE(regarg_t);
//------------------------------------------------------------------------
/// A function is a set of continuous ranges of addresses with characteristics
class func_t : public range_t
{
public:
uint64 flags; ///< \ref FUNC_
/// \defgroup FUNC_ Function flags
/// Used by func_t::flags
//@{
#define FUNC_NORET 0x00000001 ///< Function doesn't return
#define FUNC_FAR 0x00000002 ///< Far function
#define FUNC_LIB 0x00000004 ///< Library function
#define FUNC_STATICDEF 0x00000008 ///< Static function
#define FUNC_FRAME 0x00000010 ///< Function uses frame pointer (BP)
#define FUNC_USERFAR 0x00000020 ///< User has specified far-ness
///< of the function
#define FUNC_HIDDEN 0x00000040 ///< A hidden function chunk
#define FUNC_THUNK 0x00000080 ///< Thunk (jump) function
#define FUNC_BOTTOMBP 0x00000100 ///< BP points to the bottom of the stack frame
#define FUNC_NORET_PENDING 0x00200 ///< Function 'non-return' analysis must be performed.
///< This flag is verified upon func_does_return()
#define FUNC_SP_READY 0x00000400 ///< SP-analysis has been performed.
///< If this flag is on, the stack
///< change points should not be not
///< modified anymore. Currently this
///< analysis is performed only for PC
#define FUNC_FUZZY_SP 0x00000800 ///< Function changes SP in untraceable way,
///< for example: and esp, 0FFFFFFF0h
#define FUNC_PROLOG_OK 0x00001000 ///< Prolog analysis has be performed
///< by last SP-analysis
#define FUNC_PURGED_OK 0x00004000 ///< 'argsize' field has been validated.
///< If this bit is clear and 'argsize'
///< is 0, then we do not known the real
///< number of bytes removed from
///< the stack. This bit is handled
///< by the processor module.
#define FUNC_TAIL 0x00008000 ///< This is a function tail.
///< Other bits must be clear
///< (except #FUNC_HIDDEN).
#define FUNC_LUMINA 0x00010000 ///< Function info is provided by Lumina.
#define FUNC_RESERVED 0x8000000000000000LL ///< Reserved (for internal usage)
//@}
/// Is a far function?
bool is_far(void) const { return (flags & FUNC_FAR) != 0; }
/// Does function return?
bool does_return(void) const { return (flags & FUNC_NORET) == 0; }
/// Has SP-analysis been performed?
bool analyzed_sp(void) const { return (flags & FUNC_SP_READY) != 0; }
/// Needs prolog analysis?
bool need_prolog_analysis(void) const { return (flags & FUNC_PROLOG_OK) == 0; }
#ifndef SWIG
union
{
/// attributes of a function entry chunk
struct
{
#endif // SWIG
//
// Stack frame of the function. It is represented as a structure:
//
// +------------------------------------------------+
// | function arguments |
// +------------------------------------------------+
// | return address (isn't stored in func_t) |
// +------------------------------------------------+
// | saved registers (SI, DI, etc - func_t::frregs) |
// +------------------------------------------------+ <- typical BP
// | | |
// | | | func_t::fpd
// | | |
// | | <- real BP
// | local variables (func_t::frsize) |
// | |
// | |
// +------------------------------------------------+ <- SP
//
uval_t frame; ///< netnode id of frame structure - see frame.hpp
asize_t frsize; ///< size of local variables part of frame in bytes.
///< If #FUNC_FRAME is set and #fpd==0, the frame pointer
///< (EBP) is assumed to point to the top of the local
///< variables range.
ushort frregs; ///< size of saved registers in frame. This range is
///< immediately above the local variables range.
asize_t argsize; ///< number of bytes purged from the stack
///< upon returning
asize_t fpd; ///< frame pointer delta. (usually 0, i.e. realBP==typicalBP)
///< use update_fpd() to modify it.
bgcolor_t color; ///< user defined function color
// the following fields should not be accessed directly:
uint32 pntqty; ///< number of SP change points
stkpnt_t *points; ///< array of SP change points.
///< use ...stkpnt...() functions to access this array.
int regvarqty; ///< number of register variables (-1-not read in yet)
///< use find_regvar() to read register variables
regvar_t *regvars; ///< array of register variables.
///< this array is sorted by: start_ea.
///< use ...regvar...() functions to access this array.
int llabelqty; ///< number of local labels
llabel_t *llabels; ///< local labels.
///< this array shouldn't be accessed directly; name.hpp
///< functions should be used instead.
int regargqty; ///< number of register arguments.
///< During analysis IDA tries to guess the register
///< arguments. It stores store the guessing outcome
///< in this field. As soon as it determines the final
///< function prototype, regargqty is set to zero.
regarg_t *regargs; ///< unsorted array of register arguments.
///< use ...regarg...() functions to access this array.
///< regargs are destroyed when the full function
///< type is determined.
int tailqty; ///< number of function tails
range_t *tails; ///< array of tails, sorted by ea.
///< use func_tail_iterator_t to access function tails.
#ifndef SWIG
};
/// attributes of a function tail chunk
struct
{
#endif // SWIG
ea_t owner; ///< the address of the main function possessing this tail
int refqty; ///< number of referers
ea_t *referers; ///< array of referers (function start addresses).
///< use func_parent_iterator_t to access the referers.
#ifndef SWIG
};
};
#endif // SWIG
func_t(ea_t start=0, ea_t end=0, flags_t f=0)
: range_t(start, end), flags(f|FUNC_NORET_PENDING), frame(BADNODE),
frsize(0), frregs(0), argsize(0), fpd(0), color(DEFCOLOR),
pntqty(0), points(nullptr),
regvarqty(0), regvars(nullptr),
llabelqty(0), llabels(nullptr),
regargqty(0), regargs(nullptr),
tailqty(0), tails(nullptr)
{
}
#ifndef SWIG
DECLARE_COMPARISONS(func_t);
#endif
};
DECLARE_TYPE_AS_MOVABLE(func_t);
/// Does function describe a function entry chunk?
inline bool is_func_entry(const func_t *pfn) { return pfn != nullptr && (pfn->flags & FUNC_TAIL) == 0; }
/// Does function describe a function tail chunk?
inline bool is_func_tail(const func_t *pfn) { return pfn != nullptr && (pfn->flags & FUNC_TAIL) != 0; }
/// Lock function pointer
/// Locked pointers are guaranteed to remain valid until they are unlocked.
/// Ranges with locked pointers cannot be deleted or moved.
idaman void ida_export lock_func_range(const func_t *pfn, bool lock);
/// Helper class to lock a function pointer so it stays valid
class lock_func
{
const func_t *pfn;
public:
lock_func(const func_t *_pfn) : pfn(_pfn)
{
lock_func_range(pfn, true);
}
~lock_func(void)
{
lock_func_range(pfn, false);
}
};
/// Is the function pointer locked?
idaman bool ida_export is_func_locked(const func_t *pfn);
//--------------------------------------------------------------------
// F U N C T I O N S
//--------------------------------------------------------------------
/// Get pointer to function structure by address.
/// \param ea any address in a function
/// \return ptr to a function or nullptr.
/// This function returns a function entry chunk.
idaman func_t *ida_export get_func(ea_t ea);
/// Get the containing tail chunk of 'ea'.
/// \retval -1 means 'does not contain ea'
/// \retval 0 means the 'pfn' itself contains ea
/// \retval >0 the number of the containing function tail chunk
idaman int ida_export get_func_chunknum(func_t *pfn, ea_t ea);
/// Does the given function contain the given address?
inline bool func_contains(func_t *pfn, ea_t ea)
{
return get_func_chunknum(pfn, ea) >= 0;
}
/// Do two addresses belong to the same function?
inline bool is_same_func(ea_t ea1, ea_t ea2)
{
func_t *pfn = get_func(ea1);
return pfn != nullptr && func_contains(pfn, ea2);
}
/// Get pointer to function structure by number.
/// \param n number of function, is in range 0..get_func_qty()-1
/// \return ptr to a function or nullptr.
/// This function returns a function entry chunk.
idaman func_t *ida_export getn_func(size_t n);
/// Get total number of functions in the program
idaman size_t ida_export get_func_qty(void);
/// Get ordinal number of a function.
/// \param ea any address in the function
/// \return number of function (0..get_func_qty()-1).
/// -1 means 'no function at the specified address'.
idaman int ida_export get_func_num(ea_t ea);
/// Get pointer to the previous function.
/// \param ea any address in the program
/// \return ptr to function or nullptr if previous function doesn't exist
idaman func_t *ida_export get_prev_func(ea_t ea);
/// Get pointer to the next function.
/// \param ea any address in the program
/// \return ptr to function or nullptr if next function doesn't exist
idaman func_t *ida_export get_next_func(ea_t ea);
/// Get function ranges.
/// \param ranges buffer to receive the range info
/// \param pfn ptr to function structure
/// \return end address of the last function range (BADADDR-error)
idaman ea_t ida_export get_func_ranges(rangeset_t *ranges, func_t *pfn);
/// Get function comment.
/// \param buf buffer for the comment
/// \param pfn ptr to function structure
/// \param repeatable get repeatable comment?
/// \return size of comment or -1
/// In fact this function works with function chunks too.
idaman ssize_t ida_export get_func_cmt(qstring *buf, const func_t *pfn, bool repeatable);
/// Set function comment.
/// This function works with function chunks too.
/// \param pfn ptr to function structure
/// \param cmt comment string, may be multiline (with '\n').
/// Use empty str ("") to delete comment
/// \param repeatable set repeatable comment?
idaman bool ida_export set_func_cmt(const func_t *pfn, const char *cmt, bool repeatable);
/// Update information about a function in the database (::func_t).
/// You must not change the function start and end addresses using this function.
/// Use set_func_start() and set_func_end() for it.
/// \param pfn ptr to function structure
/// \return success
idaman bool ida_export update_func(func_t *pfn);
/// Add a new function.
/// If the fn->end_ea is #BADADDR, then IDA will try to determine the
/// function bounds by calling find_func_bounds(..., #FIND_FUNC_DEFINE).
/// \param pfn ptr to filled function structure
/// \return success
idaman bool ida_export add_func_ex(func_t *pfn);
/// Add a new function.
/// If the function end address is #BADADDR, then IDA will try to determine
/// the function bounds by calling find_func_bounds(..., #FIND_FUNC_DEFINE).
/// \param ea1 start address
/// \param ea2 end address
/// \return success
inline bool add_func(ea_t ea1, ea_t ea2=BADADDR)
{
func_t fn(ea1, ea2);
return add_func_ex(&fn);
}
/// Delete a function.
/// \param ea any address in the function entry chunk
/// \return success
idaman bool ida_export del_func(ea_t ea);
/// Move function chunk start address.
/// \param ea any address in the function
/// \param newstart new end address of the function
/// \return \ref MOVE_FUNC_
idaman int ida_export set_func_start(ea_t ea, ea_t newstart);
/// \defgroup MOVE_FUNC_ Function move result codes
/// Return values for set_func_start()
//@{
#define MOVE_FUNC_OK 0 ///< ok
#define MOVE_FUNC_NOCODE 1 ///< no instruction at 'newstart'
#define MOVE_FUNC_BADSTART 2 ///< bad new start address
#define MOVE_FUNC_NOFUNC 3 ///< no function at 'ea'
#define MOVE_FUNC_REFUSED 4 ///< a plugin refused the action
//@}
/// Move function chunk end address.
/// \param ea any address in the function
/// \param newend new end address of the function
/// \return success
idaman bool ida_export set_func_end(ea_t ea, ea_t newend);
/// Reanalyze a function.
/// This function plans to analyzes all chunks of the given function.
/// Optional parameters (ea1, ea2) may be used to narrow the analyzed range.
/// \param pfn pointer to a function
/// \param ea1 start of the range to analyze
/// \param ea2 end of range to analyze
/// \param analyze_parents meaningful only if pfn points to a function tail.
/// if true, all tail parents will be reanalyzed.
/// if false, only the given tail will be reanalyzed.
idaman void ida_export reanalyze_function(
func_t *pfn,
ea_t ea1=0,
ea_t ea2=BADADDR,
bool analyze_parents=false);
/// Determine the boundaries of a new function.
/// This function tries to find the start and end addresses of a new function.
/// It calls the module with \ph{func_bounds} in order to fine tune
/// the function boundaries.
/// \param nfn structure to fill with information
/// \ nfn->start_ea points to the start address of the new function.
/// \param flags \ref FIND_FUNC_F
/// \return \ref FIND_FUNC_R
idaman int ida_export find_func_bounds(func_t *nfn, int flags);
/// \defgroup FIND_FUNC_F Find function bounds flags
/// Passed as 'flags' parameter to find_func_bounds()
//@{
#define FIND_FUNC_NORMAL 0x0000 ///< stop processing if undefined byte is encountered
#define FIND_FUNC_DEFINE 0x0001 ///< create instruction if undefined byte is encountered
#define FIND_FUNC_IGNOREFN 0x0002 ///< ignore existing function boundaries.
///< by default the function returns function boundaries
///< if ea belongs to a function.
#define FIND_FUNC_KEEPBD 0x0004 ///< do not modify incoming function boundaries,
///< just create instructions inside the boundaries.
//@}
/// \defgroup FIND_FUNC_R Find function bounds result codes
/// Return values for find_func_bounds()
//@{
#define FIND_FUNC_UNDEF 0 ///< function has instructions that pass execution flow to unexplored bytes.
///< nfn->end_ea will have the address of the unexplored byte.
#define FIND_FUNC_OK 1 ///< ok, 'nfn' is ready for add_func()
#define FIND_FUNC_EXIST 2 ///< function exists already.
///< its bounds are returned in 'nfn'.
//@}
/// Get function name.
/// \param out buffer for the answer
/// \param ea any address in the function
/// \return length of the function name
idaman ssize_t ida_export get_func_name(qstring *out, ea_t ea);
/// Calculate function size.
/// This function takes into account all fragments of the function.
/// \param pfn ptr to function structure
idaman asize_t ida_export calc_func_size(func_t *pfn);
/// Get function bitness (which is equal to the function segment bitness).
/// pfn==nullptr => returns 0
/// \retval 0 16
/// \retval 1 32
/// \retval 2 64
idaman int ida_export get_func_bitness(const func_t *pfn);
/// Get number of bits in the function addressing
inline int idaapi get_func_bits(const func_t *pfn) { return 1 << (get_func_bitness(pfn)+4); }
/// Get number of bytes in the function addressing
inline int idaapi get_func_bytes(const func_t *pfn) { return get_func_bits(pfn)/8; }
/// Is the function visible (not hidden)?
inline bool is_visible_func(func_t *pfn) { return (pfn->flags & FUNC_HIDDEN) == 0; }
/// Is the function visible (event after considering #SCF_SHHID_FUNC)?
inline bool is_finally_visible_func(func_t *pfn)
{
return (inf_get_cmtflg() & SCF_SHHID_FUNC) != 0 || is_visible_func(pfn);
}
/// Set visibility of function
idaman void ida_export set_visible_func(func_t *pfn, bool visible);
/// Give a meaningful name to function if it consists of only 'jump' instruction.
/// \param pfn pointer to function (may be nullptr)
/// \param oldname old name of function.
/// if old name was in "j_..." form, then we may discard it
/// and set a new name.
/// if oldname is not known, you may pass nullptr.
/// \return success
idaman int ida_export set_func_name_if_jumpfunc(func_t *pfn, const char *oldname);
/// Calculate target of a thunk function.
/// \param pfn pointer to function (may not be nullptr)
/// \param fptr out: will hold address of a function pointer (if indirect jump)
/// \return the target function or #BADADDR
idaman ea_t ida_export calc_thunk_func_target(func_t *pfn, ea_t *fptr);
/// Does the function return?.
/// To calculate the answer, #FUNC_NORET flag and is_noret() are consulted
/// The latter is required for imported functions in the .idata section.
/// Since in .idata we have only function pointers but not functions, we have
/// to introduce a special flag for them.
idaman bool ida_export func_does_return(ea_t callee);
/// Plan to reanalyze noret flag.
/// This function does not remove FUNC_NORET if it is already present.
/// It just plans to reanalysis.
idaman bool ida_export reanalyze_noret_flag(ea_t ea);
/// Signal a non-returning instruction.
/// This function can be used by the processor module to tell the kernel
/// about non-returning instructions (like call exit). The kernel will
/// perform the global function analysis and find out if the function
/// returns at all. This analysis will be done at the first call to func_does_return()
/// \return true if the instruction 'noret' flag has been changed
idaman bool ida_export set_noret_insn(ea_t insn_ea, bool noret);
//--------------------------------------------------------------------
// F U N C T I O N C H U N K S
//--------------------------------------------------------------------
/// Get pointer to function chunk structure by address.
/// \param ea any address in a function chunk
/// \return ptr to a function chunk or nullptr.
/// This function may return a function entry as well as a function tail.
idaman func_t *ida_export get_fchunk(ea_t ea);
/// Get pointer to function chunk structure by number.
/// \param n number of function chunk, is in range 0..get_fchunk_qty()-1
/// \return ptr to a function chunk or nullptr.
/// This function may return a function entry as well as a function tail.
idaman func_t *ida_export getn_fchunk(int n);
/// Get total number of function chunks in the program
idaman size_t ida_export get_fchunk_qty(void);
/// Get ordinal number of a function chunk in the global list of function chunks.
/// \param ea any address in the function chunk
/// \return number of function chunk (0..get_fchunk_qty()-1).
/// -1 means 'no function chunk at the specified address'.
idaman int ida_export get_fchunk_num(ea_t ea);
/// Get pointer to the previous function chunk in the global list.
/// \param ea any address in the program
/// \return ptr to function chunk or nullptr if previous function chunk doesn't exist
idaman func_t *ida_export get_prev_fchunk(ea_t ea);
/// Get pointer to the next function chunk in the global list.
/// \param ea any address in the program
/// \return ptr to function chunk or nullptr if next function chunk doesn't exist
idaman func_t *ida_export get_next_fchunk(ea_t ea);
//--------------------------------------------------------------------
// Functions to manipulate function chunks
/// Append a new tail chunk to the function definition.
/// If the tail already exists, then it will simply be added to the function tail list
/// Otherwise a new tail will be created and its owner will be set to be our function
/// If a new tail cannot be created, then this function will fail.
/// \param ea1 start of the tail. If a tail already exists at the specified address
/// it must start at 'ea1'
/// \param ea2 end of the tail. If a tail already exists at the specified address
/// it must end at 'ea2'. If specified as BADADDR, IDA will determine
/// the end address itself.
idaman bool ida_export append_func_tail(func_t *pfn, ea_t ea1, ea_t ea2);
/// Remove a function tail.
/// If the tail belongs only to one function, it will be completely removed.
/// Otherwise if the function was the tail owner, the first function using
/// this tail becomes the owner of the tail.
idaman bool ida_export remove_func_tail(func_t *pfn, ea_t tail_ea);
/// Set a function as the possessing function of a function tail.
/// The function should already refer to the tail (after append_func_tail).
idaman bool ida_export set_tail_owner(func_t *fnt, ea_t func_start);
// Auxiliary function(s) to be used in func_..._iterator_t
class func_parent_iterator_t;
class func_tail_iterator_t;
class func_item_iterator_t;
/// Declare helper functions for ::func_item_iterator_t
#define DECLARE_FUNC_ITERATORS(prefix) \
prefix bool ida_export func_tail_iterator_set(func_tail_iterator_t *fti, func_t *pfn, ea_t ea);\
prefix bool ida_export func_tail_iterator_set_ea(func_tail_iterator_t *fti, ea_t ea);\
prefix bool ida_export func_parent_iterator_set(func_parent_iterator_t *fpi, func_t *pfn);\
prefix bool ida_export func_item_iterator_next(func_item_iterator_t *fii, testf_t *testf, void *ud);\
prefix bool ida_export func_item_iterator_prev(func_item_iterator_t *fii, testf_t *testf, void *ud);\
prefix bool ida_export func_item_iterator_decode_prev_insn(func_item_iterator_t *fii, insn_t *out); \
prefix bool ida_export func_item_iterator_decode_preceding_insn(func_item_iterator_t *fii, eavec_t *visited, bool *p_farref, insn_t *out);
DECLARE_FUNC_ITERATORS(idaman)
/// Helper function to accept any address
inline THREAD_SAFE bool idaapi f_any(flags_t, void *) { return true; }
/// Class to enumerate all function tails sorted by addresses.
/// Enumeration is started with main(), first(), or last().
/// If first() is used, the function entry chunk will be excluded from the enumeration.
/// Otherwise it will be included in the enumeration (for main() and last()).
/// The loop may continue until the next() or prev() function returns false.
/// These functions return false when the enumeration is over.
/// The tail chunks are always sorted by their addresses.
///
/// Sample code:
/// \code
/// func_tail_iterator_t fti(pfn);
/// for ( bool ok=fti.first(); ok; ok=fti.next() )
/// const range_t &a = fti.chunk();
/// ....
/// \endcode
///
/// If the 'ea' parameter is used in the constructor, then the iterator is positioned
/// at the chunk containing the specified 'ea'. Otherwise it is positioned at the
/// function entry chunk.
/// If 'pfn' is specified as nullptr then the set() function will fail,
/// but it is still possible to use the class. In this case the iteration will be
/// limited by the segment boundaries.
/// The function main chunk is locked during the iteration.
/// It is also possible to enumerate one single arbitrary range using set_range()
/// This function is mainly designed to be used from ::func_item_iterator_t.
class func_tail_iterator_t
{
func_t *pfn;
int idx;
range_t seglim; // valid and used only if pfn == nullptr
public:
func_tail_iterator_t(void) : pfn(nullptr), idx(-1) {}
func_tail_iterator_t(func_t *_pfn, ea_t ea=BADADDR) : pfn(nullptr) { set(_pfn, ea); }
~func_tail_iterator_t(void)
{
// if was iterating over function chunks, unlock the main chunk
if ( pfn != nullptr )
lock_func_range(pfn, false);
}
bool set(func_t *_pfn, ea_t ea=BADADDR) { return func_tail_iterator_set(this, _pfn, ea); }
bool set_ea(ea_t ea) { return func_tail_iterator_set_ea(this, ea); }
// set an arbitrary range
bool set_range(ea_t ea1, ea_t ea2)
{
this->~func_tail_iterator_t();
pfn = nullptr;
idx = -1;
seglim = range_t(ea1, ea2);
return !seglim.empty();
}
const range_t &chunk(void) const
{
if ( pfn == nullptr )
return seglim;
return idx >= 0 && idx < pfn->tailqty ? pfn->tails[idx] : *(range_t*)pfn;
}
bool first(void) { if ( pfn != nullptr ) { idx = 0; return pfn->tailqty > 0; } return false; } // get only tail chunks
bool last(void) { if ( pfn != nullptr ) { idx = pfn->tailqty - 1; return true; } return false; } // get all chunks (the entry chunk last)
bool next(void) { if ( pfn != nullptr && idx+1 < pfn->tailqty ) { idx++; return true; } return false; }
bool prev(void) { if ( idx >= 0 ) { idx--; return true; } return false; }
bool main(void) { idx = -1; return pfn != nullptr; } // get all chunks (the entry chunk first)
};
/// Function to iterate function chunks (all of them including the entry chunk)
/// \param pfn pointer to the function
/// \param func function to call for each chunk
/// \param ud user data for 'func'
/// \param include_parents meaningful only if pfn points to a function tail.
/// if true, all tail parents will be iterated.
/// if false, only the given tail will be iterated.
idaman void ida_export iterate_func_chunks(
func_t *pfn,
void (idaapi *func)(ea_t ea1, ea_t ea2, void *ud),
void *ud=nullptr,
bool include_parents=false);
/// Class to enumerate all function instructions and data sorted by addresses.
/// The function entry chunk items are enumerated first regardless of their addresses
///
/// Sample code:
/// \code
/// func_item_iterator_t fii;
/// for ( bool ok=fii.set(pfn, ea); ok; ok=fii.next_addr() )
/// ea_t ea = fii.current();
/// ....
/// \endcode
///
/// If 'ea' is not specified in the call to set(), then the enumeration starts at
/// the function entry point.
/// If 'pfn' is specified as nullptr then the set() function will fail,
/// but it is still possible to use the class. In this case the iteration will be
/// limited by the segment boundaries.
/// It is also possible to enumerate addresses in an arbitrary range using set_range().
class func_item_iterator_t
{
func_tail_iterator_t fti;
ea_t ea;
public:
func_item_iterator_t(void) : ea(BADADDR) {}
func_item_iterator_t(func_t *pfn, ea_t _ea=BADADDR) { set(pfn, _ea); }
/// Set a function range. if pfn == nullptr then a segment range will be set.
bool set(func_t *pfn, ea_t _ea=BADADDR)
{
ea = (_ea != BADADDR || pfn == nullptr) ? _ea : pfn->start_ea;
return fti.set(pfn, _ea);
}
/// Set an arbitrary range
bool set_range(ea_t ea1, ea_t ea2) { ea = ea1; return fti.set_range(ea1, ea2); }
bool first(void) { if ( !fti.main() ) return false; ea=fti.chunk().start_ea; return true; }
bool last(void) { if ( !fti.last() ) return false; ea=fti.chunk().end_ea; return true; }
ea_t current(void) const { return ea; }
const range_t &chunk(void) const { return fti.chunk(); }
bool next(testf_t *func, void *ud) { return func_item_iterator_next(this, func, ud); }
bool prev(testf_t *func, void *ud) { return func_item_iterator_prev(this, func, ud); }
bool next_addr(void) { return next(f_any, nullptr); }
bool next_head(void) { return next(f_is_head, nullptr); }
bool next_code(void) { return next(f_is_code, nullptr); }
bool next_data(void) { return next(f_is_data, nullptr); }
bool next_not_tail(void) { return next(f_is_not_tail, nullptr); }
bool prev_addr(void) { return prev(f_any, nullptr); }
bool prev_head(void) { return prev(f_is_head, nullptr); }
bool prev_code(void) { return prev(f_is_code, nullptr); }
bool prev_data(void) { return prev(f_is_data, nullptr); }
bool prev_not_tail(void) { return prev(f_is_not_tail, nullptr); }
bool decode_prev_insn(insn_t *out) { return func_item_iterator_decode_prev_insn(this, out); }
bool decode_preceding_insn(eavec_t *visited, bool *p_farref, insn_t *out)
{ return func_item_iterator_decode_preceding_insn(this, visited, p_farref, out); }
};
/// Class to enumerate all function parents sorted by addresses.
/// Enumeration is started with first() or last().
/// The loop may continue until the next() or prev() function returns false.
/// The parent functions are always sorted by their addresses.
/// The tail chunk is locked during the iteration.
///
/// Sample code:
/// \code
/// func_parent_iterator_t fpi(fnt);
/// for ( bool ok=fpi.first(); ok; ok=fpi.next() )
/// ea_t parent = fpi.parent();
/// ....
/// \endcode
class func_parent_iterator_t
{
func_t *fnt;
int idx;
public:
func_parent_iterator_t(void) : fnt(nullptr), idx(0) {}
func_parent_iterator_t(func_t *_fnt) : fnt(nullptr) { set(_fnt); }
~func_parent_iterator_t(void)
{
if ( fnt != nullptr )
lock_func_range(fnt, false);
}
bool set(func_t *_fnt) { return func_parent_iterator_set(this, _fnt); }
ea_t parent(void) const { return fnt->referers[idx]; }
bool first(void) { idx = 0; return is_func_tail(fnt) && fnt->refqty > 0; }
bool last(void) { idx = fnt->refqty - 1; return idx >= 0; }
bool next(void) { if ( idx+1 < fnt->refqty ) { idx++; return true; } return false; }
bool prev(void) { if ( idx > 0 ) { idx--; return true; } return false; }
void reset_fnt(func_t *_fnt) { fnt = _fnt; } // for internal use only!
};
/// \name Get prev/next address in function
/// Unlike func_item_iterator_t which always enumerates the main function
/// chunk first, these functions respect linear address ordering.
//@{
idaman ea_t ida_export get_prev_func_addr(func_t *pfn, ea_t ea);
idaman ea_t ida_export get_next_func_addr(func_t *pfn, ea_t ea);
//@}
//--------------------------------------------------------------------
/// \name
/// Functions to work with temporary register argument definitions
//@{
idaman void ida_export read_regargs(func_t *pfn);
idaman void ida_export add_regarg(func_t *pfn, int reg, const tinfo_t &tif, const char *name);
//@}
//--------------------------------------------------------------------
// L I B R A R Y M O D U L E S I G N A T U R E S
//--------------------------------------------------------------------
/// \defgroup IDASGN_ Error codes for signature functions:
/// See calc_idasgn_state() and del_idasgn()
//@{
#define IDASGN_OK 0 ///< ok
#define IDASGN_BADARG 1 ///< bad number of signature
#define IDASGN_APPLIED 2 ///< signature is already applied
#define IDASGN_CURRENT 3 ///< signature is currently being applied
#define IDASGN_PLANNED 4 ///< signature is planned to be applied
//@}
/// Add a signature file to the list of planned signature files.
/// \param fname file name. should not contain directory part.
/// \return 0 if failed, otherwise number of planned (and applied) signatures
idaman int ida_export plan_to_apply_idasgn(const char *fname); // plan to use library
/// Apply a signature file to the specified address.
/// \param signame short name of signature file (the file name without path)
/// \param ea address to apply the signature
/// \param is_startup if set, then the signature is treated as a startup one
/// for startup signature ida doesn't rename the first
/// function of the applied module.
/// \return \ref LIBFUNC_
idaman int ida_export apply_idasgn_to(const char *signame, ea_t ea, bool is_startup);
/// Get number of signatures in the list of planned and applied signatures.
/// \return 0..n
idaman int ida_export get_idasgn_qty(void);
/// Get number of the the current signature.
/// \return 0..n-1
idaman int ida_export get_current_idasgn(void);
/// Get state of a signature in the list of planned signatures
/// \param n number of signature in the list (0..get_idasgn_qty()-1)
/// \return state of signature or #IDASGN_BADARG
idaman int ida_export calc_idasgn_state(int n);
/// Remove signature from the list of planned signatures.
/// \param n number of signature in the list (0..get_idasgn_qty()-1)
/// \return #IDASGN_OK, #IDASGN_BADARG, #IDASGN_APPLIED
idaman int ida_export del_idasgn(int n);
/// Get information about a signature in the list.
/// \param signame buffer for the name of the signature.
/// (short form, only base name without the directory part
/// will be stored).
/// if signame == nullptr, then the name won't be returned.
/// \param optlibs buffer for the names of the optional libraries
/// if optlibs == nullptr, then the optional libraries are not returned
/// \param n number of signature in the list (0..get_idasgn_qty()-1)
/// \return number of successfully recognized modules using this signature.
/// -1 means the 'n' is a bad argument, i.e. no signature with this
/// number exists..
idaman int32 ida_export get_idasgn_desc(
qstring *signame,
qstring *optlibs,
int n);
class idasgn_t;
/// Get idasgn header by a short signature name.
/// \param name short name of a signature
/// \return nullptr if can't find the signature
idaman idasgn_t *ida_export get_idasgn_header_by_short_name(const char *name);
/// Get full description of the signature by its short name.
/// \param buf the output buffer
/// \param name short name of a signature
/// \return size of signature description or -1
idaman ssize_t ida_export get_idasgn_title(
qstring *buf,
const char *name);
/// Determine compiler/vendor using the startup signatures.
/// If determined, then appropriate signature files are included into
/// the list of planned signature files.
idaman void ida_export determine_rtl(void);
/// Apply a startup signature file to the specified address.
/// \param ea address to apply the signature to; usually \inf{start_ea}
/// \param startup the name of the signature file without path and extension
/// \return true if successfully applied the signature
idaman bool ida_export apply_startup_sig(ea_t ea, const char *startup);
/// Apply the currently loaded signature file to the specified address.
/// If a library function is found, then create a function and name
/// it accordingly.
/// \param ea any address in the program
/// \returns \ref LIBFUNC_
idaman int ida_export try_to_add_libfunc(ea_t ea);
/// \defgroup LIBFUNC_ Library function codes
/// Return values for try_to_add_libfunc() and apply_idasgn_to()
//@{
#define LIBFUNC_FOUND 0 ///< ok, library function is found
#define LIBFUNC_NONE 1 ///< no, this is not a library function
#define LIBFUNC_DELAY 2 ///< no decision because of lack of information
//@}
// KERNEL mode functions
/// \cond
/// kept in the sdk because inlined
inline void save_signatures(void) {}
bool invalidate_sp_analysis(func_t *pfn);
inline bool invalidate_sp_analysis(ea_t ea)
{ return invalidate_sp_analysis(get_func(ea)); }
/// \endcond
#endif

365
idasdk76/include/gdl.hpp Normal file
View File

@@ -0,0 +1,365 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*
* Graph drawing support
*
*/
#ifndef __GDLDRAW_HPP
#define __GDLDRAW_HPP
#include <funcs.hpp>
/*! \file gdl.hpp
\brief Low level graph drawing operations
*/
//-------------------------------------------------------------------------
// forward declarations:
class node_iterator;
class qflow_chart_t;
class gdl_graph_t;
/// Flow chart block types
enum fc_block_type_t
{
fcb_normal, ///< normal block
fcb_indjump, ///< block ends with indirect jump
fcb_ret, ///< return block
fcb_cndret, ///< conditional return block
fcb_noret, ///< noreturn block
fcb_enoret, ///< external noreturn block (does not belong to the function)
fcb_extern, ///< external normal block
fcb_error, ///< block passes execution past the function end
};
#ifndef SWIG
#define DECLARE_HELPER(decl) \
decl node_iterator *ida_export node_iterator_goup(node_iterator *); \
decl void ida_export create_qflow_chart(qflow_chart_t &); \
decl bool ida_export append_to_flowchart(qflow_chart_t &, ea_t, ea_t); \
decl fc_block_type_t ida_export fc_calc_block_type(const qflow_chart_t &, size_t); \
decl bool ida_export create_multirange_qflow_chart(qflow_chart_t &, const rangevec_t &);
#else
#define DECLARE_HELPER(decl)
#endif // SWIG
DECLARE_HELPER(idaman)
//-------------------------------------------------------------------------
/// Set of integer constants
class intset_t : public std::set<int>
{
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
size_t idaapi print(char *buf, size_t bufsize) const;
const char *idaapi dstr(void) const;
bool has(int value) const
{
const_iterator p = find(value);
const_iterator q = end();
return p != q;
}
};
typedef qvector<intvec_t> array_of_intvec_t;
/// Map of integer constants to integer constants
class intmap_t : public std::map<int, int>
{
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
size_t idaapi print(char *buf, size_t bufsize) const;
const char *idaapi dstr(void) const;
};
typedef qvector<intmap_t> array_of_intmap_t;
//-------------------------------------------------------------------------
/// Set of graph nodes
class node_set_t : public intset_t
{
public:
idaapi node_set_t(void) {}
idaapi node_set_t(int node) { insert(node); }
idaapi node_set_t(const gdl_graph_t *g);
bool idaapi add(int node) { return insert(node).second; }
void idaapi sub(int node) { erase(node); }
void idaapi sub(const node_set_t &r);
void idaapi add(const node_set_t &r);
void idaapi intersect(const node_set_t &r);
void idaapi extract(intvec_t &out) const;
int idaapi first(void) const { return empty() ? -1 : *begin(); }
};
typedef qvector<node_set_t> array_of_node_set_t;
//-------------------------------------------------------------------------
/// Node iterator (used to draw graphs)
class node_iterator
{
DECLARE_HELPER(friend)
friend class gdl_graph_t;
const gdl_graph_t *g;
int i;
node_iterator &_goup(void);
node_iterator &goup(void) { return *node_iterator_goup(this); }
public:
node_iterator(const gdl_graph_t *_g, int n) : g(_g), i(n) {}
node_iterator &operator++(void) { i++; return goup(); }
bool operator==(const node_iterator &n) const { return i == n.i && g == n.g; }
bool operator!=(const node_iterator &n) const { return !(*this == n); }
int operator*(void) const { return i; }
};
//-------------------------------------------------------------------------
/// gdl graph interface - includes only functions required to draw it
class gdl_graph_t
{
// does a path from 'm' to 'n' exist?
bool idaapi path(node_set_t &visited, int m, int n) const;
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
virtual ~gdl_graph_t() {}
virtual char *idaapi get_node_label(char *iobuf, int iobufsize, int n) const { qnotused(iobufsize); qnotused(n); iobuf[0] = '\0'; return iobuf; }
virtual void idaapi print_graph_attributes(FILE *fp) const { qnotused(fp); }
virtual bool idaapi print_node(FILE *fp, int n) const { qnotused(fp); qnotused(n); return false; }
virtual bool idaapi print_edge(FILE *fp, int i, int j) const { qnotused(fp); qnotused(i); qnotused(j); return false; }
virtual void idaapi print_node_attributes(FILE *fp, int n) const { qnotused(fp); qnotused(n); }
virtual int idaapi size(void) const = 0; // number of the max node number
virtual int idaapi node_qty(void) const { return size(); } // number of alive nodes
virtual bool idaapi exists(int node) const { qnotused(node); return true; }
virtual int idaapi entry(void) const { return 0; }
virtual int idaapi exit(void) const { return size()-1; }
virtual int idaapi nsucc(int node) const = 0;
virtual int idaapi npred(int node) const = 0;
virtual int idaapi succ(int node, int i) const = 0;
virtual int idaapi pred(int node, int i) const = 0;
virtual bool idaapi empty(void) const { return node_qty() == 0; }
virtual bgcolor_t idaapi get_node_color(int n) const { qnotused(n); return DEFCOLOR; }
virtual bgcolor_t idaapi get_edge_color(int i, int j) const { qnotused(i); qnotused(j); return DEFCOLOR; }
void idaapi gen_gdl(FILE *fp) const;
void idaapi gen_gdl(const char *file) const;
size_t idaapi nedge(int node, bool ispred) const { return ispred ? npred(node) : nsucc(node); }
int idaapi edge(int node, int i, bool ispred) const { return ispred ? pred(node, i) : succ(node, i); }
int idaapi front(void) { return *begin(); }
node_iterator idaapi begin(void) const { return node_iterator(this, 0).goup(); }
node_iterator idaapi end(void) const { return node_iterator(this, size()); }
// does a path from 'm' to 'n' exist?
bool idaapi path_exists(int m, int n) const { node_set_t v; return path(v, m, n); }
void idaapi gen_dot(FILE *fp) const;
void idaapi gen_dot(const char *file) const;
};
/// Create GDL file for graph
idaman void ida_export gen_gdl(const gdl_graph_t *g, const char *fname);
/// Display GDL file by calling wingraph32.
/// The exact name of the grapher is taken from the configuration file
/// and set up by setup_graph_subsystem().
/// \return error code from os, 0 if ok
idaman int ida_export display_gdl(const char *fname);
//-------------------------------------------------------------------------
// Build and display program graphs
/// Build and display a flow graph.
/// \param filename output file name. the file extension is not used. maybe NULL.
/// \param title graph title
/// \param pfn function to graph
/// \param ea1, ea2 if pfn == NULL, then the address range
/// \param gflags combination of \ref CHART_1.
/// if none of #CHART_GEN_DOT, #CHART_GEN_GDL, #CHART_WINGRAPH
/// is specified, the function will return false
/// \return success. if fails, a warning message is displayed on the screen
idaman bool ida_export gen_flow_graph(
const char *filename,
const char *title,
func_t *pfn,
ea_t ea1,
ea_t ea2,
int gflags);
/// \defgroup CHART_1 Flow graph building flags
/// Passed as flags parameter to:
/// - gen_flow_graph()
/// - gen_simple_call_chart()
/// - gen_complex_call_chart()
//@{
#define CHART_PRINT_NAMES 0x1000 ///< print labels for each block?
#define CHART_GEN_DOT 0x2000 ///< generate .dot file (file extension is forced to .dot)
#define CHART_GEN_GDL 0x4000 ///< generate .gdl file (file extension is forced to .gdl)
#define CHART_WINGRAPH 0x8000 ///< call grapher to display the graph
//@}
/// Build and display a simple function call graph.
/// \param filename output file name. the file extension is not used. maybe NULL.
/// \param wait message to display during graph building
/// \param title graph title
/// \param gflags combination of #CHART_NOLIBFUNCS and \ref CHART_1.
/// if none of #CHART_GEN_DOT, #CHART_GEN_GDL, #CHART_WINGRAPH
/// is specified, the function will return false.
/// \return success. if fails, a warning message is displayed on the screen
idaman bool ida_export gen_simple_call_chart(
const char *filename,
const char *wait,
const char *title,
int gflags);
/// Build and display a complex xref graph.
/// \param filename output file name. the file extension is not used. maybe NULL.
/// \param wait message to display during graph building
/// \param title graph title
/// \param ea1, ea2 address range
/// \param flags combination of \ref CHART_2 and \ref CHART_1.
/// if none of #CHART_GEN_DOT, #CHART_GEN_GDL, #CHART_WINGRAPH
/// is specified, the function will return false.
/// \param recursion_depth optional limit of recursion
/// \return success. if fails, a warning message is displayed on the screen
idaman bool ida_export gen_complex_call_chart(
const char *filename,
const char *wait,
const char *title,
ea_t ea1,
ea_t ea2,
int flags,
int32 recursion_depth=-1);
/// \defgroup CHART_2 Call chart building flags
/// Passed as flags parameter to gen_complex_call_chart()
//@{
#define CHART_NOLIBFUNCS 0x0400 ///< don't include library functions in the graph
#define CHART_REFERENCING 0x0001 ///< references to the addresses in the list
#define CHART_REFERENCED 0x0002 ///< references from the addresses in the list
#define CHART_RECURSIVE 0x0004 ///< analyze added blocks
#define CHART_FOLLOW_DIRECTION 0x0008 ///< analyze references to added blocks only in the direction of the reference who discovered the current block
#define CHART_IGNORE_XTRN 0x0010
#define CHART_IGNORE_DATA_BSS 0x0020
#define CHART_IGNORE_LIB_TO 0x0040 ///< ignore references to library functions
#define CHART_IGNORE_LIB_FROM 0x0080 ///< ignore references from library functions
#define CHART_PRINT_COMMENTS 0x0100
#define CHART_PRINT_DOTS 0x0200 ///< print dots if xrefs exist outside of the range recursion depth
//@}
/// Setup the user-defined graph colors and graph viewer program.
/// This function is called by the GUI at the beginning, so no need to call
/// it again.
idaman void ida_export setup_graph_subsystem(const char *_grapher, bgcolor_t (idaapi *get_graph_color)(int color));
//-V:cancellable_graph_t:730 not all members of a class are initialized inside the constructor
class cancellable_graph_t : public gdl_graph_t
{
public:
mutable bool cancelled;
char padding[3]; // make the class nicely aligned. otherwise we have problems
// with gcc in qflow_chart_t.
cancellable_graph_t(void) : cancelled(false) {}
virtual ~cancellable_graph_t() {}
bool idaapi check_cancel(void) const;
};
//--------------------------------------------------------------------------
/// Information about a basic block of a \ref qflow_chart_t
struct qbasic_block_t : public range_t
{
intvec_t succ; ///< list of node successors
intvec_t pred; ///< list of node predecessors
};
/// Does this block never return?
inline THREAD_SAFE bool is_noret_block(fc_block_type_t btype)
{
return btype == fcb_noret || btype == fcb_enoret;
}
/// Does this block return?
inline THREAD_SAFE bool is_ret_block(fc_block_type_t btype)
{
return btype == fcb_ret || btype == fcb_cndret;
}
/// \defgroup FC_ Flow chart flags
/// Passed as 'flags' parameter to qflow_chart_t
//@{
#define FC_PRINT 0x0001 ///< print names (used only by display_flow_chart())
#define FC_NOEXT 0x0002 ///< do not compute external blocks. Use this to prevent jumps leaving the
///< function from appearing in the flow chart. Unless specified, the
///< targets of those outgoing jumps will be present in the flow
///< chart under the form of one-instruction blocks
#define FC_RESERVED 0x0004 // former FC_PREDS
#define FC_APPND 0x0008 ///< multirange flowchart (set by append_to_flowchart)
#define FC_CHKBREAK 0x0010 ///< build_qflow_chart() may be aborted by user
#define FC_CALL_ENDS 0x0020 ///< call instructions terminate basic blocks
#define FC_NOPREDS 0x0040 ///< do not compute predecessor lists
//@}
/// A flow chart for a function, or a set of address ranges
class qflow_chart_t : public cancellable_graph_t
{
public:
typedef qvector<qbasic_block_t> blocks_t;
DECLARE_HELPER(friend)
qstring title;
range_t bounds; ///< overall bounds of the qflow_chart_t instance
func_t *pfn = nullptr; ///< the function this instance was built upon
int flags = 0; ///< flags. See \ref FC_
blocks_t blocks; ///< basic blocks
int nproper = 0; ///< number of basic blocks belonging to the specified range
idaapi qflow_chart_t(void) {}
idaapi qflow_chart_t(const char *_title, func_t *_pfn, ea_t _ea1, ea_t _ea2, int _flags)
: title(_title), bounds(_ea1, _ea2), pfn(_pfn), flags(_flags)
{
refresh();
}
virtual ~qflow_chart_t() {}
void idaapi create(const char *_title, func_t *_pfn, ea_t _ea1, ea_t _ea2, int _flags)
{
title = _title;
pfn = _pfn;
bounds = range_t(_ea1, _ea2);
flags = _flags;
refresh();
}
void idaapi create(const char *_title, const rangevec_t &ranges, int _flags)
{
title = _title;
flags = _flags;
create_multirange_qflow_chart(*this, ranges);
}
void idaapi append_to_flowchart(ea_t ea1, ea_t ea2) { ::append_to_flowchart(*this, ea1, ea2); }
void idaapi refresh(void) { create_qflow_chart(*this); }
fc_block_type_t calc_block_type(size_t blknum) const
{ return fc_calc_block_type(*this, blknum); }
bool is_ret_block(size_t blknum) const { return ::is_ret_block(calc_block_type(blknum)); }
bool is_noret_block(size_t blknum) const { return ::is_noret_block(calc_block_type(blknum)); }
virtual void idaapi print_node_attributes(FILE *fp, int n) const override { qnotused(fp); qnotused(n); }
virtual int idaapi nsucc(int node) const override { return int(blocks[node].succ.size()); }
virtual int idaapi npred(int node) const override { return int(blocks[node].pred.size()); }
virtual int idaapi succ(int node, int i) const override { return blocks[node].succ[i]; }
virtual int idaapi pred(int node, int i) const override { return blocks[node].pred[i]; }
virtual char *idaapi get_node_label(char *iobuf, int iobufsize, int n) const override { qnotused(iobuf); qnotused(iobufsize); qnotused(n); return NULL; }
virtual int idaapi size(void) const override { return int(blocks.size()); }
bool idaapi print_names(void) const { return (flags & FC_PRINT) != 0; }
};
#endif // __GDLDRAW_HPP

1782
idasdk76/include/graph.hpp Normal file

File diff suppressed because it is too large Load Diff

73
idasdk76/include/help.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _HELP_H
#define _HELP_H
typedef int help_t; /* Help messages are referred by ints */
// Get pointer to message text by its message id
// The message texts are read from ida.hlp at the beginning
// Returns: pointer to message text (NULL is never returned by IDA)
idaman THREAD_SAFE const char *ida_export itext(help_t msg_id);
#ifdef __KERNWIN_HPP
GCC_DIAG_OFF(format-nonliteral);
NORETURN inline void Err(help_t format, ...)
{
va_list va;
va_start(va, format);
verror(itext(format), va);
// NOTREACHED
}
inline void Warn(help_t format, ...)
{
va_list va;
va_start(va, format);
vwarning(itext(format), va);
va_end(va);
}
inline void Info(help_t format, ...)
{
va_list va;
va_start(va, format);
vinfo(itext(format), va);
va_end(va);
}
inline int Message(help_t format,...)
{
va_list va;
va_start(va, format);
int nbytes = vmsg(itext(format), va);
va_end(va);
return nbytes;
}
inline int vask_yn(int deflt, help_t format, va_list va)
{
return vask_yn(deflt, itext(format), va);
}
inline int ask_yn(int deflt, help_t format, ...)
{
va_list va;
va_start(va, format);
int code = vask_yn(deflt, itext(format), va);
va_end(va);
return code;
}
GCC_DIAG_ON(format-nonliteral);
#endif
#ifndef NO_OBSOLETE_FUNCS
#endif
#endif /* _HELP_H */

1306
idasdk76/include/ida.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,146 @@
#ifndef IDA_HIGHLIGHTER
#define IDA_HIGHLIGHTER
#include <expr.hpp>
idaman void ida_export code_highlight_block(void *context, highlighter_cbs_t *highlighter_cbs, const qstring &text);
// returns the length of text to colorize
// negative values may have special meaning in the future.
typedef ssize_t idaapi external_colorizer_t(syntax_highlight_style *color, const char *str);
typedef qvector<external_colorizer_t *> external_colorizers_t;
// returns true if identifier is colorized
typedef bool idaapi external_ident_colorizer_t(syntax_highlight_style *color, const qstring &ident);
typedef qvector<external_ident_colorizer_t *> external_ident_colorizers_t;
#define MLTCMTMASK 0xF
#define PREPROC_FLAG 0x10
// Common implementation of syntax_highlighter_t used in different parts of IDA
//-V:ida_syntax_highlighter_t:730 not all members of a class are initialized inside the constructor
struct ida_syntax_highlighter_t : syntax_highlighter_t
{
protected:
// keys of keywords_t point to memory from keyword_strings.
// once allocated, this buffer won't be moved in the memory.
qstrvec_t keyword_memory;
// helper class so that keywords_t gets sorted by string contents, not pointer values.
struct plain_char_ptr_t
{
const char *ptr;
plain_char_ptr_t(const char *p = NULL) : ptr(p) {}
bool operator <(const plain_char_ptr_t &r) const
{
return strcmp(ptr, r.ptr) < 0;
}
bool operator ==(const plain_char_ptr_t &r) const
{
return strcmp(ptr, r.ptr) == 0;
}
};
struct multicmt_t
{
qstring open_multicmt;
qstring close_multicmt;
multicmt_t() {}
multicmt_t(const char *_open_multicmt, const char *_close_multicmt) :
open_multicmt(_open_multicmt),
close_multicmt(_close_multicmt)
{}
};
// typedef std::map<plain_char_ptr_t, syntax_highlight_style> keywords_t;
struct keywords_style_t
{
qvector<plain_char_ptr_t> keywords;
syntax_highlight_style style;
};
typedef qvector<keywords_style_t> keywords_t;
//typedef qvector<plain_char_ptr_t> keywords_t;
typedef qvector<multicmt_t> multicmtvec_t;
keywords_t keywords;
qstring open_cmt; // string that opens a regular line comment
multicmtvec_t multicmts;
char literal_closer; // either close_strconst or close_chrconst for the current literal
// color mappings
syntax_highlight_style text_color = HF_DEFAULT;
syntax_highlight_style comment_color = HF_COMMENT;
syntax_highlight_style string_color = HF_STRING;
syntax_highlight_style preprocessor_color = HF_PREPROC;
external_colorizers_t external_colorizers;
external_ident_colorizers_t external_ident_colorizers;
// work variables
const char *input; // pointer to the start of the input buffer
const char *pending; // pointer in the input buffer
syntax_highlight_style style = HF_DEFAULT; // current highlighting style
bool pending_nonspaces_present(const char *end)
{
for ( const char *p = pending; p != end; ++p )
if ( !qisspace(*p) )
return true;
return false;
}
const char *parse_literal_const(highlighter_cbs_t *highlighter_cbs, const char *ptr, char literal_closer);
void flush_output(highlighter_cbs_t *highlighter_cbs, const char *ptr, syntax_highlight_style style);
void handle_cmt(highlighter_cbs_t *highlighter_cbs, int mcmt_idx, const char **ptr);
void handle_preproc(highlighter_cbs_t *highlighter_cbs, const char **ptr);
public:
// if any of the following features is not needed, just zero them out:
char open_strconst; // character that opens a string constant
char close_strconst; // character that closes a string constant
char open_chrconst; // character that closes a character constant
char close_chrconst; // character that opens a character constant
char escape_char; // backslash
char preprocessor_char; // #
ida_syntax_highlighter_t() : syntax_highlighter_t(&code_highlight_block) {}
void highlight_block_ex(highlighter_cbs_t *highlighter_cbs, const qstring &text);
void add_external_colorizer(external_colorizer_t *th) { external_colorizers.push_back(th); }
void add_external_ident_colorizer(external_ident_colorizer_t *th) { external_ident_colorizers.push_back(th); }
void set_open_cmt(const char *begin) { open_cmt = begin; }
void add_multi_line_comment(const char *begin, const char *end)
{
multicmt_t &mcmt = multicmts.push_back();
mcmt.open_multicmt = begin;
mcmt.close_multicmt = end;
}
void add_keywords(const char *kwstr, syntax_highlight_style _style)
{
char *ctx;
// in order not to allocate every keyword separately, we allocate the whole
// kwstr string at once and will just store pointers to it in the map.
qstring &mem = keyword_memory.push_back();
mem = kwstr;
keywords_style_t *pair_p = NULL;
for ( int i = 0; i < keywords.size(); i++ )
{
if ( keywords[i].style == _style )
{
pair_p = &keywords[i];
break;
}
}
if ( pair_p == NULL )
{
keywords_style_t &pair = keywords.push_back();
pair_p = &pair;
pair_p->style = _style;
}
for ( char *kw = qstrtok(mem.begin(), "|", &ctx); kw != NULL; kw = qstrtok(NULL, "|", &ctx) )
pair_p->keywords.push_back(kw);
}
};
#endif // IDA_HIGHLIGHTER

1966
idasdk76/include/idd.hpp Normal file

File diff suppressed because it is too large Load Diff

3157
idasdk76/include/idp.hpp Normal file

File diff suppressed because it is too large Load Diff

263
idasdk76/include/ieee.h Normal file
View File

@@ -0,0 +1,263 @@
/*
* Interactive disassembler (IDA)
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
* Floating Point Number Libary.
* Copyright (c) 1995-2006 by Iouri Kharon.
* E-mail: yjh@styx.cabel.net
*
*/
#include <pro.h>
#ifndef _IEEE_H_
#define _IEEE_H_
/*! \file ieee.h
\brief IEEE floating point functions
*/
struct fpvalue_t; // processor-independent representation of floats
#define FPVAL_NWORDS 6 // number of words in fpvalue_t
/// Floating value kinds.
/// They are useful when checking for NaN/Inf
enum fpvalue_kind_t
{
FPV_BADARG, ///< wrong value of max_exp
FPV_NORM, ///< regular value
FPV_NAN, ///< NaN
FPV_PINF, ///< positive infinity
FPV_NINF, ///< negative infinity
};
/// \name max_exp values
/// Common values for max_exp (for IEEE floating point values)
//@{
const uint32
MAXEXP_FLOAT = 0x80,
MAXEXP_DOUBLE = 0x400,
MAXEXP_LNGDBL = 0x4000;
//@}
/// \defgroup REAL_ERROR_ Floating point/IEEE Conversion codes
/// Return values for ieee_realcvt and processor_t::realcvt_t request
enum fpvalue_error_t
{
REAL_ERROR_OK = 0, ///< no error
REAL_ERROR_FORMAT = -1, ///< realcvt: not supported format for current .idp
REAL_ERROR_RANGE = -2, ///< realcvt: number too big (small) for store (mem NOT modified)
REAL_ERROR_BADDATA = -3, ///< realcvt: illegal real data for load (IEEE data not filled)
REAL_ERROR_FPOVER = 1, ///< floating overflow or underflow
REAL_ERROR_BADSTR = 2, ///< asctoreal: illegal input string
REAL_ERROR_ZERODIV = 3, ///< ediv: divide by 0
REAL_ERROR_INTOVER = 4, ///< eetol*: integer overflow
};
/// Standard IEEE 754 floating point conversion function
/// \param m pointer to data
/// \param out internal IEEE format data
/// \param swt operation:
/// - 000: load trunc. float (DEC ^F) 2 bytes (m->e)
/// - 001: load float 4 bytes (m->e)
/// - 003: load double 8 bytes (m->e)
/// - 004: load long double 10 bytes (m->e)
/// - 005: load long double 12 bytes (m->e)
/// - 010: store trunc. float (DEC ^F) 2 bytes (e->m)
/// - 011: store float 4 bytes (e->m)
/// - 013: store double 8 bytes (e->m)
/// - 014: store long double 10 bytes (e->m)
/// - 015: store long double 12 bytes (e->m)
/// bit 0x80 forces little endian even for big endian processors
/// \return fpvalue_error_t
idaman THREAD_SAFE fpvalue_error_t ida_export ieee_realcvt(void *m, fpvalue_t *out, uint16 swt);
// Helper functions. Better use members of fpvalue_t, they are nicer.
idaman THREAD_SAFE void ida_export realtoasc(char *buf, size_t bufsize, const fpvalue_t &x, uint mode);
idaman THREAD_SAFE fpvalue_error_t ida_export asctoreal(const char **sss, fpvalue_t *out);
idaman THREAD_SAFE void ida_export eltoe(sval_t l, fpvalue_t *vout);
idaman THREAD_SAFE void ida_export eltoe64(int64 l, fpvalue_t *vout);
idaman THREAD_SAFE void ida_export eltoe64u(uint64 l, fpvalue_t *vout);
idaman THREAD_SAFE fpvalue_error_t ida_export eetol(sval_t *out, const fpvalue_t &a, bool roundflg);
idaman THREAD_SAFE fpvalue_error_t ida_export eetol64(int64 *out, const fpvalue_t &a, bool roundflg);
idaman THREAD_SAFE fpvalue_error_t ida_export eetol64u(uint64 *out, const fpvalue_t &a, bool roundflg);
idaman THREAD_SAFE fpvalue_error_t ida_export eldexp(const fpvalue_t &a, int32 pwr2, fpvalue_t *zout);
idaman THREAD_SAFE fpvalue_error_t ida_export eadd(const fpvalue_t &a, const fpvalue_t &b, fpvalue_t *zout, bool subflg);
idaman THREAD_SAFE fpvalue_error_t ida_export emul(const fpvalue_t &a, const fpvalue_t &b, fpvalue_t *zout);
idaman THREAD_SAFE fpvalue_error_t ida_export ediv(const fpvalue_t &a, const fpvalue_t &b, fpvalue_t *zout);
idaman THREAD_SAFE int ida_export ecmp(const fpvalue_t &a, const fpvalue_t &b);
idaman THREAD_SAFE fpvalue_kind_t ida_export get_fpvalue_kind(const fpvalue_t &a, uint16 reserved = 0);
//------------------------------------------------------------------------
/// Processor-independent representation of a floating point value.
/// IDA uses this structure to store and manipulate floating point values.
struct fpvalue_t
{
uint16 w[FPVAL_NWORDS];
void clear(void) { memset(this, 0, sizeof(*this)); }
DECLARE_COMPARISONS(fpvalue_t) { return ecmp(*this, r); }
/// Convert to the processor-independent representation.
fpvalue_error_t from_half(uint16 fpval) { return ieee_realcvt(&fpval, this, sizeof(fpval)/2-1); }
fpvalue_error_t from_float(float fpval) { return ieee_realcvt(&fpval, this, sizeof(fpval)/2-1); }
fpvalue_error_t from_double(double fpval) { return ieee_realcvt(&fpval, this, sizeof(fpval)/2-1); }
/// Convert from the processor-independent representation.
fpvalue_error_t to_half(uint16 *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|(sizeof(*fpval)/2-1)); }
fpvalue_error_t to_float(float *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|(sizeof(*fpval)/2-1)); }
fpvalue_error_t to_double(double *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|(sizeof(*fpval)/2-1)); }
/// Conversions for 10-byte floating point values.
fpvalue_error_t from_10bytes(const void *fpval) { return ieee_realcvt((void *)fpval, this, 4); }
fpvalue_error_t to_10bytes(void *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|4); }
/// Conversions for 12-byte floating point values.
fpvalue_error_t from_12bytes(const void *fpval) { return ieee_realcvt((void*)fpval, this, 5); }
fpvalue_error_t to_12bytes(void *fpval) const { return ieee_realcvt(fpval, (fpvalue_t*)this, 8|5); }
/// Convert string to IEEE.
/// \param p_str pointer to pointer to string. it will advanced.
fpvalue_error_t from_str(const char **p_str) { return asctoreal(p_str, this); }
/// Convert IEEE to string.
/// \param mode broken down into:
/// - low byte: number of digits after '.'
/// - second byte: FPNUM_LENGTH
/// - third byte: FPNUM_DIGITS
void to_str(char *buf, size_t bufsize, uint mode) const { realtoasc(buf, bufsize, *this, mode); }
/// Convert integer to IEEE
void from_sval(sval_t x) { eltoe(x, this); }
void from_int64(int64 x) { eltoe64(x, this); }
void from_uint64(uint64 x) { eltoe64u(x, this); }
/// Convert IEEE to integer (+-0.5 if round)
fpvalue_error_t to_sval(sval_t *out, bool round=false) const { return eetol(out, *this, round); }
fpvalue_error_t to_int64(int64 *out, bool round=false) const { return eetol64(out, *this, round); }
fpvalue_error_t to_uint64(uint64 *out, bool round=false) const { return eetol64u(out, *this, round); }
/// Arithmetic operations
fpvalue_error_t fadd(const fpvalue_t &y) { return eadd(*this, y, this, false); }
fpvalue_error_t fsub(const fpvalue_t &y) { return eadd(*this, y, this, true); }
fpvalue_error_t fmul(const fpvalue_t &y) { return emul(*this, y, this); }
fpvalue_error_t fdiv(const fpvalue_t &y) { return ediv(*this, y, this); }
/// Multiply by a power of 2.
fpvalue_error_t mul_pow2(int32 power_of_2) { return eldexp(*this, power_of_2, this); }
/// Calculate absolute value.
void eabs() { w[FPVAL_NWORDS-1] &= 0x7fff; }
/// Is negative value?
bool is_negative() const { return (w[FPVAL_NWORDS-1] & 0x8000) != 0; }
/// Negate.
void negate()
{
if ( w[FPVAL_NWORDS-1] != 0 )
w[FPVAL_NWORDS-1] ^= 0x8000;
}
/// Get value kind.
fpvalue_kind_t get_kind() const { return get_fpvalue_kind(*this, 0); }
};
//------------------------------------------------------------------------]
/// The exponent of 1.0
#define IEEE_EXONE (0x3fff)
/// \name Prototypes
/// IDP module event prototype -- should be implemented in idp
//@{
/// Floating point conversion function: implemented by \ph{realcvt}.
/// See ieee_realcvt
fpvalue_error_t idaapi realcvt(void *m, fpvalue_t *out, uint16 swt);
/// Little endian
fpvalue_error_t l_realcvt(void *m, fpvalue_t *out, uint16 swt);
/// Big endian
fpvalue_error_t b_realcvt(void *m, fpvalue_t *out, uint16 swt);
//@}
/// Exponent in fpvalue_t for NaN and Inf
#define E_SPECIAL_EXP 0x7fff
/// 0.0
extern const fpvalue_t ieee_ezero;
#define EZERO { 0, 0000000,0000000,0000000,0000000,0000000 }
/// 1.0
extern const fpvalue_t ieee_eone;
#define EONE { 0, 0000000,0000000,0000000,0100000,IEEE_EXONE }
/// 2.0
extern const fpvalue_t ieee_etwo;
/// 32.0
extern const fpvalue_t ieee_e32;
/// 6.93147180559945309417232121458176568075500134360255E-1
extern const fpvalue_t ieee_elog2;
/// 1.41421356237309504880168872420969807856967187537695E0
extern const fpvalue_t ieee_esqrt2;
/// 2/sqrt(PI) = 1.12837916709551257389615890312154517168810125865800E0
extern const fpvalue_t ieee_eoneopi;
/// 3.14159265358979323846264338327950288419716939937511E0
extern const fpvalue_t ieee_epi;
/// 5.7721566490153286060651209008240243104215933593992E-1
extern const fpvalue_t ieee_eeul;
#if !defined(NO_OBSOLETE_FUNCS) || defined(IEEE_SOURCE) //-[
#define IEEE_NI (FPVAL_NWORDS+3) // Number of 16 bit words in ::eNI
#define IEEE_E 1 // Array offset to exponent
#define IEEE_M 2 // Array offset to high guard word
/// There is one more internal format used by IDA to store intermediate values.
/// - 0 : sign (0/1)
/// - 1 : exponent (based of #IEEE_EXONE). If exp = 0, value = 0.
/// - 2 : high word of mantissa (always zero after normalize)
typedef uint16 eNI[IEEE_NI];
#ifdef IEEE_SOURCE
# define IEEE_DEPRECATED
#else
# define IEEE_DEPRECATED DEPRECATED
#endif
inline IEEE_DEPRECATED void ecleaz(eNI x) { memset(x, 0, sizeof(eNI)); }
idaman IEEE_DEPRECATED THREAD_SAFE void ida_export emovo(const eNI a, fpvalue_t *vout); /// Move eNI => eNE
idaman IEEE_DEPRECATED THREAD_SAFE void ida_export emovi(const fpvalue_t &a, eNI vout); /// Move eNE => eNI
idaman IEEE_DEPRECATED THREAD_SAFE int ida_export eshift(eNI x, int sc); /// Shift NI format up (+) or down
/// Normalize and round off.
/// \param s the internal format number to be rounded
/// \param lost indicates whether or not the number is exact.
/// this is the so-called sticky bit.
/// \param subflg indicates whether the number was obtained
/// by a subtraction operation. In that case if lost is nonzero
/// then the number is slightly smaller than indicated.
/// \param exp the biased exponent, which may be negative.
/// the exponent field of "s" is ignored but is replaced by
/// "exp" as adjusted by normalization and rounding.
/// \param rndbase if 0 => is the rounding control.
/// else is processor defined base (rndprc)
/// \return success
idaman IEEE_DEPRECATED THREAD_SAFE bool ida_export emdnorm(eNI s, bool lost, bool subflg, int32 exp, int rndbase);
#endif
#endif

1232
idasdk76/include/intel.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,839 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __JUMPTABLE_HPP
#define __JUMPTABLE_HPP
#include <pro.h>
#include <ua.hpp> // op_t
#include <nalt.hpp> // switch_info_t, jumptable_info_t
// Class to check for a jump table sequence.
// This class should be used in preference to the hard encoding of jump table sequences
// because it allows for:
// - instruction rescheduling
// - intermingling the jump sequence with other instructions
// - sequence variants
//
// For this class:
// all instructions of the sequence are numbered starting from the last instruction.
// The last instruction has the number 0.
// The instruction before the last instruciton has the number 1, etc.
// There is a virtual function jpiN() for each instruction of the sequence
// These functions return true if 'insn' is filled with the required instruction
//
// The comparison is made in the match() function:
//
// ea points to the last instruction of the sequence (instruction #0)
//
// the 'depends' array contains dependencies between the instructions of the sequence.
// For example:
// ARM thumb LDRH switch
// 7 SUB Ra, #minv (optional)
// 6 CMP Ra, #size
// 5 BCS defea
// 4 ADR Rb, jt
// 3 ADD Rb, Rb, Ra
// 2 LDRH Rb, [Rb,Ra]
// 1 LSL Rb, Rb, #1
// 0 ADD PC, Rb
// In this sequence, instruction #0 depends on the value of Rb which is produced
// by the instruction #1. So, the instruction #0 depends on #1. Therefore, depends[0]
// will contain '1' as its element.
// The instruction #3 depends on 2 registers: Ra and Rb, or in other words,
// it depends on the instructions #4 and #6. Therefore, depends[2] will contain { 4, 6 }
// Maximum 4 dependencies per instruction are allowed.
//
// FIXME
// The 'roots' array contains the first instruction of the dependency chains.
// In our case we can say that there are 2 dependency chains:
// 0 -> 1 -> 2 -> 3 -> 4
// -> 6 -> 7
// 5 -> 6
// Therefore the roots array will consist of {1, 5}.
// 0 denotes the end of the chain and cannot be the root of a dependency chain
// Usually 1 is a root of any jump sequence.
//
// The dependency array allows for checking for optimized sequences of instructions.
// If 2 instructions are not dependent on each other, they may appear in any order.
// (for example, the instruction #4 and the instruction sequence #5-6-7 may appear
// in any order because they do not depend on each other)
// Also any other instructions not modifying the register values may appear between
// the instructions of the sequence (due to the instruction rescheduling performed
// by the compiler).
//
// Provision for optional instructions:
// The presence of an optional instruction in the sequence (like #7) is signalled
// by a negative number of the dependency in the 'depends' array.
//
// Provision for variable instructions:
// In some cases several variants of the same instructions may be supported.
// For example, the instruction #5 might be BCS as well as BGE. It is the job of
// the jpi5() function to check for all variants.
//
// In order to use the 'jump_pattern_t' class you should derive another class from it
// and define the jpiN() virtual functions.
// Then you have to define the 'depends' and 'roots' arrays and call the match()
// function.
// If you processor contains instructions who modify registers in peculiar ways
// you might want to override the check_spoiled() function.
//----------------------------------------------------------------------
// Macro to declare implementation of methods of jump_pattern_t
class jump_pattern_t;
// tracked registers
// We use the 'size' term to denote the number of bits involved in the insn.
// E.g. an operand of type dt_byte has 8-bit size.
// We store the current size (the number of used bits) in the DTYPE field
// of the 'op_t' structure. It may differ from the size of operand in the
// insn. See the comment for set_moved().
// We extend the 'op_dtype_t' type by some negative constants to denote
// sizes from 2 to 7 bits.
typedef qvector<op_t> tracked_regs_t;
#define DECLARE_JUMP_PATTERN_HELPERS(decl)\
decl void ida_export check_spoiled_jpt(const jump_pattern_t *_this, tracked_regs_t *_regs); \
decl bool ida_export match_jpt(jump_pattern_t *_this);\
decl bool ida_export same_value_jpt(jump_pattern_t *_this, const op_t &op, int r_i);\
decl bool ida_export track_value_until_address_jpt(jump_pattern_t *_this, op_t *op, ea_t ea);\
decl void ida_export combine_regs_jpt(jump_pattern_t *_this, tracked_regs_t *dst, const tracked_regs_t &src, ea_t ea);\
decl void ida_export mark_switch_insns_jpt(const jump_pattern_t *_this, int last, int);\
decl bool ida_export set_moved_jpt(const jump_pattern_t *_this, const op_t &dst, const op_t &src, tracked_regs_t &_regs, op_dtype_t real_dst_dtype, op_dtype_t real_src_dtype);
DECLARE_JUMP_PATTERN_HELPERS(idaman)
class jump_pattern_t
{
protected:
// 32-bit operand generates a 32-bit result, zero- or sign-extended to a
// 64-bit result. This flag may be overwritten in processor modules.
// For example:
// ARM: MOV W8, #0x3C will clear the upper 32 bits of X8,
// PC : mov eax, 3Ch will clear the upper 32 bits of rax
bool modifying_r32_spoils_r64;
public:
typedef bool (jump_pattern_t::*check_insn_t)(void);
inline jump_pattern_t(
switch_info_t *si, // may be NULL
const char (*depends)[4],
int last_reg);
insn_t insn; // current instruction
switch_info_t *si; // answers will be here
enum
{
NINS = 16, // the maximum length of the sequence
INS_MASK = 0x0F,
};
ea_t eas[NINS];
bool skip[NINS]; // do not check the Nth insn if skip[N] is true
int non_spoiled_reg; // if non_spoiled_reg was spoiled then we stop
// matching
check_insn_t check[NINS];
// this is the hidden return value of the jpiN() methods. If it is set and
// jpiN() returned 'true' then we stop processing the dependency chain. If
// it is set and jpiN() returned 'false' then we stop checking the insns
// in the current basic block and we are switching to the next one (and we
// fail if there is no such block).
bool stop_matching;
// this flag can be analyzed by jpiN(). It means that the current insn is
// in the linear flow from the previous insn. It is always 'true' if the
// insn has JPT_NEAR flag.
bool in_linear_flow;
// this address can be analyzed by jpiN(). It means the end of the current
// block. It may help if we want to check in-block jumps.
ea_t block_end;
#define JPT_OPT 0x10 // the dependent insn might be missing
#define JPT_NEAR 0x20 // the dependent insn must be in the linear flow
const char (*depends)[4]; // instruction, on which we depend, and
// additional JPT_... flags
// mark swith instructions to be ignored by the decompiler
// do not mark the indirect jmp (eas[0]) as ignored
// it will be used to recognize switch idioms
// unmark NLOWCASE insns after LAST (in the case of SWI_HXNOLOWCASE flag)
void mark_switch_insns(int last = NINS - 1, int nlowcase = 0) const
{
mark_switch_insns_jpt(this, last, nlowcase);
}
// for fragmented switch idioms, cmp/jbe might be located in a separate
// fragment. we must not mark these instructions as part of the switch
// idiom because doing so would spoil the program logic for the decompiler
// and make the switch operator unreachable. the following vector keeps
// addresses of all instructions which must not be marked. this vector is
// maintained by derived classes.
eavec_t remote_code;
// extra insns used to calculate values (discovered by find_op_value)
eavec_t extra_insn_eas;
// tracked registers
tracked_regs_t regs;
// handle a possible delay slot situation
// while walking backwards in the execution flow
// if <branch> is false and <ea> is in a delay
// slot of a branch likely instruction
// then set <ea> to the branch instruction
// (=annul the delay slot)
// if <branch> is true and the instruction at <ea>
// has a delay slot then set <ea> to the delay slot
// (=execute the delay slot)
virtual void process_delay_slot(ea_t &/*ea*/, bool /*branch*/) const {}
// an artificial register to track the address of the conditional jump
// .value - condition
// .addr - address of the conditional jump
// .specval - address of the default case
// the derived class can use .reg to track the condition register
enum
{
o_condjump = 99,
cc_inc_ncases = 0x01, // increment ncases
cc_check_max_ncases = 0x02, // comparison with the maximum value
};
// compare supported operands
virtual bool equal_ops(const op_t &x, const op_t &y) const
{
if ( x.type != y.type )
return false;
switch ( x.type )
{
case o_void:
// consider spoiled values as not equal
return false;
case o_reg:
// ignore difference in the data size of registers
return x.reg == y.reg;
case o_condjump:
// we do not track the condition flags
return true;
}
return false;
}
// return true if the instruction `insn' is a move one,
// there is no need check spoiled registers in this case
virtual bool handle_mov(tracked_regs_t & /*_regs*/ )
{
return false;
}
// does the instruction `insn' spoil `_regs' ?
virtual void check_spoiled(tracked_regs_t *_regs) const
{
check_spoiled_jpt(this, _regs);
}
// some binaries use the following pattern
// xor eax, eax | mov al, cl
// so we can extend dtype of the operand from dt_byte to dt_dword
virtual op_dtype_t extend_dtype(const op_t &op) const
{
return op.dtype; // do not extend
}
// these methods are not virtual and should be used in processor
// module only
inline void track(int reg, int r_i, op_dtype_t dtype);
inline void trackop(const op_t &op, int r_i);
inline bool is_spoiled(int r_i) { return regs[r_i].type == o_void; }
inline bool is_equal(int reg, int r_i, op_dtype_t dtype);
inline bool is_equal(const op_t &op, int r_i);
inline bool same_value(const op_t &op, int r_i);
inline bool track_value_until_address(op_t *op, ea_t ea);
virtual bool jpi0(void) = 0;
virtual bool jpi1(void) { return false; }
virtual bool jpi2(void) { return false; }
virtual bool jpi3(void) { return false; }
virtual bool jpi4(void) { return false; }
virtual bool jpi5(void) { return false; }
virtual bool jpi6(void) { return false; }
virtual bool jpi7(void) { return false; }
virtual bool jpi8(void) { return false; }
virtual bool jpi9(void) { return false; }
virtual bool jpia(void) { return false; }
virtual bool jpib(void) { return false; }
virtual bool jpic(void) { return false; }
virtual bool jpid(void) { return false; }
virtual bool jpie(void) { return false; }
virtual bool jpif(void) { return false; }
// jpi<n> will be called if pre_jpi returns true
virtual bool pre_jpi(int /*n*/) { return true; }
bool match(const insn_t &_insn) { insn = _insn; return match_jpt(this); }
// remove compiler warnings -- class with virtual functions MUST have virtual destructor
virtual ~jump_pattern_t() {}
// helpers for mov instruction tracing (see methods handle_mov(),
// check_spoiled() above)
inline static void set_spoiled(tracked_regs_t *_regs);
inline void set_spoiled(tracked_regs_t *_regs, const op_t &op) const;
// track 'mov' insn: dst <- src
// it returns 'true' if insn changes any of the tracked registers
// REAL_DST_DTYPE is the size that will be changed in the DST operand by
// the insn. It can be greater than the operand size because some insns
// clear the upper bits. For example:
// xor eax, eax | mov ax, cx REAL_DST_DTYPE is 32
// xor bh, bh | mov bl, cl REAL_DST_DTYPE is 16
// Extending of the 32-bit register to 64 bits is performed automatically
// based on the modifying_r32_spoils_r64 flag.
// REAL_SRC_DTYPE is the size that will be used in the SRC operand by the
// insn. It can be less than the operand size. For example:
// ARM: AND W8, W8, #0xFF will use 8 bits of X8,
// PC : cwde will use 16 bits of rax.
bool set_moved(
const op_t &dst,
const op_t &src,
tracked_regs_t &_regs,
op_dtype_t real_dst_dtype = dt_void,
op_dtype_t real_src_dtype = dt_void) const
{
return set_moved_jpt(this, dst, src, _regs, real_dst_dtype, real_src_dtype);
}
// calculate state of registers before a conditional jump <ea> as the
// combination of states of each branch
void combine_regs(
tracked_regs_t *dst,
const tracked_regs_t &src,
ea_t ea)
{
combine_regs_jpt(this, dst, src, ea);
}
protected:
bool match_tree();
bool follow_tree(ea_t ea, int n);
bool same_value_impl(const op_t &op, int r_i);
bool track_value_until_address_impl(op_t *op, ea_t ea);
inline bool equal_ops_dtype(const op_t &op, const op_t &reg) const;
static inline bool is_narrower(op_dtype_t dt1, op_dtype_t dt2);
enum
{
dt_7bit = 255,
dt_6bit = 254,
dt_5bit = 253,
dt_4bit = 252,
dt_3bit = 251,
dt_2bit = 250,
};
static inline int get_dtype_nbits(op_dtype_t dtype);
// helper for check_spoiled()
// TODO introduce new virtual methods spoils() and spoils_flags() and
// replace check_spoiled() by non-virtual method
inline void check_spoiled_not_reg(
tracked_regs_t *_regs,
uint maxop = UA_MAXOP) const;
DECLARE_JUMP_PATTERN_HELPERS(friend)
};
//----------------------------------------------------------------------
// kinds of jump tables
enum { JT_NONE = 0, JT_SWITCH, JT_CALL };
// It returns a nonzero JT_... kind if it found a jump pattern. This kind is
// passed to the check_table() function.
typedef int is_pattern_t(switch_info_t *si, const insn_t &insn, procmod_t *procmod);
// It returns a refined kind. For example, JT_NONE if the found jump pattern
// is not a switch, or JT_CALL if it is a call of a func from an array
typedef int table_checker_t(
switch_info_t *si,
ea_t jump_ea,
int is_pattern_res,
procmod_t *pm);
// check a flat 32/16/8 bit jump table -- the most common case
idaman int ida_export check_flat_jump_table(
switch_info_t *si,
ea_t jump_ea,
int is_pattern_res = JT_SWITCH);
// This function finds a switch. It calls functions from the PATTERNS
// array in turn until the first one returns a nonzero value.
// If a suitable pattern is found, it calls check_table() for the final
// check, passing a nonzero result code of the 'is_pattern_t' function.
// If the CHECK_TABLE parameter is NULL then check_flat_jump_table() is
// called.
// NAME is used for a debug output.
// It returns 'false' if INSN is not a switch or it is a call of a func from
// an array. In the latter case it defines this array.
idaman bool ida_export check_for_table_jump(
switch_info_t *si,
const insn_t &insn,
is_pattern_t *const patterns[],
size_t qty,
table_checker_t *check_table = NULL,
const char *name = NULL);
//----------------------------------------------------------------------
// sometimes the size of the jump table is misdetected
// check if any of the would-be targets point into the table
// and if so, truncate it
// if 'ignore_refs' is false, also stop at first data reference
idaman void ida_export trim_jtable(
switch_info_t *si,
ea_t jump_ea,
bool ignore_refs = false);
//----------------------------------------------------------------------
// this function find the size of the jump table for indirect switches
// (indirect switches have the values table which contains indexes into
// the jump table)
// in: si->ncases has the size of the values table
// out: si->jcases is initialized
idaman bool ida_export find_jtable_size(switch_info_t *si);
//----------------------------------------------------------------------
// get default jump address from the jump table.
// This method can be used only for a sparse nonindirect switch with default
// case in the jump table.
idaman ea_t ida_export find_defjump_from_table(
ea_t jump_ea,
const switch_info_t &si);
//----------------------------------------------------------------------
// get the specified target from the jump table.
idaman ea_t ida_export get_jtable_target(
ea_t jump_ea,
const switch_info_t &si,
int i);
//----------------------------------------------------------------------
// iterate instructions in the backward execution flow
//lint -esym(1512,backward_flow_iterator_t*) destructor is not virtual
template<class State,class Ctrl>
// State: default constructor, operator=
// Ctrl: combine_regs(State *, const State& ,ea_t)
// process_delay_slot(ea_t &/*ea*/, bool /*branch*/)
struct backward_flow_iterator_t
{
public:
ea_t cur_ea; // current address
State &regs; // current state of the tracked registers
Ctrl &ctrl; // to combine state
bool only_near; // should we follow only the linear flow?
uint max_insn_cnt;
protected:
//lint --e{958} padding is required
func_t *pfn; // to check bounds
const segment_t *seg;
ea_t start_ea;
ea_t cur_end; // end of current basic block
uint insn_cnt;
// visited basic blocks:
// key_type - start of the block, mapped_type - end of the block;
typedef std::map<ea_t, ea_t> visited_t;
visited_t visited;
// waiting basic blocks:
// key_type - end of the block, mapped_type - state at the end;
struct state_t
{
State regs;
uint insn_cnt;
state_t() : regs(), insn_cnt(UINT_MAX) {}
};
typedef std::map<ea_t, state_t> waiting_t;
waiting_t waiting;
public:
backward_flow_iterator_t(
ea_t start_ea_,
State &start_regs,
Ctrl &ctrl_,
bool only_near_,
uint max_insn_cnt_ = 0)
: cur_ea(start_ea_),
regs(start_regs),
ctrl(ctrl_),
only_near(only_near_),
max_insn_cnt(max_insn_cnt_),
pfn(NULL),
seg(NULL),
start_ea(start_ea_),
cur_end(BADADDR),
insn_cnt(0),
visited(),
waiting()
{
// to check bounds
pfn = get_func(start_ea);
if ( pfn == NULL )
{
seg = getseg(start_ea);
QASSERT(10183, seg != NULL);
}
}
// fl_U : no previous instruction (start of a function or a cycle,
// or non linear flow if ONLY_NEAR is true),
// fl_F : got previous instruction by linear flow,
// fl_JF: got previous instruction by jump;
inline cref_t prev_insn();
// stop iterating the current basic block, switch to the lowest waiting
// block
inline cref_t skip_block();
inline ea_t get_cur_end() const
{
return cur_end == BADADDR ? cur_ea : cur_end;
}
protected:
// find visited basic block containing the address
// it returns the pointer to the address of the block end or NULL
inline ea_t *find_visited(ea_t ea);
// get the lowest to start_ea waiting block
inline cref_t get_waiting();
// combine insn counter - count the shortest path
static inline void combine_insn_cnt(uint *dst, uint src)
{
if ( src < *dst )
*dst = src;
}
bool check_bounds() const
{
if ( pfn != NULL )
return func_contains(pfn, cur_ea);
return seg->contains(cur_ea);
}
};
//-------------------------------------------------------------------------
// simple backward flow iterator
struct no_regs_t {};
struct simple_bfi_t
: public backward_flow_iterator_t<no_regs_t, simple_bfi_t>
{
typedef backward_flow_iterator_t<no_regs_t, simple_bfi_t> base_t;
protected:
no_regs_t regs_;
public:
simple_bfi_t(ea_t ea)
: base_t(ea, regs_, *this, false) {}
static void combine_regs(no_regs_t *, const no_regs_t &, ea_t) {}
static void process_delay_slot(ea_t &, bool) {}
};
//======================================================================
// inline implementation
//----------------------------------------------------------------------
//-V:jump_pattern_t:730 not all members of a class are initialized inside the constructor
inline jump_pattern_t::jump_pattern_t(
switch_info_t *_si,
const char (*_depends)[4],
int last_reg)
: modifying_r32_spoils_r64(true),
si(_si),
non_spoiled_reg(-1),
in_linear_flow(false),
depends(_depends),
regs()
{
if ( si != NULL )
si->clear();
regs.resize(last_reg + 1);
}
//----------------------------------------------------------------------
inline bool jump_pattern_t::equal_ops_dtype(
const op_t &op,
const op_t &reg) const
{
if ( !equal_ops(op, reg) )
return false;
// operand should be wider than a tracked register
// e.g. after 'cmp cl, imm' we cannot use cx
if ( !is_narrower(op.dtype, reg.dtype) )
return true;
// we believe that dword is widened to qword
if ( modifying_r32_spoils_r64 && op.dtype == dt_dword )
return true;
// try to extend
if ( !is_narrower(extend_dtype(op), reg.dtype) )
return true;
return false;
}
//----------------------------------------------------------------------
// return true if size1 is narrow than size2
inline bool jump_pattern_t::is_narrower(op_dtype_t dt1, op_dtype_t dt2)
{
if ( dt1 < dt_2bit )
return dt2 < dt_2bit && dt1 < dt2;
else
return dt2 < dt_2bit || dt1 < dt2;
}
//----------------------------------------------------------------------
inline int jump_pattern_t::get_dtype_nbits(op_dtype_t dtype)
{
switch ( dtype )
{
case dt_byte: return 8;
case dt_word: return 16;
case dt_dword: return 32;
case dt_qword: return 64;
case dt_7bit: return 7;
case dt_6bit: return 6;
case dt_5bit: return 5;
case dt_4bit: return 4;
case dt_3bit: return 3;
case dt_2bit: return 2;
default: return -1;
}
}
//----------------------------------------------------------------------
inline void jump_pattern_t::check_spoiled_not_reg(
tracked_regs_t *_regs,
uint maxop) const
{
uint32 feature = insn.get_canon_feature(PH);
if ( feature == 0 )
return;
for ( uint i = 0; i < maxop; ++i )
{
if ( has_cf_chg(feature, i)
&& insn.ops[i].type != o_void
&& insn.ops[i].type != o_reg )
{
set_spoiled(_regs, insn.ops[i]);
}
}
}
//----------------------------------------------------------------------
inline void jump_pattern_t::track(int reg, int r_i, op_dtype_t dtype)
{
regs[r_i].type = o_reg;
regs[r_i].reg = reg;
regs[r_i].dtype = dtype;
}
inline void jump_pattern_t::trackop(const op_t &op, int r_i)
{
regs[r_i] = op;
}
//----------------------------------------------------------------------
inline bool jump_pattern_t::is_equal(int reg, int r_i, op_dtype_t dtype)
{
op_t op;
op.type = o_reg;
op.reg = reg;
op.dtype = dtype;
return is_equal(op, r_i);
}
inline bool jump_pattern_t::is_equal(const op_t &op, int r_i)
{
if ( regs[r_i].type == o_void )
{
// there is no reason to continue match
stop_matching = true;
return false;
}
return equal_ops_dtype(op, regs[r_i]);
}
//----------------------------------------------------------------------
inline bool jump_pattern_t::same_value(const op_t &op, int r_i)
{
return same_value_jpt(this, op, r_i);
}
//----------------------------------------------------------------------
inline bool jump_pattern_t::track_value_until_address(op_t *op, ea_t ea)
{
return track_value_until_address_jpt(this, op, ea);
}
//----------------------------------------------------------------------
inline void jump_pattern_t::set_spoiled(tracked_regs_t *__regs)
{
tracked_regs_t &_regs = *__regs;
// spoil all registers
for ( size_t i = 0; i < _regs.size(); ++i )
_regs[i].type = o_void;
}
inline void jump_pattern_t::set_spoiled(tracked_regs_t *__regs, const op_t &op) const
{
tracked_regs_t &_regs = *__regs;
for ( size_t i = 0; i < _regs.size(); ++i )
if ( equal_ops(_regs[i], op) )
_regs[i].type = o_void; // spoil register
}
//----------------------------------------------------------------------
// find the previous instruction in code flow
// take into account branches and potential delay slots
template<class State,class Ctrl>
inline cref_t backward_flow_iterator_t<State,Ctrl>::prev_insn()
{
size_t refcnt = 0;
// check visited basic block
ea_t *visited_end = find_visited(cur_ea);
if ( visited_end == NULL )
{
// analyze references to the current address
flags_t F = get_flags(cur_ea);
if ( is_flow(F) )
++refcnt;
if ( has_xref(F) && !is_func(F) ) // do not count jumps to function
{
xrefblk_t xb;
for ( bool ok = xb.first_to(cur_ea, XREF_FAR);
ok && xb.iscode;
ok = xb.next_to() )
{
// count only xrefs from jumps
if ( xb.type == fl_JF || xb.type == fl_JN )
{
if ( only_near )
{
if ( refcnt > 0 )
return fl_U;
// do not consider the flow through another switch as linear
if ( (get_flags(xb.from) & FF_JUMP) != 0 )
return fl_U;
}
++refcnt;
ea_t ea = xb.from;
ctrl.process_delay_slot(ea, true);
// ignore jumps from already visited blocks
if ( find_visited(ea) != NULL )
continue;
// add basic block to the waiting set (combine state of the
// tracked registers at the jump source)
state_t &src_state = waiting[ea];
ctrl.combine_regs(&src_state.regs, regs, ea);
combine_insn_cnt(&src_state.insn_cnt, insn_cnt);
}
}
}
if ( cur_end == BADADDR )
cur_end = cur_ea;
// try ordinary flow
if ( is_flow(F) )
{
ea_t prev_ea = prev_not_tail(cur_ea);
if ( prev_ea != BADADDR )
{
cur_ea = prev_ea;
if ( check_bounds()
&& (max_insn_cnt == 0 || insn_cnt < max_insn_cnt) )
{
++insn_cnt;
// remove reached waiting basic block
typename waiting_t::iterator w = waiting.find(cur_ea);
if ( w != waiting.end() )
{
ctrl.combine_regs(&regs, w->second.regs, cur_ea);
combine_insn_cnt(&insn_cnt, w->second.insn_cnt);
waiting.erase(w);
}
else
{
ctrl.process_delay_slot(cur_ea, false);
}
return fl_F;
}
}
// choose another branch
}
// save block [cur_ea, cur_end] as visited
visited[cur_ea] = cur_end;
}
else if ( cur_end != BADADDR )
{
// reach visited basic block => extend it
*visited_end = cur_end;
}
// get the lowest waiting block
cref_t ret = get_waiting();
// consider one xref as a linear flow
if ( ret == fl_JF && refcnt == 1 && waiting.empty() )
ret = fl_F;
return ret;
}
//----------------------------------------------------------------------
template<class State,class Ctrl>
inline cref_t backward_flow_iterator_t<State,Ctrl>::skip_block()
{
// check visited basic block
ea_t *visited_end = find_visited(cur_ea);
if ( visited_end == NULL )
{
if ( cur_end == BADADDR )
cur_end = cur_ea;
// save block [cur_ea, cur_end] as visited
visited[cur_ea] = cur_end;
}
else if ( cur_end != BADADDR )
{
// reach visited basic block => extend it
*visited_end = cur_end;
}
// get the lowest waiting block
return get_waiting();
}
//----------------------------------------------------------------------
template<class State,class Ctrl>
inline cref_t backward_flow_iterator_t<State,Ctrl>::get_waiting()
{
while ( !waiting.empty() )
{
typename waiting_t::iterator w = waiting.upper_bound(start_ea);
if ( w != waiting.begin() )
--w;
cur_ea = w->first;
if ( check_bounds() )
{
cur_end = BADADDR;
regs = w->second.regs;
insn_cnt = w->second.insn_cnt;
waiting.erase(w);
return fl_JF;
}
waiting.erase(w);
}
return fl_U;
}
//----------------------------------------------------------------------
template<class State,class Ctrl>
inline ea_t *backward_flow_iterator_t<State,Ctrl>::find_visited(ea_t ea)
{
visited_t::iterator v = visited.upper_bound(ea);
// assert: v == visited.end() || v->first > ea
if ( v == visited.begin() )
return NULL;
--v;
// assert: v->first <= ea
if ( ea > v->second )
return NULL;
return &v->second;
}
#endif

7761
idasdk76/include/kernwin.hpp Normal file

File diff suppressed because it is too large Load Diff

351
idasdk76/include/lex.hpp Normal file
View File

@@ -0,0 +1,351 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef LEX_HPP
#define LEX_HPP
#include <ieee.h>
/*! \file lex.hpp
\brief Tools for parsing C-like input
Functions in this file use objects of opaque type lexer_t.
To create a lexer_t instance, use create_lexer().
*/
typedef ushort lxtype; ///< see \ref lx_
/// \defgroup lx_ Parser token types
/// See token_t::type
/// \note All separators have their ASCII codes as lxtype
//@{
const lxtype
lx_end = 1, ///< no more tokens
lx_ident = 2, ///< ident
lx_number = 3, ///< long constant
lx_string = 4, ///< string constant (token_t.chr != 0 => unicode string)
lx_char = 5, ///< char constant
lx_typename = 6, ///< user-defined type
lx_float = 7, ///< IEEE floating point constant
lx_int64 = 8, ///< int64 constant
lx_key = 128; ///< keywords start. All keys are lx_key + keynum. \n
///< Two-char separators are: (c1 + (c2 << 8)). \n
///< Three-char separators:
///< - "<<=" = ('<' + ('<'<<8)) + '='
///< - ">>=" = ('>' + ('>'<<8)) + '='
//@}
/// Parser token
struct token_t
{
qstring str; ///< idents & strings
lxtype type = 0; ///< see \ref lx_
sval_t num = 0; ///< long & char constants
union
{
bool unicode = false; ///< (::lx_string: != 0 => unicode string)
bool is_unsigned; ///< (::lx_number, ::lx_int64: != 0 => unsigned value)
};
union
{
fpvalue_t fnum; ///< floating point constant
int64 i64; ///< ::lx_int64
};
token_t() : fnum() {}
};
DECLARE_TYPE_AS_MOVABLE(token_t);
class lexer_t; // lexical analyzer, opaque structure
/// Preprocessor callback for unknown tokens.
/// Will be called when preprocessor calculates the value of #if expression.
typedef error_t lx_resolver_t(lexer_t *lx, void *ud, token_t *curtok, sval_t *res);
#ifdef _MSC_VER
#pragma warning(push)
// Conversion from 'type1 ' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
// We want this sign-extension to happen, since it comes mostly from HANDLEs.
// (see https://msdn.microsoft.com/en-us/library/ms235307.aspx )
#pragma warning(disable:4826)
#endif
/// Preprocessor cast
struct cast_t
{
bool is_unsigned;
int size;
cast_t()
{
reset();
}
void reset(void)
{
is_unsigned = false;
size = 0;
}
};
struct lex_value_t
{
bool is_unsigned;
union
{
int64 val;
uint64 uval;
};
lex_value_t()
{
reset();
}
void set(const lex_value_t &v)
{
set_val(v.val, v.is_unsigned);
}
void reset(void)
{
set_val(0, true);
}
void set_val(int64 v, bool _is_unsigned)
{
is_unsigned = _is_unsigned;
val = v;
}
uint64 get_uval(void) const
{
return val;
}
int64 get_val(void) const
{
return val;
}
bool is_zero(void) const
{
return get_val() == 0;
}
void perform_cast(const cast_t &cast);
void unary_minus(const lex_value_t &v);
void unary_plus(const lex_value_t &v);
void unary_not(const lex_value_t &v);
void bitwise_not(const lex_value_t &v);
void mul(const lex_value_t &v);
void div(const lex_value_t &v);
void mod(const lex_value_t &v);
void add(const lex_value_t &v);
void sub(const lex_value_t &v);
void shift_right(const lex_value_t &v);
void shift_left(const lex_value_t &v);
void bitwise_and(const lex_value_t &v);
void bitwise_xor(const lex_value_t &v);
void bitwise_or(const lex_value_t &v);
void logical_and(const lex_value_t &v);
void logical_or(const lex_value_t &v);
void cmpge(const lex_value_t &v);
void cmple(const lex_value_t &v);
void cmplt(const lex_value_t &v);
void cmpgt(const lex_value_t &v);
void cmpeq(const lex_value_t &v);
void cmpneq(const lex_value_t &v);
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
/// Preprocessor callbacks for casts.
/// Will be called when preprocessor calculates the value of #if expression.
typedef error_t lx_parse_cast_t(lexer_t *lx, cast_t *cast, token_t *ct);
/// Preprocessor callback.
/// It will be called for each input line.
/// \return an error code (0-ok)
typedef int idaapi lx_preprocessor_cb(void *ud, const char *fname, int nl, const char *line);
/// Callback for #pragma directives.
/// \return an error code (0-ok)
typedef int idaapi lx_pragma_cb(void *ud, const char *line);
/// Callback for #warning directives.
/// \return an error code (0-ok)
typedef int idaapi lx_warning_cb(void *ud, const char *line);
/// Callback for #define directives
/// \return an error code (0-ok)
typedef int idaapi lx_macro_cb(
void *ud,
const char *name,
const char *body,
int nargs,
bool isfunc,
bool is_new_macro);
/// Callback for #undef directives
/// \return an error code (0-ok)
typedef int idaapi lx_undef_cb(void *ud, const char *name);
/// Create new lexical analyzer and set its keyword table.
/// If keys==NULL, then set the default C keyword table
idaman lexer_t *ida_export create_lexer(
const char *const *keys,
size_t size,
void *ud=NULL);
/// Destroy a lexical analyzer
idaman void ida_export destroy_lexer(lexer_t *lx);
/// Define a macro
idaman error_t ida_export lex_define_macro(
lexer_t *lx,
const char *macro,
const char *body,
int nargs=0,
bool isfunc=false);
/// Undefine a macro
idaman void ida_export lex_undefine_macro(
lexer_t *lx,
const char *macro);
/// Set lexer options.
/// \param options \ref LXOPT_
/// \return the old options
idaman int ida_export lex_set_options(lexer_t *lx, int options);
/// \defgroup LXOPT_ Lexer options
/// Passed as 'options' parameter to lex_set_options().
/// By default all options are on.
//@{
#define LXOPT_PARSE_FLOATS 0x0001 ///< enable floating point constants
#define LXOPT_REQ_SEPARATOR 0x0002 ///< require a separator between a number and an ident or a character/string constant or dot
#define LXOPT_NOCASE_FILES 0x0004 ///< case-insensitive file search
#define LXOPT_C99_CONSTANTS 0x0008 ///< the size and sign of constants depend on the value itself and the 'U', 'L', and 'LL'
///< modifier suffixes. otherwise the constant is always considered as signed and the size
///< depends only on the number of bytes in the value
//@}
/// Get next token
/// \param p_lnnum line number where the token starts
idaman error_t ida_export lex_get_token(lexer_t *lx, token_t *t);
idaman error_t ida_export lex_get_token2(lexer_t *lx, token_t *t, int32 *p_lnnum);
/// Enumerate all macros.
/// Do so until 'cb' returns non-zero.
idaman int ida_export lex_enum_macros(
const lexer_t *lx,
int idaapi cb(const char *name, const char *body, int nargs, bool isfunc, void *ud),
void *ud=NULL);
/// Debug: get text representation of token
idaman const char *ida_export lex_print_token(qstring *buf, const token_t *t);
//-------------------------------------------------------------------------
/// \name String oriented functions
//@{
/// Set the input line and the macro table.
/// if macros==NULL, the macro table will not be changed.
idaman error_t ida_export lex_init_string(
lexer_t *lx,
const char *line,
void *macros=NULL);
//@}
//-------------------------------------------------------------------------
/// \name File oriented functions
//@{
/// Initialization: file may be NULL.
/// Also see lex_term_file().
idaman error_t ida_export lex_init_file(lexer_t *lx, const char *file);
/// Error handling.
/// if level > 0, then return information about the enclosing file which
/// included the current one.
idaman const char *ida_export lex_get_file_line(
lexer_t *lx,
int32 *linenum,
const char **lineptr,
int level=0);
/// Termination: also see lex_init_file()
idaman void ida_export lex_term_file(lexer_t *lx, bool del_macros);
//@}
//-------------------------------------------------------------------------
/// \name Token stack
//@{
typedef qstack<token_t> tokenstack_t; ///< see get_token(), unget_token()
/// Retrieve token from a stack or lexer.
/// If buf is not empty then get the token on top of the stack.
/// If buf is empty then gen the next token from the lexer.
/// \return success
inline bool get_token(token_t *t, lexer_t *lx, tokenstack_t &buf)
{
if ( !buf.empty() )
*t = buf.pop();
else if ( lex_get_token(lx, t) != eOk )
return false;
return true;
}
/// Push a token back onto the token stack
inline void unget_token(const token_t &t, tokenstack_t &buf)
{
buf.push(t);
}
//@}
#endif // LEX_HPP

595
idasdk76/include/lines.hpp Normal file
View File

@@ -0,0 +1,595 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _LINES_HPP
#define _LINES_HPP
#include <ida.hpp>
/*! \file lines.hpp
\brief High level functions that deal with the generation
of the disassembled text lines.
This file also contains definitions for the syntax highlighting.
Finally there are functions that deal with anterior/posterior
user-defined lines.
*/
struct range_t;
//---------------------------------------------------------------------------
// C O L O R D E F I N I T I O N S
//---------------------------------------------------------------------------
/// \defgroup color_def Color definitions
///
/// Here we describe the structure of embedded escape sequences used to
/// implement syntax highlighting.
///
/// IDP module should insert appropriate escape characters into the
/// output lines as necessary. This approach allows to create an IDP
/// module without the syntax highlighting too - just don't use
/// escape sequences.
///
/// A typical color sequence looks like this:
///
/// #COLOR_ON COLOR_xxx text #COLOR_OFF COLOR_xxx
///
/// The first 2 items turn color 'xxx' on, then the text follows,
/// and the color is turned off by two last items.
///
/// For the convenience we've defined a set of macro definitions
/// and functions to deal with colors.
//@{
/// \defgroup color_esc Color escape characters
/// Initiate/Terminate a color tag
//@{
#define COLOR_ON '\1' ///< Escape character (ON).
///< Followed by a color code (::color_t).
#define COLOR_OFF '\2' ///< Escape character (OFF).
///< Followed by a color code (::color_t).
#define COLOR_ESC '\3' ///< Escape character (Quote next character).
///< This is needed to output '\1' and '\2'
///< characters.
#define COLOR_INV '\4' ///< Escape character (Inverse foreground and background colors).
///< This escape character has no corresponding #COLOR_OFF.
///< Its action continues until the next #COLOR_INV or end of line.
#define SCOLOR_ON "\1" ///< Escape character (ON)
#define SCOLOR_OFF "\2" ///< Escape character (OFF)
#define SCOLOR_ESC "\3" ///< Escape character (Quote next character)
#define SCOLOR_INV "\4" ///< Escape character (Inverse colors)
/// Is the given char a color escape character?
inline THREAD_SAFE bool requires_color_esc(char c) { return c >= COLOR_ON && c <= COLOR_INV; }
//@}
typedef uchar color_t; ///< color tag - see \ref COLOR_
/// \defgroup COLOR_ Color tags
/// Specify a color for a syntax item
//@{
const color_t
COLOR_DEFAULT = 0x01, ///< Default
COLOR_REGCMT = 0x02, ///< Regular comment
COLOR_RPTCMT = 0x03, ///< Repeatable comment (comment defined somewhere else)
COLOR_AUTOCMT = 0x04, ///< Automatic comment
COLOR_INSN = 0x05, ///< Instruction
COLOR_DATNAME = 0x06, ///< Dummy Data Name
COLOR_DNAME = 0x07, ///< Regular Data Name
COLOR_DEMNAME = 0x08, ///< Demangled Name
COLOR_SYMBOL = 0x09, ///< Punctuation
COLOR_CHAR = 0x0A, ///< Char constant in instruction
COLOR_STRING = 0x0B, ///< String constant in instruction
COLOR_NUMBER = 0x0C, ///< Numeric constant in instruction
COLOR_VOIDOP = 0x0D, ///< Void operand
COLOR_CREF = 0x0E, ///< Code reference
COLOR_DREF = 0x0F, ///< Data reference
COLOR_CREFTAIL = 0x10, ///< Code reference to tail byte
COLOR_DREFTAIL = 0x11, ///< Data reference to tail byte
COLOR_ERROR = 0x12, ///< Error or problem
COLOR_PREFIX = 0x13, ///< Line prefix
COLOR_BINPREF = 0x14, ///< Binary line prefix bytes
COLOR_EXTRA = 0x15, ///< Extra line
COLOR_ALTOP = 0x16, ///< Alternative operand
COLOR_HIDNAME = 0x17, ///< Hidden name
COLOR_LIBNAME = 0x18, ///< Library function name
COLOR_LOCNAME = 0x19, ///< Local variable name
COLOR_CODNAME = 0x1A, ///< Dummy code name
COLOR_ASMDIR = 0x1B, ///< Assembler directive
COLOR_MACRO = 0x1C, ///< Macro
COLOR_DSTR = 0x1D, ///< String constant in data directive
COLOR_DCHAR = 0x1E, ///< Char constant in data directive
COLOR_DNUM = 0x1F, ///< Numeric constant in data directive
COLOR_KEYWORD = 0x20, ///< Keywords
COLOR_REG = 0x21, ///< Register name
COLOR_IMPNAME = 0x22, ///< Imported name
COLOR_SEGNAME = 0x23, ///< Segment name
COLOR_UNKNAME = 0x24, ///< Dummy unknown name
COLOR_CNAME = 0x25, ///< Regular code name
COLOR_UNAME = 0x26, ///< Regular unknown name
COLOR_COLLAPSED= 0x27, ///< Collapsed line
COLOR_FG_MAX = 0x28, ///< Max color number
// Fictive colors
COLOR_ADDR = COLOR_FG_MAX, ///< hidden address marks.
///< the address is represented as 8digit
///< hex number: 01234567.
///< it doesn't have #COLOR_OFF pair.
///< NB: for 64-bit IDA, the address is 16digit.
COLOR_OPND1 = COLOR_ADDR+1, ///< Instruction operand 1
COLOR_OPND2 = COLOR_ADDR+2, ///< Instruction operand 2
COLOR_OPND3 = COLOR_ADDR+3, ///< Instruction operand 3
COLOR_OPND4 = COLOR_ADDR+4, ///< Instruction operand 4
COLOR_OPND5 = COLOR_ADDR+5, ///< Instruction operand 5
COLOR_OPND6 = COLOR_ADDR+6, ///< Instruction operand 6
COLOR_OPND7 = COLOR_ADDR+7, ///< Instruction operand 7
COLOR_OPND8 = COLOR_ADDR+8, ///< Instruction operand 8
COLOR_RESERVED1= COLOR_ADDR+11,///< This tag is reserved for internal IDA use
COLOR_LUMINA = COLOR_ADDR+12;///< Lumina-related, only for the navigation band
//@}
/// Size of a tagged address (see ::COLOR_ADDR)
#define COLOR_ADDR_SIZE (sizeof(ea_t)*2)
/// \defgroup SCOLOR_ Color string constants
/// These definitions are used with the #COLSTR macro
//@{
#define SCOLOR_DEFAULT "\x01" ///< Default
#define SCOLOR_REGCMT "\x02" ///< Regular comment
#define SCOLOR_RPTCMT "\x03" ///< Repeatable comment (defined not here)
#define SCOLOR_AUTOCMT "\x04" ///< Automatic comment
#define SCOLOR_INSN "\x05" ///< Instruction
#define SCOLOR_DATNAME "\x06" ///< Dummy Data Name
#define SCOLOR_DNAME "\x07" ///< Regular Data Name
#define SCOLOR_DEMNAME "\x08" ///< Demangled Name
#define SCOLOR_SYMBOL "\x09" ///< Punctuation
#define SCOLOR_CHAR "\x0A" ///< Char constant in instruction
#define SCOLOR_STRING "\x0B" ///< String constant in instruction
#define SCOLOR_NUMBER "\x0C" ///< Numeric constant in instruction
#define SCOLOR_VOIDOP "\x0D" ///< Void operand
#define SCOLOR_CREF "\x0E" ///< Code reference
#define SCOLOR_DREF "\x0F" ///< Data reference
#define SCOLOR_CREFTAIL "\x10" ///< Code reference to tail byte
#define SCOLOR_DREFTAIL "\x11" ///< Data reference to tail byte
#define SCOLOR_ERROR "\x12" ///< Error or problem
#define SCOLOR_PREFIX "\x13" ///< Line prefix
#define SCOLOR_BINPREF "\x14" ///< Binary line prefix bytes
#define SCOLOR_EXTRA "\x15" ///< Extra line
#define SCOLOR_ALTOP "\x16" ///< Alternative operand
#define SCOLOR_HIDNAME "\x17" ///< Hidden name
#define SCOLOR_LIBNAME "\x18" ///< Library function name
#define SCOLOR_LOCNAME "\x19" ///< Local variable name
#define SCOLOR_CODNAME "\x1A" ///< Dummy code name
#define SCOLOR_ASMDIR "\x1B" ///< Assembler directive
#define SCOLOR_MACRO "\x1C" ///< Macro
#define SCOLOR_DSTR "\x1D" ///< String constant in data directive
#define SCOLOR_DCHAR "\x1E" ///< Char constant in data directive
#define SCOLOR_DNUM "\x1F" ///< Numeric constant in data directive
#define SCOLOR_KEYWORD "\x20" ///< Keywords
#define SCOLOR_REG "\x21" ///< Register name
#define SCOLOR_IMPNAME "\x22" ///< Imported name
#define SCOLOR_SEGNAME "\x23" ///< Segment name
#define SCOLOR_UNKNAME "\x24" ///< Dummy unknown name
#define SCOLOR_CNAME "\x25" ///< Regular code name
#define SCOLOR_UNAME "\x26" ///< Regular unknown name
#define SCOLOR_COLLAPSED "\x27" ///< Collapsed line
#define SCOLOR_ADDR "\x28" ///< Hidden address mark
//@}
//----------------- Line prefix colors --------------------------------------
/// \defgroup COLOR_PFX Line prefix colors
/// Note: line prefix colors are not used in processor modules
//@{
#define COLOR_DEFAULT 0x01 ///< Default
#define COLOR_SELECTED 0x02 ///< Selected
#define COLOR_LIBFUNC 0x03 ///< Library function
#define COLOR_REGFUNC 0x04 ///< Regular function
#define COLOR_CODE 0x05 ///< Single instruction
#define COLOR_DATA 0x06 ///< Data bytes
#define COLOR_UNKNOWN 0x07 ///< Unexplored byte
#define COLOR_EXTERN 0x08 ///< External name definition segment
#define COLOR_CURITEM 0x09 ///< Current item
#define COLOR_CURLINE 0x0A ///< Current line
#define COLOR_HIDLINE 0x0B ///< Hidden line
#define COLOR_LUMFUNC 0x0C ///< Lumina function
#define COLOR_BG_MAX 0x0D ///< Max color number
#define PALETTE_SIZE (COLOR_FG_MAX+COLOR_BG_MAX)
//@}
/// This macro is used to build colored string constants (e.g. for format strings)
/// \param str string literal to surround with color tags
/// \param tag one of SCOLOR_xxx constants
#define COLSTR(str,tag) SCOLOR_ON tag str SCOLOR_OFF tag
//------------------------------------------------------------------------
/// \defgroup color_conv Convenience functions
/// Higher level convenience functions are defined in ua.hpp.
/// Please use the following functions only if functions from ua.hpp
/// are not useful in your case.
//@{
/// Insert an address mark into a string.
/// \param buf pointer to the output buffer; the tag will be appended or inserted into it
/// \param ea address to include
/// \param ins if true, the tag will be inserted at the beginning of the buffer
idaman THREAD_SAFE void ida_export tag_addr(qstring *buf, ea_t ea, bool ins=false);
/// Move pointer to a 'line' to 'cnt' positions right.
/// Take into account escape sequences.
/// \param line pointer to string
/// \param cnt number of positions to move right
/// \return moved pointer
idaman THREAD_SAFE const char *ida_export tag_advance(const char *line, int cnt);
/// Move the pointer past all color codes.
/// \param line can't be NULL
/// \return moved pointer, can't be NULL
idaman THREAD_SAFE const char *ida_export tag_skipcodes(const char *line);
/// Skip one color code.
/// This function should be used if you are interested in color codes
/// and want to analyze all of them.
/// Otherwise tag_skipcodes() function is better since it will skip all colors at once.
/// This function will skip the current color code if there is one.
/// If the current symbol is not a color code, it will return the input.
/// \return moved pointer
idaman THREAD_SAFE const char *ida_export tag_skipcode(const char *line);
/// Calculate length of a colored string
/// This function computes the length in unicode codepoints of a line
/// \return the number of codepoints in the line, or -1 on error
idaman THREAD_SAFE ssize_t ida_export tag_strlen(const char *line);
/// Remove color escape sequences from a string.
/// \param buf output buffer with the string, cannot be NULL.
/// \param str input string, cannot be NULL.
/// \param init_level used to verify that COLOR_ON and COLOR_OFF tags are balanced
/// \return length of resulting string, -1 if error
idaman THREAD_SAFE ssize_t ida_export tag_remove(qstring *buf, const char *str, int init_level=0);
inline THREAD_SAFE ssize_t idaapi tag_remove(qstring *buf, const qstring &str, int init_level=0)
{
return tag_remove(buf, str.c_str(), init_level);
}
inline THREAD_SAFE ssize_t idaapi tag_remove(qstring *buf, int init_level=0)
{
if ( buf->empty() )
return 0;
return tag_remove(buf, buf->begin(), init_level);
}
//@} color_conv
//@} color_def
/// Get prefix color for line at 'ea'
/// \return \ref COLOR_PFX
idaman color_t ida_export calc_prefix_color(ea_t ea);
/// Get background color for line at 'ea'
/// \return RGB color
idaman bgcolor_t ida_export calc_bg_color(ea_t ea);
//------------------------------------------------------------------------
// S O U R C E F I L E S
//------------------------------------------------------------------------
/// \name Source files
/// IDA can keep information about source files used to create the program.
/// Each source file is represented by a range of addresses.
/// A source file may contain several address ranges.
//@{
/// Mark a range of address as belonging to a source file.
/// An address range may belong only to one source file.
/// A source file may be represented by several address ranges.
/// \param ea1 linear address of start of the address range
/// \param ea2 linear address of end of the address range (excluded)
/// \param filename name of source file.
/// \return success
idaman bool ida_export add_sourcefile(ea_t ea1, ea_t ea2, const char *filename);
/// Get name of source file occupying the given address.
/// \param ea linear address
/// \param bounds pointer to the output buffer with the address range
/// for the current file. May be NULL.
/// \return NULL if source file information is not found,
/// otherwise returns pointer to file name
idaman const char *ida_export get_sourcefile(ea_t ea, range_t *bounds=NULL);
/// Delete information about the source file.
/// \param ea linear address
/// \return success
idaman bool ida_export del_sourcefile(ea_t ea);
//@}
//------------------------------------------------------------------------
// G E N E R A T I O N O F D I S A S S E M B L E D T E X T
//------------------------------------------------------------------------
/// \name Generation of disassembled text
//@{
/// User-defined line-prefixes are displayed just after the autogenerated
/// line prefixes in the disassembly listing.
/// There is no need to call this function explicitly.
/// Use the user_defined_prefix_t class.
/// \param prefix_len prefixed length. if 0, then uninstall UDP
/// \param udp object to generate user-defined prefix
/// \param install true:install, false:uninstall
/// \param owner pointer to the plugin_t that owns UDP
/// if non-NULL, then the object will be uninstalled and destroyed
/// when the plugin gets unloaded
idaman bool ida_export install_user_defined_prefix(
size_t prefix_len,
struct user_defined_prefix_t *udp,
const void *owner);
/// Class to generate user-defined prefixes in the disassembly listing.
struct user_defined_prefix_t
{
/// Creating a user-defined prefix object installs it.
user_defined_prefix_t(size_t prefix_len, const void *owner)
{
install_user_defined_prefix(prefix_len, this, owner);
}
/// Destroying a user-defined prefix object uninstalls it.
virtual idaapi ~user_defined_prefix_t()
{
install_user_defined_prefix(0, this, nullptr);
}
// Get a user-defined prefix.
/// This callback must be overridden by the derived class.
/// \param out the output buffer
/// \param ea the current address
/// \param insn the current instruction. if the current item is not
/// an instruction, then insn.itype is zero.
/// \param indent see explanations for \ref gen_printf()
/// \param line the line to be generated.
/// the line usually contains color tags.
/// this argument can be examined to decide
/// whether to generate the prefix.
virtual void idaapi get_user_defined_prefix(
qstring *vout,
ea_t ea,
const class insn_t &insn,
int lnnum,
int indent,
const char *line) = 0;
};
//@}
//------------------------------------------------------------------------
// A N T E R I O R / P O S T E R I O R L I N E S
//------------------------------------------------------------------------
/// \name Anterior/Posterior lines
//@{
/// See higher level functions below
idaman AS_PRINTF(3, 0) bool ida_export vadd_extra_line(
ea_t ea,
int vel_flags, // see VEL_...
const char *format,
va_list va);
#define VEL_POST 0x01 // append posterior line
#define VEL_CMT 0x02 // append comment line
/// Add anterior/posterior non-comment line(s).
/// \param ea linear address
/// \param isprev do we add anterior lines? (0-no, posterior)
/// \param format printf() style format string. may contain \\n to denote new lines.
/// \return true if success
AS_PRINTF(3, 4) inline bool add_extra_line(ea_t ea, bool isprev, const char *format, ...)
{
va_list va;
va_start(va,format);
int vel_flags = (isprev ? 0 : VEL_POST);
bool ok = vadd_extra_line(ea, vel_flags, format, va);
va_end(va);
return ok;
}
/// Add anterior/posterior comment line(s).
/// \param ea linear address
/// \param isprev do we add anterior lines? (0-no, posterior)
/// \param format printf() style format string. may contain \\n to denote
/// new lines. The resulting string should not contain comment
/// characters (;), the kernel will add them automatically.
/// \return true if success
AS_PRINTF(3, 4) inline bool add_extra_cmt(ea_t ea, bool isprev, const char *format, ...)
{
va_list va;
va_start(va,format);
int vel_flags = (isprev ? 0 : VEL_POST) | VEL_CMT;
bool ok = vadd_extra_line(ea, vel_flags, format, va);
va_end(va);
return ok;
}
/// Add anterior comment line(s) at the start of program.
/// \param format printf() style format string. may contain \\n to denote
/// new lines. The resulting string should not contain comment
/// characters (;), the kernel will add them automatically.
/// \return true if success
AS_PRINTF(1, 2) inline bool add_pgm_cmt(const char *format, ...)
{
va_list va;
va_start(va,format);
bool ok = vadd_extra_line(inf_get_min_ea(), VEL_CMT, format, va);
va_end(va);
return ok;
}
//@}
///---------------------------------------------------------------------\cond
/// The following functions are used in kernel only:
// Generate disassembly (many lines) and put them into a buffer
// Returns number of generated lines
idaman int ida_export generate_disassembly(
qstrvec_t *out, // buffer to hold generated lines
int *lnnum, // number of "the most interesting" line
ea_t ea, // address to generate disassembly for
int maxsize, // maximum number of lines
bool as_stack); // Display undefined items as 2/4/8 bytes
// Generate one line of disassembly
// This function discards all "non-interesting" lines
// It is designed to generate one-line descriptions
// of addresses for lists, etc.
idaman bool ida_export generate_disasm_line(
qstring *buf, // output buffer
ea_t ea, // address to generate disassembly for
int flags=0);
#define GENDSM_FORCE_CODE (1 << 0) // generate a disassembly line as if
// there is an instruction at 'ea'
#define GENDSM_MULTI_LINE (1 << 1) // if the instruction consists of several lines,
// produce all of them (useful for parallel instructions)
#define GENDSM_REMOVE_TAGS (1 << 2) // remove tags from output buffer
/// Get length of the line prefix that was used for the last generated line
idaman int ida_export get_last_pfxlen(void);
// Get pointer to the sequence of characters denoting 'close comment'
// empty string means no comment (the current assembler has no open-comment close-comment pairs)
// This function uses ash.cmnt2
idaman const char *ida_export closing_comment(void);
// Every anterior/posterior line has its number.
// Anterior lines have numbers from E_PREV
// Posterior lines have numbers from E_NEXT
const int E_PREV = 1000;
const int E_NEXT = 2000;
idaman int ida_export get_first_free_extra_cmtidx(ea_t ea, int start);
idaman void ida_export update_extra_cmt(ea_t ea, int what, const char *str);
idaman void ida_export del_extra_cmt(ea_t ea, int what);
idaman ssize_t ida_export get_extra_cmt(qstring *buf, ea_t ea, int what);
idaman void ida_export delete_extra_cmts(ea_t ea, int what);
idaman ea_t ida_export align_down_to_stack(ea_t newea);
idaman ea_t ida_export align_up_to_stack(ea_t ea1, ea_t ea2=BADADDR);
// A helper class, to encode from UTF-8, -> into the target encoding.
// This is typically used when generating listings (or any kind of
// output file.)
struct encoder_t
{
// whether or not a message should be printed, letting the
// user know that some text couldn't be recoded properly
enum notify_recerr_t
{
nr_none,
nr_once,
};
virtual ~encoder_t() {}
virtual bool idaapi get_bom(bytevec_t *out) const = 0;
// returns true if conversion was entirely successful, false otherwise.
// codepoints that couldn't be converted, will be output as C
// literal-escaped UTF-8 sequences (e.g., "\xC3\xD9"), and if
// 'nr_once' was passed at creation-time, a one-time notification
// well be output in the messages window.
virtual bool idaapi encode(qstring *s) const = 0;
// encode()s the UTF-8 string composed by format + args, and
// returns true if all the resulting bytes could be written to
// the output file.
AS_PRINTF(3, 4) virtual bool idaapi print(FILE *out, const char *format, ...) const = 0;
// should a file be opened as binary, or should it rather be opened
// in text mode? This will have an importance in how '\n' characters
// are possibly converted into '\x0A\x0D' on windows, which is most
// inappropriate when output'ing e.g., UTF-16, UTF-32..
virtual bool idaapi requires_binary_mode() const = 0;
};
// Create the encoder with the given target encoding. If -1 is passed
// then the effective target encoding will be computed like so:
// if ( encidx < 0 )
// {
// encidx = get_outfile_encoding_idx();
// if ( encidx == STRENC_DEFAULT )
// encidx = get_default_encoding_idx(BPU_1B);
// }
idaman encoder_t *ida_export create_encoding_helper(
int encidx=-1,
encoder_t::notify_recerr_t nr=encoder_t::nr_once);
/// Callback functions to output lines:
//@{
typedef int idaapi html_header_cb_t(FILE *fp);
typedef int idaapi html_footer_cb_t(FILE *fp);
typedef int idaapi html_line_cb_t(
FILE *fp,
const qstring &line,
bgcolor_t prefix_color,
bgcolor_t bg_color);
#define gen_outline_t html_line_cb_t
//@}
///-------------------------------------------------------------------\endcond
#ifndef NO_OBSOLETE_FUNCS
idaman DEPRECATED void ida_export set_user_defined_prefix( // use install_user_defined_prefix()
size_t width,
void (idaapi *get_user_defined_prefix)(
qstring *buf,
ea_t ea,
int lnnum,
int indent,
const char *line));
#endif
#endif

293
idasdk76/include/llong.hpp Normal file
View File

@@ -0,0 +1,293 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _LLONG_HPP
#define _LLONG_HPP
//---------------------------------------------------------------------------
#if defined(_MSC_VER)
typedef unsigned __int64 ulonglong;
typedef __int64 longlong;
#elif defined(__GNUC__)
typedef unsigned long long ulonglong;
typedef long long longlong;
#endif
//---------------------------------------------------------------------------
#ifdef __cplusplus
inline constexpr longlong make_longlong(uint32 ll,int32 hh) { return ll | (longlong(hh) << 32); }
inline constexpr ulonglong make_ulonglong(uint32 ll,int32 hh) { return ll | (ulonglong(hh) << 32); }
inline uint32 low(const ulonglong &x) { return uint32(x); }
inline uint32 high(const ulonglong &x) { return uint32(x>>32); }
inline uint32 low(const longlong &x) { return uint32(x); }
inline int32 high(const longlong &x) { return uint32(x>>32); }
#else
#define make_longlong(ll,hh) (ll | (longlong(hh) << 32))
#define make_ulonglong(ll,hh) (ll | (ulonglong(hh) << 32))
#endif
idaman THREAD_SAFE longlong ida_export llong_scan(
const char *buf,
int radix,
const char **end);
#ifndef swap64
idaman THREAD_SAFE ulonglong ida_export swap64(ulonglong);
# ifdef __cplusplus
inline longlong swap64(longlong x)
{
return longlong(swap64(ulonglong(x)));
}
# endif
#endif
//---------------------------------------------------------------------------
// 128 BIT NUMBERS
//---------------------------------------------------------------------------
#ifdef __HAS_INT128__
typedef unsigned __int128 uint128;
typedef __int128 int128;
inline int128 make_int128(ulonglong ll,longlong hh) { return ll | (int128(hh) << 64); }
inline uint128 make_uint128(ulonglong ll,ulonglong hh) { return ll | (uint128(hh) << 64); }
inline ulonglong low(const uint128 &x) { return ulonglong(x); }
inline ulonglong high(const uint128 &x) { return ulonglong(x>>64); }
inline ulonglong low(const int128 &x) { return ulonglong(x); }
inline longlong high(const int128 &x) { return ulonglong(x>>64); }
#else
#ifdef __cplusplus
//-V:uint128:730 not all members of a class are initialized inside the constructor
class uint128
{
ulonglong l;
ulonglong h;
friend class int128;
public:
uint128(void) {}
uint128(uint x) { l = x; h = 0; }
uint128(int x) { l = x; h = (x < 0)? -1 : 0; }
uint128(ulonglong x) { l = x; h = 0; }
uint128(longlong x) { l = x; h = (x < 0) ? -1 : 0; }
uint128(ulonglong ll, ulonglong hh) { l = ll; h = hh; }
friend ulonglong low (const uint128 &x) { return x.l; }
friend ulonglong high(const uint128 &x) { return x.h; }
friend uint128 operator+(const uint128 &x, const uint128 &y);
friend uint128 operator-(const uint128 &x, const uint128 &y);
friend uint128 operator/(const uint128 &x, const uint128 &y);
friend uint128 operator%(const uint128 &x, const uint128 &y);
friend uint128 operator*(const uint128 &x, const uint128 &y);
friend uint128 operator|(const uint128 &x, const uint128 &y);
friend uint128 operator&(const uint128 &x, const uint128 &y);
friend uint128 operator^(const uint128 &x, const uint128 &y);
friend uint128 operator>>(const uint128 &x, int cnt);
friend uint128 operator<<(const uint128 &x, int cnt);
uint128 &operator+=(const uint128 &y);
uint128 &operator-=(const uint128 &y);
uint128 &operator/=(const uint128 &y);
uint128 &operator%=(const uint128 &y);
uint128 &operator*=(const uint128 &y);
uint128 &operator|=(const uint128 &y);
uint128 &operator&=(const uint128 &y);
uint128 &operator^=(const uint128 &y);
uint128 &operator>>=(int cnt);
uint128 &operator<<=(int cnt);
uint128 &operator++(void);
uint128 &operator--(void);
friend uint128 operator+(const uint128 &x) { return x; }
friend uint128 operator-(const uint128 &x);
friend uint128 operator~(const uint128 &x) { return uint128(~x.l,~x.h); }
friend int operator==(const uint128 &x, const uint128 &y) { return x.l == y.l && x.h == y.h; }
friend int operator!=(const uint128 &x, const uint128 &y) { return x.l != y.l || x.h != y.h; }
friend int operator> (const uint128 &x, const uint128 &y) { return x.h > y.h || (x.h == y.h && x.l > y.l); }
friend int operator< (const uint128 &x, const uint128 &y) { return x.h < y.h || (x.h == y.h && x.l < y.l); }
friend int operator>=(const uint128 &x, const uint128 &y) { return x.h > y.h || (x.h == y.h && x.l >= y.l); }
friend int operator<=(const uint128 &x, const uint128 &y) { return x.h < y.h || (x.h == y.h && x.l <= y.l); }
};
//-V:int128:730 not all members of a class are initialized inside the constructor
class int128
{
ulonglong l;
longlong h;
friend class uint128;
public:
int128(void) {}
int128(uint x) { l = x; h = 0; }
int128(int x) { l = x; h = (x < 0) ? -1 : 0; }
int128(ulonglong x) { l = x; h = 0; }
int128(longlong x) { l = x; h = (x < 0) ? -1 : 0; }
int128(ulonglong ll, ulonglong hh) { l=ll; h=hh; }
int128(const uint128 &x) { l=x.l; h=x.h; }
friend ulonglong low (const int128 &x) { return x.l; }
friend ulonglong high(const int128 &x) { return x.h; }
friend int128 operator+(const int128 &x, const int128 &y);
friend int128 operator-(const int128 &x, const int128 &y);
friend int128 operator/(const int128 &x, const int128 &y);
friend int128 operator%(const int128 &x, const int128 &y);
friend int128 operator*(const int128 &x, const int128 &y);
friend int128 operator|(const int128 &x, const int128 &y);
friend int128 operator&(const int128 &x, const int128 &y);
friend int128 operator^(const int128 &x, const int128 &y);
friend int128 operator>>(const int128 &x, int cnt);
friend int128 operator<<(const int128 &x, int cnt);
int128 &operator+=(const int128 &y);
int128 &operator-=(const int128 &y);
int128 &operator/=(const int128 &y);
int128 &operator%=(const int128 &y);
int128 &operator*=(const int128 &y);
int128 &operator|=(const int128 &y);
int128 &operator&=(const int128 &y);
int128 &operator^=(const int128 &y);
int128 &operator>>=(int cnt);
int128 &operator<<=(int cnt);
int128 &operator++(void);
int128 &operator--(void);
friend int128 operator+(const int128 &x) { return x; }
friend int128 operator-(const int128 &x);
friend int128 operator~(const int128 &x) { return int128(~x.l,~x.h); }
friend int operator==(const int128 &x, const int128 &y) { return x.l == y.l && x.h == y.h; }
friend int operator!=(const int128 &x, const int128 &y) { return x.l != y.l || x.h != y.h; }
friend int operator> (const int128 &x, const int128 &y) { return x.h > y.h || (x.h == y.h && x.l > y.l); }
friend int operator< (const int128 &x, const int128 &y) { return x.h < y.h || (x.h == y.h && x.l < y.l); }
friend int operator>=(const int128 &x, const int128 &y) { return x.h > y.h || (x.h == y.h && x.l >= y.l); }
friend int operator<=(const int128 &x, const int128 &y) { return x.h < y.h || (x.h == y.h && x.l <= y.l); }
};
inline int128 make_int128(ulonglong ll, longlong hh) { return int128(ll, hh); }
inline uint128 make_uint128(ulonglong ll, longlong hh) { return uint128(ll, hh); }
idaman THREAD_SAFE void ida_export swap128(uint128 *x);
//---------------------------------------------------------------------------
inline uint128 operator+(const uint128 &x, const uint128 &y)
{
ulonglong h = x.h + y.h;
ulonglong l = x.l + y.l;
if ( l < x.l )
h = h + 1;
return uint128(l,h);
}
//---------------------------------------------------------------------------
inline uint128 operator-(const uint128 &x, const uint128 &y)
{
ulonglong h = x.h - y.h;
ulonglong l = x.l - y.l;
if ( l > x.l )
h = h - 1;
return uint128(l,h);
}
//---------------------------------------------------------------------------
inline uint128 operator|(const uint128 &x, const uint128 &y)
{
return uint128(x.l | y.l, x.h | y.h);
}
//---------------------------------------------------------------------------
inline uint128 operator&(const uint128 &x, const uint128 &y)
{
return uint128(x.l & y.l, x.h & y.h);
}
//---------------------------------------------------------------------------
inline uint128 operator^(const uint128 &x, const uint128 &y)
{
return uint128(x.l ^ y.l, x.h ^ y.h);
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator+=(const uint128 &y)
{
return *this = *this + y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator-=(const uint128 &y)
{
return *this = *this - y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator|=(const uint128 &y)
{
return *this = *this | y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator&=(const uint128 &y)
{
return *this = *this & y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator^=(const uint128 &y)
{
return *this = *this ^ y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator/=(const uint128 &y)
{
return *this = *this / y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator%=(const uint128 &y)
{
return *this = *this % y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator*=(const uint128 &y)
{
return *this = *this * y;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator<<=(int cnt)
{
return *this = *this << cnt;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator>>=(int cnt)
{
return *this = *this >> cnt;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator++(void)
{
if ( ++l == 0 )
++h;
return *this;
}
//---------------------------------------------------------------------------
inline uint128 &uint128::operator--(void)
{
if ( l == 0 )
--h;
--l;
return *this;
}
//---------------------------------------------------------------------------
inline uint128 operator-(const uint128 &x)
{
return ~x + 1;
}
#endif // ifdef __cplusplus
#endif // ifdef __HAS_INT128__
#endif // define _LLONG_HPP

1042
idasdk76/include/loader.hpp Normal file

File diff suppressed because it is too large Load Diff

16
idasdk76/include/md5.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef MD5_H
#define MD5_H
struct MD5Context
{
uint32 buf[4];
uint32 bits[2];
unsigned char in[64];
};
idaman THREAD_SAFE void ida_export MD5Init(MD5Context *context);
idaman THREAD_SAFE void ida_export MD5Update(MD5Context *context, const uchar *buf, size_t len);
idaman THREAD_SAFE void ida_export MD5Final(uchar digest[16], MD5Context *context);
idaman THREAD_SAFE void ida_export MD5Transform(uint32 buf[4], uint32 const in[16]);
#endif /* !MD5_H */

391
idasdk76/include/moves.hpp Normal file
View File

@@ -0,0 +1,391 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __MOVES_HPP
#define __MOVES_HPP
#include <dirtree.hpp>
//-------------------------------------------------------------------------
struct graph_location_info_t
{
double zoom; // zoom level, 1.0 == 100%, 0 means auto position
double orgx; // graph origin, x coord
double orgy; // graph origin, y coord
graph_location_info_t(void) : zoom(0), orgx(0), orgy(0) {}
bool operator == (const graph_location_info_t &r) const
{ return zoom == r.zoom && orgx == r.orgx && orgy == r.orgy; } //-V550 An odd precise comparison: zoom == r.zoom
bool operator != (const graph_location_info_t &r) const
{ return !(*this == r); }
void serialize(bytevec_t *out) const;
bool deserialize(memory_deserializer_t &mmdsr);
};
//-------------------------------------------------------------------------
inline void graph_location_info_t::serialize(bytevec_t *out) const
{
CASSERT(sizeof(graph_location_info_t) == 3*8);
out->append(this, sizeof(graph_location_info_t));
}
//-------------------------------------------------------------------------
inline bool graph_location_info_t::deserialize(memory_deserializer_t &mmdsr)
{
return mmdsr.unpack_obj(this, sizeof(graph_location_info_t)) != NULL;
}
//-------------------------------------------------------------------------
struct segm_move_info_t
{
segm_move_info_t(ea_t _from = 0, ea_t _to = 0, size_t _sz = 0)
: from(_from), to(_to), size(_sz) {}
ea_t from, to;
size_t size;
bool operator == (const segm_move_info_t &r) const
{ return from == r.from && to == r.to && size == r.size; }
bool operator != (const segm_move_info_t &r) const
{ return !(*this == r); }
};
DECLARE_TYPE_AS_MOVABLE(segm_move_info_t);
typedef qvector<segm_move_info_t> segm_move_info_vec_t;
struct segm_move_infos_t : public segm_move_info_vec_t
{
const segm_move_info_t *find(ea_t ea) const
{
for ( size_t i = 0; i < size(); ++i )
{
const segm_move_info_t &cur = at(i);
if ( ea >= cur.from && ea < cur.from + cur.size )
return &cur;
}
return NULL;
}
};
//-------------------------------------------------------------------------
class place_t;
//-------------------------------------------------------------------------
struct renderer_info_pos_t // out of renderer_info_t, to enable SWiG parsing
{
int node;
short cx;
short cy;
renderer_info_pos_t() : node(-1), cx(-1), cy(-1) {}
bool operator == (const renderer_info_pos_t &r) const
{ return node == r.node && cx == r.cx && cy == r.cy; }
bool operator != (const renderer_info_pos_t &r) const
{ return !(*this == r); }
void serialize(bytevec_t *out) const;
bool deserialize(memory_deserializer_t &mmdsr);
};
//-------------------------------------------------------------------------
inline void renderer_info_pos_t::serialize(bytevec_t *out) const
{
out->pack_dd(node);
out->pack_dw(cx);
out->pack_dw(cy);
}
//-------------------------------------------------------------------------
inline bool renderer_info_pos_t::deserialize(memory_deserializer_t &mmdsr)
{
node = mmdsr.unpack_dd();
cx = mmdsr.unpack_dw();
if ( mmdsr.empty() )
return false;
cy = mmdsr.unpack_dw();
return true;
}
//-------------------------------------------------------------------------
struct renderer_info_t
{
graph_location_info_t gli;
typedef renderer_info_pos_t pos_t;
pos_t pos;
tcc_renderer_type_t rtype = TCCRT_INVALID;
bool operator == (const renderer_info_t &r) const
{ return rtype == r.rtype && pos == r.pos && gli == r.gli; }
bool operator != (const renderer_info_t &r) const
{ return !(*this == r); }
};
//-------------------------------------------------------------------------
class lochist_t;
struct lochist_entry_t;
struct expanded_area_t;
#define LSEF_PLACE (1 << 0)
#define LSEF_RINFO (1 << 1)
#define LSEF_PTYPE (1 << 2)
#define LSEF_ALL (LSEF_PLACE|LSEF_RINFO|LSEF_PTYPE)
#ifndef SWIG
#define DEFINE_LOCHIST_T_HELPERS(decl) \
decl void ida_export lochist_t_register_live(lochist_t &); \
decl void ida_export lochist_t_deregister_live(lochist_t &); \
decl bool ida_export lochist_t_init (lochist_t &, const char *, const place_t &, void *, uint32); \
decl void ida_export lochist_t_jump (lochist_t &, bool try_to_unhide, const lochist_entry_t &e); \
decl bool ida_export lochist_t_fwd (lochist_t &, uint32 cnt, bool try_to_unhide); \
decl bool ida_export lochist_t_back (lochist_t &, uint32 cnt, bool try_to_unhide); \
decl bool ida_export lochist_t_seek (lochist_t &, uint32 index, bool try_to_unhide, bool apply_cur); \
decl const lochist_entry_t *ida_export lochist_t_get_current(const lochist_t &); \
decl uint32 ida_export lochist_t_current_index(const lochist_t &); \
decl void ida_export lochist_t_set (lochist_t &, uint32, const lochist_entry_t &); \
decl bool ida_export lochist_t_get (lochist_entry_t *, const lochist_t &, uint32); \
decl uint32 ida_export lochist_t_size (const lochist_t &);\
decl void ida_export lochist_t_save (const lochist_t &); \
decl void ida_export lochist_t_clear (lochist_t &);
#else
#define DEFINE_LOCHIST_T_HELPERS(decl)
#endif // SWIG
DEFINE_LOCHIST_T_HELPERS(idaman)
#ifndef SWIG
#define DEFINE_LOCHIST_ENTRY_T_HELPERS(decl) \
decl void ida_export lochist_entry_t_serialize(bytevec_t *, const lochist_entry_t &); \
decl bool ida_export lochist_entry_t_deserialize(lochist_entry_t *, const uchar **, const uchar *const, const place_t *);
#else
#define DEFINE_LOCHIST_ENTRY_T_HELPERS(decl)
#endif // SWIG
DEFINE_LOCHIST_ENTRY_T_HELPERS(idaman)
//-------------------------------------------------------------------------
struct lochist_entry_t
{
renderer_info_t rinfo;
place_t *plce;
lochist_entry_t() : plce(NULL) {}
lochist_entry_t(const place_t *p, const renderer_info_t &r)
: rinfo(r), plce((place_t *) p)
{
if ( plce != NULL )
plce = plce->clone();
}
#ifndef SWIG
lochist_entry_t(const lochist_t &s);
#endif // SWIG
lochist_entry_t(const lochist_entry_t &other) : plce(NULL) { *this = other; }
~lochist_entry_t() { clear(); }
const renderer_info_t &renderer_info() const { return rinfo; }
const place_t *place() const { return plce; }
renderer_info_t &renderer_info() { return rinfo; }
place_t *place() { return plce; }
void set_place(const place_t *p) { clear(); if ( p != NULL ) plce = p->clone(); }
void set_place(const place_t &p) { set_place(&p); }
bool is_valid() const { return plce != NULL; }
lochist_entry_t &operator=(const lochist_entry_t &r)
{
clear();
(*this).rinfo = r.rinfo;
if ( r.plce != NULL )
plce = r.plce->clone();
return *this;
}
void acquire_place(place_t *in_p)
{ clear(); plce = in_p; }
void serialize(bytevec_t *out) const { lochist_entry_t_serialize(out, *this); }
bool deserialize(const uchar **ptr, const uchar *const end, const place_t *tmplate)
{ return lochist_entry_t_deserialize(this, ptr, end, tmplate); }
private:
void clear()
{
if ( plce != NULL )
qfree(plce);
plce = NULL;
}
friend class lochist_t;
DEFINE_LOCHIST_T_HELPERS(friend)
DEFINE_LOCHIST_ENTRY_T_HELPERS(friend)
};
DECLARE_TYPE_AS_MOVABLE(lochist_entry_t);
typedef qvector<lochist_entry_t> lochist_entry_vec_t;
#define UNHID_SEGM 0x0001 // unhid a segment at 'target'
#define UNHID_FUNC 0x0002 // unhid a function at 'target'
#define UNHID_RANGE 0x0004 // unhid an range at 'target'
#define DEFAULT_CURSOR_Y 0xFFFF
#define DEFAULT_LNNUM -1
#define CURLOC_LIST "$ curlocs"
#define MAX_MARK_SLOT 1024 // Max number of marked locations
//-------------------------------------------------------------------------
class lochist_t
{
void *ud;
DEFINE_LOCHIST_T_HELPERS(friend)
lochist_entry_t cur;
netnode node;
#define LHF_HISTORY_DISABLED (1 << 0) // enable history?
uint32 flags;
public:
lochist_t() : flags(0) { lochist_t_register_live(*this); }
~lochist_t() { lochist_t_deregister_live(*this); }
bool is_history_enabled() const { return (flags & LHF_HISTORY_DISABLED) == 0; }
int get_place_id() const
{
const place_t *p = cur.place();
return p == NULL ? -1 : p->id();
}
bool init(const char *stream_name, const place_t *_defpos, void *_ud, uint32 _flags)
{ return lochist_t_init(*this, stream_name, *_defpos, _ud, _flags); }
nodeidx_t netcode() const
{ return node; }
void jump(bool try_to_unhide, const lochist_entry_t &e)
{ lochist_t_jump(*this, try_to_unhide, e); }
uint32 current_index() const
{ return lochist_t_current_index(*this); }
bool seek(uint32 index, bool try_to_unhide)
{ return lochist_t_seek(*this, index, try_to_unhide, true); }
bool fwd(uint32 cnt, bool try_to_unhide)
{ return lochist_t_fwd(*this, cnt, try_to_unhide); }
bool back(uint32 cnt, bool try_to_unhide)
{ return lochist_t_back(*this, cnt, try_to_unhide); }
void save() const
{ lochist_t_save(*this); }
void clear()
{ lochist_t_clear(*this); }
const lochist_entry_t &get_current() const
{ return *lochist_t_get_current(*this); }
void set_current(const lochist_entry_t &e)
{ return set(current_index(), e); }
void set(uint32 index, const lochist_entry_t &e)
{ lochist_t_set(*this, index, e); }
bool get(lochist_entry_t *out, uint32 index) const
{ return lochist_t_get(out, *this, index); }
uint32 size(void) const
{ return lochist_t_size(*this); }
const place_t *get_template_place() const
{ return cur.place(); }
};
DECLARE_TYPE_AS_MOVABLE(lochist_t);
//-------------------------------------------------------------------------
#ifndef SWIG
idaman uint32 ida_export bookmarks_t_mark(const lochist_entry_t &, uint32, const char *, const char *, void *);
idaman bool ida_export bookmarks_t_get(lochist_entry_t *, qstring *, uint32 *, void *);
idaman bool ida_export bookmarks_t_get_desc(qstring *, const lochist_entry_t &, uint32, void *);
idaman bool ida_export bookmarks_t_set_desc(qstring, const lochist_entry_t &, uint32, void *);
idaman uint32 ida_export bookmarks_t_find_index(const lochist_entry_t &, void *);
idaman uint32 ida_export bookmarks_t_size(const lochist_entry_t &, void *);
idaman bool ida_export bookmarks_t_erase(const lochist_entry_t &, uint32, void *);
idaman dirtree_id_t ida_export bookmarks_t_get_dirtree_id(const lochist_entry_t &, void *);
#endif // SWIG
//-------------------------------------------------------------------------
class bookmarks_t
{
bookmarks_t(); // No.
~bookmarks_t() {}
public:
#define BOOKMARKS_CHOOSE_INDEX (uint32(-1))
#define BOOKMARKS_BAD_INDEX (uint32(-1))
#define BOOKMARKS_PROMPT_WITH_HINT_PREFIX '\x01'
// Mark/unmark position
// index - the marked position number (0..MAX_MARK_SLOT)
// if specified as BOOKMARKS_CHOOSE_INDEX: ask the user to select the mark slot.
// title - if index == BOOKMARKS_CHOOSE_INDEX, then the window caption of
// the dialog which will appear on the screen. title==NULL will
// lead to the default caption: "please select a mark slot"
// desc - description of the marked position. If NULL, IDA will show a
// dialog box asking the user to enter the description.
// If non-NULL but starts with BOOKMARKS_PROMPT_WITH_HINT_PREFIX,
// IDA will also prompt the user, but with a pre-filled value
// starting at &desc[1].
// returns used marker number (BOOKMARKS_BAD_INDEX - none)
static uint32 mark(
const lochist_entry_t &e,
uint32 index,
const char *title,
const char *desc,
void *ud)
{ return bookmarks_t_mark(e, index, title, desc, ud); }
// 'out_entry' MUST:
// - contain a valid place_t*; data will be deserialized into it
// - have a valid, corresponding tcc_place_type_t
static bool get(
lochist_entry_t *out_entry,
qstring *out_desc,
uint32 *index, // index==BOOKMARKS_CHOOSE_INDEX? let the user choose
void *ud)
{ return bookmarks_t_get(out_entry, out_desc, index, ud); }
static bool get_desc(
qstring *out,
const lochist_entry_t &e,
uint32 index,
void *ud)
{ return bookmarks_t_get_desc(out, e, index, ud); }
static uint32 find_index(
const lochist_entry_t &e,
void *ud)
{ return bookmarks_t_find_index(e, ud); }
static uint32 size(
const lochist_entry_t &e,
void *ud)
{ return bookmarks_t_size(e, ud); }
static bool erase(
const lochist_entry_t &e,
uint32 index,
void *ud)
{ return bookmarks_t_erase(e, index, ud); }
static dirtree_id_t get_dirtree_id(
const lochist_entry_t &e,
void *ud)
{ return bookmarks_t_get_dirtree_id(e, ud); }
};
//-------------------------------------------------------------------------
inline lochist_entry_t::lochist_entry_t(const lochist_t &lh)
: plce(NULL)
{
*this = lh.get_current();
}
#endif // __MOVES_HPP

1705
idasdk76/include/nalt.hpp Normal file

File diff suppressed because it is too large Load Diff

786
idasdk76/include/name.hpp Normal file
View File

@@ -0,0 +1,786 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _NAME_HPP
#define _NAME_HPP
#include <ida.hpp>
/*! \file name.hpp
\brief Functions that deal with names.
A non-tail address of the program may have a name.
Tail addresses (i.e. the addresses in the middle of an instruction or
data item) cannot have names.
*/
class func_t; // funcs.hpp
typedef uchar color_t; // lines.hpp
/// Maximum length of a name in IDA (with the trailing zero)
#define MAXNAMELEN 512
/// Name prefix used by IDA for the imported functions
#define FUNC_IMPORT_PREFIX "__imp_"
/// Set or delete name of an item at the specified address.
/// An item can be anything: instruction, function, data byte, word, string,
/// structure, etc...
/// Include name into the list of names.
/// \param ea linear address.
/// do nothing if ea is not valid (return 0).
/// tail bytes can't have names.
/// \param name new name.
/// - NULL: do nothing (return 0).
/// - "" : delete name.
/// - otherwise this is a new name.
/// \param flags \ref SN_.
/// If a bit is not specified, then the corresponding action is not performed
/// and the name will retain the same bits as before calling this function.
/// For new names, default is: non-public, non-weak, non-auto.
/// \retval 1 ok, name is changed
/// \retval 0 failure, a warning is displayed
idaman bool ida_export set_name(ea_t ea, const char *name, int flags=0);
/// \defgroup SN_ Set name flags
/// Passed as 'flag' parameter to set_name(ea_t, const char *, int)
//@{
#define SN_CHECK 0x00
#define SN_NOCHECK 0x01 ///< Don't fail if the name contains invalid characters.
///< If this bit is clear, all invalid chars
///< (those !is_ident_cp()) will be replaced
///< by SUBSTCHAR
///< List of valid characters is defined in ida.cfg
#define SN_PUBLIC 0x02 ///< if set, make name public
#define SN_NON_PUBLIC 0x04 ///< if set, make name non-public
#define SN_WEAK 0x08 ///< if set, make name weak
#define SN_NON_WEAK 0x10 ///< if set, make name non-weak
#define SN_AUTO 0x20 ///< if set, make name autogenerated
#define SN_NON_AUTO 0x40 ///< if set, make name non-autogenerated
#define SN_NOLIST 0x80 ///< if set, exclude name from the list.
///< if not set, then include the name into
///< the list (however, if other bits are set,
///< the name might be immediately excluded
///< from the list).
#define SN_NOWARN 0x100 ///< don't display a warning if failed
#define SN_LOCAL 0x200 ///< create local name. a function should exist.
///< local names can't be public or weak.
///< also they are not included into the list of names
///< they can't have dummy prefixes.
#define SN_IDBENC 0x400 ///< the name is given in the IDB encoding;
///< non-ASCII bytes will be decoded accordingly.
///< Specifying SN_IDBENC also implies SN_NODUMMY
#define SN_FORCE 0x800 ///< if the specified name is already present
///< in the database, try variations with a
///< numerical suffix like "_123"
#define SN_NODUMMY 0x1000 ///< automatically prepend the name with '_' if it
///< begins with a dummy suffix such as 'sub_'.
///< See also SN_IDBENC
#define SN_DELTAIL 0x2000 ///< if name cannot be set because of a tail byte,
///< delete the hindering item
//@}
inline bool force_name(ea_t ea, const char *name, int flags=0)
{
return set_name(ea, name, flags|SN_FORCE|SN_NODUMMY);
}
/// \name Delete a name of a program item
/// \param ea linear address
/// \retval 1 ok, name is deleted
/// \retval 0 failure, invalid address
//@{
inline bool del_global_name(ea_t ea) { return set_name(ea,"", SN_NOWARN); }
inline bool del_local_name(ea_t ea) { return set_name(ea,"", SN_LOCAL|SN_NOWARN); }
//@}
/// Give an autogenerated (dummy) name.
/// Autogenerated names have special prefixes (loc_...).
/// \param from linear address of the operand which references to the address
/// \param ea linear address
/// \retval 1 ok, dummy name is generated or the byte already had a name
/// \retval 0 failure, invalid address or tail byte
idaman bool ida_export set_dummy_name(ea_t from, ea_t ea); // give dummy name
/// \name Set/Clear bit in flags for 'autogenerated but meaningful name'
/// This bit affects value of has_user_name(), has_auto_name() functions.
/// \param ea linear address
/// \retval 1 ok
/// \retval 0 no meaningful name is present at the specified address
//@{
idaman bool ida_export make_name_auto(ea_t ea);
idaman bool ida_export make_name_user(ea_t ea);
//@}
enum ucdr_kind_t
{
UCDR_STRLIT = 0x01, // string literals
UCDR_NAME = 0x02, // regular (unmangled) names
UCDR_MANGLED = 0x04, // mangled names
UCDR_TYPE = 0x08, // type names
};
enum nametype_t
{
// identifier (e.g., function name)
VNT_IDENT = UCDR_NAME|UCDR_MANGLED,
// type name (can contain '<', '>', ...)
VNT_TYPE = UCDR_TYPE,
// UDT (structure, union, enum) member
VNT_UDTMEM = UCDR_NAME,
// string literal
VNT_STRLIT = UCDR_STRLIT,
VNT_VISIBLE = VNT_UDTMEM,// visible cp (obsolete; will be deleted)
};
/// Validate a name.
/// This function replaces all invalid characters in the name with SUBSTCHAR.
/// However, it will return false if name is valid but not allowed to be an
/// identifier (is a register name).
///
/// \param[in,out] name ptr to name. the name will be modified
/// \param type the type of name we want to validate
/// \param flags see SN_* . Only SN_IDBENC is currently considered
///
/// \return success
idaman bool ida_export validate_name(
qstring *name,
nametype_t type,
int flags = 0);
/// Is the given codepoint acceptable in the given context?
idaman bool ida_export is_valid_cp(wchar32_t cp, nametype_t kind, void *data=NULL);
/// Mark the given codepoint (or range) as acceptable or unacceptable in the given context
/// If 'endcp' is not BADCP, it is considered to be the end of the range:
/// [cp, endcp), and is not included in the range
idaman void ida_export set_cp_validity(ucdr_kind_t kind, wchar32_t cp, wchar32_t endcp=BADCP, bool valid=true);
/// Is the given codepoint (or range) acceptable in the given context?
/// If 'endcp' is not BADCP, it is considered to be the end of the range:
/// [cp, endcp), and is not included in the range
idaman bool ida_export get_cp_validity(ucdr_kind_t kind, wchar32_t cp, wchar32_t endcp=BADCP);
/// Can a character appear in a name? (present in ::NameChars or ::MangleChars)
inline bool is_ident_cp(wchar32_t cp) { return is_valid_cp(cp, VNT_IDENT); }
/// Can a character appear in a string literal (present in ::StrlitChars)
/// If 'specific_ranges' are specified, those will be used instead of
/// the ones corresponding to the current culture (only if ::StrlitChars
/// is configured to use the current culture)
inline bool is_strlit_cp(wchar32_t cp, const rangeset_crefvec_t *specific_ranges=NULL)
{ return is_valid_cp(cp, VNT_STRLIT, (void *) specific_ranges); }
/// Can a character be displayed in a name? (present in ::NameChars)
inline bool is_visible_cp(wchar32_t cp)
{ return is_valid_cp(cp, VNT_VISIBLE); }
/// Is a valid name? (including ::MangleChars)
idaman bool ida_export is_ident(const char *name);
/// Is valid user-specified name? (valid name & !dummy prefix).
/// \param name name to test. may be NULL.
/// \retval 1 yes
/// \retval 0 no
idaman bool ida_export is_uname(const char *name);
/// Is valid type name?
/// \param name name to test. may be NULL.
/// \retval 1 yes
/// \retval 0 no
idaman bool ida_export is_valid_typename(const char *name);
/// Is dummy name?
/// \param name name to test. may be NULL.
/// \return #BADADDR if not, otherwise the address denoted by the name
idaman ea_t ida_export dummy_name_ea(const char *name);
/// Extract a name or address from the specified string.
/// \param[out] out output buffer for the identifier
/// \param line input string
/// \param x x coordinate of cursor
/// \return -1 if cannot extract. otherwise length of the name
idaman ssize_t ida_export extract_name(qstring *out, const char *line, int x);
/// Remove name from the list of names
/// \param ea address of the name
idaman void ida_export hide_name(ea_t ea);
/// Insert name to the list of names
idaman void ida_export show_name(ea_t ea);
/// Get address of the name.
/// Dummy names (like byte_xxxx where xxxx are hex digits) are parsed by this
/// function to obtain the address. The database is not consulted for them.
/// This function works only with regular names.
/// \param from linear address where the name is used.
/// if not applicable, then should be #BADADDR.
/// \param name any name in the program or NULL
/// \return address of the name or #BADADDR
idaman ea_t ida_export get_name_ea(ea_t from, const char *name);
/// Get address of the name used in the expression for the address
/// \param from address of the operand which references to the address
/// \param to the referenced address
/// \return address of the name used to represent the operand
idaman ea_t ida_export get_name_base_ea(ea_t from, ea_t to);
/// Get value of the name.
/// This function knows about: regular names, enums, special segments, etc.
/// \param[out] value pointer to variable with answer
/// \param from linear address where the name is used
/// if not applicable, then should be BADADDR
/// \param name any name in the program or NULL
/// \return \ref NT_
idaman int ida_export get_name_value(uval_t *value, ea_t from, const char *name);
/// \defgroup NT_ Name value result codes
/// Return values for get_name_value()
//@{
#define NT_NONE 0 ///< name doesn't exist or has no value
#define NT_BYTE 1 ///< name is byte name (regular name)
#define NT_LOCAL 2 ///< name is local label
#define NT_STKVAR 3 ///< name is stack variable name
#define NT_ENUM 4 ///< name is symbolic constant
#define NT_ABS 5 ///< name is absolute symbol (#SEG_ABSSYM)
#define NT_SEG 6 ///< name is segment or segment register name
#define NT_STROFF 7 ///< name is structure member
#define NT_BMASK 8 ///< name is a bit group mask name
#define NT_REGVAR 9 ///< name is a renamed register (*value is idx into pfn->regvars)
//@}
/// Additional information for get_ea_name() function
struct getname_info_t
{
size_t cb; ///< size of this struct
int32 inhibitor; ///< codes to inhibit parts of demangled name (see \ref MNG_).
///< Usually this is one of \inf{short_demnames} or \inf{long_demnames}.
int32 demform; ///< demangle only if \inf{demnames} is equal to 'demform'.
int32 demcode; ///< out: return value of demangler
getname_info_t(void) : cb(sizeof(*this)), inhibitor(0), demform(0), demcode(0) {}
};
/// Get name at the specified address.
/// \param[out] out buffer to hold the name
/// \param ea linear address
/// \param gtn_flags how exactly the name should be retrieved.
/// combination of \ref GN_ bits
/// \param gtni additional information for name demangling
/// Please use the convenience functions declared below instead of calling
/// get_ea_name directly.
/// \return success
idaman ssize_t ida_export get_ea_name(
qstring *out,
ea_t ea,
int gtn_flags=0,
getname_info_t *gtni=NULL);
/// \defgroup GN_ bits for get_ea_name() function. There is a convenience
/// function calc_gtn_flags() to calculate the GN_LOCAL flag
//@{
#define GN_VISIBLE 0x0001 ///< replace forbidden characters by SUBSTCHAR
#define GN_COLORED 0x0002 ///< return colored name
#define GN_DEMANGLED 0x0004 ///< return demangled name
#define GN_STRICT 0x0008 ///< fail if cannot demangle
#define GN_SHORT 0x0010 ///< use short form of demangled name
#define GN_LONG 0x0020 ///< use long form of demangled name
#define GN_LOCAL 0x0040 ///< try to get local name first; if failed, get global
#define GN_ISRET 0x0080 ///< for dummy names: use retloc
#define GN_NOT_ISRET 0x0100 ///< for dummy names: do not use retloc
#define GN_NOT_DUMMY 0x0200 ///< do not return a dummy name
//@}
// Convenience functions for get_ea_name returning ssize_t
inline ssize_t get_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, gtn_flags);
}
inline ssize_t idaapi get_visible_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|gtn_flags);
}
inline ssize_t idaapi get_colored_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_COLORED|gtn_flags);
}
inline ssize_t idaapi get_short_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_DEMANGLED|GN_SHORT|gtn_flags);
}
inline ssize_t idaapi get_long_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_DEMANGLED|GN_LONG|gtn_flags);
}
inline ssize_t idaapi get_colored_short_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_COLORED|GN_DEMANGLED|GN_SHORT|gtn_flags);
}
inline ssize_t idaapi get_colored_long_name(qstring *out, ea_t ea, int gtn_flags=0)
{
return get_ea_name(out, ea, GN_VISIBLE|GN_COLORED|GN_DEMANGLED|GN_LONG|gtn_flags);
}
inline ssize_t idaapi get_demangled_name(
qstring *out,
ea_t ea,
int32 inhibitor,
int demform,
int gtn_flags=0)
{
getname_info_t gtni;
gtni.inhibitor = inhibitor;
gtni.demform = demform;
gtn_flags |= GN_VISIBLE | GN_DEMANGLED;
return get_ea_name(out, ea, gtn_flags, &gtni);
}
inline ssize_t idaapi get_colored_demangled_name(
qstring *out,
ea_t ea,
int32 inhibitor,
int demform,
int gtn_flags=0)
{
return get_demangled_name(out, ea, inhibitor, demform, gtn_flags|GN_COLORED);
}
// Convenience functions for get_ea_name returning qstring
inline qstring get_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, gtn_flags);
return out;
}
inline qstring get_visible_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|gtn_flags);
return out;
}
inline qstring idaapi get_colored_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_COLORED|gtn_flags);
return out;
}
inline qstring idaapi get_short_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_DEMANGLED|GN_SHORT|gtn_flags);
return out;
}
inline qstring idaapi get_long_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_DEMANGLED|GN_LONG|gtn_flags);
return out;
}
inline qstring idaapi get_colored_short_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_COLORED|GN_DEMANGLED|GN_SHORT|gtn_flags);
return out;
}
inline qstring idaapi get_colored_long_name(ea_t ea, int gtn_flags=0)
{
qstring out;
get_ea_name(&out, ea, GN_VISIBLE|GN_COLORED|GN_DEMANGLED|GN_LONG|gtn_flags);
return out;
}
inline qstring idaapi get_demangled_name(
ea_t ea,
int32 inhibitor,
int demform,
int gtn_flags=0)
{
qstring out;
getname_info_t gtni;
gtni.inhibitor = inhibitor;
gtni.demform = demform;
gtn_flags |= GN_VISIBLE | GN_DEMANGLED;
get_ea_name(&out, ea, gtn_flags, &gtni);
return out;
}
inline qstring idaapi get_colored_demangled_name(
ea_t ea,
int32 inhibitor,
int demform,
int gtn_flags=0)
{
qstring out;
get_demangled_name(&out, ea, inhibitor, demform, gtn_flags|GN_COLORED);
return out;
}
/// Calculate flags for get_ea_name() function
#ifdef FUNCS_HPP
inline int calc_gtn_flags(ea_t from, ea_t ea)
{
return func_contains(get_func(from), ea) ? GN_LOCAL : 0;
}
#endif
/// Get name color.
/// \param from linear address where the name is used.
/// if not applicable, then should be #BADADDR.
/// The kernel returns a local name color if the reference is
/// within a function, i.e. 'from' and 'ea' belong to the same function.
/// \param ea linear address
idaman color_t ida_export get_name_color(ea_t from, ea_t ea);
/// \defgroup GETN_ Name expression flags
/// Passed as 'flags' parameter to get_name_expr()
//@{
#define GETN_APPZERO 0x0001 ///< meaningful only if the name refers to a structure.
///< append a struct field name if the field offset is zero?
#define GETN_NOFIXUP 0x0002 ///< ignore the fixup information when producing the name
#define GETN_NODUMMY 0x0004 ///< do not create a new dummy name but pretend it exists
//@}
/// Convert address to name expression (name with a displacement).
/// This function takes into account fixup information and returns
/// a colored name expression (in the form <name> +/- <offset>).
/// It also knows about structure members and arrays.
/// If the specified address doesn't have a name, a dummy name is generated.
/// \param[out] out output buffer for the name
/// \param from linear address of instruction operand or data referring to
/// the name. This address will be used to get fixup information,
/// so it should point to exact position of the operand in the
/// instruction.
/// \param n number of referencing operand. for data items specify 0
/// \param ea address to convert to name expression
/// \param off the value of name expression. this parameter is used only to
/// check that the name expression will have the wanted value.
/// 'off' may be equal to BADADDR but this is discouraged
/// because it prohibits checks.
/// \param flags \ref GETN_
/// \return < 0 if address is not valid, no segment or other failure.
/// otherwise the length of the name expression in characters.
idaman ssize_t ida_export get_name_expr(
qstring *out,
ea_t from,
int n,
ea_t ea,
uval_t off,
int flags=GETN_APPZERO);
/// Get a nice colored name at the specified address.
/// Ex:
/// - segment:sub+offset
/// - segment:sub:local_label
/// - segment:label
/// - segment:address
/// - segment:address+offset
/// \param[out] buf buffer to hold the name
/// \param ea linear address
/// \param flags \ref GNCN_
/// \return the length of the generated name in bytes.
idaman ssize_t ida_export get_nice_colored_name(
qstring *buf,
ea_t ea,
int flags=0);
/// \defgroup GNCN_ Nice colored name flags
/// Passed as 'flags' parameter to get_nice_colored_name()
//@{
#define GNCN_NOSEG 0x0001 ///< ignore the segment prefix when producing the name
#define GNCN_NOCOLOR 0x0002 ///< generate an uncolored name
#define GNCN_NOLABEL 0x0004 ///< don't generate labels
#define GNCN_NOFUNC 0x0008 ///< don't generate funcname+... expressions
#define GNCN_SEG_FUNC 0x0010 ///< generate both segment and function names (default is to omit segment name if a function name is present)
#define GNCN_SEGNUM 0x0020 ///< segment part is displayed as a hex number
#define GNCN_REQFUNC 0x0040 ///< return 0 if the address does not belong to a function
#define GNCN_REQNAME 0x0080 ///< return 0 if the address can only be represented as a hex number
#define GNCN_NODBGNM 0x0100 ///< don't use debug names
#define GNCN_PREFDBG 0x0200 ///< if using debug names, prefer debug names over function names
//@}
/// Append names of struct fields to a name if the name is a struct name.
/// \param out pointer to the output buffer
/// \param disp displacement from the name
/// \param n number of operand n which the name appears
/// \param path path in the struct. path is an array of id's.
/// maximal length of array is #MAXSTRUCPATH.
/// the first element of the array is the structure id.
/// consecutive elements are id's of used union members (if any).
/// \param plen size of path array
/// \param flags the input flags. they will be returned if the struct
/// cannot be found.
/// \param delta delta to add to displacement
/// \param appzero should append a struct field name if the displacement is zero?
/// \return flags of the innermost struct member or the input flags
idaman flags_t ida_export append_struct_fields(
qstring *out,
adiff_t *disp,
int n,
const tid_t *path,
int plen,
flags_t flags,
adiff_t delta,
bool appzero);
/// Get offset within a structure if the operand refers to structure.
/// Ex:
/// \v{mov ax, somedata.field5-2 (before it was max ax, 3)}
/// for this instruction, op #1 the function will return
/// - disp: the value of 'field5', i.e. 5
/// - delta: -2
/// - path: the existing path if any
/// \param disp pointer to displacement (answer will be here)
/// \param delta pointer to displacement delta (answer will be here)
/// \param path existing strpath (if any)
/// \param ea linear address of instruction/data
/// \param n number of operand
/// \return if success, then length of path + 1.
/// if failed, then 0.
idaman int ida_export get_struct_operand(
adiff_t *disp,
adiff_t *delta,
tid_t *path,
ea_t ea,
int n);
/// \name Work with publicness of a name
//@{
idaman bool ida_export is_public_name(ea_t ea);
idaman void ida_export make_name_public(ea_t ea);
idaman void ida_export make_name_non_public(ea_t ea);
//@}
/// \name Work with weak names.
//@{
idaman bool ida_export is_weak_name(ea_t ea);
idaman void ida_export make_name_weak(ea_t ea);
idaman void ida_export make_name_non_weak(ea_t ea);
//@}
/// \name Work with the list of names
//@{
/// Get number of names in the list
idaman size_t ida_export get_nlist_size(void);
/// Get index of the name in the list
/// \warning returns the closest match.
/// may return idx >= size.
idaman size_t ida_export get_nlist_idx(ea_t ea);
/// Is the name included into the name list?
idaman bool ida_export is_in_nlist(ea_t ea);
/// Get address from the list at 'idx'
idaman ea_t ida_export get_nlist_ea(size_t idx);
/// Get name using idx
idaman const char *ida_export get_nlist_name(size_t idx);
/// Rebuild the name list
idaman void ida_export rebuild_nlist(void);
//@}
/// Renumber dummy names
idaman void ida_export reorder_dummy_names(void);
/// Specify strategy for retrieving debug names
enum debug_name_how_t
{
DEBNAME_EXACT, ///< find a name at exactly the specified address
DEBNAME_LOWER, ///< find a name with the address >= the specified address
DEBNAME_UPPER, ///< find a name with the address > the specified address
DEBNAME_NICE, ///< find a name with the address <= the specified address
};
/// ea, name pair
struct ea_name_t
{
ea_t ea;
qstring name;
ea_name_t(void) : ea(BADADDR) {}
ea_name_t(ea_t _ea, const qstring &_name) : ea(_ea), name(_name) {}
};
DECLARE_TYPE_AS_MOVABLE(ea_name_t);
typedef qvector<ea_name_t> ea_name_vec_t; ///< vector of ea,name pairs
/// \name Debug names
/// Debug names exist during the debugging session.
/// The kernel does not verify them for anything and happily accepts
/// any string as a name.
//@{
idaman int ida_export set_debug_names(const ea_t *addrs, const char *const *names, int qty);
idaman bool ida_export set_debug_name(ea_t ea, const char *name);
idaman ssize_t ida_export get_debug_name(
qstring *out,
ea_t *ea_ptr,
debug_name_how_t how);
idaman void ida_export del_debug_names(ea_t ea1, ea_t ea2);
idaman ea_t ida_export get_debug_name_ea(const char *name);
idaman void ida_export get_debug_names(ea_name_vec_t *names, ea_t ea1, ea_t ea2);
//@}
enum demreq_type_t
{
DQT_NPURGED_8 = -8, // only calculate number of purged bytes (sizeof(arg)==8)
DQT_NPURGED_4 = -4, // only calculate number of purged bytes (sizeof(arg)==4)
DQT_NPURGED_2 = -2, // only calculate number of purged bytes (sizeof(arg)==2)
DQT_COMPILER = 0, // only detect compiler that generated the name
DQT_NAME_TYPE = 1, // only detect the name type (data/code)
DQT_FULL = 2, // really demangle
};
/// Demangle a name.
/// \param out output buffer
/// \param name name to demangle
/// \param disable_mask bits to inhibit parts of demangled name (see \ref MNG_).
/// by the M_COMPILER bits a specific compiler can be
/// selected (see \ref MT_).
/// \return ME_... or MT__ bitmasks from demangle.hpp
idaman int32 ida_export demangle_name(
qstring *out,
const char *name,
uint32 disable_mask,
demreq_type_t demreq=DQT_FULL);
/// Demangle a name.
inline qstring idaapi demangle_name(
const char *name,
uint32 disable_mask,
demreq_type_t demreq=DQT_FULL)
{
qstring out;
demangle_name(&out, name, disable_mask, demreq);
return out;
}
inline int32 detect_compiler_using_demangler(const char *name)
{
return demangle_name(NULL, name, 0, DQT_COMPILER);
}
/// What name types to ignore
typedef int ignore_name_def_t;
const ignore_name_def_t
ignore_none = 0,
ignore_regvar = 1,
ignore_llabel = 2,
ignore_stkvar = 3,
ignore_glabel = 4;
/// Is the name defined locally in the specified function?
/// \param pfn pointer to function
/// \param name name to check
/// \param ignore_name_def which names to ignore when checking
/// \param ea1 the starting address of the range inside the function (optional)
/// \param ea2 the ending address of the range inside the function (optional)
/// \return true if the name has been defined
idaman bool ida_export is_name_defined_locally(
func_t *pfn,
const char *name,
ignore_name_def_t ignore_name_def,
ea_t ea1=BADADDR,
ea_t ea2=BADADDR);
// Clean a name.
// This function removes punctuation marks (underscores and dots) from both
// ends of the name, and other typical prefixes/suffixes. Name is assumed to
// have the following format: [j_][@][.][_*][imp_]name[@digits][_NN]
// \param out output buffer
// \param ea address of the name (used to remove the module name)
// if != BADADDR, the optional prefix (module name) will be
// removed
// \param name name to clean
// \param flags combination of CN_... bits
// \return true if returned a non-empty name
idaman bool ida_export cleanup_name(
qstring *out,
ea_t ea,
const char *name,
uint32 flags=0);
#define CN_KEEP_TRAILING__DIGITS 0x01 // do not remove "_\d+" at the end of name
#endif // _NAME_HPP

1123
idasdk76/include/netnode.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,486 @@
#ifndef NETWORK_HPP
#define NETWORK_HPP
#include <pro.h>
#ifdef __NT__
# if !defined(AF_MAX)
# include <ws2tcpip.h>
# endif
# define SYSTEM "Windows"
# define socklen_t int
# define SHUT_RD SD_RECEIVE
# define SHUT_WR SD_SEND
# define SHUT_RDWR SD_BOTH
#else // not NT, i.e. UNIX
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <netdb.h>
# define closesocket(s) close(s)
# define SOCKET size_t
# define INVALID_SOCKET size_t(-1)
# define SOCKET_ERROR (-1)
# if defined(__LINUX__)
# if defined(__ARM__)
# if defined(__ANDROID__)
# define SYSTEM "Android"
# else
# define SYSTEM "ARM Linux"
# endif
# else
# if defined(__ANDROID__)
# define SYSTEM "Android x86"
# else
# define SYSTEM "Linux"
# endif
# endif
// linux debugger cannot be multithreaded because it uses thread_db.
// i doubt that this library is meant to be used with multiple
// applications simultaneously.
# define __SINGLE_THREADED_SERVER__
# elif defined(__MAC__)
# define SYSTEM "Mac OS X"
# else
# error "Unknown platform"
# endif
# include <sys/socket.h>
# include <netinet/in.h>
#endif
#ifndef __X86__
# define _SYSBITS " 64-bit"
#else
# define _SYSBITS " 32-bit"
#endif
#ifdef TESTABLE_BUILD
# ifdef __EA64__
# define SYSBITS _SYSBITS " (sizeof ea=64)"
# else
# define SYSBITS _SYSBITS " (sizeof ea=32)"
# endif
#else
# define SYSBITS _SYSBITS
#endif
#ifdef __SINGLE_THREADED_SERVER__
# define __SERVER_TYPE__ "ST"
#else
# define __SERVER_TYPE__ "MT"
#endif
#define TIMEOUT (1000/25) // timeout for polling (ms)
#define TIMEOUT_INFINITY -1
#define RECV_HELLO_TIMEOUT 1000 // timeout for the first packet (ms)
#define RECV_TIMEOUT_PERIOD 10000 // timeout for recv (ms)
// bidirectional codes (client <-> server)
enum base_packet_id_t
{
RPC_OK = 0, // response: function call succeeded
RPC_UNK, // response: unknown function code
RPC_MEM, // response: no memory
base_packet_id_last
};
#define RPC_OPEN 3 // server->client: i'm ready, the very first packet
#define RPC_EVENT 4 // server->client: debug event ready, followed by debug_event
#define RPC_EVOK 5 // client->server: event processed (in response to RPC_EVENT)
#define RPC_CANCELLED 6 // client->server: operation was cancelled by the user
// we need EVOK to handle the situation when the debug
// event was detected by the server during polling and
// was sent to the client using RPC_EVENT but client has not received it yet
// and requested GET_DEBUG_EVENT. In this case we should not
// call remote_get_debug_event() but instead force the client
// to use the event sent by RPC_EVENT.
// In other words, if the server has sent RPC_EVENT but has not
// received RPC_EVOK, it should fail all GET_DEBUG_EVENTS.
// client->server codes
#define RPC_INIT 10
#define RPC_TERM 11
#define RPC_GET_PROCESSES 12
#define RPC_START_PROCESS 13
#define RPC_EXIT_PROCESS 14
#define RPC_ATTACH_PROCESS 15
#define RPC_DETACH_PROCESS 16
#define RPC_GET_DEBUG_EVENT 17
#define RPC_PREPARE_TO_PAUSE_PROCESS 18
#define RPC_STOPPED_AT_DEBUG_EVENT 19
#define RPC_CONTINUE_AFTER_EVENT 20
#define RPC_TH_SUSPEND 21
#define RPC_TH_CONTINUE 22
#define RPC_SET_RESUME_MODE 23
#define RPC_GET_MEMORY_INFO 24
#define RPC_READ_MEMORY 25
#define RPC_WRITE_MEMORY 26
#define RPC_UPDATE_BPTS 27
#define RPC_UPDATE_LOWCNDS 28
#define RPC_EVAL_LOWCND 29
#define RPC_ISOK_BPT 30
#define RPC_READ_REGS 31
#define RPC_WRITE_REG 32
#define RPC_GET_SREG_BASE 33
#define RPC_SET_EXCEPTION_INFO 34
#define RPC_OPEN_FILE 35
#define RPC_CLOSE_FILE 36
#define RPC_READ_FILE 37
#define RPC_WRITE_FILE 38
#define RPC_IOCTL 39 // both client and the server may send this packet
#define RPC_UPDATE_CALL_STACK 40
#define RPC_APPCALL 41
#define RPC_CLEANUP_APPCALL 42
#define RPC_REXEC 43
#define RPC_GET_SCATTERED_IMAGE 44
#define RPC_GET_IMAGE_UUID 45
#define RPC_GET_SEGM_START 46
#define RPC_BIN_SEARCH 47
// server->client codes
#define RPC_SET_DEBUG_NAMES 50
#define RPC_SYNC_STUB 51
#define RPC_ERROR 52
#define RPC_MSG 53
#define RPC_WARNING 54
#define RPC_HANDLE_DEBUG_EVENT 55
#define RPC_REPORT_IDC_ERROR 56
#define RPC_IMPORT_DLL 57
#pragma pack(push, 1)
struct PACKED rpc_packet_t
{ // fields are always sent in the network order
uint32 length; // length of the packet (do not count length & code)
uchar code; // function code
};
CASSERT(sizeof(rpc_packet_t) == 5);
#pragma pack(pop)
enum rpc_notification_type_t
{
rnt_unknown = 0,
rnt_msg,
rnt_warning,
rnt_error,
};
#define DEFINE_ONE_NOTIFICATION_FUNCTION(FuncName, NotifCode, RpcEngineInst) \
AS_PRINTF(2, 3) void FuncName(const char *format, ...) \
{ \
va_list va; \
va_start(va, format); \
dvnotif(NotifCode, RpcEngineInst, format, va); \
va_end(va); \
}
#define DEFINE_ALL_NOTIFICATION_FUNCTIONS(RpcEngineInst) \
DEFINE_ONE_NOTIFICATION_FUNCTION(dmsg, 0, RpcEngineInst) \
DEFINE_ONE_NOTIFICATION_FUNCTION(dwarning, 1, RpcEngineInst) \
DEFINE_ONE_NOTIFICATION_FUNCTION(derror, -1, RpcEngineInst)
class rpc_engine_t;
//-------------------------------------------------------------------------
AS_PRINTF(2, 0) ssize_t dvnotif_client(
int code,
const char *format,
va_list va);
#ifdef __NT__
# define IRSERR_TIMEOUT WAIT_TIMEOUT
#else
# define IRSERR_TIMEOUT ETIME
#endif
#define IRSERR_CANCELLED -0xE5CA7E // escape
#define IRSERR_SKIP_ITER -0x5217 // skip recv() in rpc_engine_t's recv_data loop
//-------------------------------------------------------------------------
// idarpc_stream_t
//-------------------------------------------------------------------------
// the idarpc_stream_t structure is not defined.
// it is used as an opaque type provided by the transport level.
// the transport level defines its own local type for it.
struct idarpc_stream_t;
idarpc_stream_t *irs_new(bool use_tls=false);
bool irs_init_client(idarpc_stream_t *irs, const char *hostname, int port_number);
bool irs_init_server(
idarpc_stream_t *irs,
const char *hostname,
int port_number,
const char *certchain=nullptr,
const char *privkey=nullptr);
bool irs_accept(idarpc_stream_t *irs, idarpc_stream_t *listener);
bool irs_handshake(idarpc_stream_t *irs, int timeout_ms = -1);
int irs_ready(idarpc_stream_t *irs, int timeout_ms = -1);
ssize_t irs_recv(idarpc_stream_t *irs, void *buf, size_t n);
ssize_t irs_send(idarpc_stream_t *irs, const void *buf, size_t n);
void irs_term(idarpc_stream_t **pirs, int shutdown_flags = -1);
int irs_get_error(idarpc_stream_t *irs);
const char *irs_strerror(idarpc_stream_t *irs);
bool irs_peername(idarpc_stream_t *irs, qstring *out, bool lookupname = true);
bool irs_sockname(idarpc_stream_t *irs, qstring *out, bool lookupname = true);
enum progress_loop_ctrl_t
{
plc_proceed,
plc_skip_iter,
plc_cancel,
};
typedef progress_loop_ctrl_t irs_progress_cb_t(bool receiving, size_t processed, size_t total, void *);
void irs_set_progress_cb(idarpc_stream_t *irs, int ms, irs_progress_cb_t cb, void *ud=NULL);
struct irs_cancellable_op_t
{
idarpc_stream_t *irs;
irs_cancellable_op_t(idarpc_stream_t *_irs, bool receiving, size_t goal=0);
~irs_cancellable_op_t();
void inc_progress(size_t progress);
};
//-------------------------------------------------------------------------
typedef qtime64_t utc_timestamp_t;
typedef uint64 lofi_timestamp_t; // low-fidelity timestamp. Only encodes up to 1/10th seconds
//-------------------------------------------------------------------------
THREAD_SAFE inline lofi_timestamp_t to_lofi_timestamp(qtime64_t ts)
{
const uint64 s = get_secs(ts);
const uint64 us = get_usecs(ts);
return s * 10 + us / (100 * 1000);
}
//-------------------------------------------------------------------------
THREAD_SAFE inline qtime64_t from_lofi_timestamp(lofi_timestamp_t lts)
{
return make_qtime64(lts / 10, (lts % 10) * (100 * 1000));
}
//-------------------------------------------------------------------------
// base_dispatcher_t + client_handler_t
//-------------------------------------------------------------------------
struct client_handler_t
{
FILE *channels[16];
idarpc_stream_t *irs;
qstring peer_name;
uint32 session_id;
utc_timestamp_t session_start;
bool verbose;
void close_all_channels();
void clear_channels();
int find_free_channel() const;
client_handler_t(idarpc_stream_t *_irs, bool _verbose);
virtual ~client_handler_t();
virtual bool handle() = 0; // true - delete this
virtual void shutdown_gracefully(int signum) = 0;
//lint -sem(client_handler_t::term_irs,cleanup)
void term_irs();
AS_PRINTF(2, 3) int lprintf(const char *format, ...) const;
private:
DECLARE_UNCOPYABLE(client_handler_t);
};
//-------------------------------------------------------------------------
struct client_handlers_list_t
{
typedef std::map<client_handler_t *, qthread_t> storage_t;
storage_t storage;
virtual ~client_handlers_list_t() {}
virtual void lock() {}
virtual void unlock() {}
virtual bool is_multi_threaded() const { return false; }
};
//-------------------------------------------------------------------------
struct mt_client_handlers_list_t : public client_handlers_list_t
{
qmutex_t mutex;
mt_client_handlers_list_t() { mutex = qmutex_create(); QASSERT(1540, mutex != NULL); }
virtual ~mt_client_handlers_list_t() { qmutex_free(mutex); }
virtual void lock() override { qmutex_lock(mutex); }
virtual void unlock() override { qmutex_unlock(mutex); }
virtual bool is_multi_threaded() const override { return true; }
};
//-------------------------------------------------------------------------
struct base_dispatcher_t
{
qstring ipv4_address;
qstring certchain;
qstring privkey;
idarpc_stream_t *irs = nullptr;
client_handlers_list_t *clients_list = nullptr;
ushort port_number = -1;
bool use_tls = false;
bool verbose = false;
base_dispatcher_t(bool multi_threaded);
virtual ~base_dispatcher_t();
NORETURN void dispatch();
virtual void collect_cliopts(cliopts_t *out);
//
void install_signal_handlers();
//
virtual client_handler_t *new_client_handler(idarpc_stream_t *_irs) = 0;
void delete_client_handler(client_handler_t *inst);
virtual void shutdown_gracefully(int signum);
private:
void handle_session(client_handler_t *handler);
void add_to_clients_list(client_handler_t *handler, qthread_t t);
DECLARE_UNCOPYABLE(base_dispatcher_t);
};
//-------------------------------------------------------------------------
// packing/unpacking utils
//-------------------------------------------------------------------------
bytevec_t prepare_rpc_packet(uchar code);
void finalize_packet(bytevec_t &pkt);
//const char *get_rpc_name(int code);
//-------------------------------------------------------------------------
struct rpc_connection_params_t
{
size_t cb;
qstring host;
ushort port;
bool tls;
rpc_connection_params_t(
const char *_host=nullptr,
ushort _port=0,
bool _tls=true)
: cb(sizeof(*this)), host(_host), port(_port), tls(_tls) {}
};
//-------------------------------------------------------------------------
// rpc_engine_t
//-------------------------------------------------------------------------
#define VERBOSE_ENABLED
#ifdef VERBOSE_ENABLED
#define verb(x) do { if ( verbose ) msg x; } while(0)
#define verb_eng(engine, x) do { if ( (engine)->verbose ) msg x; } while(0)
#else
#define verb(x) //msg x
#define verb_eng(engine, x)
#endif
#define verbev(x) //msg x
//-------------------------------------------------------------------------
struct rpc_packet_data_t
{
uchar code;
rpc_packet_data_t(uchar _code) : code(_code) {}
virtual ~rpc_packet_data_t() {}
virtual void serialize(bytevec_t *out, int version) const = 0;
virtual bool deserialize(const uchar **ptr, size_t len, int version) = 0;
};
//-------------------------------------------------------------------------
typedef int ioctl_handler_t(
class rpc_engine_t *rpc,
int fn,
const void *buf,
size_t size,
void **poutbuf,
ssize_t *poutsize);
//-------------------------------------------------------------------------
typedef rpc_packet_data_t *rpc_packet_instantiator_t(const uchar *ptr, size_t len, int version);
//-------------------------------------------------------------------------
struct rpc_packet_type_desc_t
{
uchar code;
const char *name;
rpc_packet_instantiator_t *instantiate;
};
DECLARE_TYPE_AS_MOVABLE(rpc_packet_type_desc_t);
typedef qvector<rpc_packet_type_desc_t> rpc_packet_type_desc_vec_t;
//---------------------------------------------------------------------------
class rpc_engine_t
{
public:
bool network_error;
// pointer to the ioctl request handler, in case you
// need to handle ioctl requests from the server.
ioctl_handler_t *ioctl_handler;
int recv_timeout;
bool is_client;
bool logged_in;
protected:
void register_packet_type_descs(const rpc_packet_type_desc_t *ptypes, size_t cnt);
const rpc_packet_type_desc_t *find_packet_type_desc(int code) const;
const rpc_packet_type_desc_t *find_packet_type_desc(const char *name) const;
public:
rpc_engine_t(bool is_client);
virtual ~rpc_engine_t() {}
int handle_ioctl_packet(bytevec_t &pkt, const uchar *ptr, const uchar *end);
// low-level: deal with bytes, and don't handle "conversations".
int send_data(bytevec_t &data);
rpc_packet_t *recv_packet();
virtual rpc_packet_t *send_request_and_receive_reply(bytevec_t &pkt) = 0;
virtual idarpc_stream_t *get_irs() const = 0;
AS_PRINTF(3, 0) virtual ssize_t send_notif(int code, const char *format, va_list va);
virtual bool get_broken_connection(void) { return false; }
virtual void set_broken_connection(void) {}
int send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize);
void set_ioctl_handler(ioctl_handler_t *h) { ioctl_handler = h; }
DEFINE_ALL_NOTIFICATION_FUNCTIONS(this);
private:
rpc_packet_type_desc_vec_t ptypes;
int recv_data(void *out, size_t len);
AS_PRINTF(3,0) static ssize_t dvnotif(int code, rpc_engine_t *rpc, const char *format, va_list va);
};
//-------------------------------------------------------------------------
AS_PRINTF(3, 0) ssize_t dvnotif_rpc(
int code,
rpc_engine_t *rpc,
const char *format,
va_list va);
//---------------------------------------------------------------------------
AS_PRINTF(1, 0) int vlprintf(const char *format, va_list va);
AS_PRINTF(1, 2) int lprintf(const char *format, ...);
void set_lprintf_output(FILE *out);
//---------------------------------------------------------------------------
THREAD_SAFE inline size_t format_timestamp(char *buf, size_t bufsize, qtime64_t ts)
{
return qstrftime64(buf, bufsize, "%Y-%m-%d %H:%M:%S", ts);
}
#endif // NETWORK_HPP

254
idasdk76/include/offset.hpp Normal file
View File

@@ -0,0 +1,254 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _OFFSET_HPP
#define _OFFSET_HPP
#include <nalt.hpp>
#include <segment.hpp>
/*! \file offset.hpp
\brief Functions that deal with offsets.
"Being an offset" is a characteristic of an operand.
This means that operand or its part represent offset from
some address in the program. This linear address is called
"offset base". Some operands may have 2 offsets simultaneously.
Generally, IDA doesn't handle this except for Motorola outer offsets.
Thus there may be two offset values in an operand: simple offset and
outer offset.
Outer offsets are handled by specifying special operand number:
it should be ORed with #OPND_OUTER value.
See bytes.hpp for further explanation of operand numbers.
*/
/// Get default reference type depending on the segment.
/// \return one of ::REF_OFF8,::REF_OFF16,::REF_OFF32
idaman reftype_t ida_export get_default_reftype(ea_t ea);
/// Convert operand to a reference.
/// To delete an offset, use clr_op_type() function.
/// \param ea linear address.
/// if 'ea' has unexplored bytes, try to convert them to
/// - no segment: fail
/// - 16bit segment: to 16bit word data
/// - 32bit segment: to dword
/// \param n number of operand (may be ORed with #OPND_OUTER)
/// - 0: first
/// - 1: second
/// - 2: third
/// - #OPND_MASK: all operands
/// \param ri reference information
/// \return success
idaman bool ida_export op_offset_ex(ea_t ea, int n, const refinfo_t *ri);
/// See op_offset_ex()
idaman bool ida_export op_offset(
ea_t ea,
int n,
uint32 type_and_flags,
ea_t target=BADADDR,
ea_t base=0,
adiff_t tdelta=0);
/// Convert operand to a reference with the default reference type
inline bool op_plain_offset(ea_t ea, int n, ea_t base)
{
reftype_t reftype = get_default_reftype(ea);
return op_offset(ea, n, reftype, BADADDR, base) != 0;
}
/// Get offset base value
/// \param ea linear address
/// \param n number of operand
/// \return offset base or #BADADDR
inline ea_t get_offbase(ea_t ea, int n)
{
refinfo_t ri;
if ( !get_refinfo(&ri, ea, n) )
return BADADDR;
return ri.base;
}
/// Get offset expression (in the form "offset name+displ").
/// This function uses offset translation function (\ph{translate}) if your IDP
/// module has such a function. Translation function is used to map linear
/// addresses in the program (only for offsets).
///
/// Example: suppose we have instruction at linear address 0x00011000:
/// \v{mov ax, [bx+7422h]}
/// and at ds:7422h:
/// \v{array dw ...}
/// We want to represent the second operand with an offset expression, so
/// then we call:
/// \v{
/// get_offset_expresion(0x001100, 1, 0x001102, 0x7422, buf);
/// | | | | |
/// | | | | +output buffer
/// | | | +value of offset expression
/// | | +address offset value in the instruction
/// | +the second operand
/// +address of instruction
/// }
/// and the function will return a colored string:
/// \v{offset array}
/// \param buf output buffer to hold offset expression
/// \param ea start of instruction or data with the offset expression
/// \param n number of operand (may be ORed with #OPND_OUTER)
/// - 0: first operand
/// - 1: second operand
/// \param from linear address of instruction operand or data referring to
/// the name. This address will be used to get fixup information,
/// so it should point to exact position of operand in the
/// instruction.
/// \param offset value of operand or its part. The function will return
/// text representation of this value as offset expression.
/// \param getn_flags combination of:
/// - #GETN_APPZERO: meaningful only if the name refers to
/// a structure. appends the struct field name
/// if the field offset is zero
/// - #GETN_NODUMMY: do not generate dummy names for the expression
/// but pretend they already exist
/// (useful to verify that the offset expression
/// can be represented)
/// \retval 0 can't convert to offset expression
/// \retval 1 ok, a simple offset expression
/// \retval 2 ok, a complex offset expression
idaman int ida_export get_offset_expression(
qstring *buf,
ea_t ea,
int n,
ea_t from,
adiff_t offset,
int getn_flags=0);
/// See get_offset_expression()
idaman int ida_export get_offset_expr(
qstring *buf,
ea_t ea,
int n,
const refinfo_t &ri,
ea_t from,
adiff_t offset,
int getn_flags=0);
/// Does the specified address contain a valid OFF32 value?.
/// For symbols in special segments the displacement is not taken into account.
/// If yes, then the target address of OFF32 will be returned.
/// If not, then #BADADDR is returned.
idaman ea_t ida_export can_be_off32(ea_t ea);
/// Try to calculate the offset base
/// This function takes into account the fixup information,
/// current ds and cs values.
/// \param ea the referencing instruction/data address
/// \param n operand number
/// - 0: first operand
/// - 1: other operand
/// \return output base address or #BADADDR
idaman ea_t ida_export calc_offset_base(ea_t ea, int n);
/// Try to calculate the offset base.
/// 2 bases are checked: current ds and cs.
/// If fails, return #BADADDR
idaman ea_t ida_export calc_probable_base_by_value(ea_t ea, uval_t off);
/// Calculate the target and base addresses of an offset expression.
/// The calculated target and base addresses are returned in the locations
/// pointed by 'base' and 'target'. In case 'ri.base' is #BADADDR, the
/// function calculates the offset base address from the referencing
/// instruction/data address.
/// The target address is copied from ri.target. If ri.target is #BADADDR
/// then the target is calculated using the base address and 'opval'.
/// This function also checks if 'opval' matches the full value of the
/// reference and takes in account the memory-mapping.
/// \param target output target address
/// \param base output base address
/// \param from the referencing instruction/data address
/// \param ri reference info block from the database
/// \param opval operand value (usually op_t::value or op_t::addr)
/// \return success
idaman bool ida_export calc_reference_data(
ea_t *target,
ea_t *base,
ea_t from,
const refinfo_t &ri,
adiff_t opval);
/// Add xrefs for a reference from the given instruction (\insn_t{ea}).
/// This function creates a cross references to the target and the base.
/// insn_t::add_off_drefs() calls this function to create xrefs for
/// 'offset' operand.
/// \param insn the referencing instruction
/// \param from the referencing instruction/data address
/// \param ri reference info block from the database
/// \param opval operand value (usually op_t::value or op_t::addr)
/// \param type type of xref
/// \param opoff offset of the operand from the start of instruction
/// \return the target address of the reference
idaman ea_t ida_export add_refinfo_dref(
const insn_t &insn,
ea_t from,
const refinfo_t &ri,
adiff_t opval,
dref_t type,
int opoff);
/// Calculates the target, using the provided refinfo_t
inline ea_t calc_target(ea_t from, adiff_t opval, const refinfo_t &ri)
{
ea_t target;
if ( !calc_reference_data(&target, NULL, from, ri, opval) )
return BADADDR;
return target;
}
/// Retrieves refinfo_t structure and calculates the target
inline ea_t calc_target(ea_t from, ea_t ea, int n, adiff_t opval)
{
refinfo_t ri;
return get_refinfo(&ri, ea, n) ? calc_target(from, opval, ri) : BADADDR;
}
/// Calculate the value of the reference base.
inline ea_t calc_basevalue(ea_t target, ea_t base)
{
return base - get_segm_base(getseg(target));
}
#endif // _OFFSET_HPP

View File

@@ -0,0 +1,260 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef PARSEJSON_HPP
#define PARSEJSON_HPP
/*! \file parsejson.hpp
\brief Tools for parsing JSON-formatted input
See also lex.hpp/parse.hpp for finer-grained functions & documentation.
*/
#include <lex.hpp>
//---------------------------------------------------------------------------
enum jtype_t
{
JT_UNKNOWN = 0,
JT_NUM,
JT_STR,
JT_OBJ,
JT_ARR,
JT_BOOL,
};
//---------------------------------------------------------------------------
struct jobj_t;
struct jarr_t;
#define DECLARE_JVALUE_HELPERS(decl) \
decl void ida_export jvalue_t_clear(jvalue_t *); \
decl void ida_export jvalue_t_copy(jvalue_t *, const jvalue_t &);
struct jvalue_t;
DECLARE_JVALUE_HELPERS(idaman)
//-------------------------------------------------------------------------
struct jvalue_t
{
jvalue_t() : _type(JT_UNKNOWN), _num(0) {}
jvalue_t(const jvalue_t &o) : _type(JT_UNKNOWN) { jvalue_t_copy(this, o); }
~jvalue_t() { clear(); }
void clear() { jvalue_t_clear(this); }
jvalue_t &operator=(const jvalue_t &o) { jvalue_t_copy(this, o); return *this; }
jtype_t type() const { return _type; }
int64 num() const { QASSERT(1277, _type == JT_NUM); return _num; }
const char *str() const { QASSERT(1278, _type == JT_STR); return _str->c_str(); }
const qstring &qstr() const { QASSERT(1623, _type == JT_STR); return *_str; }
const jobj_t &obj() const { QASSERT(1279, _type == JT_OBJ); return *_obj; }
const jarr_t &arr() const { QASSERT(1280, _type == JT_ARR); return *_arr; }
bool vbool() const { QASSERT(1281, _type == JT_BOOL); return _bool; }
jobj_t &obj() { QASSERT(1282, _type == JT_OBJ); return *_obj; }
jarr_t &arr() { QASSERT(1283, _type == JT_ARR); return *_arr; }
//lint -sem(jvalue_t::set_str, custodial(1)) function takes ownership of its argument
//lint -sem(jvalue_t::set_obj, custodial(1)) function takes ownership of its argument
//lint -sem(jvalue_t::set_arr, custodial(1)) function takes ownership of its argument
void set_num(int64 i) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_NUM; _num = i; }
void set_str(qstring *s) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_STR; _str = s; }
void set_obj(jobj_t *o) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_OBJ; _obj = o; }
void set_arr(jarr_t *a) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_ARR; _arr = a; }
void set_bool(bool b) { if ( _type != JT_UNKNOWN ) clear(); _type = JT_BOOL; _bool = b; }
jobj_t *extract_obj() { QASSERT(1624, _type == JT_OBJ); jobj_t *o = _obj; _obj = NULL; _type = JT_UNKNOWN; return o; }
jarr_t *extract_arr() { QASSERT(1625, _type == JT_ARR); jarr_t *a = _arr; _arr = NULL; _type = JT_UNKNOWN; return a; }
void swap(jvalue_t &r)
{
qswap(_type, r._type);
qswap(_str, r._str);
}
private:
DECLARE_JVALUE_HELPERS(friend)
jtype_t _type;
union
{
int64 _num;
qstring *_str;
jobj_t *_obj;
jarr_t *_arr;
bool _bool;
};
};
DECLARE_TYPE_AS_MOVABLE(jvalue_t);
typedef qvector<jvalue_t> jvalues_t;
//---------------------------------------------------------------------------
struct kvp_t
{
qstring key;
jvalue_t value;
};
DECLARE_TYPE_AS_MOVABLE(kvp_t);
//-------------------------------------------------------------------------
struct jobj_t : public qvector<kvp_t>
{
bool has_value(const char *k) const { return get_value(k) != NULL; }
jvalue_t *get_value(const char *k, jtype_t t=JT_UNKNOWN)
{
jvalue_t *v = NULL;
for ( size_t i = 0, _n = size(); i < _n; ++i )
{
if ( at(i).key == k )
{
if ( t == JT_UNKNOWN || at(i).value.type() == t )
v = &at(i).value;
break;
}
}
return v;
}
const jvalue_t *get_value(const char *k, jtype_t t=JT_UNKNOWN) const
{
return ((jobj_t *) this)->get_value(k, t);
}
const jvalue_t *get_value_or_fail(const char *k, jtype_t t=JT_UNKNOWN) const
{
const jvalue_t *v = get_value(k, t);
QASSERT(1289, v != NULL);
return v;
}
jvalue_t *get_value_or_new(const char *key)
{
jvalue_t *v = get_value(key);
if ( v == NULL )
{
kvp_t &kvp = push_back();
kvp.key = key;
v = &kvp.value;
}
return v;
}
int64 get_num(const char *k) const { return get_value_or_fail(k)->num(); }
bool get_bool(const char *k) const { return get_value_or_fail(k)->vbool(); }
const char *get_str(const char *k) const { return get_value_or_fail(k)->str(); }
const jobj_t &get_obj(const char *k) const { return get_value_or_fail(k)->obj(); }
const jarr_t &get_arr(const char *k) const { return get_value_or_fail(k)->arr(); }
#define DEFINE_FLAG_GETTER(Type, JType, GetExpr) \
bool get(Type *out, const char *k) const \
{ \
const jvalue_t *v = get_value(k, JType); \
bool ok = v != NULL; \
if ( ok ) \
*out = GetExpr; \
return ok; \
}
#define DEFINE_DFLT_GETTER(Type, JType, GetExpr) \
Type get(const char *k, Type dflt) const \
{ \
const jvalue_t *v = get_value(k, JType); \
return v != NULL ? GetExpr : dflt; \
}
#define DEFINE_SETTER(Type, SetExpr) \
void put(const char *key, Type value) \
{ \
jvalue_t *v = get_value_or_new(key); \
SetExpr; \
}
#define DEFINE_ACCESSORS(Type, ConstType, JType, GetExpr, SetExpr) \
DEFINE_FLAG_GETTER(ConstType, JType, GetExpr) \
DEFINE_DFLT_GETTER(ConstType, JType, GetExpr) \
DEFINE_SETTER(Type, SetExpr)
DEFINE_ACCESSORS(int, int, JT_NUM, v->num(), v->set_num(value));
DEFINE_ACCESSORS(int64, int64, JT_NUM, v->num(), v->set_num(value));
DEFINE_ACCESSORS(bool, bool, JT_BOOL, v->vbool(), v->set_bool(value));
DEFINE_ACCESSORS(jarr_t *, const jarr_t *, JT_ARR, &v->arr(), v->set_arr(value)); // setter takes ownership
DEFINE_ACCESSORS(jobj_t *, const jobj_t *, JT_OBJ, &v->obj(), v->set_obj(value)); // setter takes ownership
DEFINE_ACCESSORS(const char *, const char *, JT_STR, v->str(), v->set_str(new qstring(value)));
#undef DEFINE_ACCESSORS
#undef DEFINE_SETTER
#undef DEFINE_DFLT_GETTER
#undef DEFINE_FLAG_GETTER
bool get(qstring *out, const char *k) const
{
const jvalue_t *v = get_value(k, JT_STR);
bool ok = v != NULL;
if ( ok )
*out = v->qstr();
return ok;
}
const qstring &get(const char *k, const qstring &dflt) const
{
const jvalue_t *v = get_value(k, JT_STR);
return v != NULL ? v->qstr() : dflt;
}
void put(const char *key, const qstring &value)
{
jvalue_t *v = get_value_or_new(key);
v->set_str(new qstring(value));
}
};
DECLARE_TYPE_AS_MOVABLE(jobj_t);
//---------------------------------------------------------------------------
struct jarr_t
{
jvalues_t values;
size_t count_items_with_type(jtype_t t) const
{
size_t cnt = 0;
for ( size_t i = 0, n = values.size(); i < n; ++i )
if ( values[i].type() == t )
++cnt;
return cnt;
}
bool is_homogeneous(jtype_t t) const
{
return count_items_with_type(t) == values.size();
}
};
DECLARE_TYPE_AS_MOVABLE(jarr_t);
//---------------------------------------------------------------------------
// Note: If 'ungot_tokens' is not NULL, its contents will be used before fetching tokens from the lexer
idaman THREAD_SAFE error_t ida_export parse_json(jvalue_t *out, lexer_t *lx, tokenstack_t *ungot_tokens = NULL);
idaman THREAD_SAFE error_t ida_export parse_json_string(jvalue_t *out, const char *s);
//-------------------------------------------------------------------------
#define SJF_PRETTY 0x1
idaman THREAD_SAFE bool ida_export serialize_json(
qstring *out,
const jvalue_t &v,
uint32 flags=0);
inline THREAD_SAFE bool serialize_json(
qstring *out,
const jobj_t *o,
uint32 flags=0)
{
jvalue_t v;
v.set_obj((jobj_t *) o);
bool rc = serialize_json(out, v, flags);
v.extract_obj();
return rc;
}
#endif // PARSEJSON_HPP

4847
idasdk76/include/pro.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,104 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _PROBLEMS_HPP
#define _PROBLEMS_HPP
/*! \file problems.hpp
\brief Functions that deal with the list of problems.
There are several problem lists. An address may be inserted to any list.
The kernel simply maintains these lists, no additional processing
is done.
The problem lists are accessible for the user
from the View->Subviews->Problems menu item.
Addresses in the lists are kept sorted. In general IDA just maintains
these lists without using them during analysis (except PR_ROLLED).
*/
typedef uchar problist_id_t; ///< see \ref PR_
/// \defgroup PR_ Problem types
//@{
const problist_id_t
PR_NOBASE = 1, ///< Can't find offset base
PR_NONAME = 2, ///< Can't find name
PR_NOFOP = 3, ///< Can't find forced op (not used anymore)
PR_NOCMT = 4, ///< Can't find comment (not used anymore)
PR_NOXREFS = 5, ///< Can't find references
PR_JUMP = 6, ///< Jump by table !!!! ignored
PR_DISASM = 7, ///< Can't disasm
PR_HEAD = 8, ///< Already head
PR_ILLADDR = 9, ///< Exec flows beyond limits
PR_MANYLINES = 10, ///< Too many lines
PR_BADSTACK = 11, ///< Failed to trace the value of the stack pointer
PR_ATTN = 12, ///< Attention! Probably erroneous situation.
PR_FINAL = 13, ///< Decision to convert to instruction/data is made by IDA
PR_ROLLED = 14, ///< The decision made by IDA was wrong and rolled back
PR_COLLISION = 15, ///< FLAIR collision: the function with the given name already exists
PR_DECIMP = 16, ///< FLAIR match indecision: the patterns matched, but not the function(s) being referenced
PR_END = 17; ///< Number of problem types
//@}
/// Get the human-friendly description of the problem,
/// if one was provided to remember_problem.
/// \param buf a buffer to store the message into.
/// \param t problem list type.
/// \param ea linear address.
/// \return the message length or -1 if none
idaman ssize_t ida_export get_problem_desc(qstring *buf, problist_id_t t, ea_t ea);
/// Insert an address to a list of problems.
/// Display a message saying about the problem (except of ::PR_ATTN,::PR_FINAL)
/// ::PR_JUMP is temporarily ignored.
/// \param type problem list type
/// \param ea linear address
/// \param msg a user-friendly message to be displayed instead of
/// the default more generic one associated with
/// the type of problem. Defaults to NULL.
idaman void ida_export remember_problem(problist_id_t type, ea_t ea, const char *msg = NULL);
/// Get an address from the specified problem list.
/// The address is not removed from the list.
/// \param type problem list type
/// \param lowea the returned address will be higher or equal
/// than the specified address
/// \return linear address or #BADADDR
idaman ea_t ida_export get_problem(problist_id_t type, ea_t lowea);
/// Remove an address from a problem list
/// \param type problem list type
/// \param ea linear address
/// \return success
idaman bool ida_export forget_problem(problist_id_t type, ea_t ea);
/// Get problem list description
idaman const char *ida_export get_problem_name(problist_id_t type, bool longname=true);
/// Check if the specified address is present in the problem list
idaman bool ida_export is_problem_present(problist_id_t t, ea_t ea);
inline bool was_ida_decision(ea_t ea) { return is_problem_present(PR_FINAL, ea); }
#endif // _PROBLEMS_HPP

172
idasdk76/include/prodir.h Normal file
View File

@@ -0,0 +1,172 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _PRODIR_H
#define _PRODIR_H
//-V:qffblk_t:730 not all members of a class are initialized inside the constructor
//-V:qffblk64_t:730
/*! \file prodir.h
\brief Unified interface to qfindfirst(),qfindnext(),qfindclose() functions.
These are low level functions, it is better to use enumerate_files2().
*/
/// \def{DIRCHAR, Path separator}
/// \def{SDIRCHAR, Path separator as a string}
/// \def{DRVCHAR, Windows drive separator}
#ifdef __NT__
#define __FAT__
#define SDIRCHAR "\\"
#define DIRCHAR '\\'
#define DRVCHAR ':'
#else
#define SDIRCHAR "/"
#define DIRCHAR '/'
#endif
/// Extension character is '.' for all systems
#define EXTCHAR '.'
//----------------------------------------------------------------------------
/// \struct{qffblk_t, Various file statistics returned by qfind()-like functions}
/// \var{qffblk_t::ff_name, file path}
/// \var{qffblk_t::ff_fsize, file size}
/// \var{qffblk_t::ff_attrib, file attribute}
/// \var{qffblk_t::ff_ftime, file time stamp (ms dos fat format)}
/// \var{qffblk_t::ff_fdate, file date stamp (ms dos fat format)}
/// \def{FA_RDONLY, File cannot be opened for writing}
/// \def{FA_DIREC, Directory}
/// \def{FA_ARCH, File has not been backed up}
/// \def{MAXPATH, Size limit of qffblk_t::ff_name}
#if defined(__UNIX__)
#define MAXPATH QMAXPATH
struct qffblk_t // Unix
{
// user fields:
int ff_attrib;
#define FA_DIREC S_IFDIR
#define FA_ARCH 0
#define FA_RDONLY 0
char ff_name[QMAXPATH];
uint32 ff_fsize;
uint16 ff_fdate;
uint16 ff_ftime;
// private fields:
void *filelist;
int fileidx, fileqty;
char dirpath[QMAXPATH];
char pattern[QMAXPATH];
int attr;
qffblk_t(void) : filelist(NULL), fileqty(0) {}
};
#elif !defined(__X86__)
// Win64 - use Visual Studio's ffblk
#define MAXPATH _MAX_PATH
struct qffblk_t
{
// inlined __finddata64_t from Visual Studio (for compatibility with IDA 7.0 API)
unsigned attrib;
// Time values are stored in UTC format.
__time64_t time_create; // -1 for FAT file systems
__time64_t time_access; // -1 for FAT file systems
__time64_t time_write;
__int64 size;
char name[260]; // NB: file name is assumed to be UTF-8
intptr_t handle; // handle returned by _wfindfirst64
int attr; // attr value passed to qfindfirst. only FA_DIREC is checked
#define FA_RDONLY 0x01
#define FA_DIREC 0x10
#define FA_ARCH 0x20
#define ff_name name
#define ff_attrib attrib
#define ff_fsize size
unsigned short ff_ftime; // FAT/DOS format modification time
unsigned short ff_fdate; // FAT/DOS format modification date
qffblk_t(void) : handle(-1) {}
};
CASSERT(sizeof(qffblk_t) == 0x140);
#else
#define MAXPATH 260
struct qffblk_t // Win32 - use Borland's ffblk (IDA 6.95 API compatibility)
{
long ff_reserved;
long ff_fsize;
unsigned long ff_attrib;
#define FA_RDONLY 0x01
#define FA_DIREC 0x10
#define FA_ARCH 0x20
unsigned short ff_ftime;
unsigned short ff_fdate;
char ff_name[MAXPATH];
qffblk_t(void) : ff_reserved(0) {}
};
#endif
/// \def{MAXDRIVE, Max drive name size}
/// \def{MAXDIR, Max directory name size}
/// \def{MAXFILE, Max file name size}
/// \def{MAXEXT, Max file extension size}
#if defined(__UNIX__)
#define MAXDRIVE QMAXPATH
#define MAXDIR QMAXPATH
#define MAXFILE QMAXPATH
#define MAXEXT QMAXPATH
#else
#define MAXDRIVE _MAX_DRIVE
#define MAXDIR _MAX_DIR
#define MAXFILE _MAX_FNAME
#define MAXEXT _MAX_EXT
#endif
/// Find first file that matches the pattern.
/// \param pattern file name pattern, usually with * and ? wildcards
/// \param blk structure that will hold the answer.
/// blk->ff_name will hold the file name, for example.
/// \param attr the desired file types (#FA_DIREC for directories only or 0 for both directories and files)
/// \return 0 if found a file, other values mean error (check qerrno)
idaman THREAD_SAFE int ida_export qfindfirst(
const char *pattern,
struct qffblk64_t *blk,
int attr);
/// Find next file that matches the pattern.
/// \param blk structure that holds the current state.
/// blk->ff_name will hold the next file name upon return.
/// \return 0 if found the next file, other values mean error (check qerrno)
idaman THREAD_SAFE int ida_export qfindnext(struct qffblk64_t *blk);
/// Stop the file enumeration and free internal structures.
/// \note usually there is no need to call this function manually, it is called
/// from the ::qffblk64_t destructor.
/// \param blk file enumeration structure
idaman THREAD_SAFE void ida_export qfindclose(struct qffblk64_t *blk);
/// Common structure with 64-bit ff_fsize - see ::qffblk_t.
struct qffblk64_t
{
int ff_attrib;
char ff_name[QMAXPATH];
uint64 ff_fsize;
uint16 ff_fdate;
uint16 ff_ftime;
// private field
struct qffblk_t base;
qffblk64_t(void) {}
~qffblk64_t(void) { qfindclose(this); }
};
#endif // _PRODIR_H

129
idasdk76/include/pronet.h Normal file
View File

@@ -0,0 +1,129 @@
// socket API wrappers
#ifndef __PRONET_H__
#define __PRONET_H__
#ifdef __NT__
# pragma pack(push)
# include <winsock2.h> // may change structure packing?!
# pragma pack(pop)
#else // __NT__
# include <errno.h>
# include <sys/socket.h>
# include <sys/select.h>
#endif
#ifdef __NT__
#pragma comment(lib, "WS2_32.lib")
#endif
/*! \file pronet.h
\brief Network related functions
Each of the following functions work just like their C standard equivalent, only
they are safer and system independent.
*/
//---------------------------------------------------------------------------
#ifdef __NT__
# define SIG_SAFE_CALL(expr) return expr
# define SOCKLEN_T int
# define SOCKBUF_T char *
#else
# define SIG_SAFE_CALL(expr) \
do \
{ \
long rc = expr; \
if ( rc != -1 || errno != EINTR ) \
return rc; \
} \
while ( true )
# define SOCKLEN_T socklen_t
# define SOCKBUF_T void *
#endif
//---------------------------------------------------------------------------
inline ssize_t qsendto(int socket, const SOCKBUF_T buf, size_t size, int flags, const struct sockaddr *dest_addr, SOCKLEN_T addrlen)
{
SIG_SAFE_CALL(::sendto(socket, buf, size, flags, dest_addr, addrlen));
}
//---------------------------------------------------------------------------
inline ssize_t qrecvfrom(int socket, SOCKBUF_T buf, size_t size, int flags, struct sockaddr *src_addr, SOCKLEN_T *addrlen)
{
SIG_SAFE_CALL(::recvfrom(socket, buf, size, flags, src_addr, addrlen));
}
//---------------------------------------------------------------------------
inline ssize_t qsend(int socket, const void *buf, size_t size)
{
#ifdef __NT__
return qsendto(socket, (SOCKBUF_T)buf, size, 0, NULL, 0);
#else
SIG_SAFE_CALL(::send(socket, buf, size, 0));
#endif
}
//---------------------------------------------------------------------------
inline ssize_t qrecv(int socket, void *buf, size_t size)
{
#ifdef __NT__
return qrecvfrom(socket, (SOCKBUF_T)buf, size, 0, NULL, NULL);
#else
SIG_SAFE_CALL(::recv(socket, buf, size, 0));
#endif
}
//---------------------------------------------------------------------------
inline int qselect(int nflds, fd_set *rds, fd_set *wds, fd_set *eds, struct timeval *timeout)
{
SIG_SAFE_CALL(::select(nflds, rds, wds, eds, timeout));
}
//---------------------------------------------------------------------------
// Prevent using of the socket functions directly
// (compiler diagnostics: call of overloaded ... is ambiguous)
namespace DONT_USE_FUNCS
{
inline ssize_t sendto(int, const SOCKBUF_T, size_t, int, const struct sockaddr *, SOCKLEN_T) { return 0; }
inline ssize_t recvfrom(int, SOCKBUF_T, size_t, int, struct sockaddr *, SOCKLEN_T *) { return 0; }
inline ssize_t send(int, const SOCKBUF_T, size_t, int) { return 0; }
inline ssize_t recv(int, SOCKBUF_T, size_t, int) { return 0; }
inline int select(int, fd_set *, fd_set *, fd_set *, struct timeval *) { return 0; }
}
using namespace DONT_USE_FUNCS;
//-------------------------------------------------------------------------
/// Get the IPv4 or IPv6 address corresponding to the given host.
///
/// \param out should be of type 'sockaddr_in' or 'sockaddr_in6', depending
/// on the value of 'family'.
/// \param name the host name.
/// \param family either AF_INET or AF_INET6.
/// \param port a port number, or 0 for none.
/// \return true on success, false otherwise
idaman bool ida_export qhost2addr_(
void *out,
const char *name,
ushort family,
ushort port = 0);
//-------------------------------------------------------------------------
inline bool qhost2addr(struct sockaddr_in *out, const char *name, ushort port = 0)
{
return qhost2addr_(out, name, AF_INET, port);
}
//-------------------------------------------------------------------------
inline bool qhost2addr(struct sockaddr_in6 *out, const char *name, ushort port = 0)
{
return qhost2addr_(out, name, AF_INET6, port);
}
#undef SIG_SAFE_CALL
#undef SOCKLEN_T
#undef SOCKBUF_T
#endif // __PRONET_H__

290
idasdk76/include/range.hpp Normal file
View File

@@ -0,0 +1,290 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _RANGE_HPP
#define _RANGE_HPP
/*! \file range.hpp
\brief Contains the definition of ::range_t.
A range is a non-empty continuous range of addresses (specified by
its start and end addresses, the end address is excluded from the
range).
Ranges are stored in the Btree part of the IDA database.
To learn more about Btrees (Balanced Trees):
http://www.bluerwhite.org/btree/
*/
#ifndef SWIG
struct range_t;
/// Helper function. Should not be called directly!
idaman size_t ida_export range_t_print(const range_t *, char *buf, size_t bufsize);
#endif
//--------------------------------------------------------------------------
/// Base class for an range. This class is used as a base class for
/// a class with real information - see segment.hpp for example.
/// The end address points beyond the range.
struct range_t
{
friend size_t ida_export range_t_print(const range_t *cb, char *buf, size_t bufsize);
ea_t start_ea; ///< start_ea included
ea_t end_ea; ///< end_ea excluded
/// Constructor
range_t(void) : start_ea(0), end_ea(0) {}
/// Constructor
range_t(ea_t ea1, ea_t ea2) : start_ea(ea1), end_ea(ea2) {}
/// Compare two range_t instances, based on the start_ea
int compare(const range_t &r) const { return start_ea > r.start_ea ? 1 : start_ea < r.start_ea ? -1 : 0; }
bool operator ==(const range_t &r) const { return compare(r) == 0; } ///< Compare two range_t's with '=='
bool operator !=(const range_t &r) const { return compare(r) != 0; } ///< Compare two range_t's with '!='
bool operator > (const range_t &r) const { return compare(r) > 0; } ///< Compare two range_t's with '<'
bool operator < (const range_t &r) const { return compare(r) < 0; } ///< Compare two range_t's with '>'
/// Is 'ea' in the address range?
bool contains(ea_t ea) const { return start_ea <= ea && end_ea > ea; }
/// Is every ea in 'r' also in this range_t?
bool contains(const range_t &r) const { return r.start_ea >= start_ea && r.end_ea <= end_ea; }
/// Is there an ea in 'r' that is also in this range_t?
bool overlaps(const range_t &r) const { return r.start_ea < end_ea && start_ea < r.end_ea; }
/// Set #start_ea, #end_ea to 0
void clear(void) { start_ea = end_ea = 0; }
/// Is the size of the range_t <= 0?
bool empty(void) const { return start_ea >= end_ea; }
/// Get #end_ea - #start_ea
asize_t size(void) const { return end_ea - start_ea; }
/// Assign the range_t to the intersection between the range_t and 'r'
void intersect(const range_t &r)
{
if ( start_ea < r.start_ea )
start_ea = r.start_ea;
if ( end_ea > r.end_ea )
end_ea = r.end_ea;
if ( end_ea < start_ea )
end_ea = start_ea;
}
/// Ensure that the range_t includes 'ea'
void extend(ea_t ea)
{
if ( start_ea > ea )
start_ea = ea;
if ( end_ea < ea )
end_ea = ea;
}
/// Print the range_t.
/// \param buf the output buffer
/// \param bufsize the size of the buffer
size_t print(char *buf, size_t bufsize) const { return range_t_print(this, buf, bufsize); }
};
DECLARE_TYPE_AS_MOVABLE(range_t);
typedef qvector<range_t> rangevec_base_t;
struct rangevec_t : public rangevec_base_t /// Vector of range_t instances
{
};
//--------------------------------------------------------------------------
// Various kinds of ranges, see
// \ref idb_event::changing_range_cmt
// \ref idb_event::range_cmt_changed
enum range_kind_t
{
RANGE_KIND_UNKNOWN,
RANGE_KIND_FUNC, ///< \ref func_t
RANGE_KIND_SEGMENT, ///< \ref segment_t
RANGE_KIND_HIDDEN_RANGE, ///< \ref hidden_range_t
};
//--------------------------------------------------------------------------
/// Helper functions. Should not be called directly!
#ifndef SWIG
#define RANGESET_HELPER_DEFINITIONS(decl) \
decl bool ida_export rangeset_t_add(rangeset_t *, const range_t &range);\
decl bool ida_export rangeset_t_sub(rangeset_t *, const range_t &range);\
decl bool ida_export rangeset_t_add2(rangeset_t *, const rangeset_t &aset);\
decl bool ida_export rangeset_t_sub2(rangeset_t *, const rangeset_t &aset);\
decl bool ida_export rangeset_t_has_common(const rangeset_t *, const range_t &range, bool strict);\
decl bool ida_export rangeset_t_has_common2(const rangeset_t *, const rangeset_t &aset);\
decl bool ida_export rangeset_t_contains(const rangeset_t *, const rangeset_t &aset);\
decl size_t ida_export rangeset_t_print(const rangeset_t *, char *buf, size_t bufsize);\
decl bool ida_export rangeset_t_intersect(rangeset_t *, const rangeset_t &aset);\
decl const range_t *ida_export rangeset_t_find_range(const rangeset_t *, ea_t ea);\
decl ea_t ida_export rangeset_t_next_addr(const rangeset_t *, ea_t ea);\
decl ea_t ida_export rangeset_t_prev_addr(const rangeset_t *, ea_t ea);\
decl ea_t ida_export rangeset_t_next_range(const rangeset_t *, ea_t ea);\
decl ea_t ida_export rangeset_t_prev_range(const rangeset_t *, ea_t ea);\
decl rangevec_t::const_iterator ida_export rangeset_t_lower_bound(const rangeset_t *, ea_t ea);\
decl rangevec_t::const_iterator ida_export rangeset_t_upper_bound(const rangeset_t *, ea_t ea);\
decl void ida_export rangeset_t_swap(rangeset_t *, rangeset_t &r);
#else
#define RANGESET_HELPER_DEFINITIONS(decl)
#endif // SWIG
class rangeset_t;
RANGESET_HELPER_DEFINITIONS(idaman)
/// An ordered set of non-overlapping address ranges
class rangeset_t
{
rangevec_t bag;
mutable const range_t *cache;
int undo_code = -1;
RANGESET_HELPER_DEFINITIONS(friend)
bool verify(void) const;
public:
DEFINE_MEMORY_ALLOCATION_FUNCS()
/// Constructor
rangeset_t(void) : cache(NULL) {}
/// Constructor - Initialize set with 'range'
rangeset_t(const range_t &range): cache(NULL) { if ( !range.empty() ) bag.push_back(range); }
/// Constructor - Initialize set with 'ivs'
rangeset_t(const rangeset_t &ivs) : bag(ivs.bag), cache(NULL) {}
rangeset_t &operator=(const rangeset_t &ivs) { bag = ivs.bag; cache = NULL; return *this; }
/// Set this = 'r' and 'r' = this. See qvector::swap()
void swap(rangeset_t &r) { rangeset_t_swap(this, r); }
/// Add an address range to the set.
/// If 'range' intersects an existing element e, then e is extended
/// to include 'range', and any superfluous elements (subsets of e) are removed.
/// \param range address range to add. cannot be empty
/// \return false if 'range' was not added (the set was unchanged)
bool add(const range_t &range) { return rangeset_t_add(this, range); }
/// Create a new range_t from 'start' and 'end' and add it to the set
bool add(ea_t start, ea_t _end) { return add(range_t(start, _end)); }
/// Add each element of 'aset' to the set.
/// \return false if no elements were added (the set was unchanged)
bool add(const rangeset_t &aset) { return rangeset_t_add2(this, aset); }
/// Subtract an address range from the set.
/// All subsets of 'range' will be removed, and all elements that intersect
/// 'range' will be truncated/split so they do not include 'range'.
/// \param range address range to subtract. cannot be empty.
/// \return false if 'range' was not subtracted (the set was unchanged)
bool sub(const range_t &range) { return rangeset_t_sub(this, range); }
/// Subtract an ea (an range of size 1) from the set. See sub(const range_t &)
bool sub(ea_t ea) { return sub(range_t(ea, ea+1)); }
/// Subtract each range in 'aset' from the set
/// \return false if nothing was subtracted (the set was unchanged)
bool sub(const rangeset_t &aset) { return rangeset_t_sub2(this, aset); }
/// Is there an ea in 'range' that is also in the rangeset?
bool has_common(const range_t &range) const
{ return rangeset_t_has_common(this, range, false); }
/// Is every ea in 'range' contained in the rangeset?
bool includes(const range_t &range) const
{ return rangeset_t_has_common(this, range, true); }
/// Print each range_t in the rangeset
size_t print(char *buf, size_t bufsize) const
{ return rangeset_t_print(this, buf, bufsize); }
/// Size in bytes
asize_t count(void) const;
/// Get the range_t at index 'idx'
const range_t &getrange(int idx) const { return bag[idx]; }
/// Get the last range_t in the set
const range_t &lastrange(void) const { return bag.back(); }
/// Get the number of range_t elements in the set
size_t nranges(void) const { return bag.size(); }
/// Does the set have zero elements
bool empty(void) const { return bag.empty(); }
/// Delete all elements from the set. See qvector::clear()
void clear(void) { bag.clear(); cache = NULL; }
/// Does any element of 'aset' overlap with an element in this rangeset?. See range_t::overlaps()
bool has_common(const rangeset_t &aset) const
{ return rangeset_t_has_common2(this, aset); }
/// Does an element of the rangeset contain 'ea'? See range_t::contains(ea_t)
bool contains(ea_t ea) const { return !empty() && find_range(ea) != NULL; }
/// Is every element in 'aset' contained in an element of this rangeset?. See range_t::contains(range_t)
bool contains(const rangeset_t &aset) const
{ return rangeset_t_contains(this, aset); }
/// Set the rangeset to its intersection with 'aset'.
/// \return false if the set was unchanged
bool intersect(const rangeset_t &aset)
{ return rangeset_t_intersect(this, aset); }
/// Is every element in the rangeset contained in an element of 'aset'?
bool is_subset_of(const rangeset_t &aset) const { return aset.contains(*this); }
/// Do this rangeset and 'aset' have identical elements?
bool is_equal(const rangeset_t &aset) const { return bag == aset.bag; }
bool operator==(const rangeset_t &aset) const { return is_equal(aset); } ///< Compare two rangesets with '=='
bool operator!=(const rangeset_t &aset) const { return !is_equal(aset); } ///< Compare two rangesets with '!='
typedef rangevec_t::iterator iterator; ///< Iterator for rangesets
typedef rangevec_t::const_iterator const_iterator; ///< Const iterator for rangesets
const_iterator begin(void) const { return bag.begin(); } ///< Get an iterator that points to the first element in the set
const_iterator end(void) const { return bag.end(); } ///< Get an iterator that points to the end of the set. (This is NOT the last element)
iterator begin(void) { return bag.begin(); } ///< \copydoc begin
iterator end(void) { return bag.end(); } ///< \copydoc end
/// Get the first range that contains at least one ea_t value greater than 'ea'
const_iterator lower_bound(ea_t ea) const { return rangeset_t_lower_bound(this, ea); }
/// Get the first range such that every ea_t value in this range is strictly greater than 'ea'
const_iterator upper_bound(ea_t ea) const { return rangeset_t_upper_bound(this, ea); }
/// Get the element from the set that contains 'ea'.
/// \return NULL if there is no such element
const range_t *find_range(ea_t ea) const
{ return rangeset_t_find_range(this, ea); }
/// When searching the rangeset, we keep a cached element to help speed up searches.
/// \return a pointer to the cached element
const range_t *cached_range(void) const { return cache; }
/// Get the smallest ea_t value greater than 'ea' contained in the rangeset
ea_t next_addr(ea_t ea) const { return rangeset_t_next_addr(this, ea); }
/// Get the largest ea_t value less than 'ea' contained in the rangeset
ea_t prev_addr(ea_t ea) const { return rangeset_t_prev_addr(this, ea); }
/// Get the smallest ea_t value greater than 'ea' that is not in the same range as 'ea'
ea_t next_range(ea_t ea) const { return rangeset_t_next_range(this, ea); }
/// Get the largest ea_t value less than 'ea' that is not in the same range as 'ea'
ea_t prev_range(ea_t ea) const { return rangeset_t_prev_range(this, ea); }
/// Subtract the address range (from, from+size) and add the range (to, to+size)
int move_chunk(ea_t from, ea_t to, asize_t size);
/// TODO: return code borrowed from va.hpp, same with move_chunk()
int check_move_args(ea_t from, ea_t to, asize_t size);
};
DECLARE_TYPE_AS_MOVABLE(rangeset_t);
typedef qvector<rangeset_t> array_of_rangesets; ///< Array of rangeset_t objects
typedef qvector<const rangeset_t*> rangeset_crefvec_t;
#endif // _RANGE_HPP

239
idasdk76/include/regex.h Normal file
View File

@@ -0,0 +1,239 @@
/*************************************************
* Perl-Compatible Regular Expressions *
*************************************************/
/* PCRE2 is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
Original API code Copyright (c) 1997-2012 University of Cambridge
New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
#ifndef _REGEX_H_
#define _REGEX_H_
#ifdef __cplusplus
#include <kernwin.hpp>
#endif
#include <pro.h>
#ifdef __GNUC__
#undef __P
#endif
typedef off_t regoff_t;
/* The structure representing a compiled regular expression. */
struct regex_t
{
int re_magic;
size_t re_nsub; /* number of parenthesized subexpressions */
const char *re_endp; /* end pointer for REG_PEND */
void *re_g; /* none of your business :-) */
};
/* The structure in which a captured offset is returned. */
struct regmatch_t
{
regoff_t rm_so; /* start of match */
regoff_t rm_eo; /* end of match */
};
#ifndef REG_ICASE
/* Options, mostly defined by POSIX, but with some extras. */
#define REG_ICASE 0x0001 /* Maps to PCRE2_CASELESS */
#define REG_NEWLINE 0x0002 /* Maps to PCRE2_MULTILINE */
#define REG_NOTBOL 0x0004 /* Maps to PCRE2_NOTBOL */
#define REG_NOTEOL 0x0008 /* Maps to PCRE2_NOTEOL */
#define REG_DOTALL 0x0010 /* NOT defined by POSIX; maps to PCRE2_DOTALL */
#define REG_NOSUB 0x0020 /* Maps to PCRE2_NO_AUTO_CAPTURE */
#define REG_UTF 0x0040 /* NOT defined by POSIX; maps to PCRE2_UTF */
#define REG_STARTEND 0x0080 /* BSD feature: pass subject string by so,eo */
#define REG_NOTEMPTY 0x0100 /* NOT defined by POSIX; maps to PCRE2_NOTEMPTY */
#define REG_UNGREEDY 0x0200 /* NOT defined by POSIX; maps to PCRE2_UNGREEDY */
#define REG_UCP 0x0400 /* NOT defined by POSIX; maps to PCRE2_UCP */
/* This is not used by PCRE2, but by defining it we make it easier
to slot PCRE2 into existing programs that make POSIX calls. */
#define REG_EXTENDED 0
#define REG_TRACE 0 // unsupported by PCRE2
/* Error values. Not all these are relevant or used by the wrapper. */
enum
{
REG_ASSERT = 1, /* internal error ? */
REG_BADBR, /* invalid repeat counts in {} */
REG_BADPAT, /* pattern error */
REG_BADRPT, /* ? * + invalid */
REG_EBRACE, /* unbalanced {} */
REG_EBRACK, /* unbalanced [] */
REG_ECOLLATE, /* collation error - not relevant */
REG_ECTYPE, /* bad class */
REG_EESCAPE, /* bad escape sequence */
REG_EMPTY, /* empty expression */
REG_EPAREN, /* unbalanced () */
REG_ERANGE, /* bad range inside [] */
REG_ESIZE, /* expression too big */
REG_ESPACE, /* failed to get memory */
REG_ESUBREG, /* bad back reference */
REG_INVARG, /* bad argument */
REG_NOMATCH /* match failed */
};
#endif //REG_ICASE
/* The functions */
// compile the regular expression
idaman THREAD_SAFE int ida_export qregcomp(
struct regex_t *preg,
const char *pattern,
int cflags);
// mapping from error codes returned by qregcomp() and qregexec() to a string
idaman THREAD_SAFE size_t ida_export qregerror(
int errcode,
const struct regex_t *preg,
char *errbuf,
size_t errbuf_size);
// match regex against a string
idaman THREAD_SAFE int ida_export qregexec(
const struct regex_t *preg,
const char *str,
size_t nmatch,
struct regmatch_t pmatch[],
int eflags);
// free any memory allocated by qregcomp
idaman THREAD_SAFE void ida_export qregfree(struct regex_t *preg);
#ifdef __cplusplus
//-------------------------------------------------------------------------
class refcnted_regex_t : public qrefcnt_obj_t
{
regex_t regex;
refcnted_regex_t()
{
regex = {};
}
virtual ~refcnted_regex_t()
{
qregfree(&regex);
}
public:
virtual void idaapi release(void) override
{
delete this;
}
int exec(const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
{
return qregexec(&regex, string, nmatch, pmatch, eflags);
}
int process_errors(int code, qstring *errmsg)
{
if ( code != 0 && errmsg != NULL )
{
char errbuf[MAXSTR];
qregerror(code, &regex, errbuf, sizeof(errbuf));
*errmsg = errbuf;
}
return code;
}
static refcnted_regex_t *create(const qstring &text, bool case_insensitive, qstring *errmsg)
{
if ( text.empty() )
return NULL;
refcnted_regex_t *p = new refcnted_regex_t();
int rflags = REG_EXTENDED;
if ( case_insensitive )
rflags |= REG_ICASE;
int code = qregcomp(&p->regex, text.begin(), rflags);
if ( p->process_errors(code, errmsg) != 0 )
{
// It is unnecessary to qregfree() here: the deletion of 'p' will
// call qregfree (but anyway, even that is unnecessary, because
// if we end up here, it means qregcomp() failed, and when that
// happens, qregcomp() frees the regex itself.)
delete p;
p = NULL;
}
return p;
}
size_t nsub(void)
{
/* number of parenthesized subexpressions */
return regex.re_nsub;
}
DECLARE_UNCOPYABLE(refcnted_regex_t);
};
typedef qrefcnt_t<refcnted_regex_t> regex_ptr_t;
//---------------------------------------------------------------------------
struct regex_cache_t
{
regex_ptr_t &find_or_create(const qstring &str)
{
regex_cache_map_t::iterator it = cache.find(str);
if ( it == cache.end() )
{
qstring errmsg;
regex_ptr_t rx = regex_ptr_t(refcnted_regex_t::create(str, false, &errmsg));
if ( rx == NULL )
error("%s", errmsg.c_str());
it = cache.insert(regex_cache_map_t::value_type(str, rx)).first;
}
return it->second;
}
private:
typedef std::map<qstring,regex_ptr_t> regex_cache_map_t;
regex_cache_map_t cache;
};
#endif //__cplusplus
#ifndef NO_OBSOLETE_FUNCS
idaman DEPRECATED THREAD_SAFE int ida_export regcomp(struct regex_t *preg, const char *pattern, int cflags);
idaman DEPRECATED THREAD_SAFE size_t ida_export regerror(int errcode, const struct regex_t *preg, char *errbuf, size_t errbuf_size);
idaman DEPRECATED THREAD_SAFE int ida_export regexec(const struct regex_t *preg, const char *str, size_t nmatch, struct regmatch_t pmatch[], int eflags);
idaman DEPRECATED THREAD_SAFE void ida_export regfree(struct regex_t *preg);
#endif
#endif /* !_REGEX_H_ */

View File

@@ -0,0 +1,375 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef __REGISTRY_HPP
#define __REGISTRY_HPP
/*! \file registry.hpp
\brief Registry related functions
IDA uses the registry to store global configuration options that must
persist after IDA has been closed.
On Windows, IDA uses the Windows registry directly. On Unix systems, the registry
is stored in a file (typically ~/.idapro/ida.reg).
The root key for accessing IDA settings in the registry is defined by #ROOT_KEY_NAME.
*/
/// Key used to store IDA settings in registry (Windows version).
/// \note this name is automatically prepended to all
/// key names passed to functions in this file.
#define ROOT_KEY_NAME "Software\\Hex-Rays\\IDA"
/// \cond
// Low level functions. DO NOT USE THEM. See the wrappers below.
// 'mode' is:
// - 0: data is a raw buffer, and its datalen must be able to hold the entire binary contents
// - 1: data is a raw buffer, and its datalen doesn't need to be able to hold the entire binary contents
// - 2: data is a ::bytevec_t*, datalen is ignored.
idaman bool ida_export reg_bin_op(
const char *name,
bool save,
void *data,
size_t datalen,
const char *subkey,
int mode = 0);
idaman bool ida_export reg_str_get(qstring *buf, const char *name, const char *subkey);
idaman void ida_export reg_str_set(const char *name, const char *subkey, const char *buf);
idaman int ida_export reg_int_op(
const char *name,
bool save,
int value,
const char *subkey = NULL);
/// \endcond
/// Types of values stored in the registry
enum regval_type_t
{
reg_unknown = 0, ///< unknown
reg_sz = 1, ///< utf8 string
reg_binary = 3, ///< binary data
reg_dword = 4 ///< 32-bit number
};
/// Delete a key from the registry
idaman bool ida_export reg_delete_subkey(const char *name);
/// Delete a subtree from the registry
idaman bool ida_export reg_delete_tree(const char *name);
/// Delete a value from the registry.
/// \param name value name
/// \param subkey parent key
/// \return success
idaman bool ida_export reg_delete(const char *name, const char *subkey = NULL);
/// Is there already a key with the given name?
idaman bool ida_export reg_subkey_exists(const char *name);
/// Is there already a value with the given name?
/// \param name value name
/// \param subkey parent key
idaman bool ida_export reg_exists(const char *name, const char *subkey = NULL);
/// Retrieve the child names of the given key.
/// \param out result
/// \param name key name
/// \param subkeys if true, collect subkey names. if false, collect value names.
/// \return false if the given key does not exist
idaman bool ida_export reg_subkey_children(qstrvec_t *out, const char *name, bool subkeys);
/// Get data type of a given value.
/// \param out result
/// \param name value name
/// \param subkey key name
/// \return false if the [key+]value doesn't exist
idaman bool ida_export reg_data_type(regval_type_t *out, const char *name, const char *subkey = NULL);
/// Retrieve all string values associated with the given key.
/// Also see reg_update_strlist().
idaman void ida_export reg_read_strlist(qstrvec_t *list, const char *subkey);
/// Update list of strings associated with given key.
/// \param subkey key name
/// \param add string to be added to list, can be NULL
/// \param maxrecs limit list to this size
/// \param rem string to be removed from list, can be NULL
/// \param ignorecase ignore case for 'add' and 'rem'
idaman void ida_export reg_update_strlist(
const char *subkey,
const char *add,
size_t maxrecs,
const char *rem = NULL,
bool ignorecase = false);
/// Write binary data to the registry.
/// \param name value name
/// \param data input, must not be NULL
/// \param datalen length of input in bytes
/// \param subkey key name
inline void reg_write_binary(
const char *name,
const void *data,
size_t datalen,
const char *subkey = NULL)
{
reg_bin_op(name, true, CONST_CAST(void *)(data), datalen, subkey);
}
/// Read binary data from the registry.
/// \param name value name
/// \param[out] data result, must not be NULL
/// \param datalen length of out buffer in bytes
/// \param subkey key name
/// \return false if 'data' is not large enough to hold all data present.
/// in this case 'data' is left untouched.
inline bool reg_read_binary(
const char *name,
void *data,
size_t datalen,
const char *subkey = NULL)
{
return reg_bin_op(name, false, data, datalen, subkey);
}
/// Read a chunk of binary data from the registry.
/// This function succeeds even in the case of a partial read.
/// \param name value name
/// \param[out] data result, must not be NULL
/// \param datalen length of output buffer in bytes
/// \param subkey key name
/// \return success
inline bool reg_read_binary_part(
const char *name,
void *data,
size_t datalen,
const char *subkey = NULL)
{
return reg_bin_op(name, false, data, datalen, subkey, 1);
}
/// Read binary data from the registry.
/// \param name value name
/// \param[out] data output buffer, must not be NULL
/// \param subkey key name
/// \return success
inline bool reg_read_binary(
const char *name,
bytevec_t *data,
const char *subkey = NULL)
{
return reg_bin_op(name, false, data, 0, subkey, 2);
}
/// Write a string to the registry.
/// \param name value name
/// \param utf8 utf8-encoded string
/// \param subkey key name
inline void reg_write_string(
const char *name,
const char *utf8,
const char *subkey = NULL)
{
reg_str_set(name, subkey, utf8);
}
/// Read a string from the registry.
/// \param[out] utf8 output buffer
/// \param name value name
/// \param subkey key name
/// \return success
inline bool reg_read_string(
qstring *utf8,
const char *name,
const char *subkey = NULL)
{
return reg_str_get(utf8, name, subkey);
}
/// Read integer value from the registry.
/// \param name value name
/// \param defval default value
/// \param subkey key name
/// \return the value read from the registry, or 'defval' if the read failed
inline int reg_read_int(const char *name, int defval, const char *subkey = NULL)
{
return reg_int_op(name, false, defval, subkey);
}
/// Write integer value to the registry.
/// \param name value name
/// \param value value to write
/// \param subkey key name
inline void reg_write_int(const char *name, int value, const char *subkey = NULL)
{
reg_int_op(name, true, value, subkey);
}
/// Read boolean value from the registry.
/// \param name value name
/// \param defval default value
/// \param subkey key name
/// \return boolean read from registry, or 'defval' if the read failed
inline bool reg_read_bool(const char *name, bool defval, const char *subkey = NULL)
{
return reg_int_op(name, false, int(defval), subkey) != 0;
}
/// Write boolean value to the registry.
/// \param name value name
/// \param value boolean to write (nonzero = true)
/// \param subkey key name
inline void reg_write_bool(const char *name, int value, const char *subkey = NULL)
{
reg_int_op(name, true, value != 0, subkey);
}
/// Get all subkey names of given key
inline bool reg_subkey_subkeys(qstrvec_t *out, const char *name)
{
return reg_subkey_children(out, name, true);
}
/// Get all value names under given key
inline bool reg_subkey_values(qstrvec_t *out, const char *name)
{
return reg_subkey_children(out, name, false);
}
/// Update registry with a file list.
/// Case sensitivity will vary depending on the target OS.
/// \note 'add' and 'rem' must be UTF-8, just like for regular string operations.
inline void reg_update_filestrlist(
const char *subkey,
const char *add,
size_t maxrecs,
const char *rem = NULL)
{
reg_update_strlist(
subkey, add, maxrecs, rem,
#ifdef __NT__ // Ignore case in Windows
true
#else
false
#endif
);
}
//-----------------------------------------------------------------------------
// INTERNALS
/// \cond
#define _RVN_(f) regname_ ## f
#ifndef __DEFINE_REG_NAMES__
#define REG_VAL_NAME(n,s) \
extern const char _RVN_(n)[]
#else
#define REG_VAL_NAME(n,s) \
extern const char _RVN_(n)[]; \
const char _RVN_(n)[] = s
#endif
#define REG_BOOL_FUNC(func, valname) \
REG_VAL_NAME(func, valname); \
inline void regset_ ## func(bool value) \
{ reg_write_bool(_RVN_(func), value); } \
inline bool regget_ ## func(bool def) \
{ return reg_read_bool(_RVN_(func), def); }
#define REG_INT_FUNC(func, valname) \
REG_VAL_NAME(func,valname); \
inline void regset_ ## func(int value) \
{ \
reg_int_op(_RVN_(func), true, value); \
} \
inline int regget_ ## func(int def=0) \
{ \
return reg_int_op(_RVN_(func), false, def); \
}
idaman void ida_export reg_load(void);
idaman void ida_export reg_flush(void);
// if using history functions below, you have to define the following two variables
extern const char regkey_history[];
extern int max_history_files; // max number of files in the file menu
// and in the welcome box
#define MAX_HISTORY_FILES_DEF 10 // default value
inline void regget_history(qstrvec_t *list)
{
#ifdef DEMO
qnotused(list);
#else
reg_read_strlist(list, regkey_history);
#endif
}
inline void reg_update_history(const char *addfile, const char *removefile = NULL)
{
#ifdef DEMO
qnotused(addfile);
qnotused(removefile);
#else
// On Windows avoid duplicate upper/lower-case entries
// by using reg_update_filestrlist() which takes care of case sensitivity
reg_update_filestrlist(regkey_history, addfile, max_history_files, removefile);
#endif
}
inline void reg_history_size_truncate(void)
{
#ifndef DEMO
reg_update_strlist(regkey_history, NULL, max_history_files, NULL);
#endif
}
/// \endcond
#endif // __REGISTRY_HPP

167
idasdk76/include/search.hpp Normal file
View File

@@ -0,0 +1,167 @@
/*
* Interactive disassembler (IDA).
* ALL RIGHTS RESERVED.
* Copyright (c) 1990-2021 Hex-Rays
*
*/
#ifndef __SEARCH_HPP
#define __SEARCH_HPP
/*! \file search.hpp
\brief Middle-level search functions
They all are controlled by \ref SEARCH_
*/
/// \defgroup SEARCH_ Search flags
//@{
#define SEARCH_UP 0x000 ///< search towards lower addresses
#define SEARCH_DOWN 0x001 ///< search towards higher addresses
#define SEARCH_NEXT 0x002 ///< skip the starting address when searching.
///< this bit is useful only for search(), bin_search2(), find_reg_access().
///< find_.. functions skip the starting address automatically.
#define SEARCH_CASE 0x004 ///< case-sensitive search (case-insensitive otherwise)
#define SEARCH_REGEX 0x008 ///< regular expressions in search string (supported only for the text search)
#define SEARCH_NOBRK 0x010 ///< do not test if the user clicked cancel to interrupt the search
#define SEARCH_NOSHOW 0x020 ///< do not display the search progress/refresh screen
#define SEARCH_IDENT 0x080 ///< search for an identifier (text search).
///< it means that the characters before
///< and after the match cannot be is_visible_char().
#define SEARCH_BRK 0x100 ///< return #BADADDR if the search was cancelled.
#define SEARCH_USE 0x200 ///< find_reg_access: search for a use (read access)
#define SEARCH_DEF 0x400 ///< find_reg_access: search for a definition (write access)
//@}
/// Is the #SEARCH_DOWN bit set?
inline THREAD_SAFE bool search_down(int sflag) { return (sflag & SEARCH_DOWN) != 0; }
/// \name find_... functions
/// \param ea start ea
/// \param sflag combination of \ref SEARCH_
/// \param[out] opnum filled with operand number whenever relevant
/// \return first ea at which the search criteria is met
//@{
/// Find next error or problem
idaman ea_t ida_export find_error(ea_t ea, int sflag, int *opnum=NULL);
/// Find next operand without any type info
idaman ea_t ida_export find_notype(ea_t ea, int sflag, int *opnum=NULL);
/// Find next unexplored address
idaman ea_t ida_export find_unknown(ea_t ea, int sflag);
/// Find next ea that is the start of an instruction or data
idaman ea_t ida_export find_defined(ea_t ea, int sflag);
/// Find next suspicious operand
idaman ea_t ida_export find_suspop(ea_t ea, int sflag, int *opnum=NULL);
/// Find next data address
idaman ea_t ida_export find_data(ea_t ea,int sflag);
/// Find next code address
idaman ea_t ida_export find_code(ea_t ea,int sflag);
/// Find next code address that does not belong to a function
idaman ea_t ida_export find_not_func(ea_t ea,int sflag);
/// Find next immediate operand with the given value
idaman ea_t ida_export find_imm(ea_t ea, int sflag, uval_t search_value, int *opnum=NULL);
/// See search()
idaman ea_t ida_export find_text(ea_t start_ea, int y, int x, const char *ustr, int sflag);
/// Find access to a register.
/// \param out pointer to the output buffer. must be non-null.
/// upon success contains info about the found register.
/// upon failed search for a read access out->range contains
/// the info about the non-redefined parts of the register.
/// \param start_ea starting address
/// \param end_ea ending address. BADADDR means that the end limit is missing.
/// otherwise, if the search direction is SEARCH_UP,
/// END_EA must be lower than START_EA.
/// \param regname the register to search for.
/// \param sflag combination of \ref SEARCH_ bits.
/// \note This function does not care about the control flow and
/// probes all instructions in the specified range, starting from START_EA.
/// Only direct references to registers are detected. Function calls and
/// system traps are ignored.
/// \return the found address. BADADDR if not found or error.
idaman ea_t ida_export find_reg_access(
struct reg_access_t *out,
ea_t start_ea,
ea_t end_ea,
const char *regname,
int sflag);
//@}
class place_t;
/// Search for a text substring (low level function).
/// \param ud line array parameter
/// \param[in,out] start pointer to starting place:
/// - start->ea: starting address
/// - start->lnnum: starting Y coordinate
/// \param end pointer to ending place:
/// - end->ea: ending address
/// - end->lnnum: ending Y coordinate
/// \param[in,out] startx pointer to starting X coordinate
/// \param str substring to search for.
/// \param sflag \ref SEARCH_
/// \retval 0 substring not found
/// \retval 1 substring found. The matching position is returned in:
/// - start->ea: address
/// - start->lnnum: Y coordinate
/// - *startx: X coordinate
/// \retval 2 search was cancelled by ctrl-break.
/// The farthest searched address is
/// returned in the same manner as in the successful return (1).
/// \retval 3 the input regular expression is bad.
/// The error message was displayed.
idaman int ida_export search(
void *ud,
place_t *start,
const place_t *end,
int *startx,
const char *str,
int sflag);
#if !defined(NO_OBSOLETE_FUNCS)
idaman DEPRECATED int ida_export user2bin(uchar *, uchar *, ea_t, const char *, int, bool); // use parse_binpat_str()
idaman DEPRECATED ea_t ida_export find_binary(ea_t, ea_t, const char *, int, int); // use bin_search2()
#endif
#endif // __SEARCH_HPP

1212
idasdk76/include/segment.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _SRAREA_HPP
#define _SRAREA_HPP
#include <range.hpp>
/*! \file segregs.hpp
\brief Functions that deal with the segment registers.
If your processor doesn't use segment registers, then these functions
are of no use for you. However, you should define
two virtual segment registers - CS and DS (for code segment and
data segment) and specify their internal numbers in the LPH structure
(processor_t::reg_code_sreg and processor_t::reg_data_sreg).
*/
//-------------------------------------------------------------------------
/// The values of the segment registers are kept as address ranges. The segment
/// register does not change its value within one address range.
/// The processor module finds segment register change points and splits
/// ::sreg_range_t ranges so that a new sreg_range_t range is started at
/// each segment register change point. The kernel deletes sreg_range_t
/// if an instruction is converted back to unexplored bytes.
///
/// So, we have information about a segment register by keeping information
/// about the range of addresses where segment register does not change the value.
///
/// Note that each segment has information about the default values of
/// the segment registers. This information is used if the value of a segment
/// register could not be determined.
struct sreg_range_t : public range_t
{
sel_t val; ///< segment register value
uchar tag; ///< \ref SR_
/// \defgroup SR_ Segment register range tags
/// Used by sreg_range_t::tag
//@{
#define SR_inherit 1 ///< the value is inherited from the previous range
#define SR_user 2 ///< the value is specified by the user
#define SR_auto 3 ///< the value is determined by IDA
#define SR_autostart 4 ///< used as #SR_auto for segment starting address
//@}
};
DECLARE_TYPE_AS_MOVABLE(sreg_range_t);
/// Get value of a segment register.
/// This function uses segment register range and default segment register
/// values stored in the segment structure.
/// \param ea linear address in the program
/// \param rg number of the segment register
/// \return value of the segment register, #BADSEL if value is unknown.
idaman sel_t ida_export get_sreg(ea_t ea, int rg);
/// Create a new segment register range.
/// This function is used when the IDP emulator detects that a segment
/// register changes its value.
/// \param ea linear address where the segment register will
/// have a new value. if ea==#BADADDR, nothing to do.
/// \param rg the number of the segment register
/// \param v the new value of the segment register. If the value is
/// unknown, you should specify #BADSEL.
/// \param tag the register info tag. see \ref SR_
/// \param silent if false, display a warning() in the case of failure
/// \return success
idaman bool ida_export split_sreg_range(
ea_t ea,
int rg,
sel_t v,
uchar tag,
bool silent=false);
/// Set default value of a segment register for a segment.
/// \param sg pointer to segment structure
/// if NULL, then set the register for all segments
/// \param rg number of segment register
/// \param value its default value. this value will be used by get_sreg()
/// if value of the register is unknown at the specified address.
/// \return success
idaman bool ida_export set_default_sreg_value(segment_t *sg, int rg, sel_t value);
/// Set the segment register value at the next instruction.
/// This function is designed to be called from idb_event::sgr_changed handler
/// in order to contain the effect of changing a segment
/// register value only until the next instruction.
///
/// It is useful, for example, in the ARM module: the modification
/// of the T register does not affect existing instructions later in the code.
/// \param ea1 address to start to search for an instruction
/// \param ea2 the maximal address
/// \param rg the segment register number
/// \param value the segment register value
idaman void ida_export set_sreg_at_next_code(ea_t ea1, ea_t ea2, int rg, sel_t value);
/// Get segment register range by linear address.
/// \param out segment register range
/// \param ea any linear address in the program
/// \param rg the segment register number
/// \return success
idaman bool ida_export get_sreg_range(sreg_range_t *out, ea_t ea, int rg);
/// Get segment register range previous to one with address.
/// \note more efficient then get_sreg_range(reg, ea-1)
/// \param out segment register range
/// \param ea any linear address in the program
/// \param rg the segment register number
/// \return success
idaman bool ida_export get_prev_sreg_range(sreg_range_t *out, ea_t ea, int rg);
/// Set default value of DS register for all segments
idaman void ida_export set_default_dataseg(sel_t ds_sel);
/// Get number of segment register ranges.
/// \param rg the segment register number
idaman size_t ida_export get_sreg_ranges_qty(int rg);
/// Get segment register range by its number.
/// \param out segment register range
/// \param rg the segment register number
/// \param n number of range (0..qty()-1)
/// \return success
idaman bool ida_export getn_sreg_range(sreg_range_t *out, int rg, int n);
/// Get number of segment register range by address.
/// \param ea any address in the range
/// \param rg the segment register number
/// \return -1 if no range occupies the specified address.
/// otherwise returns number of
/// the specified range (0..get_srranges_qty()-1)
idaman int ida_export get_sreg_range_num(ea_t ea, int rg);
/// Delete segment register range started at ea.
/// When a segment register range is deleted,
/// the previous range is extended to cover the empty space.
/// The segment register range at the beginning of a segment cannot be deleted.
/// \param ea start_ea of the deleted range
/// \param rg the segment register number
/// \return success
idaman bool ida_export del_sreg_range(ea_t ea, int rg);
/// Duplicate segment register ranges.
/// \param dst_rg number of destination segment register
/// \param src_rg copy ranges from
/// \param map_selector map selectors to linear addresses using sel2ea()
idaman void ida_export copy_sreg_ranges(int dst_rg, int src_rg, bool map_selector=false);
#endif // _SRAREA_HPP

View File

@@ -0,0 +1,78 @@
/*
* The Interactive Disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _STRLIST_HPP
#define _STRLIST_HPP
/*! \file strlist.hpp
\brief Functions that deal with the string list
While the kernel keeps the string list, it does not update it.
The string list is not used by the kernel because
keeping it up-to-date would slow down IDA without any benefit.
If the string list is not cleared using clear_strlist(), the list will be
saved to the database and restored on the next startup.
The users of this list should call build_strlist() if they need an
up-to-date version.
*/
/// Structure to keep string list parameters
struct strwinsetup_t
{
strwinsetup_t()
: minlen(-1), display_only_existing_strings(0),
only_7bit(1), ignore_heads(0) {}
bytevec_t strtypes; // set of allowed string types
sval_t minlen;
uchar display_only_existing_strings;
uchar only_7bit;
uchar ignore_heads;
};
/// Information about one string from the string list
struct string_info_t
{
ea_t ea;
int length; // in octets
int type;
string_info_t() : ea(BADADDR), length(0), type(0) {}
string_info_t(ea_t _ea) : ea(_ea), length(0), type(0) {}
bool operator<(const string_info_t &r) const { return ea < r.ea; }
};
DECLARE_TYPE_AS_MOVABLE(string_info_t);
/// Get the static string list options
idaman const strwinsetup_t *ida_export get_strlist_options();
/// Rebuild the string list.
idaman void ida_export build_strlist();
/// Clear the string list.
idaman void ida_export clear_strlist();
/// Get number of elements in the string list.
/// The list will be loaded from the database (if saved) or
/// built from scratch.
idaman size_t ida_export get_strlist_qty(void);
/// Get nth element of the string list (n=0..get_strlist_qty()-1)
idaman bool ida_export get_strlist_item(string_info_t *si, size_t n);
#endif // _STRLIST_HPP

661
idasdk76/include/struct.hpp Normal file
View File

@@ -0,0 +1,661 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 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 the innermost member at the given offset
/// \param[in] sptr the starting structure
/// \param[out] sptr the innermost structure
/// \param[in] offset offset into the starting structure
/// \param[out] offset remaining offset into the returned member
/// \retval a member in SPTR (it is not a structure) or 'nullptr'
idaman member_t *ida_export get_innermost_member(struc_t **sptr, asize_t *offset);
/// 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

View File

@@ -0,0 +1,218 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 2016-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
* Module independent exception description
*/
#ifndef TRYBLKS_HPP
#define TRYBLKS_HPP
/*! \file tryblks.hpp
*
* \brief Architecture independent exception handling info.
*
* Try blocks have the following general properties:
* - A try block specifies a possibly fragmented guarded code region.
* - Each try block has always at least one catch/except block description
* - Each catch block contains its boundaries and a filter.
* - Additionally a catch block can hold sp adjustment and the offset to the
* exception object offset (C++).
* - Try blocks can be nested. Nesting is automatically calculated at the retrieval time.
* - There may be (nested) multiple try blocks starting at the same address.
*
* See examples in tests/input/src/eh_tests.
*
*/
// We use end_ea=BADADDR if the exact boundaries are unknown of any range.
//----------------------------------------------------------------------------
// An exception handler clause (the body of __except or catch statement)
struct try_handler_t : public rangevec_t
{
sval_t disp; // displacement to the stack region of the guarded region.
// if it is valid, it is fpreg relative.
// -1 means unknown.
int fpreg; // frame register number used in handler. -1 means none.
try_handler_t() : disp(-1), fpreg(-1) {}
void clear(void)
{
rangevec_t::clear();
disp = -1;
fpreg = -1;
}
};
DECLARE_TYPE_AS_MOVABLE(try_handler_t);
//----------------------------------------------------------------------------
// __except() {} statement
struct seh_t : public try_handler_t
{
rangevec_t filter; // boundaries of the filter callback. if filter is empty,
ea_t seh_code; // then use seh_code
#define SEH_CONTINUE BADADDR // EXCEPTION_CONTINUE_EXECUTION (-1)
#define SEH_SEARCH ea_t(0) // EXCEPTION_CONTINUE_SEARCH (0) (alias of __finally)
#define SEH_HANDLE ea_t(1) // EXCEPTION_EXECUTE_HANDLER (1)
void clear(void)
{
try_handler_t::clear();
filter.clear();
seh_code = SEH_CONTINUE;
}
};
DECLARE_TYPE_AS_MOVABLE(seh_t);
//----------------------------------------------------------------------------
// catch() {} statement
struct catch_t : public try_handler_t
{
sval_t obj; // fpreg relative displacement to the exception object. -1 if unknown.
sval_t type_id; // the type caught by this catch. -1 means "catch(...)"
#define CATCH_ID_ALL sval_t(-1) // catch(...)
#define CATCH_ID_CLEANUP sval_t(-2) // a cleanup handler invoked if exception occures
catch_t() : obj(-1), type_id(-1) {}
};
DECLARE_TYPE_AS_MOVABLE(catch_t);
typedef qvector<catch_t> catchvec_t;
//----------------------------------------------------------------------------
class tryblk_t : public rangevec_t // block guarded by try/__try {...} statements
{
#ifndef SWIG
char reserve[qmax(sizeof(catchvec_t), sizeof(seh_t))]; // seh_t or catchvec_t
#endif
uchar cb; // size of tryblk_t
uchar kind; // one of the following kinds
#define TB_NONE 0 // empty
#define TB_SEH 1 // MS SEH __try/__except/__finally
#define TB_CPP 2 // C++ language try/catch
public:
uchar level; // nesting level, calculated by get_tryblks()
// C++ try/catch block (TB_CPP)
catchvec_t &cpp() { return *(( catchvec_t *)reserve); }
const catchvec_t &cpp() const { return *((const catchvec_t *)reserve); }
// SEH __except/__finally case (TB_SEH)
seh_t &seh() { return *(( seh_t *)reserve); }
const seh_t &seh() const { return *((const seh_t *)reserve); }
tryblk_t() : rangevec_t(), cb(sizeof(*this)), kind(TB_NONE), level(0) { reserve[0] = '\0'; }
~tryblk_t() { clear(); }
tryblk_t(const tryblk_t &r) : rangevec_t(), kind(TB_NONE) { *this = r; }
uchar get_kind(void) const { return kind; }
bool empty(void) const { return kind == TB_NONE; }
bool is_seh(void) const { return kind == TB_SEH; }
bool is_cpp(void) const { return kind == TB_CPP; }
//-------------------------------------------------------------------------
tryblk_t &operator=(const tryblk_t &r)
{
if ( this != &r ) // don't copy yourself
{
if ( kind != TB_NONE )
clear();
kind = r.kind;
level = r.level;
rangevec_t::operator=(r);
if ( kind == TB_SEH )
new (reserve) seh_t(r.seh());
else if ( kind == TB_CPP )
new (reserve) catchvec_t(r.cpp());
}
return *this;
}
//-------------------------------------------------------------------------
void clear(void)
{
if ( kind == TB_CPP )
cpp().~catchvec_t();
else if ( kind == TB_SEH )
seh().~seh_t();
kind = TB_NONE;
}
//-------------------------------------------------------------------------
seh_t &set_seh(void)
{
if ( kind != TB_SEH )
{
clear();
new (reserve) seh_t;
kind = TB_SEH;
}
else
{
seh().clear();
}
return seh();
}
//-------------------------------------------------------------------------
catchvec_t &set_cpp(void)
{
if ( kind != TB_CPP )
{
clear();
new (reserve) catchvec_t;
kind = TB_CPP;
}
else
{
cpp().clear();
}
return cpp();
}
};
DECLARE_TYPE_AS_MOVABLE(tryblk_t);
typedef qvector<tryblk_t> tryblks_t;
///-------------------------------------------------------------------------
/// Retrieve try block information from the specified address range.
/// Try blocks are sorted by starting address and their nest levels calculated.
/// \param tbv output buffer; may be NULL
/// \param range address range to change
/// \return number of found try blocks
idaman size_t ida_export get_tryblks(tryblks_t *tbv, const range_t &range);
/// Delete try block information in the specified range.
/// \param range the range to be cleared
idaman void ida_export del_tryblks(const range_t &range);
/// Add one try block information.
/// \param tb try block to add.
/// \return error code; 0 means good
idaman int ida_export add_tryblk(const tryblk_t &tb);
/// \defgroup TBERR_ Try block handling error codes
//@{
#define TBERR_OK 0 ///< ok
#define TBERR_START 1 ///< bad start address
#define TBERR_END 2 ///< bad end address
#define TBERR_ORDER 3 ///< bad address order
#define TBERR_EMPTY 4 ///< empty try block
#define TBERR_KIND 5 ///< illegal try block kind
#define TBERR_NO_CATCHES 6 ///< no catch blocks at all
#define TBERR_INTERSECT 7 ///< range would intersect inner tryblk
//@}
/// Find the start address of the system eh region including the argument.
/// \param ea search address
/// \return start address of surrounding tryblk, otherwise BADADDR
idaman ea_t ida_export find_syseh(ea_t ea);
#endif // TRYBLKS_HPP

4396
idasdk76/include/typeinf.hpp Normal file

File diff suppressed because it is too large Load Diff

1470
idasdk76/include/ua.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
// various workarounds/fixes for different compilers
#ifndef _IDA_WORKAROUNDS_H
#define _IDA_WORKAROUNDS_H
// MS Visual C++:
// this file should be included once in module (exe or dll) where std::stable_sort() is used
#ifdef _MSC_VER
#if (_MSC_VER < 1700) // before VS2012
// the following fixes unneeded exports caused by use
// of std::stable_sort, which uses new(std::nothrow)
// reference: http://social.msdn.microsoft.com/Forums/vstudio/en-US/4692205a-0296-4f41-adbb-fa8339597f5c/unwanted-exports
namespace std { extern const __declspec(selectany) nothrow_t nothrow = nothrow_t(); }
// explanation by Javier Blazquez:
/*
The reason why this eliminates the _Init_locks export is because the linker
no longer has to go find and use the nothrow.obj file (part of msvcprt.lib)
during linking for the definition of std::nothrow, it can just use the
definition you provided. That nothrow.obj file not only contains the
definition of std::nothrow, it also contains a dllexport definition of
std::_Init_locks::operator= (in fact, the only such definition of this
function anywhere in the standard libraries), so preventing the linker from
using the standard nothrow.obj at all has the effect of removing this ugly
export altogether.
*/
#endif // (_MSC_VER < 1700)
#endif // _MSC_VER
#ifdef __LINUX__
// suppress dependency on __longjmp_chk
// idea stolen from http://code.google.com/p/webm/issues/detail?id=166
// this file should be included in modules where longjmp is used
#if !defined(__ARM__) && defined(__GNUC_PREREQ) && __GNUC_PREREQ(2,11)
#ifndef __X86__
__asm__(".symver __longjmp_chk,longjmp@GLIBC_2.2.5");
#else
__asm__(".symver __longjmp_chk,longjmp@GLIBC_2.0");
#endif // !__X86__
#endif // __GNUC_PREREQ
#endif // __LINUX__
#endif // _IDA_WORKAROUNDS_H

417
idasdk76/include/xref.hpp Normal file
View File

@@ -0,0 +1,417 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2021 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _XREF_HPP
#define _XREF_HPP
/*! \file xref.hpp
\brief Functions that deal with cross-references
There are 2 types of xrefs: CODE and DATA references.
All xrefs are kept in the bTree except ordinary execution flow
to the next instruction. Ordinary execution flow to
the next instruction is kept in flags (see bytes.hpp)
The source address of a cross-reference must be an item head (is_head)
or a structure member id.
Cross-references are automatically sorted.
*/
class func_t; // #include <funcs.hpp>
class member_t; // #include <struct.hpp>
//---------------------------------------------------------------------------
// C R O S S - R E F E R E N C E T Y P E S
//---------------------------------------------------------------------------
/// \defgroup xref_type Cross-Reference types
/// Describe categories of code/data xrefs.
/// \note IDA handles the xrefs automatically and may delete an xref
/// added by the user if it does not contain the #XREF_USER bit.
//@{
/// CODE xref types
enum cref_t
{
fl_U, ///< unknown -- for compatibility with old
///< versions. Should not be used anymore.
fl_CF = 16, ///< Call Far
///< This xref creates a function at the
///< referenced location
fl_CN, ///< Call Near
///< This xref creates a function at the
///< referenced location
fl_JF, ///< Jump Far
fl_JN, ///< Jump Near
fl_USobsolete, ///< User specified (obsolete)
fl_F, ///< Ordinary flow: used to specify execution
///< flow to the next instruction.
};
/// DATA xref types
enum dref_t
{
dr_U, ///< Unknown -- for compatibility with old
///< versions. Should not be used anymore.
dr_O, ///< Offset
///< The reference uses 'offset' of data
///< rather than its value
///< OR
///< The reference appeared because the "OFFSET"
///< flag of instruction is set.
///< The meaning of this type is IDP dependent.
dr_W, ///< Write access
dr_R, ///< Read access
dr_T, ///< Text (for forced operands only)
///< Name of data is used in manual operand
dr_I, ///< Informational
///< (a derived java class references its base
///< class informationally)
dr_S, ///< Reference to enum member (symbolic constant)
};
/// \defgroup XREF_T Cross-Reference type flags
/// These flags are combined with a ::cref_t or ::dref_t value to describe the
/// type of a cross reference.
/// These bits are accessible to the kernel.
//@{
#define XREF_USER 0x20 ///< User specified xref.
///< This xref will not be deleted by IDA.
///< This bit should be combined with
///< the existing xref types (::cref_t & ::dref_t)
///< Cannot be used for fl_F xrefs
#define XREF_TAIL 0x40 ///< Reference to tail byte in extrn symbols
#define XREF_BASE 0x80 ///< Reference to the base part of an offset
#define XREF_MASK 0x1F ///< Mask to get xref type
#define XREF_PASTEND 0x100 ///< Reference is past item. This bit may be passed to
///< add_dref() functions but it won't be saved in
///< the database. It will prevent the destruction
///< of eventual alignment directives.
//@}
/// Get character describing the xref type.
/// \param xrtype combination of \ref XREF_T and a ::cref_t of ::dref_t value
idaman char ida_export xrefchar(char xrtype);
//@} xref_type
//---------------------------------------------------------------------------
// A D D / D E L E T E C R O S S - R E F E R E N C E S
//---------------------------------------------------------------------------
/// Create a code cross-reference.
/// \param from linear address of referencing instruction
/// \param to linear address of referenced instruction
/// \param type cross-reference type
/// \return success
idaman bool ida_export add_cref(ea_t from, ea_t to, cref_t type);
/// Delete a code cross-reference.
/// \param from linear address of referencing instruction
/// \param to linear address of referenced instruction
/// \param expand policy to delete the referenced instruction
/// - 1: plan to delete the referenced instruction if it has
/// no more references.
/// - 0: don't delete the referenced instruction even if no
/// more cross-references point to it
/// \retval true if the referenced instruction will be deleted
idaman bool ida_export del_cref(ea_t from, ea_t to, bool expand);
/// Create a data cross-reference.
/// \param from linear address of referencing instruction or data
/// \param to linear address of referenced data
/// \param type cross-reference type
/// \return success (may fail if user-defined xref exists from->to)
idaman bool ida_export add_dref(ea_t from, ea_t to, dref_t type);
/// Delete a data cross-reference.
/// \param from linear address of referencing instruction or data
/// \param to linear address of referenced data
idaman void ida_export del_dref(ea_t from, ea_t to);
//-------------------------------------------------------------------------
// E N U M E R A T E ( G E T ) C R O S S - R E F E R E N C E S
//-------------------------------------------------------------------------
struct xrefblk_t;
/// \name Helper functions
/// Should not be called directly!
//@{
idaman bool ida_export xrefblk_t_first_from(xrefblk_t *,ea_t from,int flags);
idaman bool ida_export xrefblk_t_next_from(xrefblk_t *);
idaman bool ida_export xrefblk_t_first_to(xrefblk_t *,ea_t to,int flags);
idaman bool ida_export xrefblk_t_next_to(xrefblk_t *);
//@}
/// Structure to enumerate all xrefs.
/// This structure provides a way to access cross-references from a given address.
/// For example:
///
/// \code
/// xrefblk_t xb;
/// for ( bool ok=xb.first_from(ea, XREF_ALL); ok; ok=xb.next_from() )
/// {
/// // xb.to - contains the referenced address
/// }
/// \endcode
/// or:
/// \code
/// xrefblk_t xb;
/// for ( bool ok=xb.first_to(ea, XREF_ALL); ok; ok=xb.next_to() )
/// {
/// // xb.from - contains the referencing address
/// }
/// \endcode
///
/// First, all code references will be returned, then all data references.
/// If you need only code references, stop calling next() as soon as you get a dref.
///
/// If you need only data references, pass #XREF_DATA flag to first().
/// You may not modify the contents of a xrefblk_t structure! It is read only.
struct xrefblk_t
{
ea_t from; ///< the referencing address - filled by first_to(),next_to()
ea_t to; ///< the referenced address - filled by first_from(), next_from()
uchar iscode; ///< 1-is code reference; 0-is data reference
uchar type; ///< type of the last returned reference (::cref_t & ::dref_t)
uchar user; ///< 1-is user defined xref, 0-defined by ida
/// \defgroup XREF_ Xref enumeration flags
/// Passed as 'flags' parameter to functions in ::xrefblk_t
//@{
#define XREF_ALL 0x00 ///< return all references
#define XREF_FAR 0x01 ///< don't return ordinary flow xrefs
#define XREF_DATA 0x02 ///< return data references only
//@}
/// \name Get first/next
/// The following functions first return code references, then data references.
/// If you need only code references, you need to check 'iscode' after each call.
/// If you need only data references, use #XREF_DATA bit.
/// \param flags \ref XREF_
/// \retval 1 ok
/// \retval 0 no more xrefs
//@{
/// Get first xref from the given address (store in #to)
bool first_from(ea_t _from, int flags)
{ return xrefblk_t_first_from(this, _from, flags); }
/// Get next xref from address provided to first_from()
bool next_from(void)
{ return xrefblk_t_next_from(this); }
/// Get xref to given address (store in #from)
bool first_to(ea_t _to, int flags)
{ return xrefblk_t_first_to(this, _to, flags); }
/// Get next xref to address provided to first_to()
bool next_to(void)
{ return xrefblk_t_next_to(this); }
/// Get xref from '_from' that comes after '_to'
bool next_from(ea_t _from, ea_t _to, int flags)
{
if ( first_from(_from, flags) )
{
to = _to;
return next_from();
}
return false;
}
/// Get xref to '_to' that comes after '_from'
bool next_to(ea_t _from, ea_t _to, int flags)
{
if ( first_to(_to, flags) )
{
from = _from;
return next_to();
}
return false;
}
//@}
};
//-------------------------------------------------------------------------
/// Get first data referenced from the specified address.
/// \param from linear address of referencing instruction or data
/// \return linear address of first (lowest) data referenced from the specified address.
/// Return #BADADDR if the specified instruction/data doesn't reference
/// to anything.
idaman ea_t ida_export get_first_dref_from(ea_t from);
/// Get next data referenced from the specified address.
/// \param from linear address of referencing instruction or data
/// \param current linear address of current referenced data.
/// This value is returned by get_first_dref_from() or
/// previous call to get_next_dref_from() functions.
/// \return linear address of next data or #BADADDR.
idaman ea_t ida_export get_next_dref_from(ea_t from, ea_t current);
/// Get address of instruction/data referencing to the specified data.
/// \param to linear address of referencing instruction or data
/// \return #BADADDR if nobody refers to the specified data.
idaman ea_t ida_export get_first_dref_to(ea_t to);
/// Get address of instruction/data referencing to the specified data
/// \param to linear address of referencing instruction or data
/// \param current current linear address.
/// This value is returned by get_first_dref_to() or
/// previous call to get_next_dref_to() functions.
/// \return #BADADDR if nobody refers to the specified data.
idaman ea_t ida_export get_next_dref_to(ea_t to, ea_t current);
/// Get first instruction referenced from the specified instruction.
/// If the specified instruction passes execution to the next instruction
/// then the next instruction is returned. Otherwise the lowest referenced
/// address is returned (remember that xrefs are kept sorted!).
/// \param from linear address of referencing instruction
/// \return first referenced address.
/// If the specified instruction doesn't reference to other instructions
/// then returns #BADADDR.
idaman ea_t ida_export get_first_cref_from(ea_t from);
/// Get next instruction referenced from the specified instruction.
/// \param from linear address of referencing instruction
/// \param current linear address of current referenced instruction
/// This value is returned by get_first_cref_from() or
/// previous call to get_next_cref_from() functions.
/// \return next referenced address or #BADADDR.
idaman ea_t ida_export get_next_cref_from(ea_t from, ea_t current);
/// Get first instruction referencing to the specified instruction.
/// If the specified instruction may be executed immediately after its
/// previous instruction then the previous instruction is returned.
/// Otherwise the lowest referencing address is returned.
/// (remember that xrefs are kept sorted!).
/// \param to linear address of referenced instruction
/// \return linear address of the first referencing instruction or #BADADDR.
idaman ea_t ida_export get_first_cref_to(ea_t to);
/// Get next instruction referencing to the specified instruction.
/// \param to linear address of referenced instruction
/// \param current linear address of current referenced instruction
/// This value is returned by get_first_cref_to() or
/// previous call to get_next_cref_to() functions.
/// \return linear address of the next referencing instruction or #BADADDR.
idaman ea_t ida_export get_next_cref_to(ea_t to, ea_t current);
/// \name Far code references
/// The following functions are similar to get_{first|next}_cref_{from|to}
/// functions. The only difference is that they don't take into account
/// ordinary flow of execution. Only jump and call xrefs are returned.
/// (fcref means "far code reference")
//@{
idaman ea_t ida_export get_first_fcref_from(ea_t from);
idaman ea_t ida_export get_next_fcref_from(ea_t from, ea_t current);
idaman ea_t ida_export get_first_fcref_to(ea_t to);
idaman ea_t ida_export get_next_fcref_to(ea_t to, ea_t current);
//@}
/// Has a location external to the function references?
idaman bool ida_export has_external_refs(func_t *pfn, ea_t ea);
//-------------------------------------------------------------------------
// S W I T C H T A B L E F U N C T I O N S
//-------------------------------------------------------------------------
#ifdef NALT_HPP
/// Create switch table from the switch information.
/// Usually there is no need to call this function directly because the kernel
/// will call it for the result of \ph{is_switch()}.
/// \param insn_ea address of the 'indirect jump' instruction
/// \param si switch information
/// \return success
idaman bool ida_export create_switch_table(
ea_t insn_ea,
const switch_info_t &si);
/// Create code xrefs for the switch table.
/// This function creates xrefs from the indirect jump.
/// Usually there is no need to call this function directly because the kernel
/// will call it for switch tables
/// \param insn_ea address of the 'indirect jump' instruction
/// \param si switch information
idaman void ida_export create_switch_xrefs(
ea_t insn_ea,
const switch_info_t &si);
/// Vector of case values - see calc_switch_cases()
typedef qvector<svalvec_t> casevec_t;
/// Get detailed information about the switch table cases.
/// \param casevec vector of case values...
/// \param targets ...and corresponding target addresses
/// \param insn_ea address of the 'indirect jump' instruction
/// \param si switch information
/// \return success
idaman bool ida_export calc_switch_cases(
casevec_t *casevec,
eavec_t *targets,
ea_t insn_ea,
const switch_info_t &si);
/// Delete information created by the call of create_switch_table().
/// It delete parent address for each switch target.
/// \param insn_ea address of the 'indirect jump' instruction
/// \param si switch information
idaman void ida_export delete_switch_table(
ea_t jump_ea,
const switch_info_t &si);
#endif
//-------------------------------------------------------------------------
// F U N C T I O N S F O R T H E K E R N E L
//-------------------------------------------------------------------------
/// \cond
idaman bool ida_export create_xrefs_from(ea_t ea); // returns false: no item at ea
idaman void ida_export delete_all_xrefs_from(ea_t ea, bool expand);
/// \endcond
#endif // _XREF_HPP