/* * Interactive disassembler (IDA). * Copyright (c) 1990-2020 Hex-Rays * ALL RIGHTS RESERVED. * */ #ifndef DBG_HPP #define DBG_HPP #include #include #include // for callui() and ui_notification_t /*! \file dbg.hpp \brief Contains functions to control the debugging of a process. See \ref dbg_funcs for a complete explanation of these functions. These functions are inlined for the kernel. They are not inlined for the user-interfaces. */ //-------------------------------------------------------------------- // D E B U G G E R I N F O R M A T I O N //-------------------------------------------------------------------- /// This structure contains information about the current debugger. /// (NULL if no debugger was loaded) - see idd.hpp for details about this structure. /// /// All functions defined in this structure should only be called by the kernel !!! idaman debugger_t ida_export_data *dbg; //-------------------------------------------------------------------- // D E B U G G E R C A L L B A C K S //-------------------------------------------------------------------- /// Debugger notification codes. /// /// A plugin can receive notifications of all major events in the /// debugger, by calling the hook_to_notification_point() function /// with ::HT_DBG as ::hook_type_t (see loader.hpp for details about /// installing and removing such callbacks). /// /// IDA generates two major different types of debugger notifications: /// /// - debugger event notification: /// this notification monitors usual events occurring during the /// execution of a process. /// These event notifications are always generated for any process. /// Some of these event notifications are interpreted by IDA /// (high-level events), while others are directly generated by the /// debugger module (low-level events). /// Low-level events always return a ::debug_event_t structure as an argument. /// /// - debugger asynchronous function result notification: /// such a notification occurs only when a debugger properly terminated /// the execution of an asynchronous function (see \ref dbg_funcs) /// /// How to control the process execution (after the execution of all notification /// handlers) from the notification handler: /// /// - to force the process to STOP: /// call suspend_process(). /// In this case, the current debugger command will be aborted and no new /// request will be started. /// /// - to force the process to CONTINUE: /// call continue_process(). /// In this case, no new request will be started. /// /// - to start new debugger command(s): /// call as many request_COMMAND() as needed, then call run_requests(). /// In this case, the current debugger command (if any) will be aborted. /// (see \ref dbg_funcs in this file for more details about requests) /// /// - else, the process execution will depend on the current debugger options or /// object settings. Some examples: /// - a new loaded library will stop the process depending on the associated debugger option. /// - a breakpoint will stop the process depending on its properties. /// /// A plugin must not call asynchronous debugger functions from the notification handler! /// Use the REQUEST QUEUE mechanism instead (request_...()). /// /// If the plugin wants to access the process memory from a notification point, /// it should call invalidate_dbgmem_config() and/or invalidate_dbgmem_contents() /// functions. The invalidate_dbgmem_config() is really slow, so do not call it /// unless the process memory config have changed after the last time the process /// was suspended. The invalidate_dbgmem_contents() is fast and flushes the /// memory cache in the ida kernel. Without it, functions like get_byte() would /// return stale values! enum dbg_notification_t { dbg_null = 0, // debugger low-level event notifications (see IDD.HPP for details). dbg_process_start, ///< \param event (const ::debug_event_t *) ///< \note This event notification is also an asynchronous ///< function result notification for start_process() ! dbg_process_exit, ///< \param event (const ::debug_event_t *) ///< \note This event notification is also an asynchronous ///< function result notification for start_process() ! dbg_process_attach, ///< \param event (const ::debug_event_t *) ///< \note This event notification is also an asynchronous ///< function result notification for start_process() ! dbg_process_detach, ///< \param event (const ::debug_event_t *) ///< \note This event notification is also an asynchronous ///< function result notification for start_process() ! dbg_thread_start, ///< \param event (const ::debug_event_t *) dbg_thread_exit, ///< \param event (const ::debug_event_t *) dbg_library_load, ///< \param event (const ::debug_event_t *) dbg_library_unload, ///< \param event (const ::debug_event_t *) dbg_information, ///< \param event (const ::debug_event_t *) dbg_exception, ///< \param event (const ::debug_event_t *) ///< \param[out] warn (int *) filled with: ///< - -1: display an exception warning dialog ///< if the process is suspended. ///< - 0: never display an exception warning dialog. ///< - 1: always display an exception warning dialog. // debugger high-level event notifications dbg_suspend_process, ///< The process is now suspended. ///< \param event (const ::debug_event_t *) ///< \note This event notification is also an asynchronous ///< function result notification for suspend_process() ! dbg_bpt, ///< A user defined breakpoint was reached. ///< \param tid (::thid_t) ///< \param bptea (::ea_t) ///< \param[out] warn (int *) filled with: ///< - -1: display an exception warning dialog ///< if the process is suspended. ///< - 0: never display an exception warning dialog. ///< - 1: always display an exception warning dialog. dbg_trace, ///< A step occurred (one instruction was executed). This event ///< notification is only generated if step tracing is enabled. ///< \param tid (::thid_t) thread ID ///< \param ip (::ea_t) current instruction pointer. ///< usually points after the executed instruction ///< \retval 1 do not log this trace event ///< \retval 0 log it dbg_request_error, ///< An error occurred during the processing of a request. ///< \param failed_command (::ui_notification_t) ///< \param failed_dbg_notification (::dbg_notification_t) // debugger asynchronous function result notifications // Please note some low-level event notifications also act as asynchronous // function result notifications. dbg_step_into, ///< \param event (const ::debug_event_t *) dbg_step_over, ///< \param event (const ::debug_event_t *) dbg_run_to, ///< \param event (const ::debug_event_t *) dbg_step_until_ret, ///< \param event (const ::debug_event_t *) dbg_bpt_changed, ///< Breakpoint has been changed. ///< \param bptev_code (int) \ref BPTEV_ ///< \param bpt (::bpt_t *) dbg_started_loading_bpts, ///< Started loading breakpoint info from idb dbg_finished_loading_bpts, ///< Finished loading breakpoint info from idb dbg_last, ///< The last debugger notification code }; /// \defgroup BPTEV_ Breakpoint modification events /// Passed as 'bptev_code' parameter to ::dbg_bpt_changed callback //@{ #define BPTEV_ADDED 0 ///< Breakpoint has been added #define BPTEV_REMOVED 1 ///< Breakpoint has been removed #define BPTEV_CHANGED 2 ///< Breakpoint has been modified //@} #ifndef __UI__ //-------------------------------------------------------------------- // D E B U G G E R F U N C T I O N S //-------------------------------------------------------------------- /// \defgroup dbg_funcs Debugger functions /// /// Control the debugging of a process. /// /// Debugger functions complete either SYNCHRONOUSLY or ASYNCHRONOUSLY: /// /// - SYNCHRONOUS FUNCTIONS execute the entire action before the function returns. /// /// - ASYNCHRONOUS FUNCTIONS return before the action has executed in its /// entirety. They simply start the action, but the result of the action will /// only be available later. For example, run_to() can execute a lot of /// instructions before terminating. /// Such functions provide a notification code to indicate the end of their /// execution (see the 'Notification' keyword in the function documentation). /// Install a callback using hook_to_notification_point() to be notified /// when the action is terminated. /// /// DEBUGGER COMMANDS are functions who influence the execution of the debugged /// process. They are available in 2 forms: /// /// - COMMAND(): (e.g. suspend_process()) /// In this mode, the command will be directly executed. However, it is forbidden /// to use asynchronous commands in this mode from a debugger notification handler /// (see ::dbg_notification_t). /// /// - request_COMMAND(): (e.g. request_suspend_process()) /// In this mode, a REQUEST to run the command will be memorized at the end of /// the REQUEST QUEUE (see below). This is mandatory to use this mode for asynchronous /// commands from a debugger notification handler (see ::dbg_notification_t). /// /// /// The REQUEST QUEUE contains a list of planned debugger commands. /// These commands will be started only in the following cases: /// /// - the previous command terminated, and no call to suspend_process() /// or continue_process() occurred in the asynchronous function result /// notification handler (if any). /// /// - run_requests() was called. /// Please note that when called from a debugger notification handler the /// queued requests will only be started after the execution of all /// notification handlers. /// /// A request which fails to start (by returning 0) will generate a /// ::dbg_request_error notification. //@{ /// Execute requests until all requests are processed or an asynchronous /// function is called. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return false if not all requests could be processed /// (indicates an asynchronous function was started) /// \note If called from a notification handler, the execution of requests will /// be postponed to the end of the execution of all notification handlers. inline bool idaapi run_requests(void) { return callui(ui_dbg_run_requests).cnd; } /// Get the current running request. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return ui_null if no running request inline ui_notification_t idaapi get_running_request(void) { return (ui_notification_t)callui(ui_dbg_get_running_request).i; } /// Is a request currently running? inline bool is_request_running(void) { return get_running_request() != ui_null; } /// Get the notification associated (if any) with the current running request. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return dbg_null if no running request inline dbg_notification_t idaapi get_running_notification(void) { return (dbg_notification_t)callui(ui_dbg_get_running_notification).i; } /// Clear the queue of waiting requests. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \note If a request is currently running, this one isn't stopped. inline void idaapi clear_requests_queue(void) { callui(ui_dbg_clear_requests_queue); } //@} dbg_funcs //-------------------------------------------------------------------- // P R O C E S S C O M M A N D S //-------------------------------------------------------------------- /// \defgroup dbg_funcs_cmds Process commands /// \ingroup dbg_funcs /// /// Use these functions to manipulate the debugged process. //@{ /// Return the state of the currently debugged process. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return one of \ref DSTATE_ inline int idaapi get_process_state(void) { return callui(ui_dbg_get_process_state).i; } #endif // __UI__ /// \defgroup DSTATE_ Debugged process states /// See get_process_state(), set_process_state(), invalidate_dbg_state() //@{ #define DSTATE_SUSP -1 ///< process is suspended and will not continue #define DSTATE_NOTASK 0 ///< no process is currently debugged #define DSTATE_RUN 1 ///< process is running //@} /// \defgroup DBGINV_ Debugged process invalidation options /// See set_process_state() and invalidate_dbg_state() //@{ #define DBGINV_MEMORY 0x0001 ///< invalidate cached memory contents #define DBGINV_MEMCFG 0x0002 ///< invalidate cached process segmentation #define DBGINV_REGS 0x0004 ///< invalidate cached register values #define DBGINV_ALL 0x7FFF ///< invalidate everything #define DBGINV_REDRAW 0x8000 ///< refresh the screen #define DBGINV_NONE 0 ///< invalidate nothing //@} #ifndef __UI__ /// Set new state for the debugged process. /// Notifies the IDA kernel about the change of the debugged process state. /// For example, a debugger module could call this function when it knows /// that the process is suspended for a short period of time. /// Some IDA API calls can be made only when the process is suspended. /// The process state is usually restored before returning control to the caller. /// You must know that it is ok to change the process state, doing it at arbitrary /// moments may crash the application or IDA. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param newstate new process state (one of \ref DSTATE_) /// if #DSTATE_NOTASK is passed then the state is not changed /// \param p_thid ptr to new thread id. may be NULL or pointer to #NO_THREAD. /// the pointed variable will contain the old thread id upon return /// \param dbginv \ref DBGINV_ /// \return old debugger state (one of \ref DSTATE_) inline int idaapi set_process_state(int newstate, thid_t *p_thid, int dbginv) { return callui(ui_dbg_set_process_state, newstate, p_thid, dbginv).i; } /// Invalidate cached debugger information. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param dbginv \ref DBGINV_ /// \return current debugger state (one of \ref DSTATE_) inline int idaapi invalidate_dbg_state(int dbginv) { return set_process_state(DSTATE_NOTASK, NULL, dbginv); } /// Start a process in the debugger. /// \sq{Type, Asynchronous function - available as Request, /// Notification, ::dbg_process_start} /// \note You can also use the run_to() function to easily start the execution /// of a process until a given address is reached. /// \note For all parameters, a NULL value indicates the debugger will take /// the value from the defined Process Options. /// \param path path to the executable to start /// \param args arguments to pass to process /// \param sdir starting directory for the process /// \retval -1 impossible to create the process /// \retval 0 the starting of the process was cancelled by the user /// \retval 1 the process was properly started inline int idaapi start_process( const char *path = NULL, const char *args = NULL, const char *sdir = NULL) { return callui(ui_dbg_start_process, path, args, sdir).i; } /// Post a start_process() request inline int idaapi request_start_process( const char *path = NULL, const char *args = NULL, const char *sdir = NULL) { return callui(ui_dbg_request_start_process, path, args, sdir).i; } /// Suspend the process in the debugger. /// \sq{ /// Type, /// - Synchronous function (if in a notification handler) /// - Asynchronous function (everywhere else) /// - available as Request, /// Notification, /// - none (if in a notification handler) /// - ::dbg_suspend_process (everywhere else) /// } /// \note The suspend_process() function can be called from a notification /// handler to force the stopping of the process. /// In this case, no notification will be generated. /// When you suspend a process, the running command is always aborted. inline bool idaapi suspend_process(void) { return callui(ui_dbg_suspend_process).cnd; } /// Post a suspend_process() request inline bool idaapi request_suspend_process(void) { return callui(ui_dbg_request_suspend_process).cnd; } /// Continue the execution of the process in the debugger. /// \sq{Type, Synchronous function - available as Request, /// Notification, none (synchronous function)} /// \note The continue_process() function can be called from a notification /// handler to force the continuation of the process. In this case /// the request queue will not be examined, IDA will simply resume /// execution. Usually it makes sense to call request_continue_process() /// followed by run_requests(), so that IDA will first start a queued /// request (if any) and then resume the application. inline bool idaapi continue_process(void) { return callui(ui_dbg_continue_process).cnd; } /// Post a continue_process() request. /// \note This requires an explicit call to run_requests() inline bool idaapi request_continue_process(void) { return callui(ui_dbg_request_continue_process).cnd; } /// Terminate the debugging of the current process. /// \sq{Type, Asynchronous function - available as Request, /// Notification, ::dbg_process_exit} inline bool idaapi exit_process(void) { return callui(ui_dbg_exit_process).cnd; } /// Post an exit_process() request. inline bool idaapi request_exit_process(void) { return callui(ui_dbg_request_exit_process).cnd; } /// Take a snapshot of running processes and return their description. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param[out] array with information about each running process /// \return number of processes or -1 on error inline ssize_t idaapi get_processes(procinfo_vec_t *proclist) { return callui(ui_dbg_get_processes, proclist).ssize; } /// Attach the debugger to a running process. /// \sq{Type, Asynchronous function - available as Request, /// Notification, ::dbg_process_attach} /// \note This function shouldn't be called as a request if #NO_PROCESS is used. /// \param pid PID of the process to attach to. If #NO_PROCESS, a dialog box /// will interactively ask the user for the process to attach to. /// \retval -4 debugger was not inited /// \retval -3 the attaching is not supported /// \retval -2 impossible to find a compatible process /// \retval -1 impossible to attach to the given process (process died, privilege /// needed, not supported by the debugger plugin, ...) /// \retval 0 the user cancelled the attaching to the process /// \retval 1 the debugger properly attached to the process inline int idaapi attach_process(pid_t pid=NO_PROCESS, int event_id=-1) { return callui(ui_dbg_attach_process, pid, event_id).i; } /// Post an attach_process() request inline int idaapi request_attach_process(pid_t pid, int event_id) { return callui(ui_dbg_request_attach_process, pid, event_id).i; } /// Detach the debugger from the debugged process. /// \sq{Type, Asynchronous function - available as Request, /// Notification, ::dbg_process_detach} inline bool idaapi detach_process(void) { return callui(ui_dbg_detach_process).cnd; } /// Post a detach_process() request inline bool idaapi request_detach_process(void) { return callui(ui_dbg_request_detach_process).cnd; } /// Is the debugger busy?. /// Some debuggers do not accept any commands while the debugged application /// is running. For such a debugger, it is unsafe to do anything with the /// database (even simple queries like get_byte may lead to undesired consequences). /// Returns: true if the debugged application is running under such a debugger inline bool idaapi is_debugger_busy(void) { return callui(ui_dbg_is_busy).cnd; } //@} dbg_funcs_cmds //-------------------------------------------------------------------- // T H R E A D S //-------------------------------------------------------------------- /// \defgroup dbg_funcs_threads Threads /// \ingroup dbg_funcs /// /// Inspect/Manipulate threads of debugged process. //@{ /// Get number of threads. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline int idaapi get_thread_qty(void) { return callui(ui_dbg_get_thread_qty).i; } /// Get the ID of a thread. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of thread, is in range 0..get_thread_qty()-1 /// \return #NO_THREAD if the thread doesn't exist. inline thid_t idaapi getn_thread(int n) { return (thid_t)callui(ui_dbg_getn_thread, n).i; } /// Get current thread ID. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline thid_t idaapi get_current_thread(void) { return callui(ui_dbg_get_current_thread).i; } /// Get the NAME of a thread /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of thread, is in range 0..get_thread_qty()-1 /// or -1 for the current thread /// \return thread name or NULL if the thread doesn't exist. inline const char *idaapi getn_thread_name(int n) { return callui(ui_dbg_getn_thread_name, n).cptr; } /// Select the given thread as the current debugged thread. /// All thread related execution functions will work on this thread. /// The process must be suspended to select a new thread. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \param tid ID of the thread to select /// \return false if the thread doesn't exist. inline bool idaapi select_thread(thid_t tid) { return callui(ui_dbg_select_thread, tid).cnd; } /// Post a select_thread() request inline bool idaapi request_select_thread(thid_t tid) { return callui(ui_dbg_request_select_thread, tid).cnd; } /// Suspend thread. /// Suspending a thread may deadlock the whole application if the suspended /// was owning some synchronization objects. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \param tid thread id /// \retval -1 network error /// \retval 0 failed /// \retval 1 ok inline int idaapi suspend_thread(thid_t tid) { return callui(ui_dbg_suspend_thread, tid).i; } /// Post a suspend_thread() request inline int idaapi request_suspend_thread(thid_t tid) { return callui(ui_dbg_request_suspend_thread, tid).i; } /// Resume thread. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \param tid thread id /// \retval -1 network error /// \retval 0 failed /// \retval 1 ok inline int idaapi resume_thread(thid_t tid) { return callui(ui_dbg_resume_thread, tid).i; } /// Post a resume_thread() request inline int idaapi request_resume_thread(thid_t tid) { return callui(ui_dbg_request_resume_thread, tid).i; } //@} dbg_funcs_threads //-------------------------------------------------------------------- // M O D U L E S //-------------------------------------------------------------------- /// \defgroup dbg_funcs_modules Modules /// \ingroup dbg_funcs /// /// Functions to enumerate modules loaded into the process. /// /// \param modinfo structure to receive the answer /// \return false if there are no (more) modules /// /// Typical loop to enumerate modules would look like: /// \code /// modinfo_t minfo; /// for ( bool ok=get_first_module(&minfo); ok; ok=get_next_module(&minfo) ) /// ... /// \endcode //@{ inline bool idaapi get_first_module(modinfo_t *modinfo) ///< See \ref dbg_funcs_modules { return callui(ui_dbg_get_first_module, modinfo).cnd; } inline bool idaapi get_next_module(modinfo_t *modinfo) ///< See \ref dbg_funcs_modules { return callui(ui_dbg_get_next_module, modinfo).cnd; } //@} //-------------------------------------------------------------------- // E X E C U T I O N F L O W C O N T R O L C O M M A N D S //-------------------------------------------------------------------- /// \defgroup dbg_funcs_flow Execution flow control /// \ingroup dbg_funcs /// /// Use these functions to run instructions in the debugged process. //@{ /// Execute one instruction in the current thread. /// Other threads are kept suspended. /// \sq{Type, Asynchronous function - available as Request, /// Notification, ::dbg_step_into} inline bool idaapi step_into(void) { return callui(ui_dbg_step_into).cnd; } /// Post a step_into() request inline bool idaapi request_step_into(void) { return callui(ui_dbg_request_step_into).cnd; } /// Execute one instruction in the current thread, /// but without entering into functions. /// Others threads keep suspended. /// \sq{Type, Asynchronous function - available as Request, /// Notification, ::dbg_step_over} inline bool idaapi step_over(void) { return callui(ui_dbg_step_over).cnd; } /// Post a step_over() request inline bool idaapi request_step_over(void) { return callui(ui_dbg_request_step_over).cnd; } /// Execute the process until the given address is reached. /// If no process is active, a new process is started. /// Technically, the debugger sets up a temporary breakpoint at /// the given address, and continues (or starts) the execution of /// the whole process. /// So, all threads continue their execution! /// \sq{Type, Asynchronous function - available as Request, /// Notification, ::dbg_run_to} /// \param ea target address /// \param pid not used yet. please do not specify this parameter. /// \param tid not used yet. please do not specify this parameter. inline bool idaapi run_to(ea_t ea, pid_t pid = NO_PROCESS, thid_t tid = NO_THREAD) { return callui(ui_dbg_run_to, ea, pid, tid).cnd; } /// Post a run_to() request inline bool idaapi request_run_to(ea_t ea, pid_t pid = NO_PROCESS, thid_t tid = NO_THREAD) { return callui(ui_dbg_request_run_to, ea, pid, tid).cnd; } /// Execute instructions in the current thread until /// a function return instruction is executed (aka "step out"). /// Other threads are kept suspended. /// \sq{Type, Asynchronous function - available as Request, /// Notification, ::dbg_step_until_ret} inline bool idaapi step_until_ret(void) { return callui(ui_dbg_step_until_ret).cnd; } /// Post a step_until_ret() request inline bool idaapi request_step_until_ret(void) { return callui(ui_dbg_request_step_until_ret).cnd; } /// How to resume the application. /// Set resume mode but do not resume process. inline bool idaapi set_resume_mode(thid_t tid, resume_mode_t mode) { return callui(ui_dbg_set_resume_mode, tid, mode).cnd; } /// Post a set_resume_mode() request inline bool idaapi request_set_resume_mode(thid_t tid, resume_mode_t mode) { return callui(ui_dbg_request_set_resume_mode, tid, mode).cnd; } //@} dbg_funcs_flow //-------------------------------------------------------------------- // R E G I S T E R S //-------------------------------------------------------------------- /// \defgroup dbg_funcs_regs Registers /// \ingroup dbg_funcs /// /// Inspect/Manipulate registers for debugged process. /// The debugger structure defines a set of hardware registers in \dbg{registers} /// IDA also recognizes register names for each defined bit in bit registers. /// You can use all these names to set or get a register value. /// /// For example, with the x86 Userland Win32 debugger you can use /// register names like: /// - "EAX", ... "EBP", "ESP", "EFL": for classical integer registers /// - "CS", "DS", ... : for segment registers /// - "ST0", "ST1", ... : for FPU registers /// - "CF", "PF", "AF", "ZF", ... : for special bit values //@{ /// Get register information /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline bool idaapi get_dbg_reg_info(const char *regname, register_info_t *ri) { return callui(ui_dbg_get_reg_info, regname, ri).cnd; } /// Read a register value from the current thread. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline bool idaapi get_reg_val(const char *regname, regval_t *regval) { return callui(ui_dbg_get_reg_val, regname, regval).cnd; } /// Get register value as an unsigned 64-bit int inline bool idaapi get_reg_val(const char *regname, uint64 *ival) { return callui(ui_dbg_get_reg_val_i, regname, ival).cnd; } /// Get value of the SP register for the current thread. /// Requires a suspended debugger. inline bool idaapi get_sp_val(ea_t *out) { return callui(ui_dbg_get_sp_val, out).cnd; } /// Get value of the IP (program counter) register for the current thread. /// Requires a suspended debugger. inline bool idaapi get_ip_val(ea_t *out) { return callui(ui_dbg_get_ip_val, out).cnd; } /// Write a register value to the current thread. /// \sq{Type, Synchronous function - available as Request, /// Notification, none (synchronous function)} inline bool idaapi set_reg_val(const char *regname, const regval_t *regval) { return callui(ui_dbg_set_reg_val, regname, regval).cnd; } /// Write a register value to the current thread inline bool idaapi set_reg_val(const char *regname, uint64 ival) { return callui(ui_dbg_set_reg_val_i, regname, ival).cnd; } /// Post a set_reg_val() request inline bool idaapi request_set_reg_val(const char *regname, const regval_t *regval) { return callui(ui_dbg_request_set_reg_val, regname, regval).cnd; } /// Does a register contain an integer value? /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline bool idaapi is_reg_integer(const char *regname) { return callui(ui_dbg_get_reg_value_type, regname).i-2 == RVT_INT; } /// Does a register contain a floating point value? /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline bool idaapi is_reg_float(const char *regname) { return callui(ui_dbg_get_reg_value_type, regname).i-2 == RVT_FLOAT; } /// Does a register contain a value of a custom data type? /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline bool idaapi is_reg_custom(const char *regname) { return callui(ui_dbg_get_reg_value_type, regname).i >= 2; } //@} dbg_funcs_regs #endif // __UI__ //-------------------------------------------------------------------- // B R E A K P O I N T S //-------------------------------------------------------------------- /// \defgroup dbg_funcs_bpts Breakpoints /// \ingroup dbg_funcs /// /// Work with debugger breakpoints. //@{ /// Helper function for ::bpt_location_t int idaapi set_bptloc_string(const char *s); const char *idaapi get_bptloc_string(int i); ///< \copydoc set_bptloc_string() /// Breakpoint location types enum bpt_loctype_t { BPLT_ABS, ///< absolute address: ea BPLT_REL, ///< relative address: module_path, offset BPLT_SYM, ///< symbolic: symbol_name, offset BPLT_SRC, ///< source level: filename, lineno }; /// Describes a breakpoint location struct bpt_location_t { //private: ea_t info; int index; bpt_loctype_t loctype; //public: bpt_loctype_t type(void) const { return loctype; } ///< Get bpt type bool is_empty_path(void) const { return index == 0; } ///< No path/filename specified? (::BPLT_REL, ::BPLT_SRC) const char *path(void) const { return get_bptloc_string(index); } ///< Get path/filename (::BPLT_REL, ::BPLT_SRC) const char *symbol(void) const { return get_bptloc_string(index); } ///< Get symbol name (::BPLT_SYM) int lineno(void) const { return int(info); } ///< Get line number (::BPLT_SRC) uval_t offset(void) const { return (uval_t)info; } ///< Get offset (::BPLT_REL, ::BPLT_SYM) ea_t ea(void) const { return info; } ///< Get address (::BPLT_ABS) bpt_location_t(void) : info(BADADDR), index(0), loctype(BPLT_ABS) {} ///< Constructor (default type is ::BPLT_ABS) /// Specify an absolute address location void set_abs_bpt(ea_t a) { info = a; loctype = BPLT_ABS; } /// Specify a source level location void set_src_bpt(const char *fn, int _lineno) { index = set_bptloc_string(fn); info = _lineno; loctype = BPLT_SRC; } /// Specify a symbolic location void set_sym_bpt(const char *_symbol, uval_t _offset=0) { index = set_bptloc_string(_symbol); info = _offset; loctype = BPLT_SYM; } /// Specify a relative address location void set_rel_bpt(const char *mod, uval_t _offset) { index = set_bptloc_string(mod); info = _offset; loctype = BPLT_REL; } /// Lexically compare two breakpoint locations. /// Bpt locations are first compared based on type (i.e. ::BPLT_ABS < ::BPLT_REL). /// ::BPLT_ABS locations are compared based on their ea values. /// For all other location types, locations are first compared based on their /// string (path/filename/symbol), then their offset/lineno. int compare(const bpt_location_t &r) const { return callui(ui_dbg_compare_bpt_locs, this, &r).i; } bool operator==(const bpt_location_t &r) const { return compare(r) == 0; } bool operator!=(const bpt_location_t &r) const { return compare(r) != 0; } bool operator< (const bpt_location_t &r) const { return compare(r) < 0; } bool operator> (const bpt_location_t &r) const { return compare(r) > 0; } bool operator<=(const bpt_location_t &r) const { return compare(r) <= 0; } bool operator>=(const bpt_location_t &r) const { return compare(r) >= 0; } /// Internal function size_t print(qstring *buf) const; }; /// Characteristics of a breakpoint struct bpt_t { size_t cb; ///< size of this structure qstring cndbody; ///< Condition as entered by the user bpt_location_t loc; ///< Location pid_t pid; ///< breakpoint process id thid_t tid; ///< breakpoint thread id ea_t ea; ///< Address, if known. For #BPLT_SRC, index into an internal data struct bpttype_t type; ///< Breakpoint type int pass_count; ///< Number of times the breakpoint is hit before stopping ///< (default is 0: stop always) uint32 flags; ///< \ref BPT_T /// \defgroup BPT_T Breakpoint property bits /// Used by bpt_t::flags //@{ #define BPT_BRK 0x001 ///< suspend execution upon hit #define BPT_TRACE 0x002 ///< add trace information upon hit #define BPT_UPDMEM 0x004 ///< refresh the memory layout and contents before evaluating bpt condition #define BPT_ENABLED 0x008 ///< enabled? #define BPT_LOWCND 0x010 ///< condition is calculated at low level (on the server side) #define BPT_TRACEON 0x020 ///< enable tracing when the breakpoint is reached #define BPT_TRACE_INSN 0x040 ///< instruction tracing #define BPT_TRACE_FUNC 0x080 ///< function tracing #define BPT_TRACE_BBLK 0x100 ///< basic block tracing #define BPT_TRACE_TYPES (BPT_TRACE_INSN|BPT_TRACE_FUNC|BPT_TRACE_BBLK) ///< trace insns, functions, and basic blocks. ///< if any of #BPT_TRACE_TYPES bits are set but #BPT_TRACEON is clear, ///< then turn off tracing for the specified trace types #define BPT_ELANG_MASK 0xF0000000u #define BPT_ELANG_SHIFT 28 ///< index of the extlang (scripting language) of the condition //@} uint32 props; ///< \ref BKPT_ /// \defgroup BKPT_ Internal breakpoint properties /// Used by bpt_t::props //@{ #define BKPT_BADBPT 0x01 ///< failed to write the bpt to the process memory (at least one location) #define BKPT_LISTBPT 0x02 ///< include in bpt list (user-defined bpt) #define BKPT_TRACE 0x04 ///< trace bpt; should not be deleted when the process gets suspended #define BKPT_ACTIVE 0x08 ///< active? #define BKPT_PARTIAL 0x10 ///< partially active? (some locations were not written yet) #define BKPT_CNDREADY 0x20 ///< condition has been compiled #define BKPT_FAKEPEND 0x40 ///< fake pending bpt: it is inactive but another ///< bpt of the same type is active at the same address(es) #define BKPT_PAGE 0x80 ///< written to the process as a page bpt. is available ///< only after writing the bpt to the process. //@} int size; ///< Size of the breakpoint (0 for software breakpoints) int cndidx; ///< Internal number of the condition (<0-none) bpt_t(void) : cb(sizeof(*this)), pid(NO_PROCESS), tid(NO_THREAD), ea(BADADDR), type(BPT_SOFT), pass_count(0), flags(BPT_BRK|BPT_ENABLED), props(0), size(0), cndidx(-1) {} bool is_hwbpt(void) const { return type != BPT_SOFT; } ///< Is hardware breakpoint? bool enabled(void) const { return (flags & BPT_ENABLED) != 0; } ///< Is breakpoint enabled? bool is_low_level(void) const { return (flags & BPT_LOWCND) != 0; } ///< Is bpt condition calculated at low level? bool badbpt(void) const { return (props & BKPT_BADBPT) != 0; } ///< Failed to write bpt to process memory? bool listbpt(void) const { return (props & BKPT_LISTBPT) != 0; } ///< Include in the bpt list? bool is_compiled(void) const { return (props & BKPT_CNDREADY) != 0; } ///< Condition has been compiled? /// Written completely to process? bool is_active(void) const { return (props & (BKPT_PARTIAL|BKPT_ACTIVE)) == BKPT_ACTIVE; } /// Written partially to process? bool is_partially_active(void) const { return (props & BKPT_PARTIAL) != 0; } /// Not written to process at all? bool is_inactive(void) const { return (props & (BKPT_PARTIAL|BKPT_ACTIVE)) == 0; } /// Page breakpoint? bool is_page_bpt(void) const { return (props & BKPT_PAGE) != 0; } /// Get bpt size int get_size(void) const { return is_hwbpt() ? size : 1; } /// Set bpt location to an absolute address void set_abs_bpt(ea_t a) { loc.set_abs_bpt(a); ea = a; } /// Set bpt location to a source line void set_src_bpt(const char *fn, int lineno) { loc.set_src_bpt(fn, lineno); ea = BADADDR; } /// Set bpt location to a symbol void set_sym_bpt(const char *sym, uval_t o) { loc.set_sym_bpt(sym, o); ea = BADADDR; } /// Set bpt location to a relative address void set_rel_bpt(const char *mod, uval_t o) { loc.set_rel_bpt(mod, o); ea = BADADDR; } bool is_absbpt(void) const { return loc.type() == BPLT_ABS; } ///< Is absolute address breakpoint? bool is_relbpt(void) const { return loc.type() == BPLT_REL; } ///< Is relative address breakpoint? bool is_symbpt(void) const { return loc.type() == BPLT_SYM; } ///< Is symbolic breakpoint? bool is_srcbpt(void) const { return loc.type() == BPLT_SRC; } ///< Is source level breakpoint? /// Does breakpoint trace anything? bool is_tracemodebpt(void) const { return (flags & BPT_TRACE_TYPES) != 0; } /// Is this a tracing breakpoint, and is tracing enabled? bool is_traceonbpt(void) const { return is_tracemodebpt() && (flags & BPT_TRACEON) != 0; } /// Is this a tracing breakpoint, and is tracing disabled? bool is_traceoffbpt(void) const { return is_tracemodebpt() && (flags & BPT_TRACEON) == 0; } /// Configure tracing options bool set_trace_action(bool enable, int trace_types) { trace_types &= BPT_TRACE_TYPES; if ( trace_types == 0 ) return false; flags |= trace_types; setflag(flags, BPT_TRACEON, enable); return true; } /// Get the scripting language name for the condition string const char *get_cnd_elang() const; /// Set the scripting language name for the condition string /// \return false if too many languages were used bool set_cnd_elang(const char *name); size_t get_cnd_elang_idx() const { return flags >> BPT_ELANG_SHIFT; } void set_cond(const char *cnd); ///< Internal function bool eval_cond(ea_t ea, bool *fire, const char *bpt_type); ///< Internal function }; typedef qvector bpt_vec_t; ///< vector of breakpoints enum movbpt_code_t { MOVBPT_OK, // moved ok MOVBPT_NOT_FOUND, // source bpt not found MOVBPT_DEST_BUSY, // destination location is busy (we already have such a bpt) MOVBPT_BAD_TYPE, // BPLT_ABS is not supported }; typedef qvector movbpt_codes_t; struct movbpt_info_t { bpt_location_t from; bpt_location_t to; }; DECLARE_TYPE_AS_MOVABLE(movbpt_info_t); typedef qvector movbpt_infos_t; #ifndef __UI__ /// Get number of breakpoints. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline int idaapi get_bpt_qty(void) { return callui(ui_dbg_get_bpt_qty).i; } /// Get the characteristics of a breakpoint. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of breakpoint, is in range 0..get_bpt_qty()-1 /// \param[out] bpt filled with the characteristics. /// \return false if no breakpoint exists inline bool idaapi getn_bpt(int n, bpt_t *bpt) { return callui(ui_dbg_getn_bpt, n, bpt).cnd; } /// Get the characteristics of a breakpoint. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param ea any address in the breakpoint range /// \param[out] bpt if not NULL, is filled with the characteristics. /// \return false if no breakpoint exists inline bool idaapi get_bpt(ea_t ea, bpt_t *bpt) { return callui(ui_dbg_get_bpt, ea, bpt).cnd; } /// Does a breakpoint exist at the given location? inline bool exist_bpt(ea_t ea) { return get_bpt(ea, NULL); } /// Add a new breakpoint in the debugged process. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \note Only one breakpoint can exist at a given address. /// \param ea any address in the process memory space. /// Depending on the architecture, hardware breakpoints /// always be setup at random address. For example, on x86, /// hardware breakpoints should be aligned depending on their size. /// Moreover, on the x86 architecture, it is impossible to setup /// more than 4 hardware breakpoints. /// \param size size of the breakpoint (irrelevant for software breakpoints): /// As for the address, hardware breakpoints can't always be setup /// with random size. /// \param type type of the breakpoint (#BPT_SOFT for software breakpoint) /// special case #BPT_DEFAULT (#BPT_SOFT|#BPT_EXEC): /// try to add instruction breakpoint of the appropriate type /// as follows: software bpt if supported, hwbpt otherwise inline bool idaapi add_bpt(ea_t ea, asize_t size = 0, bpttype_t type = BPT_DEFAULT) { return callui(ui_dbg_add_oldbpt, ea, size, type).cnd; } /// Post an add_bpt(ea_t, asize_t, bpttype_t) request inline bool idaapi request_add_bpt(ea_t ea, asize_t size = 0, bpttype_t type = BPT_DEFAULT) { return callui(ui_dbg_request_add_oldbpt, ea, size, type).cnd; } /// Add a new breakpoint in the debugged process. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \param bpt Breakpoint to add. It describes the break condition, /// type, flags, location (module relative, source breakpoint /// or absolute) and other attributes. inline bool idaapi add_bpt(const bpt_t &bpt) { return callui(ui_dbg_add_bpt, &bpt).cnd; } /// Post an add_bpt(const bpt_t &) request inline bool idaapi request_add_bpt(const bpt_t &bpt) { return callui(ui_dbg_request_add_bpt, &bpt).cnd; } /// Delete an existing breakpoint in the debugged process. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \param ea any address in the breakpoint range inline bool idaapi del_bpt(ea_t ea) { return callui(ui_dbg_del_oldbpt, ea).cnd; } /// Post a del_bpt(ea_t) request inline bool idaapi request_del_bpt(ea_t ea) { return callui(ui_dbg_request_del_oldbpt, ea).cnd; } /// Delete an existing breakpoint in the debugged process. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \param bptloc Breakpoint location inline bool idaapi del_bpt(const bpt_location_t &bptloc) { return callui(ui_dbg_del_bpt, &bptloc).cnd; } /// Post a del_bpt(const bpt_location_t &) request inline bool idaapi request_del_bpt(const bpt_location_t &bptloc) { return callui(ui_dbg_request_del_bpt, &bptloc).cnd; } /// Update modifiable characteristics of an existing breakpoint. /// To update the breakpoint location, use change_bptlocs() /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \note Only the following fields can be modified: /// - bpt_t::cndbody /// - bpt_t::pass_count /// - bpt_t::flags /// - bpt_t::size /// - bpt_t::type /// \note Changing some properties will require removing and then re-adding /// the breakpoint to the process memory (or the debugger backend), which /// can lead to race conditions (i.e., breakpoint(s) can be missed) in /// case the process is not suspended. /// Here are a list of scenarios that will require the breakpoint /// to be removed & then re-added: /// - bpt_t::size is modified /// - bpt_t::type is modified /// - bpt_t::flags's BPT_ENABLED is modified /// - bpt_t::flags's BPT_LOWCND is changed /// - bpt_t::flags's BPT_LOWCND remains set, but cndbody changed inline bool idaapi update_bpt(const bpt_t *bpt) { return callui(ui_dbg_update_bpt, bpt).cnd; } /// Find a breakpoint by location. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \param bptloc Breakpoint location /// \param bpt bpt is filled if the breakpoint was found inline bool idaapi find_bpt(const bpt_location_t &bptloc, bpt_t *bpt) { return callui(ui_dbg_find_bpt, &bptloc, bpt).cnd; } /// Move breakpoint(s) from one location to another /// \param movinfo what bpts to move and where to /// \param codes vector of return codes, if detailed error info is required /// \param del_hindering_bpts should delete hindering breakpoints? /// \return number of moved bpts inline int idaapi change_bptlocs( const movbpt_infos_t &movinfo, movbpt_codes_t *codes = NULL, bool del_hindering_bpts = true) { return callui(ui_dbg_change_bptlocs, &movinfo, codes, del_hindering_bpts).i; } /// \name enable/disable breakpoints /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// Enable or disable an existing breakpoint. /// A disabled breakpoint isn't available anymore in the process. //@{ inline bool idaapi enable_bpt(ea_t ea, bool enable = true) { return callui(ui_dbg_enable_oldbpt, ea, enable).cnd; } inline bool idaapi enable_bpt(const bpt_location_t &bptloc, bool enable = true) { return callui(ui_dbg_enable_bpt, &bptloc, enable).cnd; } inline bool disable_bpt(ea_t ea) { return enable_bpt(ea, false); } inline bool disable_bpt(const bpt_location_t &bptloc) { return enable_bpt(bptloc, false); } inline bool idaapi request_enable_bpt(ea_t ea, bool enable = true) { return callui(ui_dbg_request_enable_oldbpt, ea, enable).cnd; } inline bool idaapi request_enable_bpt(const bpt_location_t &bptloc, bool enable = true) { return callui(ui_dbg_request_enable_bpt, &bptloc, enable).cnd; } inline bool request_disable_bpt(ea_t ea) { return request_enable_bpt(ea, false); } inline bool request_disable_bpt(const bpt_location_t &bptloc) { return request_enable_bpt(bptloc, false); } //@} /// Check the breakpoint at the specified address. /// \return one of \ref BPTCK_ inline int idaapi check_bpt(ea_t ea) { return callui(ui_dbg_check_bpt, ea).i; } #endif // __UI__ /// \defgroup BPTCK_ Breakpoint status codes /// Return values for check_bpt() //@{ #define BPTCK_NONE -1 ///< breakpoint does not exist #define BPTCK_NO 0 ///< breakpoint is disabled #define BPTCK_YES 1 ///< breakpoint is enabled #define BPTCK_ACT 2 ///< breakpoint is active (written to the process) //@} #ifndef SWIG /// Visit all breakpoints. /// To use this class, derive your own class from it and call for_all_bpts(). /// It is forbidden to add/del bpts from the visit_bpt() function. /// If bpts are nevertheless modified, the enumeration should be stopped struct bpt_visitor_t { int _for_all_bpts(int bvflags); ///< do not use this function. range_t range; ///< if specified, restricts the address range const char *name; ///< if specified, restricts bpts to the ones that match the given name bpt_visitor_t(void) : range(0, BADADDR), name(NULL) {} /// Defines action taken when breakpoint is visited virtual int idaapi visit_bpt(const bpt_t *bpt) = 0; int idaapi for_all_bpts(int bvflags) { return callui(ui_dbg_for_all_bpts, this, bvflags).i; } }; /// \defgroup BVF_ Breakpoint visitor flags /// Passed as 'bvflags' parameter to bpt_visitor_t::_for_all_bpts() /// \note it is forbidden to modify bpt states from the bpt_visitor_t::visit_bpt() /// function if #BVF_STATE is not #BVFS_ANY //@{ #define BVF_ABS 0x0001 ///< include absolute bpts #define BVF_REL 0x0002 ///< include relative bpts #define BVF_SYM 0x0004 ///< include symbolic bpts #define BVF_SRC 0x0008 ///< include source bpts #define BVF_ALL 0x000F ///< include all bpt location types #define BVF_STATE 0x0030 ///< bpt state mask #define BVFS_ANY 0x0000 ///< any state #define BVFS_INPROC 0x0010 ///< written to process memory #define BVFS_PENDING 0x0020 ///< pending #define BVFS_DISABLED 0x0030 ///< disabled. //@} #endif // SWIG //@} dbg_funcs_bpts #ifndef __UI__ /// \defgroup dbg_funcs_tracing Tracing /// \ingroup dbg_funcs /// /// Trace instructions/functions/basic blocks //-------------------------------------------------------------------- // T R A C I N G B U F F E R //-------------------------------------------------------------------- /// \defgroup dbg_funcs_trcbuf Tracing buffer /// \ingroup dbg_funcs_tracing /// /// Work with debugger trace buffer. /// IDA memorizes various types of trace events in a circular buffer: /// instruction tracing, function call and return, breakpoint access ... //@{ /// Specify the new size of the circular buffer. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param size if 0, buffer isn't circular and events are never removed. /// If the new size is smaller than the existing number of trace events, /// a corresponding number of trace events are removed. /// \note If you specify 0, all available memory can be quickly used !!! inline bool idaapi set_trace_size(int size) { return callui(ui_dbg_set_trace_size, size).cnd; } /// Clear all events in the trace buffer. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} inline void idaapi clear_trace(void) { callui(ui_dbg_clear_trace); } /// Post a clear_trace() request inline void idaapi request_clear_trace(void) { callui(ui_dbg_request_clear_trace); } //@} dbg_funcs_trcbuf //-------------------------------------------------------------------- // S T E P T R A C I N G //-------------------------------------------------------------------- /// \defgroup dbg_funcs_strace Step tracing /// \ingroup dbg_funcs_tracing /// /// Plugins can use these functions to implement a custom tracing engine. /// When enabled, IDA uses single-stepping feature of the debugger /// and generates a dbg_trace notification after each step in the current thread. /// Tracing buffer is not maintained in this mode (you need to use one of the /// higher level tracing types for it) //@{ /// Get current state of step tracing. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline bool idaapi is_step_trace_enabled(void) { return callui(ui_dbg_is_step_trace_enabled).cnd; } /// \name Enable/Disable step tracing /// Enable or disable the step tracing /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} /// \param enable /// - 1 : enable step tracing /// - 0 : disable step tracing /// - -1 : temporarily disable step tracing /// (trace-over breakpoints are conserved: /// these could re-enable step tracing later) //@{ inline bool idaapi enable_step_trace(int enable = 1) { return callui(ui_dbg_enable_step_trace, enable).cnd; } inline bool disable_step_trace(void) { return enable_step_trace(0); } inline bool idaapi request_enable_step_trace(int enable = 1) { return callui(ui_dbg_request_enable_step_trace, enable).cnd; } inline bool request_disable_step_trace(void) { return request_enable_step_trace(false); } //@} #endif // __UI__ /// \defgroup ST_ Step trace options /// Flags returned by get_step_trace_options() //@{ #define ST_OVER_DEBUG_SEG 0x01 ///< step tracing will be disabled when IP is in a debugger segment #define ST_OVER_LIB_FUNC 0x02 ///< step tracing will be disabled when IP is in a library function #define ST_ALREADY_LOGGED 0x04 ///< step tracing will be disabled when IP is already logged #define ST_SKIP_LOOPS 0x08 ///< step tracing will try to skip loops already recorded #define ST_DIFFERENTIAL 0x10 ///< tracing: log only new instructions (not previously logged) /// mask of available options, to ensure compatibility with newer IDA versions #define ST_OPTIONS_MASK (ST_OVER_DEBUG_SEG|ST_OVER_LIB_FUNC|ST_ALREADY_LOGGED|ST_SKIP_LOOPS|ST_DIFFERENTIAL) #define ST_OPTIONS_DEFAULT (ST_OVER_DEBUG_SEG|ST_OVER_LIB_FUNC) //@} /// specific options for instruction tracing (see set_insn_trace_options()) #define IT_LOG_SAME_IP 0x01 ///< instruction tracing will log new instructions even when IP doesn't change /// specific options for function tracing (see set_func_trace_options()) #define FT_LOG_RET 0x01 ///< function tracing will log returning instructions /// specific options for basic block tracing (see set_bblk_trace_options()) #define BT_LOG_INSTS 0x01 ///< log all instructions in the current basic block #ifndef __UI__ /// Get current step tracing options. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return \ref ST_ inline int idaapi get_step_trace_options(void) { return callui(ui_dbg_get_step_trace_options).i; } /// Modify step tracing options. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} inline void idaapi set_step_trace_options(int options) { callui(ui_dbg_set_step_trace_options, options); } /// Post a set_step_trace_options() request inline void idaapi request_set_step_trace_options(int options) { callui(ui_dbg_request_set_step_trace_options, options); } //@} dbg_funcs_strace //-------------------------------------------------------------------- // I N S T R U C T I O N S T R A C I N G //-------------------------------------------------------------------- /// \defgroup dbg_funcs_trcins Instruction tracing /// \ingroup dbg_funcs_tracing /// /// When instruction tracing is active, each executed instruction is stored /// in the tracing buffer. /// Internally, IDA uses step tracing to record register values after the /// execution of the instruction. //@{ /// Get current state of instruction tracing. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline bool idaapi is_insn_trace_enabled(void) { return callui(ui_dbg_is_insn_trace_enabled).cnd; } /// \name Enable/Disable instruction tracing /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} //@{ inline bool idaapi enable_insn_trace(bool enable = true) { return callui(ui_dbg_enable_insn_trace, enable).cnd; } inline bool disable_insn_trace(void) { return enable_insn_trace(false); } inline bool idaapi request_enable_insn_trace(bool enable = true) { return callui(ui_dbg_request_enable_insn_trace, enable).cnd; } inline bool request_disable_insn_trace(void) { return request_enable_insn_trace(false); } //@} /// Get current instruction tracing options. /// Also see #IT_LOG_SAME_IP /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline int idaapi get_insn_trace_options(void) { return callui(ui_dbg_get_insn_trace_options).i; } /// Modify instruction tracing options. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} inline void idaapi set_insn_trace_options(int options) { callui(ui_dbg_set_insn_trace_options, options); } /// Post a set_insn_trace_options() request inline void idaapi request_set_insn_trace_options(int options) { callui(ui_dbg_request_set_insn_trace_options, options); } //@} dbg_funcs_trcins //-------------------------------------------------------------------- // F U N C T I O N S T R A C I N G //-------------------------------------------------------------------- /// \defgroup dbg_funcs_trcfunc Functions tracing /// \ingroup dbg_funcs_tracing /// /// Each call to a function or return from a function is stored /// in the tracing buffer. //@{ /// Get current state of functions tracing. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline bool idaapi is_func_trace_enabled(void) { return callui(ui_dbg_is_func_trace_enabled).cnd; } /// \name Enable/Disable functions tracing /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} //@{ inline bool idaapi enable_func_trace(bool enable = true) { return callui(ui_dbg_enable_func_trace, enable).cnd; } inline bool disable_func_trace(void) { return enable_func_trace(false); } inline bool idaapi request_enable_func_trace(bool enable = true) { return callui(ui_dbg_request_enable_func_trace, enable).cnd; } inline bool request_disable_func_trace(void) { return request_enable_func_trace(false); } //@} /// Get current function tracing options. /// Also see #FT_LOG_RET /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline int idaapi get_func_trace_options(void) { return callui(ui_dbg_get_func_trace_options).i; } /// Modify function tracing options. /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} inline void idaapi set_func_trace_options(int options) { callui(ui_dbg_set_func_trace_options, options); } /// Post a set_func_trace_options() request inline void idaapi request_set_func_trace_options(int options) { callui(ui_dbg_request_set_func_trace_options, options); } //@} dbg_funcs_trcfunc //-------------------------------------------------------------------- // B A S I C B L O C K T R A C I N G //-------------------------------------------------------------------- /// \defgroup dbg_funcs_trcbb Basic block tracing /// \ingroup dbg_funcs_tracing //@{ // Modify basic block tracing options. // Type: Synchronous function - available as Request // Notification: none (synchronous function) /// \name Enable/Disable basic blocks tracing /// \sq{Type, Synchronous function - available as request, /// Notification, none (synchronous function)} //@{ inline bool idaapi enable_bblk_trace(bool enable = true) { return callui(ui_dbg_enable_bblk_trace, enable).cnd; } inline bool disable_bblk_trace(void) { return enable_bblk_trace(false); } inline bool idaapi request_enable_bblk_trace(bool enable = true) { return callui(ui_dbg_request_enable_bblk_trace, enable).cnd; } inline bool request_disable_bblk_trace(void) { return request_enable_bblk_trace(false); } inline bool idaapi is_bblk_trace_enabled(void) { return callui(ui_dbg_is_bblk_trace_enabled).cnd; } //@} /// Get current basic block tracing options. /// Also see #BT_LOG_INSTS /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline int idaapi get_bblk_trace_options(void) { return callui(ui_dbg_get_bblk_trace_options).i; } /// Modify basic block tracing options (see #BT_LOG_INSTS) inline void idaapi set_bblk_trace_options(int options) { callui(ui_dbg_set_bblk_trace_options, options); } /// Post a set_bblk_trace_options() request inline void idaapi request_set_bblk_trace_options(int options) { callui(ui_dbg_request_set_bblk_trace_options, options); } //@} dbg_funcs_trcbb #endif // __UI__ //-------------------------------------------------------------------- // T R A C I N G E V E N T S //-------------------------------------------------------------------- /// \defgroup dbg_funcs_trcev Tracing events /// \ingroup dbg_funcs_tracing //@{ /// Trace event types enum tev_type_t { tev_none = 0, ///< no event tev_insn, ///< an instruction trace tev_call, ///< a function call trace tev_ret, ///< a function return trace tev_bpt, ///< write, read/write, execution trace tev_mem, ///< memory layout changed tev_event, ///< debug event occurred tev_max, ///< first unused event type }; typedef qvector dbgevt_vec_t; ///< vector of debug events /// Common information for all trace events struct tev_info_t { tev_type_t type; ///< trace event type thid_t tid; ///< thread where the event was recorded ea_t ea; ///< address where the event occurred }; typedef qvector tevinfo_vec_t; ///< vector of trace event info objects /// Required typedef for get_insn_tev_reg_mem() struct memreg_info_t { ea_t ea; bytevec_t bytes; }; DECLARE_TYPE_AS_MOVABLE(memreg_info_t); typedef qvector memreg_infos_t; #ifndef __UI__ /// Get number of trace events available in trace buffer. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline int idaapi get_tev_qty(void) { return callui(ui_dbg_get_tev_qty).i; } /// Get main information about a trace event. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \param[out] tev_info result /// \return success inline bool idaapi get_tev_info(int n, tev_info_t *tev_info) { return callui(ui_dbg_get_tev_info, n, tev_info).cnd; } /// Read a register value from an instruction trace event. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \param regname name of desired register /// \param[out] regval result /// \return false if not an instruction event. /// \note This is the value of the register before the execution of /// the instruction. inline bool idaapi get_insn_tev_reg_val(int n, const char *regname, regval_t *regval) { return callui(ui_dbg_get_insn_tev_reg_val, n, regname, regval).cnd; } inline bool idaapi get_insn_tev_reg_val(int n, const char *regname, uint64 *ival) { return callui(ui_dbg_get_insn_tev_reg_val_i, n, regname, ival).cnd; } /// Read the memory pointed by register values from an instruction trace event. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \param[out] memmap result /// \return false if not an instruction event or no memory is available inline bool idaapi get_insn_tev_reg_mem(int n, memreg_infos_t *memmap) { return callui(ui_dbg_get_insn_tev_reg_mem, n, memmap).cnd; } /// Read the resulting register value from an instruction trace event. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \param regname name of desired register /// \param[out] regval result /// \return false if not an instruction trace event or register wasn't modified. inline bool idaapi get_insn_tev_reg_result(int n, const char *regname, regval_t *regval) { return callui(ui_dbg_get_insn_tev_reg_result, n, regname, regval).cnd; } inline bool idaapi get_insn_tev_reg_result(int n, const char *regname, uint64 *ival) { return callui(ui_dbg_get_insn_tev_reg_result_i, n, regname, ival).cnd; } /// Get the called function from a function call trace event. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \return #BADADDR if not a function call event. inline ea_t idaapi get_call_tev_callee(int n) { ea_t ea; callui(ui_dbg_get_call_tev_callee, n, &ea); return ea; } /// Get the return address from a function return trace event. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \return #BADADDR if not a function return event. inline ea_t idaapi get_ret_tev_return(int n) { ea_t ea; callui(ui_dbg_get_ret_tev_return, n, &ea); return ea; } /// Get the address associated to a read, read/write or execution trace event. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \return #BADADDR if not a read, read/write or execution trace event. /// \note Usually, a breakpoint is associated with a read, read/write or execution /// trace event. However, the returned address could be any address in the /// range of this breakpoint. /// If the breakpoint was deleted after the trace event, the address no longer /// corresponds to a valid breakpoint. inline ea_t idaapi get_bpt_tev_ea(int n) { ea_t ea; callui(ui_dbg_get_bpt_tev_ea, n, &ea); return ea; } /// Get the memory layout, if any, for the specified tev object. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \param[out] mi result /// \return false if the tev_t object is not of type ::tev_mem, true otherwise, /// with the new memory layout in "mi". inline bool idaapi get_tev_memory_info(int n, meminfo_vec_t *mi) { return callui(ui_dbg_get_tev_memory_info, n, mi).cnd; } /// Get the corresponding debug event, if any, for the specified tev object. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \param n number of trace event, is in range 0..get_tev_qty()-1. /// 0 represents the latest added trace event. /// \param[out] d result /// \return false if the tev_t object doesn't have any associated debug /// event, true otherwise, with the debug event in "d". inline bool idaapi get_tev_event(int n, debug_event_t *d) { return callui(ui_dbg_get_tev_event, n, d).cnd; } /// Get the base address of the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return the base address of the currently loaded trace inline ea_t idaapi get_trace_base_address(void) { ea_t ea; callui(ui_dbg_get_trace_base_address, &ea); return ea; } /// Set the base address of the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline void idaapi set_trace_base_address(ea_t ea) { callui(ui_dbg_set_trace_base_address, ea); } /// Add a thread to the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline void idaapi dbg_add_thread(thid_t tid) { callui(ui_dbg_add_thread, tid); } /// Delete a thread from the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline void idaapi dbg_del_thread(thid_t tid) { callui(ui_dbg_del_thread, tid); } /// Add a new trace element to the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline void idaapi dbg_add_tev(tev_type_t type, thid_t tid, ea_t address) { callui(ui_dbg_add_tev, type, tid, address); } #endif // __UI__ /// Structure used for dbg_add_many_tevs() struct tev_reg_value_t { regval_t value; int reg_idx; tev_reg_value_t(int _reg_idx = -1, uint64 _value = uint64(-1)) : reg_idx(_reg_idx) { value._set_int(_value); } }; DECLARE_TYPE_AS_MOVABLE(tev_reg_value_t); typedef qvector tev_reg_values_t; ///< vector of trace event reg values /// Structure used for dbg_add_many_tevs() struct tev_info_reg_t { tev_info_t info; tev_reg_values_t registers; }; DECLARE_TYPE_AS_MOVABLE(tev_info_reg_t); typedef qvector tevinforeg_vec_t; ///< vector of trace elements /// Se dbg_add_insn_tev() enum save_reg_values_t { SAVE_ALL_VALUES = 0, SAVE_DIFF, SAVE_NONE }; #ifndef __UI__ /// Add many new trace elements to the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return false if the operation failed for any ::tev_info_t object inline bool idaapi dbg_add_many_tevs(tevinforeg_vec_t *new_tevs) { return callui(ui_dbg_add_many_tevs, new_tevs).cnd; } /// Add a new instruction trace element to the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return false if the operation failed, true otherwise inline bool idaapi dbg_add_insn_tev(thid_t tid, ea_t ea, save_reg_values_t save = SAVE_DIFF) { return callui(ui_dbg_add_insn_tev, tid, ea, save).cnd; } /// Add a new breakpoint trace element to the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} /// \return false if the operation failed, true otherwise inline bool idaapi dbg_add_bpt_tev(thid_t tid, ea_t ea, ea_t bp) { return callui(ui_dbg_add_bpt_tev, tid, ea, bp).cnd; } /// Add a new call trace element to the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline void idaapi dbg_add_call_tev(thid_t tid, ea_t caller, ea_t callee) { callui(ui_dbg_add_call_tev, tid, caller, callee); } /// Add a new return trace element to the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline void idaapi dbg_add_ret_tev(thid_t tid, ea_t ret_insn, ea_t return_to) { callui(ui_dbg_add_ret_tev, tid, ret_insn, return_to); } /// Add a new debug event to the current trace. /// \sq{Type, Synchronous function, /// Notification, none (synchronous function)} inline void idaapi dbg_add_debug_event(debug_event_t *event) { callui(ui_dbg_add_debug_event, event); } //@} dbg_funcs_trcev //--------------------------------------------------------------------------- // Trace management functions //--------------------------------------------------------------------------- /// \defgroup dbg_funcs_trcm Trace management functions /// \ingroup dbg_funcs_tracing //@{ /// Load a recorded trace file in the trace window. /// If the call succeeds and 'buf' is not null, the description of the /// trace stored in the binary trace file will be returned in 'buf' inline bool idaapi load_trace_file(qstring *buf, const char *filename) { return callui(ui_dbg_load_trace_file, buf, filename).cnd; } /// Save the current trace in the specified file inline bool idaapi save_trace_file(const char *filename, const char *description) { return callui(ui_dbg_save_trace_file, filename, description).cnd; } /// Is the specified file a valid trace file for the current database? inline bool idaapi is_valid_trace_file(const char *filename) { return callui(ui_dbg_is_valid_trace_file, filename).cnd; } /// Change the description of the specified trace file inline bool idaapi set_trace_file_desc(const char *filename, const char *description) { return callui(ui_dbg_set_trace_file_desc, filename, description).cnd; } /// Get the file header of the specified trace file inline bool idaapi get_trace_file_desc(qstring *buf, const char *filename) { return callui(ui_dbg_get_trace_file_desc, buf, filename).cnd; } /// Show the choose trace dialog inline bool idaapi choose_trace_file(qstring *buf) { return callui(ui_dbg_choose_trace_file, buf).cnd; } /// Show difference between the current trace and the one from 'filename' inline bool idaapi diff_trace_file(const char *NONNULL filename) { return callui(ui_dbg_diff_trace_file, filename).cnd; } /// Show the trace callgraph inline bool idaapi graph_trace(void) { return callui(ui_dbg_graph_trace).cnd; } /// Set highlight trace parameters. inline void idaapi set_highlight_trace_options( bool hilight, bgcolor_t color, bgcolor_t diff) { callui(ui_dbg_set_highlight_trace_options, hilight, color, diff); } /// Set platform name of current trace inline void idaapi set_trace_platform(const char *platform) { callui(ui_dbg_set_trace_platform, platform); } /// Get platform name of current trace inline const char *idaapi get_trace_platform() { return callui(ui_dbg_get_trace_platform).cptr; } /// Set dynamic register set of current trace inline void idaapi set_trace_dynamic_register_set(dynamic_register_set_t &idaregs) { callui(ui_dbg_set_trace_dynamic_register_set, &idaregs); } /// Get dynamic register set of current trace inline void idaapi get_trace_dynamic_register_set(dynamic_register_set_t *idaregs) { callui(ui_dbg_get_trace_dynamic_register_set, idaregs); } //@} dbg_funcs_trcm #endif // __UI__ //--------------------------------------------------------------------------- // High level functions (usable from scripts) //-------------------------------------------------------------------- /// \defgroup dbg_funcs_high High level functions /// \ingroup dbg_funcs /// /// These functions can be used from scripts //@{ /// Wait for the next debugger event. /// See also get_process_state() to get info about the current state /// of the debugged application /// Debugger event codes enum dbg_event_code_t { DEC_NOTASK = -2, ///< process does not exist DEC_ERROR = -1, ///< error DEC_TIMEOUT = 0, ///< timeout }; /// \defgroup WFNE_ Wait for debugger event flags /// Passed as 'wfne' parameter to wait_for_next_event() //@{ #define WFNE_ANY 0x0001 ///< return the first event (even if it doesn't suspend the process) #define WFNE_SUSP 0x0002 ///< wait until the process gets suspended #define WFNE_SILENT 0x0004 ///< 1: be slient, 0:display modal boxes if necessary #define WFNE_CONT 0x0008 ///< continue from the suspended state #define WFNE_NOWAIT 0x0010 ///< do not wait for any event, immediately return ::DEC_TIMEOUT ///< (to be used with #WFNE_CONT) #define WFNE_USEC 0x0020 ///< timeout is specified in microseconds ///< (minimum non-zero timeout is 40000us) //@} /// \defgroup DOPT_ Debugger options /// Passed as 'options' parameter to set_debugger_options() //@{ #define DOPT_SEGM_MSGS 0x00000001 ///< log debugger segments modifications #define DOPT_START_BPT 0x00000002 ///< break on process start #define DOPT_THREAD_MSGS 0x00000004 ///< log thread starts/exits #define DOPT_THREAD_BPT 0x00000008 ///< break on thread start/exit #define DOPT_BPT_MSGS 0x00000010 ///< log breakpoints //#define DOPT_BINS_BPT 0x00000020 // break on breakpoint instruction #define DOPT_LIB_MSGS 0x00000040 ///< log library loads/unloads #define DOPT_LIB_BPT 0x00000080 ///< break on library load/unload #define DOPT_INFO_MSGS 0x00000100 ///< log debugging info events #define DOPT_INFO_BPT 0x00000200 ///< break on debugging information #define DOPT_REAL_MEMORY 0x00000400 ///< do not hide breakpoint instructions #define DOPT_REDO_STACK 0x00000800 ///< reconstruct the stack #define DOPT_ENTRY_BPT 0x00001000 ///< break on program entry point #define DOPT_EXCDLG 0x00006000 ///< exception dialogs: # define EXCDLG_NEVER 0x00000000 ///< never display exception dialogs # define EXCDLG_UNKNOWN 0x00002000 ///< display for unknown exceptions # define EXCDLG_ALWAYS 0x00006000 ///< always display #define DOPT_LOAD_DINFO 0x00008000 ///< automatically load debug files (pdb) #define DOPT_END_BPT 0x00010000 ///< evaluate event condition on process end #define DOPT_TEMP_HWBPT 0x00020000 ///< when possible use hardware bpts for temp bpts //@} #ifndef __UI__ /// Wait for the next event. /// /// This function (optionally) resumes the process execution, /// and waits for a debugger event until a possible timeout occurs. /// /// \param wfne combination of \ref WFNE_ constants /// \param timeout number of seconds to wait, -1-infinity /// \return either an event_id_t (if > 0), or a dbg_event_code_t (if <= 0) inline dbg_event_code_t idaapi wait_for_next_event(int wfne, int timeout) { return dbg_event_code_t(callui(ui_dbg_wait_for_next_event, wfne, timeout).i); } /// Get the current debugger event inline const debug_event_t *idaapi get_debug_event(void) { return (const debug_event_t *)callui(ui_dbg_get_debug_event).vptr; } /// Set debugger options. /// Replaces debugger options with the specification combination \ref DOPT_ /// \return the old debugger options inline uint idaapi set_debugger_options(uint options) { return callui(ui_dbg_set_debugger_options, options).i; } /// Set remote debugging options. /// Should be used before starting the debugger. /// \param host If empty, IDA will use local debugger. /// If NULL, the host will not be set. /// \param pass If NULL, the password will not be set /// \param port If -1, the default port number will be used inline void idaapi set_remote_debugger(const char *host, const char *pass, int port=-1) { callui(ui_dbg_set_remote_debugger, host, pass, port); } /// Get process options. /// Any of the arguments may be NULL inline void idaapi get_process_options( qstring *path, qstring *args, qstring *sdir, qstring *host, qstring *pass, int *port) { callui(ui_dbg_get_process_options, path, args, sdir, host, pass, port); } /// Set process options. /// Any of the arguments may be NULL, which means 'do not modify' inline void idaapi set_process_options( const char *path, const char *args, const char *sdir, const char *host, const char *pass, int port) { callui(ui_dbg_set_process_options, path, args, sdir, host, pass, port); } /// Retrieve the exception information. /// You may freely modify the returned vector and add/edit/delete exceptions /// You must call store_exceptions() after any modifications /// Note: exceptions with code zero, multiple exception codes or names are prohibited inline excvec_t *idaapi retrieve_exceptions(void) { return (excvec_t *)callui(ui_dbg_retrieve_exceptions).vptr; } /// Update the exception information stored in the debugger module by /// invoking its dbg->set_exception_info callback inline bool idaapi store_exceptions(void) { return callui(ui_dbg_store_exceptions).cnd; } /// Convenience function: define new exception code. /// \param code exception code (cannot be 0) /// \param name exception name (cannot be empty or NULL) /// \param desc exception description (maybe NULL) /// \param flags combination of \ref EXC_ /// \return failure message or NULL. /// You must call store_exceptions() if this function succeeds inline const char *idaapi define_exception(uint code, const char *name, const char *desc, int flags) { return callui(ui_dbg_define_exception, code, name, desc, flags).cptr; } #endif // __UI__ //-------------------------------------------------------------------- /// Is set_dbg_options() present in ::debugger_t? inline THREAD_SAFE bool have_set_options(const debugger_t *_dbg) { return _dbg != NULL && _dbg->set_dbg_options != NULL; } //-------------------------------------------------------------------- /// Convenience function to set debugger specific options. It checks if the debugger /// is present and the function is present and calls it. inline const char *idaapi set_dbg_options( debugger_t *_dbg, const char *keyword, int pri, int value_type, const void *value) { const char *code = IDPOPT_BADKEY; if ( have_set_options(_dbg) ) code = _dbg->set_dbg_options(keyword, pri, value_type, value); return code; } inline const char *idaapi set_dbg_default_options( debugger_t *_dbg, const char *keyword, int value_type, const void *value) { return set_dbg_options(_dbg, keyword, IDPOPT_PRI_DEFAULT, value_type, value); } inline const char *idaapi set_int_dbg_options( debugger_t *_dbg, const char *keyword, int32 value) { sval_t sv = value; return set_dbg_default_options(_dbg, keyword, IDPOPT_NUM, &sv); } #ifndef __KERNEL__ /// Set options for ::dbg inline const char *idaapi set_dbg_options( const char *keyword, int pri, int value_type, const void *value) { return set_dbg_options(dbg, keyword, pri, value_type, value); } /// Set ::dbg options with #IDPOPT_PRI_DEFAULT inline const char *idaapi set_dbg_default_options( const char *keyword, int value_type, const void *value) { return set_dbg_options(keyword, IDPOPT_PRI_DEFAULT, value_type, value); } /// Set an integer value option for ::dbg inline const char *idaapi set_int_dbg_options( const char *keyword, int32 value) { sval_t sv = value; return set_dbg_default_options(keyword, IDPOPT_NUM, &sv); } #endif // __KERNEL__ //@} dbg_funcs_high //--------------------------------------------------------------------------- // S O U R C E I N F O R M A T I O N P R O V I D E R S //--------------------------------------------------------------------------- /// \defgroup dbg_funcs_srcinfo Source information providers /// \ingroup dbg_funcs /// /// These providers supply information about the source files and lines /// to the source level debugger. /// /// \note objects that inherit from ::qrefcnt_obj_t must be freed /// using the release() method. do not use the 'delete' operator! /// See description for qrefcnt_obj_t::release() /// /// Currently this interface is not frozen and may change. /// We will freeze it once we settle things down. //@{ class srcinfo_provider_t; class idc_value_t; class rangeset_t; class source_item_t; class argloc_t; /// Maintain a reference count for source items typedef qrefcnt_t source_item_ptr; /// Iterator for source items typedef qiterator _source_item_iterator; /// Maintain a reference count for source item iterators typedef qrefcnt_t<_source_item_iterator> source_item_iterator; /// Vector of source items typedef qvector source_items_t; //-------------------------------------------------------------------------- /// Execution context. Currently not defined in detail. Will probably /// hold information about the execution context, like: /// - thread id /// - current register values /// - stack frame address class eval_ctx_t { int size_cb; public: eval_ctx_t(ea_t _ea) : size_cb(sizeof(*this)), ea(_ea) {} ea_t ea; }; #ifndef __UI__ class TWidget; #endif //-------------------------------------------------------------------------- /// Describes a source file class source_file_t : public qrefcnt_obj_t { public: /// Call this function to free source_file_t virtual void idaapi release() override = 0; /// Get source info provider. /// There is no need to free or release it after using virtual srcinfo_provider_t *idaapi get_provider(void) const = 0; /// Get path to the source file (or a symbolic name). /// \param[out] errbuf pointer to buffer for the error message virtual const char *idaapi get_path(qstring *errbuf) = 0; /// Open window with source code (optional function). /// \param[out] strvec pointer to source text. the text should not be destroyed until the form is closed /// \param[out] pview pointer to view that displays the source text (subview of TWidget) /// \param lnnum,colnum cursor coordinates virtual TWidget *open_srcview(strvec_t **strvec, TWidget **pview, int lnnum, int colnum) = 0; /// Read entire file (colored lines). /// \param[out] buf pointer to output buffer /// \param[out] errbuf pointer to buffer for the error message virtual bool idaapi read_file(strvec_t *buf, qstring *errbuf) = 0; }; /// Maintain a reference count for source file objects typedef qrefcnt_t source_file_ptr; /// Iterator for source files typedef qiterator _source_file_iterator; /// Maintain a reference count for source file iterators typedef qrefcnt_t<_source_file_iterator> source_file_iterator; //-------------------------------------------------------------------------- /// Kinds of source items. /// Source items are organized into trees. Each tree starts with a MODULE. /// Each MODULE consists of FUNC and STTVAR global items. /// Each FUNC consists of STMTs (statements). /// Each STMT contains some EXPRs (expressions). enum src_item_kind_t { SRCIT_NONE, ///< unknown SRCIT_MODULE, ///< module SRCIT_FUNC, ///< function SRCIT_STMT, ///< a statement (if/while/for...) SRCIT_EXPR, ///< an expression (a+b*c) SRCIT_STTVAR, ///< static variable/code SRCIT_LOCVAR ///< a stack, register, or register-relative local variable or parameter }; //-------------------------------------------------------------------------- /// Describes a subdivision of source information class source_item_t : public qrefcnt_obj_t { public: /// Call this function to free source_item_t virtual void idaapi release() override = 0; /// Get source files of the item virtual source_file_iterator idaapi get_source_files() = 0; /// Get name of the item virtual bool idaapi get_name(qstring *buf) const = 0; /// Get line number of the item (1-based) virtual int idaapi get_lnnum() const = 0; /// Get ending line number (1-based.) /// The returned line number is the next /// line after the expression virtual int idaapi get_end_lnnum() const = 0; /// Get column number of the item. /// If unknown, return -1 virtual int idaapi get_colnum() const = 0; /// Get ending column number. /// The returned column number is the next /// column after the expression. /// If unknown, return -1 virtual int idaapi get_end_colnum() const = 0; /// Get starting address of the item virtual ea_t idaapi get_ea() const = 0; /// Get size of the item in bytes. /// If the item is fragmented, return size /// of the main fragment. /// if unknown, return 0. /// On error, return (asize_t) -1. virtual asize_t idaapi get_size() const = 0; /// Get item boundaries as a set of ranges. /// This function will be used to determine what breakpoints to set for /// stepping into/stepping over the item. virtual bool idaapi get_item_bounds(rangeset_t *set) const = 0; /// Get parent of the item. /// \param max_kind maximal source item kind we are interested in. /// for example, if max_kinds==#SRCIT_STMT, we are not interested /// in expressions, only in the enclosing statement or function virtual source_item_ptr idaapi get_parent(src_item_kind_t max_kind) const = 0; /// Create an iterator to enumerate all children of the item virtual source_item_iterator idaapi create_children_iterator() = 0; /// Calculate a string to display as a hint. /// \param hint output buffer for the hint (may by multiline & with colors) /// \param ctx execution context. NULL means missing context. /// \param nlines number of important lines in the hint virtual bool idaapi get_hint( qstring *hint, const eval_ctx_t *ctx, int *nlines) const = 0; /// Evaluate item value (meaningful only for expression items). /// \param ctx execution context. NULL means missing context. /// \param res buffer for the result (or exception if evaluation failed) /// \param errbuf buffer for the error message virtual bool idaapi evaluate( const eval_ctx_t *ctx, idc_value_t *res, qstring *errbuf) const = 0; /// Do these two items have the same source?. /// \retval false the source of the underlying data /// differs between the two items. /// \retval true when either the source of the underlying /// data is the same for the two items, or /// when such information is not available. /// /// E.g., A DWARF implementation of source_item_t will /// return true if the two items are backed by DIEs /// that have the same file offset. virtual bool idaapi equals(const source_item_t *other) const = 0; /// \name Getters (for modification) /// The following functions can be used to extract the item information /// in order to modify it. For example, if the user wants to modify a variable /// we will find what exactly needs to be modified. //@{ /// Get item kind virtual src_item_kind_t idaapi get_item_kind(const eval_ctx_t * /*ctx*/) const newapi { return SRCIT_NONE; } /// Does this source item represent a statement? bool is_stmt(const eval_ctx_t *ctx) const { return get_item_kind(ctx) == SRCIT_STMT; } /// Does this source item represent a module? bool is_module(const eval_ctx_t *ctx) const { return get_item_kind(ctx) == SRCIT_MODULE; } /// Does this source item represent a function? bool is_func(const eval_ctx_t *ctx) const { return get_item_kind(ctx) == SRCIT_FUNC; } /// Does this source item represent an expression? bool is_expr(const eval_ctx_t *ctx) const { return get_item_kind(ctx) >= SRCIT_EXPR; } /// Does this source item represent a stack, register, or register-relative local variable or parameter? bool is_locvar(const eval_ctx_t *ctx) const { return get_item_kind(ctx) >= SRCIT_LOCVAR; } /// Does this source item represent a static variable or code? bool is_sttvar(const eval_ctx_t *ctx) const { return get_item_kind(ctx) == SRCIT_STTVAR; } /// Get source info provider. /// The instance shouldn't be freed or released after using virtual srcinfo_provider_t *idaapi get_provider(void) const = 0; /// Get the location for this source item virtual bool idaapi get_location(argloc_t * /*out*/, const eval_ctx_t * /*ctx*/) const newapi { return false; } /// Get expression type virtual bool idaapi get_expr_tinfo(tinfo_t *tif) const = 0; //@} }; #define SRCDBG_PROV_VERSION 4 //-------------------------------------------------------------------------- /// Describes the mechanism used to retrieve source file information class srcinfo_provider_t { public: /// size of this class size_t cb; /// \ref SPF_ int flags; /// \defgroup SPF_ Source info provider property bits /// Used by srcinfo_provider_t::flags //@{ #define SPF_DECOMPILER 0x0001 ///< is a decompiler? #define SPF_ENABLED 0x0002 ///< enabled by the user ///< (this bit is managed by ida) #define SPF_ACTIVE 0x0004 ///< is willing to work with the current idb ///< (this bit is managed by ida) #define SPF_VERSION_MASK 0xFF000000 ///< Version mask, in the flags. ///< No other flag should have a bit rank > 23. //@} /// internal (unique) name of srcinfo provider const char *name; /// external (displayable) name of srcinfo provider const char *display_name; srcinfo_provider_t(const char *_name, const char *_display_name, int _flags=0) : cb(sizeof(*this)), flags(_flags), name(_name), display_name(_display_name) { flags |= SRCDBG_PROV_VERSION << 24; } /// Is the source info provider a decompiler? bool is_decompiler(void) const { return (flags & SPF_DECOMPILER) != 0; } /// Has the provider been enabled by the user? bool is_enabled(void) const { return (flags & SPF_ENABLED) != 0; } /// Is the provider willing to work with the current idb? bool is_active(void) const { return (flags & SPF_ACTIVE) != 0; } /// See #SPF_VERSION_MASK uint8 get_version() const { return (flags >> 24) & 0xFF; } /// Enable or disable the provider. /// If the provider fails to initialize, it returns false, otherwise true virtual bool idaapi enable_provider(bool enable) = 0; /// Configure srcinfo provider. /// See the description of ::set_options_t virtual const char *idaapi set_options( const char *keyword, int value_type, const void *value) = 0; /// Inform the provider that a module got loaded. /// The provider is not required to read the module information immediately; /// it may postpone it until really required. virtual void idaapi add_module(const char *path, ea_t base, asize_t size) = 0; /// Inform the provider that a module got unloaded. virtual void idaapi del_module(ea_t base) = 0; /// Inform the provider that we will request for information now. /// This function must be called before calling all functions below. /// probably it will be called when the process gets suspended. virtual void idaapi get_ready(void) = 0; /// Ask the provider if the source information has changed /// and the screen should be refreshed. UI will call this function /// periodically (when idle). if it returns a flag value other than #SPCH_NONE, /// then the source information must be refreshed. virtual int idaapi get_change_flags(void) = 0; /// \defgroup SPCH_ Source info changed flags /// Returned by srcinfo_provider_t::get_change_flags() //@{ #define SPCH_NONE 0x0000 ///< nothing has changed #define SPCH_FILES 0x0001 ///< source files have changed #define SPCH_ITEMS 0x0002 ///< source items have changed #define SPCH_LINES 0x0004 ///< source line numbers have changed //@} /// Locate source item by address. /// The kernel will inquire all registered providers and use the best reply. /// \param ea linear address /// \param size size of the item /// \param level the desired item level: /// - ::SRCIT_STMT: a statement /// - ::SRCIT_EXPR: an expression /// - ::SRCIT_FUNC: a global code item /// - SRCIT_xxxVAR: a global data item (the exact type is not checked) /// \param may_decompile meaningful only for the decompiler. if set to false /// and the function at 'ea' has not been decompiled yet, fail. virtual source_item_iterator idaapi find_source_items( ea_t ea, asize_t size, src_item_kind_t level, bool may_decompile) = 0; /// Locate source item by a position in a source file. /// if colnum == 0, return the statement that starts at the specified line. /// if lnnum == 0, return information about all lines (colnum is ignored in this case) virtual source_item_iterator idaapi find_source_items(source_file_t *sf, int lnnum, int colnum=0) = 0; /// Create iterators to enumerate files. /// \param filename name of the source file to enumerate virtual source_file_iterator idaapi create_file_iterator(const char *filename=NULL) = 0; /// Create iterators to enumerate items virtual source_item_iterator idaapi create_item_iterator(const source_file_t *sf) = 0; /// Apply the debug information (types, functions, globals) /// from the module whose path is 'path', to the IDB virtual bool idaapi apply_module_info(const char * /*path*/) { return false; } /// Locate a global variable by its name. /// \param name The variable name /// \param ea The current address /// \return the source item, or NULL virtual source_item_ptr idaapi find_static_item(const char *name, ea_t ea) = 0; }; //-------------------------------------------------------------------------- /// Register a source information provider. /// Source information providers will call this function to register themselves /// with IDA kernel. /// Returns false: a service provider with this name already exists. inline bool idaapi register_srcinfo_provider(srcinfo_provider_t *sp) { return callui(ui_dbg_register_provider, sp).cnd; } /// Unregister a source information provider. /// Returns false: no such provider. inline bool idaapi unregister_srcinfo_provider(srcinfo_provider_t *sp) { return callui(ui_dbg_unregister_provider, sp).cnd; } #ifndef __UI__ class source_view_t; /// Create a source code view inline source_view_t *create_source_viewer( TWidget **out_ccv, TWidget *parent, TWidget *custview, source_file_ptr sf, strvec_t *lines, int lnnum, int colnum, int flags) { return (source_view_t *) callui( ui_create_source_viewer, out_ccv, parent, custview, &sf, lines, lnnum, colnum, flags).vptr; } #endif //-------------------------------------------------------------------------- /// Get one byte of the debugged process memory. /// \param x pointer to byte value /// \param ea linear address /// \return true success /// \return false address inaccessible or debugger not running idaman bool ida_export get_dbg_byte(uint32 *x, ea_t ea); /// Change one byte of the debugged process memory. /// \param ea linear address /// \param x byte value /// \return true if the process memory has been modified idaman bool ida_export put_dbg_byte(ea_t ea, uint32 x); //@} dbg_funcs_srcinfo //-------------------------------------------------------------------------- // D E B U G G E R M E M O R Y F U N C T I O N S F O R U I //-------------------------------------------------------------------------- /// \defgroup dbg_funcs_mem Debugger memory functions for UI /// \ingroup dbg_funcs /// /// Inspect debugged process memory. //@{ /// Set the memory information source for IDA kernel. /// This function allows the kernel to use information coming from somewhere /// other than the database (from the debugger, for example) /// \param dbg_get_memory_config returns current memory configuration /// in the dynamic memory allocated by qalloc(). /// The kernel will qfree() it automatically. /// If this argument is NULL, then the debugged /// process memory is not used. /// - n: number of ::range_t elements in the answer /// \param memory_read read bytes from the debugged process memory /// \param memory_write write bytes to the debugged process memory /// (don't forget to call invalidate_dbgmem_contents() from it) idaman void ida_export set_dbgmem_source( range_t *(idaapi*dbg_get_memory_config)(int *n), int (idaapi*memory_read) (ea_t ea, void *buffer, int size), int (idaapi*memory_write)(ea_t ea, const void *buffer, int size)); /// Invalidate the debugged process memory configuration. /// Call this function if the debugged process might have changed its memory /// layout (allocated more memory, for example) idaman void ida_export invalidate_dbgmem_config(void); /// Invalidate the debugged process memory contents. /// Call this function each time the process has been stopped or the process /// memory is modified. /// If ea == #BADADDR, then the whole memory contents will be invalidated idaman void ida_export invalidate_dbgmem_contents(ea_t ea, asize_t size); /// Is the debugger currently running? idaman bool ida_export is_debugger_on(void); /// Is the address mapped to debugger memory? idaman bool ida_export is_debugger_memory(ea_t ea); //@} dbg_funcs_mem //------------------------------------------------------------------------ #ifndef __UI__ // Not for the UI /// \defgroup dbg_funcs_conv Misc /// \ingroup dbg_funcs /// /// Convenience functions offered by the user interface //@{ inline ea_t idaapi get_tev_ea(int n) { ea_t ea; callui(ui_dbg_get_tev_ea, n, &ea); return ea; } inline int idaapi get_tev_type(int n) { return callui(ui_dbg_get_tev_type, n).i; } inline int idaapi get_tev_tid(int n) { return callui(ui_dbg_get_tev_tid, n).i; } inline bool idaapi get_module_info(ea_t ea, modinfo_t *modinfo) { return callui(ui_dbg_get_module_info, ea, modinfo).cnd; } inline void idaapi bring_debugger_to_front(void) { callui(ui_dbg_bring_to_front); } inline bool idaapi collect_stack_trace(thid_t tid, call_stack_t *trace) { return callui(ui_dbg_collect_stack_trace, tid, trace).cnd; } inline const char *idaapi get_debugger_event_cond(void) { return callui(ui_dbg_get_event_cond).cptr; } inline void idaapi set_debugger_event_cond(const char *NONNULL evcond) { callui(ui_dbg_set_event_cond, evcond); } inline bool idaapi load_debugger(const char *dbgname, bool use_remote) { return callui(ui_dbg_load_debugger, dbgname, use_remote).cnd; } inline void idaapi get_manual_regions(meminfo_vec_t *ranges) { callui(ui_dbg_get_manual_regions, ranges); } inline void idaapi set_manual_regions(const meminfo_vec_t *ranges) { callui(ui_dbg_set_manual_regions, ranges); } inline void idaapi edit_manual_regions() { callui(ui_dbg_edit_manual_regions); } inline void idaapi enable_manual_regions(bool enable) { callui(ui_dbg_enable_manual_regions, enable); } inline int idaapi hide_all_bpts(void) { return callui(ui_dbg_hide_all_bpts).i; } inline int idaapi handle_debug_event(const debug_event_t *ev, int rqflags) { return callui(ui_dbg_handle_debug_event, ev, rqflags).i; } inline bool idaapi add_virt_module(const modinfo_t *mod) { return callui(ui_dbg_add_vmod, mod).cnd; } inline bool idaapi del_virt_module(const ea_t base) { return callui(ui_dbg_del_vmod, base).cnd; } inline int idaapi set_bptloc_string(const char *s) { return callui(ui_dbg_set_bptloc_string, s).i; } inline const char *idaapi get_bptloc_string(int i) { return callui(ui_dbg_get_bptloc_string, i).cptr; } inline int idaapi internal_cleanup_appcall(thid_t tid) { return callui(ui_dbg_internal_cleanup_appcall, tid).i; } inline int idaapi internal_get_sreg_base(ea_t *answer, thid_t tid, int sreg_value) { return callui(ui_dbg_internal_get_sreg_base, answer, tid, sreg_value).i; } inline int idaapi internal_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize) { return callui(ui_dbg_internal_ioctl, fn, buf, size, poutbuf, poutsize).i; } inline ssize_t idaapi read_dbg_memory(ea_t ea, void *buffer, size_t size) { return callui(ui_dbg_read_memory, ea, buffer, size).ssize; } inline ssize_t idaapi write_dbg_memory(ea_t ea, const void *buffer, size_t size) { return callui(ui_dbg_write_memory, ea, buffer, size).ssize; } inline int idaapi get_reg_vals(thid_t tid, int clsmask, regval_t *values) { return callui(ui_dbg_read_registers, tid, clsmask, values).i; } inline int idaapi set_reg_val(thid_t tid, int regidx, const regval_t *value) { return callui(ui_dbg_write_register, tid, regidx, value).i; } inline int idaapi get_dbg_memory_info(meminfo_vec_t *ranges) { return callui(ui_dbg_get_memory_info, ranges).i; } inline void idaapi set_bpt_group(bpt_t &bpt, const char *grp_name) { callui(ui_dbg_set_bpt_group, &bpt, grp_name); } inline bool idaapi set_bptloc_group(const bpt_location_t &bptloc, const char *grp_name) { return callui(ui_dbg_set_bptloc_group, &bptloc, grp_name).cnd; } inline bool idaapi get_bpt_group(qstring *grp_name, const bpt_location_t &bptloc) { return callui(ui_dbg_get_bpt_group, grp_name, &bptloc).cnd; } inline size_t idaapi list_bptgrps(qstrvec_t *bptgrps) { return callui(ui_dbg_list_bptgrps, bptgrps).ssize; } inline bool idaapi rename_bptgrp(const char *old_name, const char *new_name) { return callui(ui_dbg_rename_bptgrp, old_name, new_name).cnd; } inline bool idaapi del_bptgrp(const char *name) { return callui(ui_dbg_del_bptgrp, name).cnd; } inline ssize_t idaapi get_grp_bpts(bpt_vec_t *bpts, const char *grp_name) { return callui(ui_dbg_get_grp_bpts, bpts, grp_name).ssize; } inline const char *bpt_t::get_cnd_elang() const { return (const char *)(callui(ui_dbg_internal_get_elang, this).cptr); } inline bool bpt_t::set_cnd_elang(const char *name) { return callui(ui_dbg_internal_set_elang, this, name).cnd; } inline srcinfo_provider_t *idaapi get_srcinfo_provider(const char *name) { return (srcinfo_provider_t *)callui(ui_dbg_get_srcinfo_provider, name).vptr; } inline bool idaapi get_global_var(srcinfo_provider_t *prov, ea_t ea, const char *name, source_item_ptr *out) { return callui(ui_dbg_get_global_var, prov, ea, name, out).cnd; } inline bool idaapi get_local_var(srcinfo_provider_t *prov, ea_t ea, const char *name, source_item_ptr *out) { return callui(ui_dbg_get_local_var, prov, ea, name, out).cnd; } inline bool idaapi get_local_vars(srcinfo_provider_t *prov, ea_t ea, source_items_t *out) { return callui(ui_dbg_get_local_vars, prov, ea, out).cnd; } inline void idaapi add_path_mapping(const char *src, const char *dst) { callui(ui_dbg_add_path_mapping, src, dst); } inline bool idaapi get_current_source_file(qstring *out) { return callui(ui_dbg_get_current_source_file, out).cnd; } inline int idaapi get_current_source_line(void) { return callui(ui_dbg_get_current_source_line).i; } inline bool idaapi srcdbg_step_into(void) { return callui(ui_dbg_srcdbg_step_into).cnd; } inline bool idaapi srcdbg_request_step_into(void) { return callui(ui_dbg_srcdbg_request_step_into).cnd; } inline bool idaapi srcdbg_step_over(void) { return callui(ui_dbg_srcdbg_step_over).cnd; } inline bool idaapi srcdbg_request_step_over(void) { return callui(ui_dbg_srcdbg_request_step_over).cnd; } inline bool idaapi srcdbg_step_until_ret(void) { return callui(ui_dbg_srcdbg_step_until_ret).cnd; } inline bool idaapi srcdbg_request_step_until_ret(void) { return callui(ui_dbg_srcdbg_request_step_until_ret).cnd; } inline drc_t idaapi dbg_bin_search(ea_t *out, ea_t start_ea, ea_t end_ea, const compiled_binpat_vec_t &data, int srch_flags, qstring *errbuf) { return drc_t(callui(ui_dbg_bin_search, out, start_ea, end_ea, &data, srch_flags, errbuf).i); } //@} dbg_funcs_conv inline bool idaapi dbg_can_query(debugger_t *_dbg) { // Debugger can be queried IIF it is set and either currently in // suspended state, or can be queried while not in suspended state return _dbg != NULL && (_dbg->may_disturb() || get_process_state() < DSTATE_NOTASK); } #ifndef __KERNEL__ inline bool idaapi dbg_can_query(void) { return dbg_can_query(dbg); } #endif // __KERNEL__ #endif // __UI__ // internal kernel functions to lock the debugger memory configuration updates // Do not use these functions! They will be removed! idaman void ida_export lock_dbgmem_config(void); idaman void ida_export unlock_dbgmem_config(void); #endif