blob: c959776e7a1a9dfe67a1022f2e6adab1448b87a8 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2021 Google, Inc. All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#ifndef _DR_OS_UTILS_H_
#define _DR_OS_UTILS_H_ 1
/**
* @file dr_os_utils.h
* @brief Operating-system-specific querying routines.
*/
/**************************************************
* STATE SWAPPING TYPES
*/
/**
* Flags that control the behavior of dr_switch_to_app_state_ex()
* and dr_switch_to_dr_state_ex().
*/
typedef enum {
#ifdef WINDOWS
DR_STATE_PEB = 0x0001, /**< Switch the PEB pointer. */
DR_STATE_TEB_MISC = 0x0002, /**< Switch miscellaneous TEB fields. */
DR_STATE_STACK_BOUNDS = 0x0004, /**< Switch the TEB stack bounds fields. */
DR_STATE_ALL = ~0, /**< Switch all state. */
#else
/**
* On Linux, DR's own TLS can optionally be swapped, but this is risky
* and not recommended as incoming signals are not properly handled when in
* such a state. Thus DR_STATE_ALL does *not* swap it.
*/
DR_STATE_DR_TLS = 0x0001,
DR_STATE_ALL = (~0) & (~DR_STATE_DR_TLS), /**< Switch all normal state. */
DR_STATE_GO_NATIVE = ~0, /**< Switch all state. Use with care. */
#endif
} dr_state_flags_t;
DR_API
/**
* Returns whether the given thread indicated by \p drcontext
* is currently using the application version of its system state.
* \sa dr_switch_to_dr_state(), dr_switch_to_app_state().
*
* This function does not indicate whether the machine context
* (registers) contains application state or not.
*
* On Linux, DR very rarely switches the system state, while on
* Windows DR switches the system state to the DR and client version
* on every event callback or clean call.
*/
bool
dr_using_app_state(void *drcontext);
DR_API
/** Equivalent to dr_switch_to_app_state_ex(drcontext, DR_STATE_ALL). */
void
dr_switch_to_app_state(void *drcontext);
DR_API
/**
* Swaps to the application version of any system state for the given
* thread. This is meant to be used prior to examining application
* memory, when private libraries are in use and there are two
* versions of system state. Invoking non-DR library routines while
* the application state is in place can lead to unpredictable
* results: call dr_switch_to_dr_state() (or the _ex version) before
* doing so.
*
* This function does not affect whether the current machine context
* (registers) contains application state or not.
*
* The \p flags argument allows selecting a subset of the state to swap.
*/
void
dr_switch_to_app_state_ex(void *drcontext, dr_state_flags_t flags);
DR_API
/** Equivalent to dr_switch_to_dr_state_ex(drcontext, DR_STATE_ALL). */
void
dr_switch_to_dr_state(void *drcontext);
DR_API
/**
* Should only be called after calling dr_switch_to_app_state() (or
* the _ex version), or in certain cases where a client is running its
* own code in an application state. Swaps from the application
* version of system state for the given thread back to the DR and
* client version.
*
* This function does not affect whether the current machine context
* (registers) contains application state or not.
*
* A client must call dr_switch_to_dr_state() in order to safely call
* private library routines if it is running in an application context
* where dr_using_app_state() returns true. On Windows, this is the
* case for any application context, as the system state is always
* swapped. On Linux, however, execution of application code in the
* code cache only swaps the machine context and not the system state.
* Thus, on Linux, while in the code cache, dr_using_app_state() will
* return false, and it is safe to invoke private library routines
* without calling dr_switch_to_dr_state(). Only if client or
* client-invoked code will examine a segment selector or descriptor
* does the state need to be swapped. A state swap is much more
* expensive on Linux (it requires a system call) than on Windows.
*
* The same flags that were passed to dr_switch_to_app_state_ex() should
* be passed here.
*/
void
dr_switch_to_dr_state_ex(void *drcontext, dr_state_flags_t flags);
/**************************************************
* APPLICATION COMMAND LINE
*/
/**
* Encodings of an application's command-line argument.
*/
typedef enum {
/**
* C String Encoding.
*/
DR_APP_ARG_CSTR_COMPAT,
/**
* UTF 16 String Encoding.
*/
DR_APP_ARG_UTF_16,
} dr_app_arg_encoding_t;
/**
* Contains information regarding an application's command-line argument.
*/
typedef struct _dr_app_arg_t {
/**
* The start boundary where the content of the arg begins.
*/
void *start;
/**
* The size, in bytes, of the argument.
*/
size_t size;
/**
* The encoding of the argument.
*/
dr_app_arg_encoding_t encoding;
} dr_app_arg_t;
DR_API
/**
* Provides information about the app's arguments by setting \p args_array up to
* the count denoted by \p args_count. Therefore, \p args_count is not the size of the
* buffer in bytes but the number of #dr_app_arg_t values that \p args_array can store.
* Returns the number of args set or -1 on error.
*
* Use dr_app_arg_as_cstring() to get the argument as a string.
*
* Use dr_num_app_args() to query the total number of command-line arguments passed to
* the application.
*
* \note Currently, this function is only available on Unix with
* early injection.
*
* \note An error code may be obtained via dr_get_error_code() when this routine fails.
*/
int
dr_get_app_args(DR_PARAM_OUT dr_app_arg_t *args_array, int args_count);
DR_API
/**
* Returns the number of command-line arguments passed to the application.
*
* \note Currently, this function is only available on Unix with
* early injection.
*
* \note An error code may be obtained via dr_get_error_code() when this routine fails.
*/
int
dr_num_app_args(void);
DR_API
/**
* Returns the passed argument \p app_arg as a string. \p buf is used only if needed, and
* therefore the caller should not assume that the string is in the \p buf. In other
* words, always use the returned value to refer to the string. Returns NULL on error
* such as when \p buf is needed as storage and the size of the buffer \p buf_size
* is not sufficient.
*
* To obtain a suitable upper-bound size of the string buffer, get the size of the
* argument from the #dr_app_arg_t value retrieved via dr_get_app_args().
*
* \note Currently, this function is only available on Unix with
* early injection.
*
* \note An error code may be obtained via dr_get_error_code() when this routine fails.
*/
const char *
dr_app_arg_as_cstring(DR_PARAM_IN dr_app_arg_t *app_arg, char *buf, int buf_size);
DR_API
/** Returns the image name (without path) of the current application. */
const char *
dr_get_application_name(void);
DR_API
/** Returns the process id of the current process. */
process_id_t
dr_get_process_id(void);
DR_API
/**
* Returns the process id of the process associated with drcontext \p drcontext.
* The returned value may be different from dr_get_process_id() if the passed context
* was created in a different process, which may happen in thread exit callbacks.
*/
process_id_t
dr_get_process_id_from_drcontext(void *drcontext);
#ifdef UNIX
DR_API
/**
* Returns the process id of the parent of the current process.
* \note Linux only.
*/
process_id_t
dr_get_parent_id(void);
#endif
#ifdef WINDOWS
/** Windows versions */
typedef enum {
/** Windows 10 1803 major update. */
DR_WINDOWS_VERSION_10_1803 = 105,
/** Windows 10 1709 major update. */
DR_WINDOWS_VERSION_10_1709 = 104,
/** Windows 10 1703 major update. */
DR_WINDOWS_VERSION_10_1703 = 103,
/** Windows 10 1607 major update. */
DR_WINDOWS_VERSION_10_1607 = 102,
/**
* Windows 10 TH2 1511. For future Windows updates that change system call
* numbers, we'll perform our own artificial minor version number update as
* done here, and use the YYMM version as the sub-name, as officially the OS
* version will supposedly remain 10.0 forever.
*/
DR_WINDOWS_VERSION_10_1511 = 101,
/** Windows 10 pre-TH2 */
DR_WINDOWS_VERSION_10 = 100,
/** Windows 8.1 */
DR_WINDOWS_VERSION_8_1 = 63,
/** Windows Server 2012 R2 */
DR_WINDOWS_VERSION_2012_R2 = DR_WINDOWS_VERSION_8_1,
/** Windows 8 */
DR_WINDOWS_VERSION_8 = 62,
/** Windows Server 2012 */
DR_WINDOWS_VERSION_2012 = DR_WINDOWS_VERSION_8,
/** Windows 7 */
DR_WINDOWS_VERSION_7 = 61,
/** Windows Server 2008 R2 */
DR_WINDOWS_VERSION_2008_R2 = DR_WINDOWS_VERSION_7,
/** Windows Vista */
DR_WINDOWS_VERSION_VISTA = 60,
/** Windows Server 2008 */
DR_WINDOWS_VERSION_2008 = DR_WINDOWS_VERSION_VISTA,
/** Windows Server 2003 */
DR_WINDOWS_VERSION_2003 = 52,
/** Windows XP 64-bit */
DR_WINDOWS_VERSION_XP_X64 = DR_WINDOWS_VERSION_2003,
/** Windows XP */
DR_WINDOWS_VERSION_XP = 51,
/** Windows 2000 */
DR_WINDOWS_VERSION_2000 = 50,
/** Windows NT */
DR_WINDOWS_VERSION_NT = 40,
} dr_os_version_t;
/** Data structure used with dr_get_os_version() */
typedef struct _dr_os_version_info_t {
/** The size of this structure. Set this to sizeof(dr_os_version_info_t). */
size_t size;
/** The operating system version */
dr_os_version_t version;
/** The service pack major number */
uint service_pack_major;
/** The service pack minor number */
uint service_pack_minor;
/** The build number. */
uint build_number;
/** The release identifier (such as "1803" for a Windows 10 release). */
char release_id[64];
/** The edition (such as "Education" or "Professional"). */
char edition[64];
} dr_os_version_info_t;
DR_API
/**
* Returns information about the version of the operating system.
* Returns whether successful. \note Windows only. \note The Windows
* API routine GetVersionEx may hide distinctions between versions,
* such as between Windows 8 and Windows 8.1. DR reports the true
* low-level version.
*
*/
bool
dr_get_os_version(dr_os_version_info_t *info);
DR_API
/**
* Returns true if this process is a 32-bit process operating on a
* 64-bit Windows kernel, known as Windows-On-Windows-64, or WOW64.
* Returns false otherwise. \note Windows only.
*/
bool
dr_is_wow64(void);
DR_API
/**
* Returns a pointer to the application's Process Environment Block
* (PEB). DR swaps to a private PEB when running client code, in
* order to isolate the client and its dependent libraries from the
* application, so conventional methods of reading the PEB will obtain
* the private PEB instead of the application PEB. \note Windows only.
*/
void *
dr_get_app_PEB(void);
DR_API
/**
* Converts a process handle to a process id.
* \return Process id if successful; INVALID_PROCESS_ID on failure.
* \note Windows only.
*/
process_id_t
dr_convert_handle_to_pid(HANDLE process_handle);
DR_API
/**
* Converts a process id to a process handle.
* \return Process handle if successful; INVALID_HANDLE_VALUE on failure.
* \note Windows only.
*/
HANDLE
dr_convert_pid_to_handle(process_id_t pid);
#endif /* WINDOWS */
/**************************************************
* CLIENT AUXILIARY LIBRARIES
*/
/**
* A handle to a loaded client auxiliary library. This is a different
* type than module_handle_t and is not necessarily the base address.
*/
typedef void *dr_auxlib_handle_t;
/** An exported routine in a loaded client auxiliary library. */
typedef void (*dr_auxlib_routine_ptr_t)();
#if defined(WINDOWS) && !defined(X64)
/**
* A handle to a loaded 64-bit client auxiliary library. This is a different
* type than module_handle_t and is not necessarily the base address.
*/
typedef uint64 dr_auxlib64_handle_t;
/** An exported routine in a loaded 64-bit client auxiliary library. */
typedef uint64 dr_auxlib64_routine_ptr_t;
#endif
DR_API
/**
* Loads the library with the given path as an auxiliary client
* library. The library is not treated as an application module but
* as an extension of DR. The library will be included in
* dr_memory_is_in_client() and any faults in the library will be
* considered client faults. The bounds of the loaded library are
* returned in the optional out variables. On failure, returns NULL.
*
* If only a filename and not a full path is given, this routine will
* search for the library in the standard search locations for DR's
* private loader.
*/
dr_auxlib_handle_t
dr_load_aux_library(const char *name, byte **lib_start /*OPTIONAL OUT*/,
byte **lib_end /*OPTIONAL OUT*/);
DR_API
/**
* Looks up the exported routine with the given name in the given
* client auxiliary library loaded by dr_load_aux_library(). Returns
* NULL on failure.
*/
dr_auxlib_routine_ptr_t
dr_lookup_aux_library_routine(dr_auxlib_handle_t lib, const char *name);
DR_API
/**
* Unloads the given library, which must have been loaded by
* dr_load_aux_library(). Returns whether successful.
*/
bool
dr_unload_aux_library(dr_auxlib_handle_t lib);
#if defined(WINDOWS) && !defined(X64)
DR_API
/**
* Similar to dr_load_aux_library(), but loads a 64-bit library for
* access from a 32-bit process running on a 64-bit Windows kernel.
* Fails if called from a 32-bit kernel or from a 64-bit process.
* The library will be located in the low part of the address space
* with 32-bit addresses.
* Functions in the library can be called with dr_invoke_x64_routine().
*
* \warning Invoking 64-bit code is fragile. Currently, this routine
* uses the system loader, under the assumption that little isolation
* is needed versus application 64-bit state. Consider use of this routine
* experimental: use at your own risk!
*
* \note Windows only.
*
* \note Currently this routine does not support loading kernel32.dll
* or any library that depends on it.
* It also does not invoke the entry point for any dependent libraries
* loaded as part of loading \p name.
*
* \note Currently this routine does not support Windows 8 or higher.
*/
dr_auxlib64_handle_t
dr_load_aux_x64_library(const char *name);
DR_API
/**
* Looks up the exported routine with the given name in the given
* 64-bit client auxiliary library loaded by dr_load_aux_x64_library(). Returns
* NULL on failure.
* The returned function can be called with dr_invoke_x64_routine().
*
* \note Windows only.
*
* \note Currently this routine does not support Windows 8.
*/
dr_auxlib64_routine_ptr_t
dr_lookup_aux_x64_library_routine(dr_auxlib64_handle_t lib, const char *name);
DR_API
/**
* Unloads the given library, which must have been loaded by
* dr_load_aux_x64_library(). Returns whether successful.
*
* \note Windows only.
*/
bool
dr_unload_aux_x64_library(dr_auxlib64_handle_t lib);
DR_API
/**
* Must be called from 32-bit mode. Switches to 64-bit mode, calls \p
* func64 with the given parameters, switches back to 32-bit mode, and
* then returns to the caller. Requires that \p func64 be located in
* the low 4GB of the address space. All parameters must be 32-bit
* sized, and all are widened via sign-extension when passed to \p
* func64.
*
* \return -1 on failure; else returns the return value of \p func64.
*
* \warning Invoking 64-bit code is fragile. The WOW64 layer assumes
* there is no other 64-bit code that will be executed.
* dr_invoke_x64_routine() attempts to save the WOW64 state, but it
* has not been tested in all versions of WOW64. Also, invoking
* 64-bit code that makes callbacks is not supported, as not only a
* custom wrapper to call the 32-bit code in the right mode would be
* needed, but also a way to restore the WOW64 state in case the
* 32-bit callback makes a system call. Consider use of this routine
* experimental: use at your own risk!
*
* \note Windows only.
*/
int64
dr_invoke_x64_routine(dr_auxlib64_routine_ptr_t func64, uint num_params, ...);
#endif /* WINDOWS && !X64 */
/**************************************************
* MEMORY QUERY/ACCESS ROUTINES
*/
#define DR_MEMPROT_NONE 0x00 /**< No read, write, or execute privileges. */
#define DR_MEMPROT_READ 0x01 /**< Read privileges. */
#define DR_MEMPROT_WRITE 0x02 /**< Write privileges. */
#define DR_MEMPROT_EXEC 0x04 /**< Execute privileges. */
#define DR_MEMPROT_GUARD 0x08 /**< Guard page (Windows only) */
/**
* DR's default cache consistency strategy modifies the page protection of
* pages containing code, making them read-only. It pretends on application
* and client queries that the page is writable. On a write fault
* to such a region by the application or by client-added instrumentation, DR
* automatically handles the fault and makes the page writable. This requires
* flushing the code from the code cache, which can only be done safely when in
* an application context. Thus, a client writing to such a page is only
* supported when these criteria are met:
*
* -# The client code must be in an application code cache context. This rules
* out all event callbacks (including the basic block event) except for the
* pre and post system call events and the nudge event.
* -# The client must not hold any locks. An exception is a lock marked as
* an application lock (via dr_mutex_mark_as_app(), dr_rwlock_mark_as_app(),
* or dr_recurlock_mark_as_app()).
* -# The client code must not rely on returning to a particular point in the
* code cache, as that point might be flushed and removed during the write
* fault processing. This rules out a clean call (unless
* dr_redirect_execution() is used), but does allow something like
* drwrap_replace_native() which uses a continuation strategy.
*
* A client write fault that does not meet the first two criteria will result in
* a fatal error report and an abort. It is up to the client to ensure it
* satisifies the third criterion.
*
* Even when client writes do meet these criteria, for performance it's best for
* clients to avoid writing to such memory.
*/
#define DR_MEMPROT_PRETEND_WRITE 0x10
/**
* In addition to the appropriate DR_MEMPROT_READ and/or DR_MEMPROT_EXEC flags,
* this flag will be set for the VDSO and VVAR pages on Linux.
* The VVAR pages may only be identified by DR on kernels that explicitly label
* the pages in the /proc/self/maps file (kernel 3.15 and above).
* In some cases, accessing the VVAR pages can cause problems
* (e.g., https://github.com/DynamoRIO/drmemory/issues/1778).
*/
#define DR_MEMPROT_VDSO 0x20
/**
* Flags describing memory used by dr_query_memory_ex().
*/
typedef enum {
DR_MEMTYPE_FREE, /**< No memory is allocated here */
DR_MEMTYPE_IMAGE, /**< An executable file is mapped here */
DR_MEMTYPE_DATA, /**< Some other data is allocated here */
DR_MEMTYPE_RESERVED, /**< Reserved address space with no physical storage */
DR_MEMTYPE_ERROR, /**< Query failed for unspecified reason */
/**
* Query failed due to the address being located in Windows kernel space.
* No further information is available so iteration must stop.
*/
DR_MEMTYPE_ERROR_WINKERNEL,
} dr_mem_type_t;
/**
* Describes a memory region. Used by dr_query_memory_ex().
*/
typedef struct _dr_mem_info_t {
/** Starting address of memory region */
byte *base_pc;
/** Size of region */
size_t size;
/** Protection of region (DR_MEMPROT_* flags) */
uint prot;
/** Type of region */
dr_mem_type_t type;
} dr_mem_info_t;
#ifdef DR_PAGE_SIZE_COMPATIBILITY
# undef PAGE_SIZE
/**
* Size of a page of memory. This uses a function call so be careful
* where performance is critical.
*/
# define PAGE_SIZE dr_page_size()
/**
* Convenience macro to align to the start of a page of memory.
* It uses a function call so be careful where performance is critical.
*/
# define PAGE_START(x) (((ptr_uint_t)(x)) & ~(dr_page_size() - 1))
#endif /* DR_PAGE_SIZE_COMPATIBILITY */
DR_API
/** Returns the size of a page of memory. */
size_t
dr_page_size(void);
DR_API
/**
* Checks to see that all bytes with addresses in the range [\p pc, \p pc + \p size - 1]
* are readable and that reading from that range won't generate an exception (see also
* dr_safe_read() and DR_TRY_EXCEPT()).
* \note Nothing guarantees that the memory will stay readable for any length of time.
* \note On Linux, especially if the app is in the middle of loading a library
* and has not properly set up the .bss yet, a page that seems readable can still
* generate SIGBUS if beyond the end of an mmapped file. Use dr_safe_read() or
* DR_TRY_EXCEPT() to avoid such problems.
*/
bool
dr_memory_is_readable(const byte *pc, size_t size);
/* FIXME - this is a real view of memory including changes made for dr cache consistency,
* but what we really want to show the client is the apps view of memory (which would
* requires fixing correcting the view and fixing up exceptions for areas we made read
* only) - see PR 198873 */
DR_API
/**
* An os neutral method for querying a memory address. Returns true
* iff a memory region containing \p pc is found. If found additional
* information about the memory region is returned in the optional out
* arguments \p base_pc, \p size, and \p prot where \p base_pc is the
* start address of the memory region continaing \p pc, \p size is the
* size of said memory region and \p prot is an ORed combination of
* DR_MEMPROT_* flags describing its current protection.
*
* \note To examine only application memory, skip memory for which
* dr_memory_is_dr_internal() or dr_memory_is_in_client() returns true.
*
* \note DR may mark writable code pages as read-only but pretend they're
* writable. When this happens, it will include both #DR_MEMPROT_WRITE
* and #DR_MEMPROT_PRETEND_WRITE in \p prot.
*/
bool
dr_query_memory(const byte *pc, byte **base_pc, size_t *size, uint *prot);
DR_API
/**
* Provides additional information beyond dr_query_memory().
* Returns true if it was able to obtain information (including about
* free regions) and sets the fields of \p info. This routine can be
* used to iterate over the entire address space. Such an iteration
* should stop on reaching the top of the address space, or on
* reaching kernel memory (look for #DR_MEMTYPE_ERROR_WINKERNEL) on
* Windows.
*
* Returns false on failure and sets info->type to a DR_MEMTYPE_ERROR*
* code indicating the reason for failure.
*
* \note To examine only application memory, skip memory for which
* dr_memory_is_dr_internal() returns true.
*
* \note DR may mark writable code pages as read-only but pretend they're
* writable. When this happens, it will include both #DR_MEMPROT_WRITE
* and #DR_MEMPROT_PRETEND_WRITE in \p info->prot.
*/
bool
dr_query_memory_ex(const byte *pc, DR_PARAM_OUT dr_mem_info_t *info);
#ifdef WINDOWS
DR_API
/**
* Equivalent to the win32 API function VirtualQuery().
* See that routine for a description of
* arguments and return values. \note Windows only.
*
* \note DR may mark writable code pages as read-only but pretend they're
* writable. When this happens, this routine will indicate that the
* memory is writable. Call dr_query_memory() or dr_query_memory_ex()
* before attempting to write to application memory to ensure it's
* not read-only underneath.
*/
size_t
dr_virtual_query(const byte *pc, MEMORY_BASIC_INFORMATION *mbi, size_t mbi_size);
#endif
DR_API
/**
* Safely reads \p size bytes from address \p base into buffer \p
* out_buf. Reading is done without the possibility of an exception
* occurring. Returns true if the entire \p size bytes were read;
* otherwise returns false and if \p bytes_read is non-NULL returns the
* partial number of bytes read in \p bytes_read.
* \note See also DR_TRY_EXCEPT().
*/
bool
dr_safe_read(const void *base, size_t size, void *out_buf, size_t *bytes_read);
DR_API
/**
* Safely writes \p size bytes from buffer \p in_buf to address \p
* base. Writing is done without the possibility of an exception
* occurring. Returns true if the entire \p size bytes were written;
* otherwise returns false and if \p bytes_written is non-NULL returns the
* partial number of bytes written in \p bytes_written.
* \note See also DR_TRY_EXCEPT().
*/
bool
dr_safe_write(void *base, size_t size, const void *in_buf, size_t *bytes_written);
DR_API
/** Do not call this directly: use the DR_TRY_EXCEPT macro instead. */
void
dr_try_setup(void *drcontext, void **try_cxt);
DR_API
/** Do not call this directly: use the DR_TRY_EXCEPT macro instead. */
int
dr_try_start(void *buf);
DR_API
/** Do not call this directly: use the DR_TRY_EXCEPT macro instead. */
void
dr_try_stop(void *drcontext, void *try_cxt);
/**
* Simple try..except support for executing operations that might
* fault and recovering if they do. Be careful with this feature
* as it has some limitations:
* - do not use a return within a try statement (we do not have
* language support)
* - any automatic variables that you want to use in the except
* block should be declared volatile
* - no locks should be grabbed in a try statement (because
* there is no finally support to release them)
* - nesting is supported, but finally statements are not
* supported
*
* For fault-free reads in isolation, use dr_safe_read() instead.
* dr_safe_read() out-performs DR_TRY_EXCEPT.
*
* For fault-free writes in isolation, dr_safe_write() can be used,
* although on Windows it invokes a system call and can be less
* performant than DR_TRY_EXCEPT.
*/
#define DR_TRY_EXCEPT(drcontext, try_statement, except_statement) \
do { \
void *try_cxt; \
dr_try_setup(drcontext, &try_cxt); \
if (dr_try_start(try_cxt) == 0) { \
try_statement dr_try_stop(drcontext, try_cxt); \
} else { \
/* roll back first in case except faults or returns */ \
dr_try_stop(drcontext, try_cxt); \
except_statement \
} \
} while (0)
DR_API
/**
* Modifies the memory protections of the region from \p start through
* \p start + \p size. Modification of memory allocated by DR or of
* the DR or client libraries themselves is allowed under the
* assumption that the client knows what it is doing. Modification of
* the ntdll.dll library on Windows is not allowed. Returns true if
* successful.
*/
bool
dr_memory_protect(void *base, size_t size, uint new_prot);
DR_API
/**
* Returns true iff pc is memory allocated by DR for its own
* purposes, and would not exist if the application were run
* natively.
*/
bool
dr_memory_is_dr_internal(const byte *pc);
DR_API
/**
* Returns true iff pc is located inside a client library, an Extension
* library used by a client, or an auxiliary client library (see
* dr_load_aux_library()).
*/
bool
dr_memory_is_in_client(const byte *pc);
#endif /* _DR_OS_UTILS_H_ */