/*
 *      Interactive disassembler (IDA).
 *      Copyright (c) 1990-98 by Ilfak Guilfanov.
 *      ALL RIGHTS RESERVED.
 *                              E-mail: ig@estar.msk.su, ig@datarescue.com
 *                              FIDO:   2:5020/209
 *
 */

#ifndef FUNCS_HPP
#define FUNCS_HPP
#pragma pack(push, 1)           // IDA uses 1 byte alignments!

//
//      This file contains the "function" definitions.
//      I mean by "functions" the functions in the program being disassembled.

//      This file contains routines for working with functions within the
//      disassembled program.
//
//      This file also contains routines for working with library signatures
//      (e.g. FLIRT).
//
//      Each function in the disassembly is represented as an "area" (a range
//      of addresses -see AREA.HPP for details) with characteristics.
//
//      A function must start with an instruction (code) byte .
#include <area.hpp>
struct stkpnt_t;                // #include <frame.hpp>
struct regvar_t;                // #include <frame.hpp>
struct llabel_t;                // #include <frame.hpp>

struct regarg_t                 // register argument description
{                               // is destroyed when the full function
  int reg;                      // type is determined
  type_t *type;
  char *name;
};

//------------------------------------------------------------------------
// A function is range of addresses with characteristics:

class func_t : public area_t
{
public:
  ushort flags;
#define FUNC_NORET      0x00000001L     // function doesn't return
#define FUNC_FAR        0x00000002L     // far function
  int is_far(void) { return (flags & FUNC_FAR) != 0; }
#define FUNC_LIB        0x00000004L     // library function
#define FUNC_STATIC     0x00000008L     // static function
#define FUNC_FRAME      0x00000010L     // function uses frame pointer (BP)
#define FUNC_USERFAR    0x00000020L     // user has specified far-ness
                                        // of the function
#define FUNC_HIDDEN     0x00000040L     // a hidden function
#define FUNC_THUNK      0x00000080L     // thunk (jump) function
#define FUNC_BOTTOMBP   0x00000100L     // BP points to the bottom of the stack frame

// Other bits are not used yet:

#define FUNC_MEMBER     0x00000200L     // member function
#define FUNC_VIRTUAL    0x00000400L     // virtual function
#define FUNC_CTR        0x00000800L     // constructor
#define FUNC_DTR        0x00001000L     // destructor
#define FUNC_VARARG     0x00002000L     // vararg function

//
// 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)            |
//    +----------------------------------------+        <- BP
//    | local variables                        |
//    +----------------------------------------+        <- SP
//
  ulong frame;                          // USED: id of frame structure
  ulong frsize;                         // size of lvar part of frame in bytes
                                        // this value is used as offset for BP
                                        // only if FUNC_FRAME is set
  ushort frregs;                        // size of saved registers in frame
  ulong argsize;                        // number of bytes purged from the stack
                                        // upon returning
  ushort pntqty;                        // number of SP change points
  stkpnt_t *points;                     // array of SP change points

  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: startEA

  int llabelqty;                        // number of local labels
  llabel_t *llabels;                    // local labels
                                        // this array is sorted by ea

  int regargqty;                        // number of register arguments
  regarg_t *regargs;                    // unsorted array of register arguments

// Unused fields:

//  uchar argsplace;
//#define FUNC_ARG_UNDEF  0             // unknown
//#define FUNC_ARG_STACK  1             // arguments are on the stack
//#define FUNC_ARG_TEXT 2               // function arguments follow its call
//#define FUNC_ARG_REG  3               // function arguments are in registers
//  uchar language;
//#define FUNC_LNG_UNDEF        0               // unknown (assume C)
//#define FUNC_LNG_C    1               // C,C++
//#define FUNC_LNG_PASCAL       2               // Pascal
//#define FUNC_LNG_INTR 3               // Interrupt
//  ulong fclass;                               // (not used yet) class of the member-function
//  ushort virt_off;                    // (not used yet) virtual offset (C++)
//  ulong type;                         // (not used yet) function return type
//  ulong args;                         // (not used yet) function argument type

};

idaman areacb_t ida_export_data funcs;  // area control block for functions

//--------------------------------------------------------------------
//      F U N C T I O N S
//--------------------------------------------------------------------
// Get pointer to function structure, in: linear address
//      ea - any address in the function
// Returns ptr to function or NULL

inline func_t *get_func(ea_t ea) { return (func_t *)funcs.get_area(ea); }


// Get pointer to function structure, in: number of function
//      n - number of fucntion, is in range 0..get_func_qty()-1
// Returns ptr to function or NULL

inline func_t *getn_func(int n)   { return (func_t *)funcs.getn_area(n); }


// Get number of functions

