update to ida 7.6, add builds
This commit is contained in:
21420
idasdk76/include/allins.hpp
Normal file
21420
idasdk76/include/allins.hpp
Normal file
File diff suppressed because it is too large
Load Diff
12
idasdk76/include/allow_deprecated.hpp
Normal file
12
idasdk76/include/allow_deprecated.hpp
Normal 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
289
idasdk76/include/auto.hpp
Normal 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
|
||||
350
idasdk76/include/bitrange.hpp
Normal file
350
idasdk76/include/bitrange.hpp
Normal 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
2556
idasdk76/include/bytes.hpp
Normal file
File diff suppressed because it is too large
Load Diff
173
idasdk76/include/compress.hpp
Normal file
173
idasdk76/include/compress.hpp
Normal 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
543
idasdk76/include/config.hpp
Normal 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
2625
idasdk76/include/dbg.hpp
Normal file
File diff suppressed because it is too large
Load Diff
269
idasdk76/include/demangle.hpp
Normal file
269
idasdk76/include/demangle.hpp
Normal 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
|
||||
468
idasdk76/include/dirtree.hpp
Normal file
468
idasdk76/include/dirtree.hpp
Normal 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
621
idasdk76/include/diskio.hpp
Normal 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
106
idasdk76/include/entry.hpp
Normal 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
371
idasdk76/include/enum.hpp
Normal 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
96
idasdk76/include/err.h
Normal 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
67
idasdk76/include/exehdr.h
Normal 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
1192
idasdk76/include/expr.hpp
Normal file
File diff suppressed because it is too large
Load Diff
572
idasdk76/include/fixup.hpp
Normal file
572
idasdk76/include/fixup.hpp
Normal 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
223
idasdk76/include/fpro.h
Normal 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
609
idasdk76/include/frame.hpp
Normal 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
984
idasdk76/include/funcs.hpp
Normal 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
365
idasdk76/include/gdl.hpp
Normal 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
1782
idasdk76/include/graph.hpp
Normal file
File diff suppressed because it is too large
Load Diff
73
idasdk76/include/help.h
Normal file
73
idasdk76/include/help.h
Normal 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
1306
idasdk76/include/ida.hpp
Normal file
File diff suppressed because it is too large
Load Diff
146
idasdk76/include/ida_highlighter.hpp
Normal file
146
idasdk76/include/ida_highlighter.hpp
Normal 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
1966
idasdk76/include/idd.hpp
Normal file
File diff suppressed because it is too large
Load Diff
3157
idasdk76/include/idp.hpp
Normal file
3157
idasdk76/include/idp.hpp
Normal file
File diff suppressed because it is too large
Load Diff
263
idasdk76/include/ieee.h
Normal file
263
idasdk76/include/ieee.h
Normal 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
1232
idasdk76/include/intel.hpp
Normal file
File diff suppressed because it is too large
Load Diff
839
idasdk76/include/jumptable.hpp
Normal file
839
idasdk76/include/jumptable.hpp
Normal 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 ®) 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 ®s; // 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 ®) 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(®s, 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
7761
idasdk76/include/kernwin.hpp
Normal file
File diff suppressed because it is too large
Load Diff
351
idasdk76/include/lex.hpp
Normal file
351
idasdk76/include/lex.hpp
Normal 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
595
idasdk76/include/lines.hpp
Normal 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
293
idasdk76/include/llong.hpp
Normal 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
1042
idasdk76/include/loader.hpp
Normal file
File diff suppressed because it is too large
Load Diff
16
idasdk76/include/md5.h
Normal file
16
idasdk76/include/md5.h
Normal 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
391
idasdk76/include/moves.hpp
Normal 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
1705
idasdk76/include/nalt.hpp
Normal file
File diff suppressed because it is too large
Load Diff
786
idasdk76/include/name.hpp
Normal file
786
idasdk76/include/name.hpp
Normal 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, >ni);
|
||||
}
|
||||
|
||||
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, >ni);
|
||||
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
1123
idasdk76/include/netnode.hpp
Normal file
File diff suppressed because it is too large
Load Diff
486
idasdk76/include/network.hpp
Normal file
486
idasdk76/include/network.hpp
Normal 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
254
idasdk76/include/offset.hpp
Normal 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
|
||||
260
idasdk76/include/parsejson.hpp
Normal file
260
idasdk76/include/parsejson.hpp
Normal 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
4847
idasdk76/include/pro.h
Normal file
File diff suppressed because it is too large
Load Diff
104
idasdk76/include/problems.hpp
Normal file
104
idasdk76/include/problems.hpp
Normal 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
172
idasdk76/include/prodir.h
Normal 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
129
idasdk76/include/pronet.h
Normal 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
290
idasdk76/include/range.hpp
Normal 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
239
idasdk76/include/regex.h
Normal 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(®ex);
|
||||
}
|
||||
public:
|
||||
virtual void idaapi release(void) override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
int exec(const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
|
||||
{
|
||||
return qregexec(®ex, string, nmatch, pmatch, eflags);
|
||||
}
|
||||
int process_errors(int code, qstring *errmsg)
|
||||
{
|
||||
if ( code != 0 && errmsg != NULL )
|
||||
{
|
||||
char errbuf[MAXSTR];
|
||||
qregerror(code, ®ex, 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_ */
|
||||
375
idasdk76/include/registry.hpp
Normal file
375
idasdk76/include/registry.hpp
Normal 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
167
idasdk76/include/search.hpp
Normal 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
1212
idasdk76/include/segment.hpp
Normal file
File diff suppressed because it is too large
Load Diff
179
idasdk76/include/segregs.hpp
Normal file
179
idasdk76/include/segregs.hpp
Normal 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
|
||||
78
idasdk76/include/strlist.hpp
Normal file
78
idasdk76/include/strlist.hpp
Normal 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
661
idasdk76/include/struct.hpp
Normal 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
|
||||
218
idasdk76/include/tryblks.hpp
Normal file
218
idasdk76/include/tryblks.hpp
Normal 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
4396
idasdk76/include/typeinf.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1470
idasdk76/include/ua.hpp
Normal file
1470
idasdk76/include/ua.hpp
Normal file
File diff suppressed because it is too large
Load Diff
46
idasdk76/include/workarounds.hpp
Normal file
46
idasdk76/include/workarounds.hpp
Normal 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
417
idasdk76/include/xref.hpp
Normal 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
|
||||
Reference in New Issue
Block a user