DynamoRIO
|
Operating-system-specific querying routines. More...
Data Structures | |
struct | _dr_app_arg_t |
struct | _dr_os_version_info_t |
struct | _dr_mem_info_t |
Macros | |
#define | DR_MEMPROT_NONE 0x00 |
#define | DR_MEMPROT_READ 0x01 |
#define | DR_MEMPROT_WRITE 0x02 |
#define | DR_MEMPROT_EXEC 0x04 |
#define | DR_MEMPROT_GUARD 0x08 |
#define | DR_MEMPROT_PRETEND_WRITE 0x10 |
#define | DR_MEMPROT_VDSO 0x20 |
#define | PAGE_SIZE dr_page_size() |
#define | PAGE_START(x) (((ptr_uint_t)(x)) & ~(dr_page_size() - 1)) |
#define | DR_TRY_EXCEPT(drcontext, try_statement, except_statement) |
Typedefs | |
typedef struct _dr_app_arg_t | dr_app_arg_t |
typedef struct _dr_os_version_info_t | dr_os_version_info_t |
typedef void * | dr_auxlib_handle_t |
typedef void(* | dr_auxlib_routine_ptr_t) () |
typedef struct _dr_mem_info_t | dr_mem_info_t |
Functions | |
DR_API bool | dr_using_app_state (void *drcontext) |
DR_API void | dr_switch_to_app_state (void *drcontext) |
DR_API void | dr_switch_to_app_state_ex (void *drcontext, dr_state_flags_t flags) |
DR_API void | dr_switch_to_dr_state (void *drcontext) |
DR_API void | dr_switch_to_dr_state_ex (void *drcontext, dr_state_flags_t flags) |
DR_API int | dr_get_app_args (DR_PARAM_OUT dr_app_arg_t *args_array, int args_count) |
DR_API int | dr_num_app_args (void) |
const DR_API char * | dr_app_arg_as_cstring (DR_PARAM_IN dr_app_arg_t *app_arg, char *buf, int buf_size) |
const DR_API char * | dr_get_application_name (void) |
DR_API process_id_t | dr_get_process_id (void) |
DR_API process_id_t | dr_get_process_id_from_drcontext (void *drcontext) |
DR_API process_id_t | dr_get_parent_id (void) |
DR_API bool | dr_get_os_version (dr_os_version_info_t *info) |
DR_API bool | dr_is_wow64 (void) |
DR_API void * | dr_get_app_PEB (void) |
DR_API process_id_t | dr_convert_handle_to_pid (HANDLE process_handle) |
DR_API HANDLE | dr_convert_pid_to_handle (process_id_t pid) |
DR_API dr_auxlib_handle_t | dr_load_aux_library (const char *name, byte **lib_start, byte **lib_end) |
DR_API dr_auxlib_routine_ptr_t | dr_lookup_aux_library_routine (dr_auxlib_handle_t lib, const char *name) |
DR_API bool | dr_unload_aux_library (dr_auxlib_handle_t lib) |
DR_API size_t | dr_page_size (void) |
DR_API bool | dr_memory_is_readable (const byte *pc, size_t size) |
DR_API bool | dr_query_memory (const byte *pc, byte **base_pc, size_t *size, uint *prot) |
DR_API bool | dr_query_memory_ex (const byte *pc, DR_PARAM_OUT dr_mem_info_t *info) |
DR_API size_t | dr_virtual_query (const byte *pc, MEMORY_BASIC_INFORMATION *mbi, size_t mbi_size) |
DR_API bool | dr_safe_read (const void *base, size_t size, void *out_buf, size_t *bytes_read) |
DR_API bool | dr_safe_write (void *base, size_t size, const void *in_buf, size_t *bytes_written) |
DR_API void | dr_try_setup (void *drcontext, void **try_cxt) |
DR_API int | dr_try_start (void *buf) |
DR_API void | dr_try_stop (void *drcontext, void *try_cxt) |
DR_API bool | dr_memory_protect (void *base, size_t size, uint new_prot) |
DR_API bool | dr_memory_is_dr_internal (const byte *pc) |
DR_API bool | dr_memory_is_in_client (const byte *pc) |
Detailed Description
Operating-system-specific querying routines.
Macro Definition Documentation
◆ DR_MEMPROT_EXEC
#define DR_MEMPROT_EXEC 0x04 |
Execute privileges.
◆ DR_MEMPROT_GUARD
#define DR_MEMPROT_GUARD 0x08 |
Guard page (Windows only)
◆ DR_MEMPROT_NONE
#define DR_MEMPROT_NONE 0x00 |
No read, write, or execute privileges.
◆ DR_MEMPROT_PRETEND_WRITE
#define DR_MEMPROT_PRETEND_WRITE 0x10 |
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.
◆ DR_MEMPROT_READ
#define DR_MEMPROT_READ 0x01 |
Read privileges.
◆ DR_MEMPROT_VDSO
#define DR_MEMPROT_VDSO 0x20 |
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).
◆ DR_MEMPROT_WRITE
#define DR_MEMPROT_WRITE 0x02 |
Write privileges.
◆ DR_TRY_EXCEPT
#define DR_TRY_EXCEPT | ( | drcontext, | |
try_statement, | |||
except_statement | |||
) |
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.
◆ PAGE_SIZE
#define PAGE_SIZE dr_page_size() |
Size of a page of memory. This uses a function call so be careful where performance is critical.
◆ PAGE_START
#define PAGE_START | ( | x | ) | (((ptr_uint_t)(x)) & ~(dr_page_size() - 1)) |
Convenience macro to align to the start of a page of memory. It uses a function call so be careful where performance is critical.
Typedef Documentation
◆ dr_app_arg_t
typedef struct _dr_app_arg_t dr_app_arg_t |
Contains information regarding an application's command-line argument.
◆ dr_auxlib_handle_t
typedef void* dr_auxlib_handle_t |
A handle to a loaded client auxiliary library. This is a different type than module_handle_t and is not necessarily the base address.
◆ dr_auxlib_routine_ptr_t
typedef void(* dr_auxlib_routine_ptr_t) () |
An exported routine in a loaded client auxiliary library.
◆ dr_mem_info_t
typedef struct _dr_mem_info_t dr_mem_info_t |
Describes a memory region. Used by dr_query_memory_ex().
◆ dr_os_version_info_t
typedef struct _dr_os_version_info_t dr_os_version_info_t |
Data structure used with dr_get_os_version()
Enumeration Type Documentation
◆ dr_app_arg_encoding_t
◆ dr_mem_type_t
enum dr_mem_type_t |
Flags describing memory used by dr_query_memory_ex().
◆ dr_os_version_t
enum dr_os_version_t |
Windows versions
◆ dr_state_flags_t
enum dr_state_flags_t |
Flags that control the behavior of dr_switch_to_app_state_ex() and dr_switch_to_dr_state_ex().
Enumerator | |
---|---|
DR_STATE_PEB | Switch the PEB pointer. |
DR_STATE_TEB_MISC | Switch miscellaneous TEB fields. |
DR_STATE_STACK_BOUNDS | Switch the TEB stack bounds fields. |
DR_STATE_ALL | Switch all state. |
Function Documentation
◆ dr_app_arg_as_cstring()
const DR_API char* dr_app_arg_as_cstring | ( | DR_PARAM_IN dr_app_arg_t * | app_arg, |
char * | buf, | ||
int | buf_size | ||
) |
Returns the passed argument app_arg
as a string. buf
is used only if needed, and therefore the caller should not assume that the string is in the buf
. In other words, always use the returned value to refer to the string. Returns NULL on error such as when buf
is needed as storage and the size of the buffer 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.
- An error code may be obtained via dr_get_error_code() when this routine fails.
◆ dr_convert_handle_to_pid()
DR_API process_id_t dr_convert_handle_to_pid | ( | HANDLE | process_handle | ) |
Converts a process handle to a process id.
- Returns
- Process id if successful; INVALID_PROCESS_ID on failure.
- Note
- Windows only.
◆ dr_convert_pid_to_handle()
DR_API HANDLE dr_convert_pid_to_handle | ( | process_id_t | pid | ) |
Converts a process id to a process handle.
- Returns
- Process handle if successful; INVALID_HANDLE_VALUE on failure.
- Note
- Windows only.
◆ dr_get_app_args()
DR_API int dr_get_app_args | ( | DR_PARAM_OUT dr_app_arg_t * | args_array, |
int | args_count | ||
) |
Provides information about the app's arguments by setting args_array
up to the count denoted by args_count
. Therefore, args_count
is not the size of the buffer in bytes but the number of dr_app_arg_t values that 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.
- An error code may be obtained via dr_get_error_code() when this routine fails.
◆ dr_get_app_PEB()
DR_API void* dr_get_app_PEB | ( | void | ) |
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.
◆ dr_get_application_name()
const DR_API char* dr_get_application_name | ( | void | ) |
Returns the image name (without path) of the current application.
◆ dr_get_os_version()
DR_API bool dr_get_os_version | ( | dr_os_version_info_t * | info | ) |
Returns information about the version of the operating system. Returns whether successful.
- Note
- Windows only.
- 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.
◆ dr_get_parent_id()
DR_API process_id_t dr_get_parent_id | ( | void | ) |
Returns the process id of the parent of the current process.
- Note
- Linux only.
◆ dr_get_process_id()
DR_API process_id_t dr_get_process_id | ( | void | ) |
Returns the process id of the current process.
◆ dr_get_process_id_from_drcontext()
DR_API process_id_t dr_get_process_id_from_drcontext | ( | void * | drcontext | ) |
Returns the process id of the process associated with drcontext 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.
◆ dr_is_wow64()
DR_API bool dr_is_wow64 | ( | void | ) |
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.
◆ dr_load_aux_library()
DR_API dr_auxlib_handle_t dr_load_aux_library | ( | const char * | name, |
byte ** | lib_start, | ||
byte ** | lib_end | ||
) |
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_lookup_aux_library_routine()
DR_API dr_auxlib_routine_ptr_t dr_lookup_aux_library_routine | ( | dr_auxlib_handle_t | lib, |
const char * | name | ||
) |
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_memory_is_dr_internal()
DR_API bool dr_memory_is_dr_internal | ( | const byte * | pc | ) |
Returns true iff pc is memory allocated by DR for its own purposes, and would not exist if the application were run natively.
◆ dr_memory_is_in_client()
DR_API bool dr_memory_is_in_client | ( | const byte * | pc | ) |
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()).
◆ dr_memory_is_readable()
DR_API bool dr_memory_is_readable | ( | const byte * | pc, |
size_t | size | ||
) |
Checks to see that all bytes with addresses in the range [pc
, pc
+ 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.
- 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.
◆ dr_memory_protect()
DR_API bool dr_memory_protect | ( | void * | base, |
size_t | size, | ||
uint | new_prot | ||
) |
Modifies the memory protections of the region from start
through start
+ 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.
◆ dr_num_app_args()
DR_API int dr_num_app_args | ( | void | ) |
Returns the number of command-line arguments passed to the application.
- Note
- Currently, this function is only available on Unix with early injection.
- An error code may be obtained via dr_get_error_code() when this routine fails.
◆ dr_page_size()
DR_API size_t dr_page_size | ( | void | ) |
Returns the size of a page of memory.
◆ dr_query_memory()
DR_API bool dr_query_memory | ( | const byte * | pc, |
byte ** | base_pc, | ||
size_t * | size, | ||
uint * | prot | ||
) |
An os neutral method for querying a memory address. Returns true iff a memory region containing pc
is found. If found additional information about the memory region is returned in the optional out arguments base_pc
, size
, and prot
where base_pc
is the start address of the memory region continaing pc
, size
is the size of said memory region and 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.
-
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
prot
.
◆ dr_query_memory_ex()
DR_API bool dr_query_memory_ex | ( | const byte * | pc, |
DR_PARAM_OUT dr_mem_info_t * | info | ||
) |
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 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.
-
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
info->prot
.
◆ dr_safe_read()
DR_API bool dr_safe_read | ( | const void * | base, |
size_t | size, | ||
void * | out_buf, | ||
size_t * | bytes_read | ||
) |
Safely reads size
bytes from address base
into buffer out_buf
. Reading is done without the possibility of an exception occurring. Returns true if the entire size
bytes were read; otherwise returns false and if bytes_read
is non-NULL returns the partial number of bytes read in bytes_read
.
- Note
- See also DR_TRY_EXCEPT().
◆ dr_safe_write()
DR_API bool dr_safe_write | ( | void * | base, |
size_t | size, | ||
const void * | in_buf, | ||
size_t * | bytes_written | ||
) |
Safely writes size
bytes from buffer in_buf
to address base
. Writing is done without the possibility of an exception occurring. Returns true if the entire size
bytes were written; otherwise returns false and if bytes_written
is non-NULL returns the partial number of bytes written in bytes_written
.
- Note
- See also DR_TRY_EXCEPT().
◆ dr_switch_to_app_state()
DR_API void dr_switch_to_app_state | ( | void * | drcontext | ) |
Equivalent to dr_switch_to_app_state_ex(drcontext, DR_STATE_ALL).
◆ dr_switch_to_app_state_ex()
DR_API void dr_switch_to_app_state_ex | ( | void * | drcontext, |
dr_state_flags_t | flags | ||
) |
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 flags
argument allows selecting a subset of the state to swap.
◆ dr_switch_to_dr_state()
DR_API void dr_switch_to_dr_state | ( | void * | drcontext | ) |
Equivalent to dr_switch_to_dr_state_ex(drcontext, DR_STATE_ALL).
◆ dr_switch_to_dr_state_ex()
DR_API void dr_switch_to_dr_state_ex | ( | void * | drcontext, |
dr_state_flags_t | flags | ||
) |
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.
◆ dr_try_setup()
DR_API void dr_try_setup | ( | void * | drcontext, |
void ** | try_cxt | ||
) |
Do not call this directly: use the DR_TRY_EXCEPT macro instead.
◆ dr_try_start()
DR_API int dr_try_start | ( | void * | buf | ) |
Do not call this directly: use the DR_TRY_EXCEPT macro instead.
◆ dr_try_stop()
DR_API void dr_try_stop | ( | void * | drcontext, |
void * | try_cxt | ||
) |
Do not call this directly: use the DR_TRY_EXCEPT macro instead.
◆ dr_unload_aux_library()
DR_API bool dr_unload_aux_library | ( | dr_auxlib_handle_t | lib | ) |
Unloads the given library, which must have been loaded by dr_load_aux_library(). Returns whether successful.
◆ dr_using_app_state()
DR_API bool dr_using_app_state | ( | void * | drcontext | ) |
Returns whether the given thread indicated by drcontext
is currently using the application version of its system 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.
◆ dr_virtual_query()
DR_API size_t dr_virtual_query | ( | const byte * | pc, |
MEMORY_BASIC_INFORMATION * | mbi, | ||
size_t | mbi_size | ||
) |
Equivalent to the win32 API function VirtualQuery(). See that routine for a description of arguments and return values.
- Note
- Windows only.
- 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.