inline int     get_func_qty(void)     { return funcs.get_area_qty(); }


// Get number of a function
//      ea - any address in the function
// Returns number of function (0..get_func_qty()-1)

inline int     get_func_num(ea_t ea)  { return funcs.get_area_num(ea); }


// Get pointer to previous function
//      ea - any address in the program
// Returns ptr to function or NULL if previous function doesn't exist

inline func_t *get_prev_func(ea_t ea) { return getn_func(funcs.get_prev_area(ea)); }


// Get pointer to next function
//      ea - any address in the program
// Returns ptr to function or NULL if next function doesn't exist

inline func_t *get_next_func(ea_t ea) { return getn_func(funcs.get_next_area(ea)); }


// Update information about a function in the database (func_t)
//      fn - ptr to function structure with updated information
// You can't change function start and end addresses using this function.
// Use ui_func_setstart() and ui_func_setend() for it.
// returns: 1-ok,0-failure

inline bool update_func(func_t *fn) { return funcs.update(fn) != 0; }

// Get function comment
//      fn        - ptr to function structure
//      repetable - get repetable comment?
// return: comment or NULL

inline char   *get_func_comment(func_t *fn,bool repeatable)
                { return funcs.get_area_comment(fn,repeatable); }


// Set function comment
//      fn        - ptr to function structure
//      repetable - set repetable comment?

inline void    set_func_comment(func_t *fn,const char *cmt,bool repeatable)
                { funcs.set_area_comment(fn,cmt,repeatable); }


// Delete function comment
//      fn        - ptr to function structure
//      repetable - delete repetable comment?

inline void    del_func_comment(func_t *fn,bool repeatable)
                { funcs.del_area_comment(fn,repeatable); }


// Add a new function
//      fn        - ptr to filled function structure
//                  If the function end address is BADADDR, then
//                  IDA will try to determine the function bounds
//                  by calling find_func_bounds(x,y,FIND_FUNC_DEFINE);
// If a function at the specified address range exists, the kernel will try
// to shrink it.
// returns: 1-ok, 0-failure

idaman int ida_export  add_func_ex(func_t *fn);


// Add a new function
//      ea1 - start address
//      ea  - end address
//                  If the function end address is BADADDR, then
//                  IDA will try to determine the function bounds
//                  by calling find_func_bounds(x,y,FIND_FUNC_DEFINE);
// If a function at the specified address range exists, the kernel will try
// to shrink it.
// returns: 1-ok, 0-failure

idaman int ida_export add_func(ea_t ea1,ea_t ea2);


// Delete a function
//      ea - any address in the function
// returns: 1-ok,0-failure

idaman int ida_export del_func(ea_t ea);


// Move function start address
//      ea       - any address in the function
//      newstart - new end address of the function
// returns: MOVE_FUNC_...

idaman int ida_export func_setstart(ea_t ea,ea_t newstart);
#define MOVE_FUNC_OK            0             // ok
#define MOVE_FUNC_NOCODE        1             // no instruction at 'newstart'
#define MOVE_FUNC_BADSTART      2             // bad new start address


// Move function end address
//      ea     - any address in the function
//      newend - new end address of the function
// returns: 1-ok,0-failure

idaman int ida_export func_setend(ea_t ea,ea_t newend);


// Fill with initial data the function structure

idaman void ida_export clear_func_struct(func_t *fn);


// Determine a new function boundaries
//      ea    - starting address of a new function
//      nfn   - structure to fill with information
//      flags - composition of the following bits:
#define FIND_FUNC_NORMAL 0x0000 // stop processing if undefined byte is encountered
#define FIND_FUNC_DEFINE 0x0001 // create instruction if undefined byte is encountered
// This function tries to find start and end addresses of new function
// returns a code, see below
// This function calls the module with ph.func_bounds to allows it to
// fine tune the function boundaries.

idaman int ida_export find_func_bounds(ea_t ea,func_t *nfn,int flags);

#define FIND_FUNC_UNDEF 0       // the function has instructions that
                                // pass execution flow to unexplored bytes
                                // nfn->endEA 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       // a function exists already,
                                // its bounds are returned in 'nfn'


// Get function name
//      ea     - any address in the function
//      buf    - buffer for the answer
//      bufsize- size of the output buffer
// returns: function name or NULL

idaman char *ida_export get_func_name(ea_t ea, char *buf, size_t bufsize);


// Is 32-bit function?

idaman bool ida_export is_32bit_func(func_t *pfn);


// Is the function visible (not hidden)?

inline bool is_visible_func(func_t *pfn) { return (pfn->flags & FUNC_HIDDEN) == 0; }


// 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
//      fn      - pointer to function (may be NULL)
//      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 NULL.
// returns: 1-ok,0-failure

