blob: 05a38f4ef4efca194a2337a0f6734cd7ee546936 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2012-2014 Google, Inc. All rights reserved.
* **********************************************************/
/* Dr. Memory: the memory debugger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License, and no later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _DR_SYSCALL_H_
#define _DR_SYSCALL_H_ 1
/* Dr. Syscall: DynamoRIO System Call Extension */
/* Framework-shared header */
#include "drmemory_framework.h"
/**
* @file drsyscall.h
* @brief Header for Dr. Syscall: System Call Monitoring Extension
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup drsyscall Dr. Syscall: System Call Monitoring Extension
*/
/*@{*/ /* begin doxygen group */
/* Users of drsyscall need to use the drmgr versions of these events to ensure
* that drsyscall's actions occur at the right time.
*/
#ifndef dr_get_tls_field
# define dr_get_tls_field DO_NOT_USE_tls_field_USE_drmgr_tls_field_instead
# define dr_set_tls_field DO_NOT_USE_tls_field_USE_drmgr_tls_field_instead
# define dr_insert_read_tls_field DO_NOT_USE_tls_field_USE_drmgr_tls_field_instead
# define dr_insert_write_tls_field DO_NOT_USE_tls_field_USE_drmgr_tls_field_instead
# define dr_register_thread_init_event DO_NOT_USE_thread_event_USE_drmgr_events_instead
# define dr_unregister_thread_init_event DO_NOT_USE_thread_event_USE_drmgr_events_instead
# define dr_register_thread_exit_event DO_NOT_USE_thread_event_USE_drmgr_events_instead
# define dr_unregister_thread_exit_event DO_NOT_USE_thread_event_USE_drmgr_events_instead
# define dr_register_pre_syscall_event DO_NOT_USE_pre_syscall_USE_drmgr_events_instead
# define dr_unregister_pre_syscall_event DO_NOT_USE_pre_syscall_USE_drmgr_events_instead
# define dr_register_post_syscall_event DO_NOT_USE_post_syscall_USE_drmgr_events_instead
# define dr_unregister_post_syscall_event DO_NOT_USE_post_syscall_USE_drmgr_events_instead
#endif /* dr_get_tls_field */
/***************************************************************************
* ENUMS AND TYPES
*/
/** Priority of drsyscall events. */
enum {
/**
* Priority of the drsyscall pre-syscall and post-syscall events
* that are meant to take place before the corresponding events of
* a regular user of drsyscall. Dynamic iteration is not allowed
* until these events have taken place. Users of drsyscall should
* arrange their pre-syscall and post-syscall event callbacks to
* be called after the drsyscall event, unless they want to modify
* the pre-syscall arguments before they're stored or they want to
* modify the application's context, in which case their event
* should go beforehand.
*/
DRMGR_PRIORITY_PRESYS_DRSYS = -100,
/** See the comment for DRMGR_PRIORITY_PRESYS_DRSYS. */
DRMGR_PRIORITY_POSTSYS_DRSYS = -100,
/**
* Priority of the drsyscall last-chance post-syscall event. This
* event must take place after any dynamic iteration of system
* call arguments, which means it must be after the post-syscall
* event in all users of drsyscall.
*/
DRMGR_PRIORITY_POSTSYS_DRSYS_LAST = 10000,
/**
* Priority of the drsyscall module load event. This
* event must take place before any user of drsyscall in order
* to populate the tables used by drsys_name_to_syscall().
*/
DRMGR_PRIORITY_MODLOAD_DRSYS = -100,
};
/**
* Name of drsyscall pre-syscall and post-syscall events that occur
* prior to iteration being allowed.
*/
#define DRMGR_PRIORITY_NAME_DRSYS "drsyscall"
/** Name of drsyscall post-syscall last-chance event. */
#define DRMGR_PRIORITY_NAME_DRSYS_LAST "drsyscall_last"
/** Opaque "system call handle" type. See #drsys_syscall_t. */
struct _drsys_syscall_t;
/**
* Opaque "system call handle" type used to refer to a particular system call.
* The system call handle can be obtained from drsys_cur_syscall(),
* drsys_iterate_syscalls(), drsys_name_to_syscall(),
* drsys_number_to_syscall(), or drsys_arg_t.syscall.
*/
typedef struct _drsys_syscall_t drsys_syscall_t;
/** Representation of a system call number. */
typedef struct _drsys_sysnum_t {
/**
* Either the sole system call number by itself (in which case \p
* secondary will be zero), or the primary component of a two-part
* system call number \p number.secondary.
*
* For MacOS, whether 32-bit or 64-bit, we normalize the system
* call number to a positive integer with the top 8 bits set to
* 0x1 for a Mach system call, 0x3 for Machdep, and 0x0 for BSD
* (allowing the direct use of SYS_ constants). Access the raw
* eax register in the pre-syscall event to view the unmodified
* number, whose encoding varies depending on the bitwidth and
* interrupt vector used.
*/
int number;
int secondary; /**< Secondary component of \p number.secondary, or zero. */
} drsys_sysnum_t;
/**
* Indicates whether a parameter is an input or an output. Used as a
* bitmask, so multiple of these can be set.
*/
typedef enum {
DRSYS_PARAM_IN = 0x01, /**< Input parameter. */
DRSYS_PARAM_OUT = 0x02, /**< Output parameter. */
/**
* May be IN or OUT. Used only in pre-syscall to indicate the
* size of an entire data structure, when only some fields are
* actually read or writen. Those fields will be presented as
* separate IN or OUT arguments which will of course overlap this
* one.
*/
DRSYS_PARAM_BOUNDS = 0x04,
/**
* Not used for memory iteration, only for type iteration, where
* the type of the return value is indicated if it is other than a
* status or error code.
*/
DRSYS_PARAM_RETVAL = 0x08,
/**
* If this flag is not set, the parameter is passed as a pointer to
* the specified type. If this flag is set, the parameter's value
* is passed in.
*/
DRSYS_PARAM_INLINED= 0x10,
} drsys_param_mode_t;
/* Keep this in synch with param_type_names[] */
/**
* Indicates the data type of a parameter.
* For the non-memarg iterators, a pointer type is implied whenever the
* mode is DRSYS_PARAM_OUT. Thus, a system call parameter of type DRSYS_TYPE_INT
* and mode DRSYS_PARAM_OUT can be assumed to be a pointer to an int.
*/
typedef enum {
DRSYS_TYPE_INVALID, /**< This type field is not used for this iteration type. */
DRSYS_TYPE_UNKNOWN, /**< Unknown type. */
/* Inlined */
DRSYS_TYPE_VOID, /**< Void type. */
DRSYS_TYPE_BOOL, /**< Boolean type. */
DRSYS_TYPE_INT, /**< Integer type of unspecified signedness. */
DRSYS_TYPE_SIGNED_INT, /**< Signed integer type. */
DRSYS_TYPE_UNSIGNED_INT,/**< Unsigned integer type. */
DRSYS_TYPE_HANDLE, /**< Windows-only: kernel/GDI/user handle type. */
DRSYS_TYPE_NTSTATUS, /**< Windows-only: NTSTATUS Native API/RTL type. */
DRSYS_TYPE_ATOM, /**< Windows-only: ATOM type. */
DRSYS_TYPE_POINTER, /**< Pointer to an unspecified type. */
/* Structs */
DRSYS_TYPE_STRUCT, /**< Unspecified structure type. */
DRSYS_TYPE_CSTRING, /**< Null-terminated string of characters (C string). */
DRSYS_TYPE_CWSTRING, /**< Null-terminated string of wide characters. */
DRSYS_TYPE_CARRAY, /**< Non-null-terminated string of characters. */
DRSYS_TYPE_CWARRAY, /**< Non-null-terminated string of wide characters. */
DRSYS_TYPE_CSTRARRAY, /**< Null-terminated array of C strings. */
DRSYS_TYPE_UNICODE_STRING, /**< UNICODE_STRING structure. */
DRSYS_TYPE_LARGE_STRING, /**< LARGE_STRING structure. */
DRSYS_TYPE_OBJECT_ATTRIBUTES, /**< OBJECT_ATTRIBUTES structure. */
DRSYS_TYPE_SECURITY_DESCRIPTOR, /**< SECURITY_DESCRIPTOR structure. */
DRSYS_TYPE_SECURITY_QOS, /**< SECURITY_QUALITY_OF_SERVICE structure */
DRSYS_TYPE_PORT_MESSAGE, /**< PORT_MESSAGE structure. */
DRSYS_TYPE_CONTEXT, /**< CONTEXT structure. */
DRSYS_TYPE_EXCEPTION_RECORD, /**< EXCEPTION_RECORD structure. */
DRSYS_TYPE_DEVMODEW, /**< DEVMODEW structure. */
DRSYS_TYPE_WNDCLASSEXW, /**< WNDCLASSEXW structure. */
DRSYS_TYPE_CLSMENUNAME, /**< CLSMENUNAME structure. */
DRSYS_TYPE_MENUITEMINFOW, /**< MENUITEMINFOW structure. */
DRSYS_TYPE_ALPC_PORT_ATTRIBUTES,/**< ALPC_PORT_ATTRIBUTES structure. */
DRSYS_TYPE_ALPC_SECURITY_ATTRIBUTES,/**< ALPC_SECURITY_ATTRIBUTES structure. */
DRSYS_TYPE_LOGFONTW, /**< LOGFONTW structure. */
DRSYS_TYPE_NONCLIENTMETRICSW, /**< NONCLIENTMETRICSW structure. */
DRSYS_TYPE_ICONMETRICSW, /**< ICONMETRICSW structure. */
DRSYS_TYPE_SERIALKEYSW, /**< SERIALKEYSW structure. */
DRSYS_TYPE_SOCKADDR, /**< struct sockaddr. */
DRSYS_TYPE_MSGHDR, /**< struct msghdr. */
DRSYS_TYPE_MSGBUF, /**< struct msgbuf. */
DRSYS_TYPE_LARGE_INTEGER, /**< LARGE_INTEGER structure. */
DRSYS_TYPE_ULARGE_INTEGER, /**< ULARGE_INTEGER structure. */
DRSYS_TYPE_IO_STATUS_BLOCK, /**< IO_STATUS_BLOCK structure. */
DRSYS_TYPE_FUNCTION, /**< Function of unspecified signature. */
DRSYS_TYPE_BITMAPINFO, /**< BITMAPINFO structure. */
DRSYS_TYPE_ALPC_CONTEXT_ATTRIBUTES,/**< ALPC_CONTEXT_ATTRIBUTES structure. */
/* Additional types may be added in the future. */
DRSYS_TYPE_LAST = DRSYS_TYPE_ALPC_CONTEXT_ATTRIBUTES,
} drsys_param_type_t;
/** Describes a system call parameter or memory region. */
typedef struct _drsys_arg_t {
/* System call context *****************************************/
/** The system call handle. */
drsys_syscall_t *syscall;
/** The system call number. */
drsys_sysnum_t sysnum;
/** The current thread's drcontext. Set for the dynamic iterators only. */
void *drcontext;
/**
* Whether operating pre-system call (if true) or post-system call (if false).
* Set for the dynamic iterators only (drsys_iterate_args() and
* drsys_iterate_memargs()).
*/
bool pre;
/**
* The application state, cached at the pre- or post-system call event.
* This contains DR_MC_CONTROL|DR_MC_INTEGER.
* Set for the dynamic iterators only.
*/
dr_mcontext_t *mc;
/* System call argument information ****************************/
/** The ordinal of the parameter. Set to -1 for a return value. */
int ordinal;
/** The mode (whether inlined, or read or written memory, etc.) of the parameter. */
drsys_param_mode_t mode;
/** The type of the parameter. */
drsys_param_type_t type;
/** A string further describing the type of the parameter. May be NULL. */
const char *type_name;
/**
* For the memarg iterator, the type of the containing structure. This is
* only set for some types when the sub-fields of the sructure are separated
* into different pieces due to gaps in the structure and the containing
* structure has its own type enum value.
* If not valid, it is set to DRSYS_TYPE_INVALID.
* Invalid for the arg iterator.
*/
drsys_param_type_t containing_type;
/** A string describing the parameter. This may be NULL. */
const char *arg_name;
/**
* If not set to DR_REG_NULL, indicates which register the parameter's
* value is stored in.
*/
reg_id_t reg;
/**
* Indicates whether the start_addr and value fields are valid. For memarg
* iteration, this is always true, as a failure to read will result in not
* calling the callback for that memarg. For arg iteration this field can
* be false. For static iteration this field is always false.
*/
bool valid;
/**
* For the memarg iterator, holds the address of the start of the memory
* region represented by this parameter.
* For the arg iterator, if this parameter is in memory, holds the
* address of the memory location; if this parameter is a register,
* holds NULL (and the register is in the \p reg field).
*/
void *start_addr;
/**
* For the arg iterator, holds the value of the parameter.
* Unused for the memarg iterator.
*
* \deprecated For 32-bit applications, some platforms (namely
* MacOS) support 64-bit arguments. For such cases, this field
* will hold only the bottom 32 bits of the value. Use the \p
* value64 field to retrieve the whole value. For cross-platform
* code, we recommend using \p value64 rather than this field.
*/
ptr_uint_t value;
/**
* For the memarg iterator, specifies the size in bytes of the memory region.
* For the arg iterator, specifies the size in bytes of the parameter.
*/
size_t size;
/**
* Identical to \p value, except it holds the full value of the
* parameter for the arg iterator for 32-bit applications on MacOS
* when the value is an 8-byte type. For cross-plaform code, we
* recommend using this field rather than \p value.
*
* Unused for the memarg iterator.
*/
uint64 value64;
} drsys_arg_t;
/** Indicates the category of system call. Relevant to Windows only. */
typedef enum {
DRSYS_SYSCALL_TYPE_KERNEL, /**< The kernel proper (ntoskrnl for Windows). */
DRSYS_SYSCALL_TYPE_USER, /**< A user-related system call. */
DRSYS_SYSCALL_TYPE_GRAPHICS, /**< A graphics-related system call. */
} drsys_syscall_type_t;
/** Specifies parameters controlling the behavior of Dr. Syscall to drsys_init(). */
typedef struct _drsys_options_t {
/** For compatibility. Set to sizeof(drsys_options_t). */
size_t struct_size;
/* For analyzing unknown system calls */
/**
* Dr. Syscall does not have information on every system call. For unknown
* syscalls, if this parameter is set, then a pre- and post-syscall memory
* comparison will be used to identify output parameters. Input parameters
* will remain unknown. When using this parameter, we recommend
* providing callbacks for is_byte_addressable(), is_byte_defined(),
* and is_register_defined(), if possible, to achieve greater accuracy.
*/
bool analyze_unknown_syscalls;
/**
* If analyze_unknown_syscalls is on and this parameter is on, when changes
* are detected, the containing dword (32 bits) are considered to have
* changed.
*/
bool syscall_dword_granularity;
/**
* If analyze_unknown_syscalls is on and this parameter is on, sentinels are
* used to detect writes and reduce false positives, in particular for
* uninitialized reads. However, enabling this option can potentially
* result in incorrect behavior if definedness information is incorrect or
* application threads read syscall parameter info simultaneously.
*/
bool syscall_sentinels;
/**
* Provides a query routine for whether a byte is addressable, i.e.,
* allocated and safe to access.
* If analyze_unknown_syscalls is on, the quality of unknown parameter
* analysis increases substantially if information on whether registers
* and memory contain valid, initialized information is available.
*/
bool (*is_byte_addressable)(byte *addr);
/**
* Provides a query routine for whether a byte is defined, i.e.,
* allocated, safe to access, and initialized.
* If analyze_unknown_syscalls is on, the quality of unknown parameter
* analysis increases substantially if information on whether registers
* and memory contain valid, initialized information is available.
*/
bool (*is_byte_defined)(byte *addr);
/**
* Provides a query routine for whether a byte is undefined, i.e.,
* allocated and safe to access yet uninitialized.
* If analyze_unknown_syscalls is on, the quality of unknown parameter
* analysis increases substantially if information on whether registers
* and memory contain valid, initialized information is available.
* If this is not provided but is_byte_addressable and is_byte_defined both
* are, those two will be called in concert to provide this information.
*/
bool (*is_byte_undefined)(byte *addr);
/**
* Provides a query routine for whether a register is defined, i.e.,
* contains a fully initialized value.
* If analyze_unknown_syscalls is on, the quality of unknown parameter
* analysis increases substantially if information on whether registers
* and memory contain valid, initialized information is available.
*/
bool (*is_register_defined)(reg_id_t reg);
/** This is an internal-only option that is reserved for developer use. */
bool verify_sysnums;
/** This is an internal-only option that is reserved for developer use. */
app_pc (*lookup_internal_symbol)(const module_data_t *mod, const char *sym);
/** This is an internal-only option that is reserved for developer use. */
bool syscall_driver;
} drsys_options_t;
/** Type of iterator callbacks. */
typedef bool (*drsys_iter_cb_t)(drsys_arg_t *arg, void *user_data);
/** Indicates the primary method of invoking the kernel for a system call. */
typedef enum {
DRSYS_GATEWAY_UNKNOWN,
DRSYS_GATEWAY_INT,
DRSYS_GATEWAY_SYSENTER,
DRSYS_GATEWAY_SYSCALL,
#ifdef WINDOWS
DRSYS_GATEWAY_WOW64,
#endif
} drsys_gateway_t;
/***************************************************************************
* TOP-LEVEL
*/
DR_EXPORT
/**
* Initializes the Dr. Syscall extension. Must be called prior to any
* of the other routines. Can be called multiple times (by separate components,
* normally) but each call must be paired with a corresponding call to
* drsys_exit().
*
* @param[in] client_id The id of the client using drsys, as passed to dr_init().
* @param[in] options Allows changing the default behavior of Dr. Syscall.
*
* \return success code.
*/
drmf_status_t
drsys_init(client_id_t client_id, drsys_options_t *options);
DR_EXPORT
/**
* Cleans up the Dr. Syscall extension.
*/
drmf_status_t
drsys_exit(void);
DR_EXPORT
/**
* Instructs Dr. Syscall that this system call will be queried and must be
* tracked. In particular, Dr. Syscall only records pre-system call arguments
* for system calls that are filtered.
*
* @param[in] sysnum The system call number to track.
*
* \return success code.
*/
drmf_status_t
drsys_filter_syscall(drsys_sysnum_t sysnum);
DR_EXPORT
/**
* Instructs Dr. Syscall that all system calls may be queried and must be
* tracked. In particular, Dr. Syscall only records pre-system call arguments
* for system calls that are filtered.
*
* \return success code.
*/
drmf_status_t
drsys_filter_all_syscalls(void);
/***************************************************************************
* STATELESS QUERIES
*/
DR_EXPORT
/**
* Given a system call name, retrieves a handle to the system call to
* be used for further queries. The handle is valid until drsys_exit()
* is called.
* On Windows, multiple versions of the name are accepted.
* For ntoskrnl system calls, the Nt or Zw varieties are supported.
* For secondary system calls like NtUserCallOneParam.RELEASEDC, the
* full name as well as just the secondary name (RELEASEDC) are accepted.
* The lookup is case-insensitive on Windows.
* This can be called in dr_init() for all system calls, even if the
* libraries containing their wrappers have not yet been loaded.
*
* @param[in] name The system call name to look up.
* @param[out] syscall The system call handle.
*
* \return success code.
*/
drmf_status_t
drsys_name_to_syscall(const char *name, OUT drsys_syscall_t **syscall);
DR_EXPORT
/**
* Given a system call number, retrieves a handle to the system call to
* be used for further queries. The handle is valid until drsys_exit()
* is called.
* This can be called in dr_init() for all system calls, even if the
* libraries containing their wrappers have not yet been loaded.
*
* @param[in] sysnum The system call number to look up.
* @param[out] syscall The system call handle.
*
* \return success code.
*/
drmf_status_t
drsys_number_to_syscall(drsys_sysnum_t sysnum, OUT drsys_syscall_t **syscall);
DR_EXPORT
/**
* Given a system call handle, retrieves the canonical system call name.
* The system call handle can be obtained from drsys_cur_syscall(),
* drsys_iterate_syscalls(), drsys_name_to_syscall(),
* drsys_number_to_syscall(), or drsys_arg_t.syscall.
*
* @param[in] syscall The handle for the system call to query.
* @param[out] name The system call name.
*
* \return success code.
*/
drmf_status_t
drsys_syscall_name(drsys_syscall_t *syscall, OUT const char **name);
DR_EXPORT
/**
* Given a system call handle, retrieves the system call number.
* The system call handle can be obtained from drsys_cur_syscall(),
* drsys_iterate_syscalls(), drsys_name_to_syscall(),
* drsys_number_to_syscall(), or drsys_arg_t.syscall.
*
* @param[in] syscall The handle for the system call to query.
* @param[out] sysnum The system call number.
*
* \return success code.
*/
drmf_status_t
drsys_syscall_number(drsys_syscall_t *syscall, OUT drsys_sysnum_t *sysnum);
DR_EXPORT
/**
* Identifies the type of system call.
* The system call handle can be obtained from drsys_cur_syscall(),
* drsys_iterate_syscalls(), drsys_name_to_syscall(),
* drsys_number_to_syscall(), or drsys_arg_t.syscall.
*
* @param[in] syscall The handle for the system call to query.
* @param[out] type The system call type.
*
* \return success code.
*/
drmf_status_t
drsys_syscall_type(drsys_syscall_t *syscall, OUT drsys_syscall_type_t *type);
DR_EXPORT
/**
* Identifies whether the system call details for the given syscall are known.
* The system call handle can be obtained from drsys_cur_syscall(),
* drsys_iterate_syscalls(), drsys_name_to_syscall(),
* drsys_number_to_syscall(), or drsys_arg_t.syscall.
*
* @param[in] syscall The handle for the system call to query.
* @param[out] known Whether known.
*
* \return success code.
*/
drmf_status_t
drsys_syscall_is_known(drsys_syscall_t *syscall, OUT bool *known);
DR_EXPORT
/**
* For Windows or Linux, identifies whether the given value is a
* successful return value for the given system call.
*
* \warning On MacOS, this routine always fails with
* DRMF_ERROR_FEATURE_NOT_AVAILABLE, as success depends on the
* condition codes and not on the value itself. Furthermore, the
* value can be 64 bits for a 32-bit application. Use
* drsys_cur_syscall_result() instead.
* The system call handle can be obtained from drsys_cur_syscall(),
* drsys_iterate_syscalls(), drsys_name_to_syscall(),
* drsys_number_to_syscall(), or drsys_arg_t.syscall.
*
* The system call result can be obtained from dr_syscall_get_result().
*
* On Windows, system calls that return an error code like
* STATUS_BUFFER_TOO_SMALL OUT but that still write an output param are
* considered to have succeeded.
*
* @param[in] syscall The handle for the system call to query.
* @param[in] result The system call return value.
* @param[out] success Whether the value indicates success.
*
* \return success code.
*/
drmf_status_t
drsys_syscall_succeeded(drsys_syscall_t *syscall, reg_t result, OUT bool *success);
DR_EXPORT
/**
* Identifies the type of the return value for the specified system call.
* The system call handle can be obtained from drsys_cur_syscall(),
* drsys_iterate_syscalls(), drsys_name_to_syscall(),
* drsys_number_to_syscall(), or drsys_arg_t.syscall.
*
* \note Some system calls have varying return types, which depend on
* the parameters passed in (e.g., on Windows, NtGdiPolyPolyDraw
* returns either a BOOL or an HRGN). The dynamic argument iterator
* drsys_iterate_args can be used to identify the precise return type
* for a particular instance.
*
* @param[in] syscall The handle for the system call to query.
* @param[out] type The system call return type.
*
* \return success code.
*/
drmf_status_t
drsys_syscall_return_type(drsys_syscall_t *syscall, OUT drsys_param_type_t *type);
#ifdef WINDOWS
DR_EXPORT
/**
* Identifies whether the given process handle refers to the current process.
*
* @param[in] h The handle to query.
* @param[out] current Whether the handle refers to the current process.
*
* \return success code.
*/
drmf_status_t
drsys_handle_is_current_process(HANDLE h, bool *current);
#endif
/**
* Returns whether the two system call numbers are equal.
*
* @param[in] num1 The first number to compare.
* @param[in] num2 The second number to compare.
*
* \return whether equal.
*/
static inline bool
drsys_sysnums_equal(drsys_sysnum_t *num1, drsys_sysnum_t *num2)
{
if (num1 == NULL || num2 == NULL)
return false;
return (num1->number == num2->number &&
num1->secondary == num2->secondary);
}
DR_EXPORT
/**
* Returns the primary method used to invoke the kernel for a system call.
* Prior to the first system call invoked by the application, this
* will return DRSYS_GATEWAY_UNKNOWN.
* Although this is the typical method, other methods may be used
* within the same application (e.g., on Linux, even when
* DRSYS_GATEWAY_SYSENTER or DRSYS_GATEWAY_SYSCALL is used for most
* system calls, DRSYS_GATEWAY_INT is still used for certain
* stack-sensitive or multi-argument system calls).
*
* @param[out] method The gateway method in use by the application.
*
* \return whether successful.
*/
drmf_status_t
drsys_syscall_gateway(drsys_gateway_t *method);
/***************************************************************************
* DYNAMIC QUERIES
*
* Must be called from syscall events.
*/
DR_EXPORT
/**
* Retrieves the system call handle for the current in-progress system call.
* The handle is only valid through the end of the post-system-call event
* for the system call.
*
* @param[in] drcontext The current DynamoRIO thread context.
* @param[out] syscall The system call handle.
*
* \return success code.
*/
drmf_status_t
drsys_cur_syscall(void *drcontext, OUT drsys_syscall_t **syscall);
DR_EXPORT
/**
* Returns whether the just-completed system call succeeded along with
* the value and error code returned. Must be called from a
* post-system-call event.
*
* This routine distinguishes itself from dr_syscall_get_result_ex()
* by providing accurate results for all system calls, in particular
* including Windows win32k.sys graphical (NtGdi) and user (NtUser)
* system calls. It also knows which system calls return 64-bit
* results, elminating the need for the caller to specifically request
* the top 32 bits in such cases.
*
* On Windows, system calls that return an error code like
* STATUS_BUFFER_TOO_SMALL OUT but that still write an output param are
* considered to have succeeded.
*
* @param[in] drcontext The current DynamoRIO thread context.
* @param[out] success Whether the system call succeeded. This parameter is
* optional and may be NULL.
* @param[out] value The value returned. This parameter is
* optional and may be NULL.
* @param[out] error_code If the system call failed, this holds the error code
* returned by the kernel, normalized to a positive value (i.e., on Linux it
* is negated from the raw value returned by the kernel). If the system call
* succeeded, *error_code is set to 0. This parameter is optional and may be NULL.
*
* \return success code.
*/
drmf_status_t
drsys_cur_syscall_result(void *drcontext, OUT bool *success, OUT uint64 *value,
OUT uint *error_code);
DR_EXPORT
/**
* Identifies the value of a system call argument as passed to the
* current in-progress system call. The value is cached in the
* pre-syscall event only for those system calls that are filtered via
* drsys_filter_syscall() or drsys_filter_all_syscalls(). Must be called
* from a system call pre- or post-event.
*
* \deprecated For 32-bit applications, some platforms (namely MacOS)
* support 64-bit arguments. For such cases, the value returned here
* will hold only the bottom 32 bits of the value. We recommend using
* drsys_pre_syscall_arg64() instead for cross-platform code.
*
* @param[in] drcontext The current DynamoRIO thread context.
* @param[in] argnum The ordinal of the parameter to query.
* @param[out] value The value of the parameter.
*
* \return success code.
*
* \note On 32-bit MacOS, the ordinal differs from that used in
* dr_syscall_get_param(), as dr_syscall_get_param() splits 64-bit
* arguments into two pieces. Here, 64-bit arguments occupy just one
* slot.
*/
drmf_status_t
drsys_pre_syscall_arg(void *drcontext, uint argnum, OUT ptr_uint_t *value);
DR_EXPORT
/**
* Identifies the value of a system call argument as passed to the
* current in-progress system call. The value is cached in the
* pre-syscall event only for those system calls that are filtered via
* drsys_filter_syscall() or drsys_filter_all_syscalls(). Must be called
* from a system call pre- or post-event.
*
* @param[in] drcontext The current DynamoRIO thread context.
* @param[in] argnum The ordinal of the parameter to query.
* @param[out] value The value of the parameter.
*
* \return success code.
*
* \note On 32-bit MacOS, the ordinal differs from that used in
* dr_syscall_get_param(), as dr_syscall_get_param() splits 64-bit
* arguments into two pieces. Here, 64-bit arguments occupy just one
* slot.
*/
drmf_status_t
drsys_pre_syscall_arg64(void *drcontext, uint argnum, OUT uint64 *value);
DR_EXPORT
/**
* Identifies the machine context of the application at the point
* of the current in-progress system call. The data is cached in the
* pre-syscall event only for those system calls that are filtered via
* drsys_filter_syscall() drsys_filter_all_syscalls(). Must be called
* from a system call pre- or post-event.
*
* This is a copy of the machine context, for convenience. It should
* not be modified. To change the context, or to change system call
* parameters or return value, the client must use a separate system
* call event that is ordered prior to DRMGR_PRIORITY_PRESYS_DRSYS or
* DRMGR_PRIORITY_POSTSYS_DRSYS.
*
* @param[in] drcontext The current DynamoRIO thread context.
* @param[out] mc The cached machine context.
*
* \return success code.
*/
drmf_status_t
drsys_get_mcontext(void *drcontext, OUT dr_mcontext_t **mc);
/***************************************************************************
* STATIC CALLBACK-BASED ITERATORS
*/
DR_EXPORT
/**
* Iterates over all system call numbers and calls the given callback
* for each one. The argument types of each system call can then be
* enumerated by calling drsys_iterate_arg_types() and passing the
* given system call handle \p syscall.
*
* This will enumerate all system calls even if the libraries
* containing their wrappers have not yet been loaded. System calls
* whose parameter details are unknown are included (see
* drsys_syscall_is_known()).
*
* @param[in] cb The callback to invoke for each system call number.
* The callback's return value indicates whether to
* continue the iteration.
* @param[in] user_data A custom parameter passed to \p cb.
*
* \return success code.
*/
drmf_status_t
drsys_iterate_syscalls(bool (*cb)(drsys_sysnum_t sysnum,
drsys_syscall_t *syscall, void *user_data),
void *user_data);
DR_EXPORT
/**
* Statically iterates over all system call parameters for the given
* system call.
* The system call handle can be obtained from drsys_cur_syscall(),
* drsys_iterate_syscalls(), drsys_name_to_syscall(),
* drsys_number_to_syscall(), or drsys_arg_t.syscall.
*
* Only the top-level types are enumerated (i.e., fields of structures
* are not recursively followed). As this is a static iteration, only
* the types are known and not any values.
* The return value is included at the end of the iteration, with a
* drsys_arg_t.ordinal value of -1.
*
* \note Some system calls have varying return types, which depend on
* the parameters passed in (e.g., on Windows, NtGdiPolyPolyDraw
* returns either a BOOL or an HRGN). The dynamic argument iterator
* drsys_iterate_args can be used to identify the precise return type
* for a particular instance.
*
* @param[in] syscall The handle for the system call to query.
* @param[in] cb The callback to invoke for each system call parameter.
* The callback's return value indicates whether to
* continue the iteration.
* @param[in] user_data A custom parameter passed to \p cb.
*
* \return success code.
*/
drmf_status_t
drsys_iterate_arg_types(drsys_syscall_t *syscall, drsys_iter_cb_t cb, void *user_data);
/***************************************************************************
* DYNAMIC CALLBACK-BASED ITERATORS
*/
DR_EXPORT
/**
* Dynamically iterates over all system call parameters for the
* current in-progress system call. Only the top-level types are
* enumerated (i.e., fields of structures are not recursively
* followed). The return value is included.
* Must be called from a system call pre- or post-event.
*
* @param[in] drcontext The current DynamoRIO thread context.
* @param[in] cb The callback to invoke for each system call parameter.
* The callback's return value indicates whether to
* continue the iteration.
* @param[in] user_data A custom parameter passed to \p cb.
*
* \return success code.
*/
drmf_status_t
drsys_iterate_args(void *drcontext, drsys_iter_cb_t cb, void *user_data);
DR_EXPORT
/**
* Dynamically iterates over all memory regions read or written by the
* current in-progress system call. Does descend into fields of data
* structures.
*
* Must be called from a system call pre- or post-event. If this is
* called from a post-system call event, it must also be called from
* the pre-system call event, as some information required for
* post-system call values is stored during pre-system call iteration.
*
* In pre-syscall, for OUT parameters, may treat a region containing
* padding between structure fields as a single region. Otherwise,
* splits up any region with padding into multiple iteration steps.
*
* For unknown syscalls, may call \p cb for each byte of memory even for
* adjacent bytes, as it uses a heuristic to try and detect written memory.
*
* Does NOT iterate over the primary parameter values themselves, even if
* they are located in memory: use drsys_iterate_args() for that.
*
* If unable to read the value of a parameter, will skip potential memory
* regions.
*
* Some memory regions may overlap each other. This occurs when the
* full capacity of a structure is passed to \p cb with a mode of
* DRSYS_PARAM_BOUNDS and the fields of the structure are subsequently
* enumerated separately.
*
* @param[in] drcontext The current DynamoRIO thread context.
* @param[in] cb The callback to invoke for each memory region.
* The callback's return value indicates whether to
* continue the iteration.
* @param[in] user_data A custom parameter passed to \p cb.
*
* \return success code.
*/
drmf_status_t
drsys_iterate_memargs(void *drcontext, drsys_iter_cb_t cb, void *user_data);
/***************************************************************************
* SYNCHRONOUS ITERATORS
*/
/* XXX i#1092: add start/next/stop synchronous layer on top of
* callback-based iterators
*/
/*@}*/ /* end doxygen group */
#ifdef __cplusplus
}
#endif
#endif /* _DR_SYSCALL_H_ */