idaman int ida_export set_func_name_if_jumpfunc(func_t *fn,const char *oldname);


// Convert address to "funcname+offset" text form.
//      ea  - linear address
//      buf - output buffer
//      bufsize - size of the output buffer
// returns: NULL if no function is found at 'ea'
//          "funcname+offset" otherwise

idaman char *ida_export a2funcoff(ea_t ea, char *buf, size_t bufsize);   // return funcname+off or NULL


// Generate standard function header lines using MakeLine()
//      pfn - pointer to function structure
//      buf - buffer of MAXSTR characters, scratch area

idaman void ida_export std_gen_func_header(func_t *pfn,char *buf);


// 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 type_t *type, const char *name);
void del_regargs(func_t *pfn);
void del_regargs(ea_t ea);      // low level
int write_regargs(func_t *pfn);
regarg_t *find_regarg(func_t *pfn, int reg);
void free_regarg(regarg_t *v);

//--------------------------------------------------------------------
//      L I B R A R Y   M O D U L E   S I G N A T U R E S
//--------------------------------------------------------------------

// Error codes for signature functions:

#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.
//      fname - file name. should not contain directory part.
// returns: 0-failed, otherwise number of planned (and applied) signatures

idaman int ida_export plan_to_apply_idasgn(const char *fname); // plan to use library


// Start application of signature file
//      advance - 0: apply the current file from the list of planned
//                   signature files
//                1: apply the next file from the list of planned
//                   signature files
// returns: 1-signature file is successfully loaded
//          0-failure, a warning was disaplyed

idaman int ida_export apply_idasgn(int advance);         // switch to current/next library


// Apply a signature file to the specified address
//      signame    - short name of signature file (the file name without path)
//      ea         - address to apply the signature
//      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.
// returns: LIBFUNC_... codes, see below.

idaman int ida_export apply_idasgn_to(const char *signame,ea_t ea,int is_startup);


// Get number of signatures in the list of planned and applied signatures
// Returns: 0..n

idaman int ida_export get_idasgn_qty(void);


// Get number of the the current signature
// Returns: 0..n-1

idaman int ida_export get_current_idasgn(void);


// Get state of a signature in the list of planned signatures
//      n - number of signature in the list (0..get_idasgn_qty()-1)
// Returns: state of signature or IDASGN_BADARG

idaman int ida_export calc_idasgn_state(int n);


// Remove signature from the list of planned signatures
//      n - number of signature in the list (0..get_idasgn_qty()-1)
// returns: IDASGN_OK, IDASGN_BADARG, IDASGN_APPLIED

idaman int ida_export del_idasgn(int n);


// Get information about a signature in the list
//      n       - number of signature in the list (0..get_idasgn_qty()-1)
//      signame - buffer for the name of the signature
//                (short form, only base name without the directory part 
//                 will be stored)
//                if signame == NULL, then the name won't be returned
//      optlibs - buffer for the names of the optional libraries
//                if optlibs == NULL, then the optional libraries are not returned
// Returns: 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 long ida_export get_idasgn_desc(int n,char *signame,char *optlibs);


// Get full path of a signature file
//      signame - short name of a signature
//      buf     - the output buffer
// returns: full path to the signature file
// This function doesn't test the presence of the file

idaman char *ida_export get_sig_filename(char *buf,const char *signame);


// Get idasgn header by a short signature name
//      name - short name of a signature
// Returns NULL-can't find the signature

class idasgn_t;
idaman idasgn_t *ida_export get_idasgn_header_by_short_name(const char *name);


// Get full description of the signature by its short name
//      name - short name of a signature
//      buf     - the output buffer
// Returns NULL-can't find the signature
//         otherwise returns the description of the signature

idaman char *ida_export get_idasgn_title(const char *name,char *buf);

// Determine compiler/vendor based on startup signatures.
// If determined, then appropriate signature files are included into
// the list of planned signature files.

void determine_rtl(void);               // find runtime library


// Apply the currently loaded signature file to the specified address.
// If a library function is found, then create a function and name
// it accordingly.
//      ea - any address in the program
// returns: code, see below.

idaman int ida_export try_to_add_libfunc(ea_t ea); // try to find and create library function

#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

// init/save/term signatures. only the kernel calls these functions

       void init_signatures(void);
inline void save_signatures(void) {}
       void term_signatures(void);


       void init_funcs(void);                                   // Initialize work with functions
inline void save_funcs(void) { funcs.save(); }                  // Flush information about function to the disk
inline void term_funcs(void) { funcs.save(); funcs.terminate(); }// Terminate work with functions

void move_funcs(ea_t from, ea_t to, ulong size);

#pragma pack(pop)
#endif
