blob: 3daab1907b5c5341f40e9767780d537e09fcf750 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2010-2014 Google, Inc. All rights reserved.
* Copyright (c) 2002-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.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2002-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2002 Hewlett-Packard Company */
/*
* instrument.h - interface for instrumentation
*/
#ifndef _INSTRUMENT_H_
#define _INSTRUMENT_H_ 1
#include "../globals.h"
#include "../module_shared.h"
#include "arch.h"
#include "instr.h"
#include "dr_config.h"
/* xref _USES_DR_VERSION_ in dr_api.h (PR 250952) and compatibility
* check in instrument.c (OLDEST_COMPATIBLE_VERSION, etc.).
* this is defined outside of CLIENT_INTERFACE b/c it's used for
* a general tracedump version as well.
*/
#define CURRENT_API_VERSION VERSION_NUMBER_INTEGER
#ifdef CLIENT_INTERFACE
/* DR_API EXPORT TOFILE dr_events.h */
/* DR_API EXPORT BEGIN */
#ifdef API_EXPORT_ONLY
#include "dr_config.h"
#endif
/**************************************************
* ROUTINES TO REGISTER EVENT CALLBACKS
*/
/**
* @file dr_events.h
* @brief Event callback registration routines.
*/
/* DR_API EXPORT END */
DR_API
/**
* Registers a callback function for the process exit event. DR calls \p
* func when the process exits. By default, the process exit event will be
* executed with only a single live thread. dr_set_process_exit_behavior()
* can provide superior exit performance for clients that have flexible
* exit event requirements.
*
* On Linux, SYS_execve does NOT result in an exit event, but it WILL
* result in the client library being reloaded and its dr_init()
* routine being called.
*/
void
dr_register_exit_event(void (*func)(void));
DR_API
/**
* Unregister a callback function for the process exit event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_exit_event(void (*func)(void));
/* DR_API EXPORT TOFILE dr_events.h */
/* DR_API EXPORT BEGIN */
/**
* Flags controlling the behavior of basic blocks and traces when emitted
* into the code cache. These flags are bitmasks that can be combined by
* or-ing together. For multiple clients, the flags returned by each
* client are or-ed together.
*/
typedef enum {
/** Emit as normal. */
DR_EMIT_DEFAULT = 0,
/**
* Store translation information at emit time rather than calling
* the basic block or trace event later to recreate the
* information. Note that even if a standalone basic block has
* stored translations, if when it is added to a trace it does not
* request storage (and the trace callback also does not request
* storage) then the basic block callback may still be called to
* translate for the trace.
*
* \sa #dr_register_bb_event()
*/
DR_EMIT_STORE_TRANSLATIONS = 0x01,
/**
* Only valid when applied to a basic block. Indicates that the
* block is eligible for persisting to a persistent code cache
* file on disk. By default, no blocks are eligible, as tools
* must take care in order to properly support persistence.
* Note that the block is not guaranteed to be persisted if
* it contains complex features that prevent DR from
* easily persisting it.
*/
DR_EMIT_PERSISTABLE = 0x02,
/**
* Only valid when applied to a basic block. Indicates that the
* block must terminate a trace. Normally this should be set when
* an abnormal exit is used from the block that is incompatible with
* trace building's attempt to inline the continuation from the block
* to its successor. Note that invoking dr_redirect_execution() from a
* clean call called from a block aborts trace building and thus this
* flag need not be set for that scenario.
*/
DR_EMIT_MUST_END_TRACE = 0x04,
/**
* Requests that DR relinquish control of the current thread and
* let it run natively until the client indicates that DR should
* take over again. While native, on Windows, currently only the
* thread init event (dr_register_thread_init_event()) will be
* raised, and nothing on Linux: no events will occur in the
* native thread. On Windows, DR tries to monitor any actions a
* native thread might take that affect correct execution from the
* code cache, but running natively carries risks. Consider this
* feature experimental, particularly on Linux.
*/
DR_EMIT_GO_NATIVE = 0x08,
} dr_emit_flags_t;
/* DR_API EXPORT END */
DR_API
/**
* Registers a callback function for the basic block event. DR calls
* \p func before inserting a new basic block into the code cache.
* When adding a basic block to a new trace, DR calls \p func again
* with \p for_trace set to true, giving the client the opportunity to
* keep its same instrumentation in the trace, or to change it. The
* original basic block's instrumentation is unchanged by whatever
* action is taken in the \p for_trace call.
*
* DR constructs <em>dynamic basic blocks</em>, which are distinct
* from a compiler's classic basic blocks. DR does not know all entry
* points ahead of time, and will end up duplicating the tail of a
* basic block if a later entry point is discovered that targets the
* middle of a block created earlier, or if a later entry point
* targets straight-line code that falls through into code already
* present in a block.
*
* DR may call \p func again if it needs to translate from code cache
* addresses back to application addresses, which happens on faulting
* instructions as well as in certain situations involving suspended
* threads or forcibly relocated threads. The \p translating
* parameter distinguishes the two types of calls and is further
* explained below.
*
* - \p drcontext is a pointer to the input program's machine context.
* Clients should not inspect or modify the context; it is provided as
* an opaque pointer (i.e., <tt>void *</tt>) to be passed to API
* routines that require access to this internal data.
* drcontext is specific to the current thread, but in normal
* configurations the basic block being created is thread-shared: thus,
* when allocating data structures with the same lifetime as the
* basic block, usually global heap (#dr_global_alloc()) is a better
* choice than heap tied to the thread that happened to first create
* the basic block (#dr_thread_alloc()). Thread-private heap is fine
* for temporary structures such as instr_t and instrlist_t.
*
* - \p tag is a unique identifier for the basic block fragment.
* Use dr_fragment_app_pc() to translate it to an application address.
* - \p bb is a pointer to the list of instructions that comprise the
* basic block. Clients can examine, manipulate, or completely
* replace the instructions in the list.
*
* - \p translating indicates whether this callback is for basic block
* creation (false) or is for address translation (true). This is
* further explained below.
*
* \return a #dr_emit_flags_t flag.
*
* The user is free to inspect and modify the block before it
* executes, but must adhere to the following restrictions:
* - If there is more than one application branch, only the last can be
* conditional.
* - An application conditional branch must be the final
* instruction in the block.
* - An application direct call must be the final
* instruction in the block unless it is inserted by DR for elision and the
* subsequent instructions are the callee.
* - There can only be one indirect branch (call, jump, or return) in
* a basic block, and it must be the final instruction in the
* block.
* - There can only be one far branch (call, jump, or return) in
* a basic block, and it must be the final instruction in the
* block.
* - The exit control-flow of a block ending in a system call or
* int instruction cannot be changed, nor can instructions be inserted
* after the system call or int instruction itself, unless
* the system call or int instruction is removed entirely.
* - The number of an interrupt cannot be changed. (Note that the
* parameter to a system call, normally kept in the eax register, can
* be freely changed in a basic block: but not in a trace.)
* - A system call or interrupt instruction can only be added
* if it satisfies the above constraints: i.e., if it is the final
* instruction in the block and the only system call or interrupt.
* - The block's application source code (as indicated by the
* translation targets, set by #instr_set_translation()) must remain
* within the original bounds of the block (the one exception to this
* is that a jump can translate to its target). Otherwise, DR's cache
* consistency algorithms cannot guarantee to properly invalidate the
* block if the source application code is modified. To send control
* to other application code regions, truncate the block and use a
* direct jump to target the desired address, which will then
* materialize in the subsequent block, rather than embedding the
* desired instructions in this block.
* - There is a limit on the size of a basic block in the code cache.
* DR performs its own modifications, especially on memory writes for
* cache consistency of self-modifying (or false sharing) code
* regions. If an assert fires in debug build indicating a limit was
* reached, either truncate blocks or use the -max_bb_instrs runtime
* option to ask DR to make them smaller.
*
* To support transparent fault handling, DR must translate a fault in the
* code cache into a fault at the corresponding application address. DR
* must also be able to translate when a suspended thread is examined by
* the application or by DR itself for internal synchronization purposes.
* If the client is only adding observational instrumentation (i.e., meta
* instructions: see #instr_set_meta()) (which should not fault) and
* is not modifying, reordering, or removing application instructions,
* these details can be ignored. In that case the client should return
* #DR_EMIT_DEFAULT and set up its basic block callback to be deterministic
* and idempotent. If the client is performing modifications, then in
* order for DR to properly translate a code cache address the client must
* use #instr_set_translation() in the basic block creation callback to set
* the corresponding application address (the address that should be
* presented to the application as the faulting address, or the address
* that should be restarted after a suspend) for each modified instruction
* and each added application instruction (see #instr_set_app()).
*
* There are two methods for using the translated addresses:
*
* -# Return #DR_EMIT_STORE_TRANSLATIONS from the basic block creation
* callback. DR will then store the translation addresses and use
* the stored information on a fault. The basic block callback for
* \p tag will not be called with \p translating set to true. Note
* that unless #DR_EMIT_STORE_TRANSLATIONS is also returned for \p
* for_trace calls (or #DR_EMIT_STORE_TRANSLATIONS is returned in
* the trace callback), each constituent block comprising the trace
* will need to be re-created with both \p for_trace and \p
* translating set to true. Storing translations uses additional
* memory that can be significant: up to 20% in some cases, as it
* prevents DR from using its simple data structures and forces it
* to fall back to its complex, corner-case design. This is why DR
* does not store all translations by default.
* -# Return #DR_EMIT_DEFAULT from the basic block creation callback.
* DR will then call the callback again during fault translation
* with \p translating set to true. All modifications to \p bb
* that were performed on the creation callback must be repeated on
* the translating callback. This option is only possible when
* basic block modifications are deterministic and idempotent, but
* it saves memory. Naturally, global state changes triggered by
* block creation should be wrapped in checks for \p translating
* being false. Even in this case, #instr_set_translation() should
* be called for application instructions even when \p translating is
* false, as DR may decide to store the translations at creation
* time for reasons of its own.
*
* Furthermore, if the client's modifications change any part of the
* machine state besides the program counter, the client should use
* #dr_register_restore_state_event() or
* #dr_register_restore_state_ex_event() to restore the registers and
* application memory to their original application values.
*
* For meta instructions that do not reference application memory
* (i.e., they should not fault), leave the translation field as NULL.
* A NULL value instructs DR to use the subsequent application
* instruction's translation as the application address, and to fail
* when translating the full state. Since the full state will only be
* needed when relocating a thread (as stated, there will not be a
* fault here), failure indicates that this is not a valid relocation
* point, and DR's thread synchronization scheme will use another
* spot. If the translation field is set to a non-NULL value, the
* client should be willing to also restore the rest of the machine
* state at that point (restore spilled registers, etc.) via
* #dr_register_restore_state_event() or
* #dr_register_restore_state_ex_event(). This is necessary for meta
* instructions that reference application memory. DR takes care of
* such potentially-faulting instructions added by its own API
* routines (#dr_insert_clean_call() arguments that reference
* application data, #dr_insert_mbr_instrumentation()'s read of
* application indirect branch data, etc.)
*
* \note In order to present a more straightforward code stream to clients,
* this release of DR disables several internal optimizations. As a result,
* some applications may see a performance degradation. Applications making
* heavy use of system calls are the most likely to be affected.
* Future releases may allow clients some control over performance versus
* visibility. The \ref op_speed "-opt_speed" option can regain some
* of this performance at the cost of more complex basic blocks that
* cross control transfers.
*
* \note If multiple clients are present, the instruction list for a
* basic block passed to earlier-registered clients will contain the
* instrumentation and modifications put in place by later-registered
* clients.
*
* \note Basic blocks can be deleted due to hitting capacity limits or
* cache consistency events (when the source application code of a
* basic block is modified). In that case, the client will see a new
* basic block callback if the block is then executed again after
* deletion. The deletion event (#dr_register_delete_event()) will be
* raised at deletion time.
*
* \note If the -thread_private runtime option is specified, clients
* should expect to see duplicate tags for separate threads, albeit
* with different dcrcontext values. Additionally, DR employs a
* cache-sizing algorithm for thread private operation that
* proactively deletes fragments. Even with thread-shared caches
* enabled, however, certain situations cause DR to emit
* thread-private basic blocks (e.g., self-modifying code). In this
* case, clients should be prepared to see duplicate tags without an
* intermediate deletion.
*
* \note A client can change the control flow of the application by
* changing the control transfer instruction at end of the basic block.
* If a basic block is ended with a non-control transfer instruction,
* an application jump instruction can be inserted.
* If a basic block is ended with a conditional branch,
* \p instrlist_set_fall_through_target can be used to change the
* fall-through target.
* If a basic block is ended with a call instruction,
* \p instrlist_set_return_target can be used to change the return
* target of the call.
*/
void
dr_register_bb_event(dr_emit_flags_t (*func)
(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating));
DR_API
/**
* Unregister a callback function for the basic block event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*
* \note We do not recommend unregistering for the basic block event
* unless it aways returned #DR_EMIT_STORE_TRANSLATIONS (including
* when \p for_trace is true, or if the client has a trace creation
* callback that returns #DR_EMIT_STORE_TRANSLATIONS). Unregistering
* can prevent proper state translation on a later fault or other
* translation event for this basic block or for a trace that includes
* this basic block. Instead of unregistering, turn the event
* callback into a nop.
*/
bool
dr_unregister_bb_event(dr_emit_flags_t (*func)
(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating));
DR_API
/**
* Registers a callback function for the trace event. DR calls \p func
* before inserting a new trace into the code cache. DR may call \p func
* again if it needs to translate from code cache addresses back to
* application addresses, which happens on faulting instructions as well as
* in certain situations involving suspended threads or forcibly relocated
* threads. The \p translating parameter distinguishes the two types of
* calls and behaves identically to the same parameter in the basic
* block callback: see #dr_register_bb_event() for further details.
*
* Traces are not built if the -disable_traces runtime option
* is specified.
*
* - \p drcontext is a pointer to the input program's machine context.
* Clients should not inspect or modify the context; it is provided as
* an opaque pointer (i.e., <tt>void *</tt>) to be passed to API
* routines that require access to this internal data.
* - \p tag is a unique identifier for the trace fragment.
* - \p trace is a pointer to the list of instructions that comprise the
* trace.
* - \p translating indicates whether this callback is for trace creation
* (false) or is for fault address recreation (true). This is further
* explained below.
*
* \return a #dr_emit_flags_t flag.
*
* The user is free to inspect and modify the non-control-flow
* instructions in the trace before it
* executes, with certain restrictions
* that include those for basic blocks (see dr_register_bb_event()).
* Additional restrictions unique to traces also apply:
* - The sequence of blocks composing the trace cannot be changed once
* the trace is created. Instead, modify the component blocks by
* changing the block continuation addresses in the basic block callbacks
* (called with \p for_trace set to true) as the trace is being built.
* - The (application) control flow instruction (if any) terminating each
* component block cannot be changed.
* - Application control flow instructions cannot be added.
* - The parameter to a system call, normally kept in the eax register,
* cannot be changed.
* - A system call or interrupt instruction cannot be added.
* - If both a floating-point state save instruction (fnstenv, fnsave,
* fxsave, xsave, or xsaveopt) and a prior regular floating-point
* instruction are present, the regular instruction cannot be
* removed.
*
* If hitting a size limit due to extensive instrumentation, reduce
* the -max_trace_bbs option to start with a smaller trace.
*
* The basic block restrictions on modifying application source code
* apply to traces as well. If the user wishes to change which basic
* blocks comprise the trace, either the
* #dr_register_end_trace_event() should be used or the \p for_trace
* basic block callbacks should modify their continuation addresses
* via direct jumps.
*
* All of the comments for #dr_register_bb_event() regarding
* transparent fault handling and state translation apply to the trace
* callback as well. Please read those comments carefully.
*
* \note As each basic block is added to a new trace, the basic block
* callback (see #dr_register_bb_event()) is called with its \p
* for_trace parameter set to true. In order to preserve basic block
* instrumentation inside of traces, a client need only act
* identically with respect to the \p for_trace parameter; it can
* ignore the trace event if its goal is to place instrumentation
* on all code.
*
* \note Certain control flow modifications applied to a basic block
* can prevent it from becoming part of a trace: e.g., adding
* additional application control transfers.
*
* \note If multiple clients are present, the instruction list for a
* trace passed to earlier-registered clients will contain the
* instrumentation and modifications put in place by later-registered
* clients; similarly for each constituent basic block.
*
* \note Traces can be deleted due to hitting capacity limits or cache
* consistency events (when the source application code of a trace is
* modified). In that case, the client will see a new trace callback
* if a new trace containing that code is created again after
* deletion. The deletion event (#dr_register_delete_event()) will be
* raised at deletion time.
*/
void
dr_register_trace_event(dr_emit_flags_t (*func)
(void *drcontext, void *tag, instrlist_t *trace,
bool translating));
DR_API
/**
* Unregister a callback function for the trace event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*
* \note We do not recommend unregistering for the trace event unless it
* always returned #DR_EMIT_STORE_TRANSLATIONS, as doing so can prevent
* proper state translation on a later fault or other translation event.
* Instead of unregistering, turn the event callback into a nop.
*/
bool
dr_unregister_trace_event(dr_emit_flags_t (*func)
(void *drcontext, void *tag, instrlist_t *trace,
bool translating));
#ifdef CUSTOM_TRACES
/* DR_API EXPORT BEGIN */
/**
* DR will call the end trace event if it is registered prior to
* adding each basic block to a trace being generated. The return
* value of the event callback should be from the
* dr_custom_trace_action_t enum.
*
* \note DR treats CUSTOM_TRACE_CONTINUE as an advisement only. Certain
* fragments are not suitable to be included in a trace and if DR runs
* into one it will end the trace regardless of what the client returns
* through the event callback.
*/
typedef enum {
CUSTOM_TRACE_DR_DECIDES,
CUSTOM_TRACE_END_NOW,
CUSTOM_TRACE_CONTINUE
} dr_custom_trace_action_t;
/* DR_API EXPORT END */
DR_API
/**
* Registers a callback function for the end-trace event. DR calls \p
* func before extending a trace with a new basic block. The \p func
* should return one of the #dr_custom_trace_action_t enum values.
*/
void
dr_register_end_trace_event(dr_custom_trace_action_t (*func)
(void *drcontext, void *tag, void *next_tag));
DR_API
/**
* Unregister a callback function for the end-trace event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_end_trace_event(dr_custom_trace_action_t (*func)
(void *drcontext, void *tag, void *next_tag));
#endif
/* For the new-bb-before-deletion-event problem (PR 495787, and
* described in the comment below):
* Note that we do not want a new "unreachable event" b/c clients need
* to keep bb info around in case the semi-flushed bb hits a fault.
* The main worry w/ the counter approach, in addition to ensuring
* it handles duplicates due to thread-private, is that can we
* guarantee that deletion events will be in order, or can a new
* fragment be deleted prior to older fragments? For most clients
* it won't matter I suppose.
*/
DR_API
/**
* Registers a callback function for the fragment deletion event. DR
* calls \p func whenever it removes a fragment from the code cache.
* Due to DR's high-performance non-precise flushing, a fragment
* can be made inaccessible but not actually freed for some time.
* A new fragment can thus be created before the deletion event
* for the old fragment is raised. We recommended using a counter
* to ignore subsequent deletion events when using per-fragment
* data structures and duplicate fragments are seen.
*
* \note drcontext may be NULL when thread-shared fragments are being
* deleted during process exit. For this reason, thread-private
* heap should not be used for data structures intended to be freed
* at thread-shared fragment deletion.
*/
void
dr_register_delete_event(void (*func)(void *drcontext, void *tag));
DR_API
/**
* Unregister a callback function for the fragment deletion event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_delete_event(void (*func)(void *drcontext, void *tag));
DR_API
/**
* Registers a callback function for the machine state restoration event.
* DR calls \p func whenever it needs to translate a code cache machine
* context from the code cache to its corresponding original application
* context. DR needs to translate when instructions fault in the cache as
* well as when a suspended thread is examined or relocated for internal
* purposes.
*
* If a client is only adding instrumentation (meta-code: see
* #instr_is_meta()) that does not reference application memory,
* and is not reordering or removing application instructions, then it
* need not register for this event. If, however, a client is
* modifying application code or is adding code that can fault, the
* client must be capable of restoring the original context.
*
* When DR needs to translate a code cache context, DR recreates the
* faulting instruction's containing fragment, storing translation
* information along the way, by calling the basic block and/or trace event
* callbacks with the \p translating parameter set to true. DR uses the
* recreated code to identify the application instruction (\p mcontext.pc)
* corresponding to the faulting code cache instruction. If the client
* asked to store translation information by returning
* #DR_EMIT_STORE_TRANSLATIONS from the basic block or trace event
* callback, then this step of re-calling the event callback is skipped and
* the stored value is used as the application address (\p mcontext.pc).
*
* DR then calls the fault state restoration event to allow the client
* to restore the registers and application memory to their proper
* values as they would have appeared if the original application code
* had been executed up to the \p mcontext.pc instruction. Memory
* should only be restored if the \p restore_memory parameter is true;
* if it is false, DR may only be querying for the address (\p
* mcontext.pc) or register state and may not relocate this thread.
*
* The \p app_code_consistent parameter indicates whether the original
* application code containing the instruction being translated is
* guaranteed to still be in the same state it was when the code was
* placed in the code cache. This guarantee varies depending on the
* type of cache consistency being used by DR.
*
* The client can update \p mcontext.pc in this callback. The client
* should not change \p mcontext.flags: it should remain DR_MC_ALL.
*
* \note The passed-in \p drcontext may correspond to a different thread
* than the thread executing the callback. Do not assume that the
* executing thread is the target thread.
*/
void
dr_register_restore_state_event(void (*func)
(void *drcontext, void *tag, dr_mcontext_t *mcontext,
bool restore_memory, bool app_code_consistent));
DR_API
/**
* Unregister a callback function for the machine state restoration event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_restore_state_event(void (*func)
(void *drcontext, void *tag, dr_mcontext_t *mcontext,
bool restore_memory, bool app_code_consistent));
/* DR_API EXPORT BEGIN */
/**
* Data structure passed within dr_exception_t, dr_siginfo_t, and
* dr_restore_state_info_t.
* Contains information about the code fragment inside the code cache
* at the exception/signal/translation interruption point.
*/
typedef struct _dr_fault_fragment_info_t {
/**
* The tag of the code fragment inside the code cache at the
* exception/signal/translation interruption point. NULL for
* interruption not in the code cache.
*/
void *tag;
/**
* The start address of the code fragment inside the code cache at
* the exception/signal/translation interruption point. NULL for interruption
* not in the code cache. Clients are cautioned when examining
* code cache instructions to not rely on any details of code
* inserted other than their own.
*/
byte *cache_start_pc;
/** Indicates whether the interrupted code fragment is a trace */
bool is_trace;
/**
* Indicates whether the original application code containing the
* code corresponding to the exception/signal/translation interruption point
* is guaranteed to still be in the same state it was when the
* code was placed in the code cache. This guarantee varies
* depending on the type of cache consistency being used by DR.
*/
bool app_code_consistent;
} dr_fault_fragment_info_t;
/**
* Data structure passed to a restore_state_ex event handler (see
* dr_register_restore_state_ex_event()). Contains the machine
* context at the translation point and other translation
* information.
*/
typedef struct _dr_restore_state_info_t {
/**
* The application machine state at the translation point.
* The client can update register values and the program counter
* by changing this context. The client should not change \p
* mcontext.flags: it should remain DR_MC_ALL.
*/
dr_mcontext_t *mcontext;
/** Whether raw_mcontext is valid. */
bool raw_mcontext_valid;
/**
* The raw pre-translated machine state at the translation
* interruption point inside the code cache. Clients are
* cautioned when examining code cache instructions to not rely on
* any details of code inserted other than their own.
* Modifying this context will not affect the translation.
*/
dr_mcontext_t *raw_mcontext;
/**
* Information about the code fragment inside the code cache
* at the translation interruption point.
*/
dr_fault_fragment_info_t fragment_info;
} dr_restore_state_info_t;
/* DR_API EXPORT END */
DR_API
/**
* Registers a callback function for the machine state restoration
* event with extended information.
*
* This event is identical to that for dr_register_restore_state_event()
* with the following exceptions:
*
* - Additional information is provided in the
* dr_restore_state_info_t structure, including the pre-translation
* context (containing the address inside the code cache of the
* translation point) and the starting address of the containing
* fragment in the code cache. Certain registers may not contain
* proper application values in \p info->raw_mcontext. Clients are
* cautioned against relying on any details of code cache layout or
* register usage beyond instrumentation inserted by the client
* itself when examining \p info->raw_mcontext.
*
* - The callback function returns a boolean indicating the success of
* the translation. When DR is translating not for a fault but for
* thread relocation, the \p restore_memory parameter will be false.
* Such translation can target a meta-instruction that can fault
* (i.e., it has a non-NULL translation field). For that scenario, a client
* can choose not to translate. Such instructions do not always
* require full translation for faults, and allowing translation
* failure removes the requirement that a client must translate at
* all such instructions. Note, however, that returning false can
* cause performance degradation as DR must then resume the thread
* and attempt to re-suspend it at a safer spot. Clients must
* return true for translation points in application code in order
* to avoid catastropic failure to suspend, and should thus identify
* whether translation points are inside their own instrumentation
* before returning false. Translation for relocation will never
* occur in meta instructions, so clients only need to look for
* meta-may-fault instructions. Clients should never return false
* when \p restore_memory is true.
*
* - If multiple callbacks are registered, the first one that returns
* false will short-circuit event delivery to later callbacks.
*/
void
dr_register_restore_state_ex_event(bool (*func) (void *drcontext, bool restore_memory,
dr_restore_state_info_t *info));
DR_API
/**
* Unregister a callback function for the machine state restoration
* event with extended ifnormation. \return true if unregistration is
* successful and false if it is not (e.g., \p func was not
* registered).
*/
bool
dr_unregister_restore_state_ex_event(bool (*func) (void *drcontext, bool restore_memory,
dr_restore_state_info_t *info));
DR_API
/**
* Registers a callback function for the thread initialization event.
* DR calls \p func whenever the application creates a new thread.
*/
void
dr_register_thread_init_event(void (*func)(void *drcontext));
DR_API
/**
* Unregister a callback function for the thread initialization event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_thread_init_event(void (*func)(void *drcontext));
DR_API
/**
* Registers a callback function for the thread exit event. DR calls
* \p func whenever an application thread exits. The passed-in
* drcontext should be used instead of calling
* dr_get_current_drcontext(), as the thread exit event may be invoked
* from other threads, and using dr_get_current_drcontext() can result
* in failure to clean up the right resources, and at process exit
* time it may return NULL.
*
* See dr_set_process_exit_behavior() for options controlling performance
* and whether thread exit events are invoked at process exit time in
* release build.
*/
void
dr_register_thread_exit_event(void (*func)(void *drcontext));
DR_API
/**
* Unregister a callback function for the thread exit event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_thread_exit_event(void (*func)(void *drcontext));
/* DR_API EXPORT TOFILE dr_events.h */
/* DR_API EXPORT BEGIN */
/**
* Flags controlling thread behavior at process exit time in release build.
* See dr_set_process_exit_behavior() for further details.
*/
typedef enum {
/**
* Do not guarantee that the process exit event is executed
* single-threaded. This is equivalent to specifying the \p
* -multi_thread_exit runtime option. Setting this flag can improve
* process exit performance, but usually only when the
* #DR_EXIT_SKIP_THREAD_EXIT flag is also set, or when no thread exit
* events are registered.
*/
DR_EXIT_MULTI_THREAD = 0x01,
/**
* Do not invoke thread exit event callbacks at process exit time.
* Thread exit event callbacks will still be invoked at other times.
* This is equivalent to setting the \p -skip_thread_exit_at_exit
* runtime option. Setting this flag can improve process exit
* performance, but usually only when the #DR_EXIT_MULTI_THREAD flag is
* also set, or when no process exit event is registered.
*/
DR_EXIT_SKIP_THREAD_EXIT = 0x02,
} dr_exit_flags_t;
/* DR_API EXPORT END */
DR_API
/**
* Specifies how process exit should be handled with respect to thread exit
* events and thread synchronization in release build. In debug build, and
* in release build by default, all threads are always synchronized at exit
* time, resulting in a single-threaded process exit event, and all thread
* exit event callbacks are always called. This routine can provide more
* performant exits in release build by avoiding the synchronization if the
* client is willing to skip thread exit events at process exit and is
* willing to execute its process exit event with multiple live threads.
*/
void
dr_set_process_exit_behavior(dr_exit_flags_t flags);
#ifdef UNIX
DR_API
/**
* Registers a callback function for the fork event. DR calls \p func
* whenever the application forks a new process.
* \note Valid on Linux only.
*/
void
dr_register_fork_init_event(void (*func)(void *drcontext));
DR_API
/**
* Unregister a callback function for the fork event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_fork_init_event(void (*func)(void *drcontext));
#endif
DR_API
/**
* Registers a callback function for the module load event. DR calls
* \p func whenever the application loads a module. The \p loaded
* parameter indicates whether the module is about to be loaded (the
* normal case) or is already loaded (if the module was already there
* at the time DR initialized). \note The client should be aware that
* if the module is being loaded it may not be fully processed by the
* loader (relocating, rebinding and on Linux segment remapping may
* have not yet occurred). \note The module_data_t \p *info passed
* to the callback routine is valid only for the duration of the
* callback and should not be freed; a persistent copy can be made with
* dr_copy_module_data().
*/
void
dr_register_module_load_event(void (*func)(void *drcontext, const module_data_t *info,
bool loaded));
DR_API
/**
* Unregister a callback for the module load event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_module_load_event(void (*func)(void *drcontext, const module_data_t *info,
bool loaded));
DR_API
/**
* Registers a callback function for the module unload event. DR
* calls \p func whenever the application unloads a module.
* \note The module_data_t \p *info passed to
* the callback routine is valid only for the duration of the callback
* and should not be freed; a persistent copy can be made with
* dr_copy_module_data().
*/
void
dr_register_module_unload_event(void (*func)(void *drcontext,
const module_data_t *info));
DR_API
/**
* Unregister a callback function for the module unload event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_module_unload_event(void (*func)(void *drcontext,
const module_data_t *info));
/* DR_API EXPORT BEGIN */
#ifdef WINDOWS
/* DR_API EXPORT END */
/* DR_API EXPORT BEGIN */
/**
* Data structure passed with an exception event. Contains the
* machine context and the Win32 exception record.
*/
typedef struct _dr_exception_t {
/**
* Machine context at exception point. The client should not
* change \p mcontext.flags: it should remain DR_MC_ALL.
*/
dr_mcontext_t *mcontext;
EXCEPTION_RECORD *record; /**< Win32 exception record. */
/**
* The raw pre-translated machine state at the exception interruption
* point inside the code cache. Clients are cautioned when examining
* code cache instructions to not rely on any details of code inserted
* other than their own.
* The client should not change \p raw_mcontext.flags: it should
* remain DR_MC_ALL.
*/
dr_mcontext_t *raw_mcontext;
/**
* Information about the code fragment inside the code cache at
* the exception interruption point.
*/
dr_fault_fragment_info_t fault_fragment_info;
} dr_exception_t;
/* DR_API EXPORT END */
DR_API
/**
* Registers a callback function for the exception event. DR calls \p func
* whenever the application throws an exception. If \p func returns true,
* the exception is delivered to the application's handler along with any
* changes made to \p excpt->mcontext. If \p func returns false, the
* faulting instruction in the code cache is re-executed using \p
* excpt->raw_mcontext, including any changes made to that structure.
* Clients are expected to use \p excpt->raw_mcontext when using faults as
* a mechanism to push rare cases out of an instrumentation fastpath that
* need to examine instrumentation instructions rather than the translated
* application state and should normally not examine it for application
* instruction faults. Certain registers may not contain proper
* application values in \p excpt->raw_mcontext for exceptions in
* application instructions. Clients are cautioned against relying on any
* details of code cache layout or register usage beyond instrumentation
* inserted by the client itself when examining \p excpt->raw_mcontext.
*
* If multiple callbacks are registered, the first one that returns
* false will short-circuit event delivery to later callbacks.
*
* DR raises this event for exceptions outside the code cache that
* could come from code generated by a client. For such exceptions,
* mcontext is not translated and is identical to raw_mcontext.
*
* To skip the passing of the exception to the application's exception
* handlers and to send control elsewhere instead, a client can call
* dr_redirect_execution() from \p func.
*
* \note \p excpt->fault_fragment_info data is provided with
* \p excpt->raw_mcontext. It is valid only if
* \p excpt->fault_fragment_info.cache_start_pc is not \p NULL.
* It provides clients information about the code fragment being
* executed at the exception interruption point. Clients are cautioned
* against relying on any details of code cache layout or register
* usage beyond instrumentation inserted by the client itself.
* \note Only valid on Windows.
* \note The function is not called for RaiseException.
*/
void
dr_register_exception_event(bool (*func)(void *drcontext, dr_exception_t *excpt));
DR_API
/**
* Unregister a callback function for the exception event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_exception_event(bool (*func)(void *drcontext, dr_exception_t *excpt));
/* DR_API EXPORT BEGIN */
#endif /* WINDOWS */
/* DR_API EXPORT END */
DR_API
/**
* Registers a callback function for the syscall filter event. DR
* calls \p func to decide whether to invoke the syscall events for
* each system call site encountered with a statically-determinable
* system call number. If \p func returns true, the pre-syscall
* (dr_register_pre_syscall_event()) and post-syscall
* (dr_register_post_syscall_event()) events will be invoked.
* Otherwise, the events may or may not occur, depending on whether DR
* itself needs to intercept them and whether the system call number
* is statically determinable. System call number determination can
* depend on whether the -opt_speed option is enabled. If a system
* call number is not determinable, the filter event will not be
* called, but the pre and post events will be called.
*
* Intercepting every system call can be detrimental to performance
* for certain types of applications. Filtering provides for greater
* performance by letting uninteresting system calls execute without
* interception overhead.
*/
void
dr_register_filter_syscall_event(bool (*func)(void *drcontext, int sysnum));
DR_API
/**
* Unregister a callback function for the syscall filter event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_filter_syscall_event(bool (*func)(void *drcontext, int sysnum));
DR_API
/**
* Registers a callback function for the pre-syscall event. DR calls
* \p func whenever the application is about to invoke a system call,
* if any client asked for that system call number to be intercepted
* via the filter event (dr_register_filter_syscall_event()).
*
* The application parameters to the system call can be viewed with
* dr_syscall_get_param() and set with dr_syscall_set_param(). The
* system call number can also be changed with
* dr_syscall_set_sysnum().
*
* The application's machine state can be accessed and set with
* dr_get_mcontext() and dr_set_mcontext(). Changing registers in
* this way overlaps with system call parameter changes on some
* platforms. On Linux, for SYS_clone, client changes to the ebp/rbp
* register will be ignored by the clone child.
*
* On MacOS, whether 32-bit or 64-bit, the system call number passed
* (\p sysnum) has been normalized to a positive number 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 to view the unmodified number.
*
* If \p func returns true, the application's system call is invoked
* normally; if \p func returns false, the system call is skipped. If
* it is skipped, the return value can be set with
* dr_syscall_set_result() or dr_syscall_set_result_ex(). If the
* system call is skipped, there will not be a post-syscall event.
* If multiple callbacks are registered, the first one that returns
* false will short-circuit event delivery to later callbacks.
*/
void
dr_register_pre_syscall_event(bool (*func)(void *drcontext, int sysnum));
DR_API
/**
* Unregister a callback function for the pre-syscall event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_pre_syscall_event(bool (*func)(void *drcontext, int sysnum));
DR_API
/**
* Registers a callback function for the post-syscall event. DR calls
* \p func whenever the application just finished invoking a system
* call, if any client asked for that system call number to be
* intercepted via the filter event
* (dr_register_filter_syscall_event()) or if DR itself needs to
* intercept the system call. The result of the system call can be
* modified with dr_syscall_set_result() or dr_syscall_set_result_ex().
*
* System calls that change control flow or terminate the current
* thread or process typically do not have a post-syscall event.
* These include SYS_exit, SYS_exit_group, SYS_execve, SYS_sigreturn,
* and SYS_rt_sigreturn on Linux, and NtTerminateThread,
* NtTerminateProcess (depending on the parameters), NtCallbackReturn,
* and NtContinue on Windows.
*
* The application's machine state can be accessed and set with
* dr_get_mcontext() and dr_set_mcontext().
*
* On MacOS, whether 32-bit or 64-bit, the system call number passed
* (\p sysnum) has been normalized to a positive number 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 to view the unmodified number.
*
* Additional system calls may be invoked by calling
* dr_syscall_invoke_another() prior to returning from the
* post-syscall event callback. The system call to be invoked should
* be specified with dr_syscall_set_sysnum(), and its parameters can
* be set with dr_syscall_set_param().
*/
void
dr_register_post_syscall_event(void (*func)(void *drcontext, int sysnum));
DR_API
/**
* Unregister a callback function for the post-syscall event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_post_syscall_event(void (*func)(void *drcontext, int sysnum));
/* DR_API EXPORT BEGIN */
#ifdef UNIX
/* DR_API EXPORT END */
/* FIXME: for PR 304708 I originally included siginfo_t in
* dr_siginfo_t. But can we really trust siginfo_t to be identical on
* all supported platforms? Esp. once we start supporting VMKUW,
* MacOS, etc. I'm removing it for now. None of my samples need it,
* and in my experience its fields are unreliable in any case.
* PR 371370 covers re-adding it if users request it.
* Xref PR 371339: we will need to not include it through signal.h but
* instead something like this:
* # define __need_siginfo_t
* # include <bits/siginfo.h>
*/
/* DR_API EXPORT BEGIN */
/**
* Data structure passed with a signal event. Contains the machine
* context at the signal interruption point and other signal
* information.
*/
typedef struct _dr_siginfo_t {
/** The signal number. */
int sig;
/** The context of the thread receiving the signal. */
void *drcontext;
/**
* The application machine state at the signal interruption point.
* The client should not change \p mcontext.flags: it should
* remain DR_MC_ALL.
*/
dr_mcontext_t *mcontext;
/**
* The raw pre-translated machine state at the signal interruption
* point inside the code cache. NULL for delayable signals. Clients
* are cautioned when examining code cache instructions to not rely on
* any details of code inserted other than their own.
* The client should not change \p mcontext.flags: it should
* remain DR_MC_ALL.
*/
dr_mcontext_t *raw_mcontext;
/** Whether raw_mcontext is valid. */
bool raw_mcontext_valid;
/**
* For SIGBUS and SIGSEGV, the address whose access caused the signal
* to be raised (as calculated by DR).
*/
byte *access_address;
/**
* Indicates this signal is blocked. DR_SIGNAL_BYPASS is not allowed,
* and a second event will be sent if the signal is later delivered to
* the application. Events are only sent for blocked non-delayable signals,
* not for delayable signals.
*/
bool blocked;
/**
* Information about the code fragment inside the code cache
* at the signal interruption point.
*/
dr_fault_fragment_info_t fault_fragment_info;
} dr_siginfo_t;
/**
* Return value of client signal event callback, determining how DR will
* proceed with the signal.
*/
typedef enum {
/** Deliver signal to the application as normal. */
DR_SIGNAL_DELIVER,
/** Suppress signal as though it never happened. */
DR_SIGNAL_SUPPRESS,
/**
* Deliver signal according to the default SIG_DFL action, as would
* happen if the application had no handler.
*/
DR_SIGNAL_BYPASS,
/**
* Do not deliver the signal. Instead, redirect control to the
* application state specified in dr_siginfo_t.mcontext.
*/
DR_SIGNAL_REDIRECT,
} dr_signal_action_t;
/* DR_API EXPORT END */
DR_API
/**
* Requests that DR call the provided callback function \p func whenever a
* signal is received by any application thread. The return value of \p
* func determines whether DR delivers the signal to the application.
* To redirect execution return DR_SIGNAL_REDIRECT (do not call
* dr_redirect_execution() from a signal callback). The callback function
* will be called even if the application has no handler or has registered
* a SIG_IGN or SIG_DFL handler. If multiple callbacks are registered,
* the first one that returns other than DR_SIGNAL_DELIVER will short-circuit
* event delivery to later callbacks.
*
* Modifications to the fields of \p siginfo->mcontext will be propagated
* to the application if it has a handler for the signal, if
* DR_SIGNAL_DELIVER is returned.
*
* The \p siginfo->raw_mcontext data is only provided for non-delayable
* signals (e.g., SIGSEGV) that must be delivered immediately. Whether it
* is supplied is specified in \p siginfo->raw_mcontext_valid. It is
* intended for clients using faults as a mechanism to push rare cases out
* of an instrumentation fastpath that need to examine instrumentation
* instructions rather than the translated application state. Certain
* registers may not contain proper application values in \p
* excpt->raw_mcontext for exceptions in application instructions. Clients
* are cautioned against relying on any details of code cache layout or
* register usage beyond instrumentation inserted by the client itself. If
* DR_SIGNAL_SUPPRESS is returned, \p siginfo->mcontext is ignored and \p
* siginfo->raw_mcontext is used as the resumption context. The client's
* changes to \p siginfo->raw_mcontext will take effect.
*
* For a delayable signal, DR raises a signal event only when about to
* deliver the signal to the application. Thus, if the application has
* blocked a delayable signal, the corresponding signal event will not
* occur until the application unblocks the signal, even if such a signal
* is delivered by the kernel. For non-delayable signals, DR will raise a
* signal event on initial receipt of the signal, with the \p
* siginfo->blocked field set. Such a blocked signal will have a second
* event raised when it is delivered to the application (if it is not
* suppressed by the client, and if there is not already a pending blocked
* signal, for non-real-time signals).
*
* DR raises this event for faults outside the code cache that
* could come from code generated by a client. For such cases,
* mcontext is not translated and is identical to raw_mcontext.
*
* DR will not raise a signal event for a SIGSEGV or SIGBUS
* raised by a client code fault rather than the application. Use
* dr_safe_read(), dr_safe_write(), or DR_TRY_EXCEPT() to prevent such
* faults.
*
* \note \p siginfo->fault_fragment_info data is provided
* with \p siginfo->raw_mcontext. It is valid only if
* \p siginfo->fault_fragment_info.cache_start_pc is not
* \p NULL. It provides clients information about the code fragment
* being executed at the signal interruption point. Clients are
* cautioned against relying on any details of code cache layout or
* register usage beyond instrumentation inserted by the client
* itself.
*
* \note Only valid on Linux.
*
* \note DR always requests SA_SIGINFO for all signals.
*
* \note This version of DR does not intercept the signals SIGCONT,
* SIGSTOP, SIGTSTP, SIGTTIN, or SIGTTOU. Future versions should add
* support for these signals.
*
* \note If the client uses signals for its own communication it should set
* a flag to distinguish its own uses of signals from the application's
* use. Races where the two are re-ordered should not be problematic.
*/
void
dr_register_signal_event(dr_signal_action_t (*func)
(void *drcontext, dr_siginfo_t *siginfo));
DR_API
/**
* Unregister a callback function for the signal event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_signal_event(dr_signal_action_t (*func)
(void *drcontext, dr_siginfo_t *siginfo));
/* DR_API EXPORT BEGIN */
#endif /* UNIX */
/* DR_API EXPORT END */
/****************************************************************************
* SECURITY SUPPORT
*/
#ifdef PROGRAM_SHEPHERDING
/* DR_API EXPORT BEGIN */
/** Types of security violations that can be received at a security violation event
* callback.
* - DR_RCO_* :
* A violation of the Restricted Code Origins policies. The target address is not
* in an allowed execution area.
* - DR_RCO_STACK_VIOLATION - The target address is on the current thread's stack.
* - DR_RCO_HEAP_VIOLATION - The target address is not on the current thread's stack.
* - DR_RCT_* :
* A violation of the Restricted Control Transfer policies. The transition from the
* source address to the target address is not allowed.
* - DR_RCT_RETURN_VIOLATION - The transition from source_pc to target_pc is via a
* return instruction. The target address does not follow an executed call
* instruction and is not exempted.
* - DR_RCT_INDIRECT_CALL_VIOLATION - The transition from source_pc to target_pc is
* via an indirect call instruction.
* - DR_RCT_INDIRECT_JUMP_VIOLATION - The transition from source_pc to target_pc is
* via an indirect jmp instruction.
* - DR_UNKNOWN_VIOLATION :
* An unknown violation type, the client shouldn't expect to see this.
*/
typedef enum {
DR_RCO_STACK_VIOLATION,
DR_RCO_HEAP_VIOLATION,
DR_RCT_RETURN_VIOLATION,
DR_RCT_INDIRECT_CALL_VIOLATION,
DR_RCT_INDIRECT_JUMP_VIOLATION,
DR_UNKNOWN_VIOLATION,
} dr_security_violation_type_t;
/** Types of remediations available at a security violation event callback.
* - DR_VIOLATION_ACTION_CONTINUE :
* Continue application execution as if no violation occurred. Use this if the
* violation is determined to be a false positive.
* - DR_VIOLATION_ACTION_CONTINUE_CHANGED_CONTEXT :
* Continue application execution after applying any changes made to the mcontext.
* Use this to fix up the application's state and continue execution.
* - DR_VIOLATION_ACTION_KILL_PROCESS :
* Immediately kills the process. This is the safest course of action to take
* when faced with possibly corrupt application state, but availability concerns
* may dictate using one of the other choices, since they can be less disruptive.
* - DR_VIOLATION_ACTION_KILL_THREAD :
* Immediately kills the thread that caused the violation (the current thread).
* If the current thread is part of a pool of worker threads kept by the application
* then it's likely the application will recover gracefully. If the thread is
* responsible for a particular function within the application (such as a
* particular service within an svchost process) then the application may continue
* with only that functionality lost. Note that no cleanup of the thread's state
* is preformed (application locks it owns are not released and, for Windows NT and
* 2000 its stack is not freed). However, the client will still receive the thread
* exit event for this thread.
* - DR_VIOLATION_ACTION_THROW_EXCEPTION :
* Causes the application to receive an unreadable memory execution exception in
* the thread that caused the violation (the current thread). The exception will
* appear to originate from an application attempt to execute from the target
* address. If the application has good exception handling it may recover
* gracefully.
*/
typedef enum {
DR_VIOLATION_ACTION_CONTINUE,
DR_VIOLATION_ACTION_CONTINUE_CHANGED_CONTEXT,
DR_VIOLATION_ACTION_KILL_PROCESS,
DR_VIOLATION_ACTION_KILL_THREAD,
DR_VIOLATION_ACTION_THROW_EXCEPTION,
} dr_security_violation_action_t;
/* DR_API EXPORT END */
DR_API
/**
* Registers a callback function for the security violation event. DR
* calls \p func whenever it intercepts a security violation. Clients
* can override the default remediation by changing \p action. If
* multiple callbacks are registered, the callback registered last has
* final control over the action. \note source_pc can be NULL if DR
* fails to recreate the source pc.
*/
void
dr_register_security_event(void (*func)(void *drcontext, void *source_tag,
app_pc source_pc, app_pc target_pc,
dr_security_violation_type_t violation,
dr_mcontext_t *mcontext,
dr_security_violation_action_t *action));
DR_API
/**
* Unregister a callback function for the security violation event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_security_event(void (*func)(void *drcontext, void *source_tag,
app_pc source_pc, app_pc target_pc,
dr_security_violation_type_t violation,
dr_mcontext_t *mcontext,
dr_security_violation_action_t *action));
#endif /* PROGRAM_SHEPHERDING */
DR_API
/**
* Registers a callback function for nudge events. External entities
* can nudge a process through the dr_nudge_process() or
* dr_nudge_pid() drconfig API routines on Windows or using the \p
* nudgeunix tool on Linux. A client in this process can use
* dr_nudge_client() to raise a nudge, while a client in another
* process can use dr_nudge_client_ex().
*
* DR calls \p func whenever the current process receives a nudge.
* On Windows, the nudge event is delivered in a new non-application
* thread. Callers must specify the target client by passing the
* client ID that was provided in dr_init().
*/
void
dr_register_nudge_event(void (*func)(void *drcontext, uint64 argument), client_id_t id);
DR_API
/**
* Unregister a callback function for the nudge event.
* \return true if unregistration is successful and false if it is not
* (e.g., \p func was not registered).
*/
bool
dr_unregister_nudge_event(void (*func)(void *drcontext, uint64 argument), client_id_t id);
DR_API
/**
* Triggers an asynchronous nudge event in the current process. The callback
* function registered with dr_register_nudge_event() will be called with the
* supplied \p argument (in a new non-application thread on Windows).
*
* \note On Linux, the nudge will not be delivered until this thread exits
* the code cache. Thus, if this routine is called from a clean call,
* dr_redirect_execution() should be used to ensure cache exit.
*/
bool
dr_nudge_client(client_id_t id, uint64 argument);
DR_API
/**
* Triggers an asynchronous nudge event in a target process. The callback
* function registered with dr_register_nudge_event() for the
* specified client in the specified process will be called with the
* supplied \p argument (in a new non-application thread on Windows).
*
* \note On Linux, if \p pid is the current process, the nudge will
* not be delivered until this thread exits the code cache. Thus, if
* this routine is called from a clean call and \p pid is the current
* process, dr_redirect_execution() should be used to ensure cache exit.
*
* \param[in] process_id The system id of the process to nudge
* (see dr_get_process_id())
*
* \param[in] client_id The unique client ID provided at client
* registration.
*
* \param[in] argument An argument passed to the client's nudge
* handler.
*
* \param[in] timeout_ms Windows only. The number of milliseconds to wait for
* each nudge to complete before continuing. If INFINITE
* is supplied then the wait is unbounded. If 0
* is supplied the no wait is performed. If a
* non-0 wait times out DR_NUDGE_TIMEOUT will be returned.
*
* \return A dr_config_status_t code indicating the result of the nudge.
*/
dr_config_status_t
dr_nudge_client_ex(process_id_t process_id, client_id_t client_id,
uint64 argument, uint timeout_ms);
#ifdef WINDOWS
DR_API
/**
* On Windows, nudges are implemented via remotely injected threads.
* This routine returns whether or not the thread indicated by
* \p drcontext is such a nudge thread.
* \note Windows only.
*/
bool
dr_is_nudge_thread(void *drcontext);
#endif
void instrument_load_client_libs(void);
void instrument_init(void);
void instrument_exit(void);
bool is_in_client_lib(app_pc addr);
bool get_client_bounds(client_id_t client_id,
app_pc *start/*OUT*/, app_pc *end/*OUT*/);
const char *get_client_path_from_addr(app_pc addr);
bool is_valid_client_id(client_id_t id);
void instrument_client_thread_init(dcontext_t *dcontext, bool client_thread);
void instrument_thread_init(dcontext_t *dcontext, bool client_thread, bool valid_mc);
void instrument_thread_exit_event(dcontext_t *dcontext);
void instrument_thread_exit(dcontext_t *dcontext);
#ifdef UNIX
void instrument_fork_init(dcontext_t *dcontext);
#endif
bool instrument_basic_block(dcontext_t *dcontext, app_pc tag, instrlist_t *bb,
bool for_trace, bool translating,
dr_emit_flags_t *emitflags);
dr_emit_flags_t instrument_trace(dcontext_t *dcontext, app_pc tag, instrlist_t *trace,
bool translating);
#ifdef CUSTOM_TRACES
dr_custom_trace_action_t instrument_end_trace(dcontext_t *dcontext, app_pc trace_tag,
app_pc next_tag);
#endif
void instrument_fragment_deleted(dcontext_t *dcontext, app_pc tag, uint flags);
bool instrument_restore_state(dcontext_t *dcontext, bool restore_memory,
dr_restore_state_info_t *info);
module_data_t * copy_module_area_to_module_data(const module_area_t *area);
void instrument_module_load_trigger(app_pc modbase);
void instrument_module_load(module_data_t *data, bool previously_loaded);
void instrument_module_unload(module_data_t *data);
/* returns whether this sysnum should be intercepted */
bool instrument_filter_syscall(dcontext_t *dcontext, int sysnum);
/* returns whether this syscall should execute */
bool instrument_pre_syscall(dcontext_t *dcontext, int sysnum);
void instrument_post_syscall(dcontext_t *dcontext, int sysnum);
bool instrument_invoke_another_syscall(dcontext_t *dcontext);
void instrument_nudge(dcontext_t *dcontext, client_id_t id, uint64 arg);
#ifdef WINDOWS
bool instrument_exception(dcontext_t *dcontext, dr_exception_t *exception);
void wait_for_outstanding_nudges(void);
#else
dr_signal_action_t instrument_signal(dcontext_t *dcontext, dr_siginfo_t *siginfo);
bool dr_signal_hook_exists(void);
#endif
int get_num_client_threads(void);
#ifdef PROGRAM_SHEPHERDING
void instrument_security_violation(dcontext_t *dcontext, app_pc target_pc,
security_violation_t violation, action_type_t *action);
#endif
#endif /* CLIENT_INTERFACE */
bool dr_get_mcontext_priv(dcontext_t *dcontext, dr_mcontext_t *dmc, priv_mcontext_t *mc);
#ifdef CLIENT_INTERFACE
void instrument_client_lib_loaded(byte *start, byte *end);
void instrument_client_lib_unloaded(byte *start, byte *end);
bool dr_bb_hook_exists(void);
bool dr_trace_hook_exists(void);
bool dr_fragment_deleted_hook_exists(void);
bool dr_end_trace_hook_exists(void);
bool dr_thread_exit_hook_exists(void);
bool dr_exit_hook_exists(void);
bool dr_xl8_hook_exists(void);
bool hide_tag_from_client(app_pc tag);
uint instrument_persist_ro_size(dcontext_t *dcontext, void *perscxt, size_t file_offs);
bool instrument_persist_ro(dcontext_t *dcontext, void *perscxt, file_t fd);
bool instrument_resurrect_ro(dcontext_t *dcontext, void *perscxt, byte *map);
uint instrument_persist_rx_size(dcontext_t *dcontext, void *perscxt, size_t file_offs);
bool instrument_persist_rx(dcontext_t *dcontext, void *perscxt, file_t fd);
bool instrument_resurrect_rx(dcontext_t *dcontext, void *perscxt, byte *map);
uint instrument_persist_rw_size(dcontext_t *dcontext, void *perscxt, size_t file_offs);
bool instrument_persist_rw(dcontext_t *dcontext, void *perscxt, file_t fd);
bool instrument_resurrect_rw(dcontext_t *dcontext, void *perscxt, byte *map);
bool instrument_persist_patch(dcontext_t *dcontext, void *perscxt,
byte *bb_start, size_t bb_size);
/* DR_API EXPORT TOFILE dr_tools.h */
/* DR_API EXPORT BEGIN */
/**************************************************
* TOP-LEVEL ROUTINES
*/
/**
* @file dr_tools.h
* @brief Main API routines, including transparency support.
*/
/* DR_API EXPORT END */
DR_API
/**
* Creates a DR context that can be used in a standalone program.
* \warning This context cannot be used as the drcontext for a thread
* running under DR control! It is only for standalone programs that
* wish to use DR as a library of disassembly, etc. routines.
* \return NULL on failure, such as running on an unsupported operating
* system version.
*/
void *
dr_standalone_init(void);
/* DR_API EXPORT BEGIN */
#ifdef API_EXPORT_ONLY
/**
* Use this dcontext for use with the standalone static decoder library.
* Pass it whenever a decoding-related API routine asks for a context.
*/
#define GLOBAL_DCONTEXT ((void *)-1)
#endif
/**************************************************
* UTILITY ROUTINES
*/
#ifdef WINDOWS
/**
* If \p x is false, displays a message about an assertion failure
* (appending \p msg to the message) and then calls dr_abort()
*/
# define DR_ASSERT_MSG(x, msg) \
((void)((!(x)) ? \
(dr_messagebox("ASSERT FAILURE: %s:%d: %s (%s)", __FILE__, __LINE__, #x, msg),\
dr_abort(), 0) : 0))
#else
# define DR_ASSERT_MSG(x, msg) \
((void)((!(x)) ? \
(dr_fprintf(STDERR, "ASSERT FAILURE: %s:%d: %s (%s)", \
__FILE__, __LINE__, #x, msg), \
dr_abort(), 0) : 0))
#endif
/**
* If \p x is false, displays a message about an assertion failure and
* then calls dr_abort()
*/
#define DR_ASSERT(x) DR_ASSERT_MSG(x, "")
/* DR_API EXPORT END */
DR_API
/** Returns true if all DynamoRIO caches are thread private. */
bool
dr_using_all_private_caches(void);
DR_API
/** \deprecated Replaced by dr_set_process_exit_behavior() */
void
dr_request_synchronized_exit(void);
DR_API
/**
* Returns the client-specific option string specified at client
* registration. \p client_id is the client ID passed to dr_init().
*/
const char *
dr_get_options(client_id_t client_id);
DR_API
/**
* Read the value of a string DynamoRIO runtime option named \p option_name into
* \p buf. Options are listed in \ref sec_options. DynamoRIO has many other
* undocumented options which may be queried through this API, but they are not
* officially supported. The option value is truncated to \p len bytes and
* null-terminated.
* \return false if no option named \p option_name exists, and true otherwise.
*/
bool
dr_get_string_option(const char *option_name, char *buf OUT, size_t len);
DR_API
/**
* Read the value of an integer DynamoRIO runtime option named \p option_name
* into \p val. This includes boolean options. Options are listed in \ref
* sec_options. DynamoRIO has many other undocumented options which may be
* queried through this API, but they are not officially supported.
* \warning Always pass a full uint64 for \p val even if the option is a smaller
* integer to avoid overwriting nearby data.
* \return false if no option named \p option_name exists, and true otherwise.
*/
bool
dr_get_integer_option(const char *option_name, uint64 *val OUT);
DR_API
/**
* Returns the client library name and path that were originally specified
* to load the library. If the resulting string is longer than #MAXIMUM_PATH
* it will be truncated. \p client_id is the client ID passed to a client's
* dr_init() function.
*/
const char *
dr_get_client_path(client_id_t client_id);
DR_API
/**
* Returns the base address of the client library. \p client_id is
* the client ID passed to a client's dr_init() function.
*/
byte *
dr_get_client_base(client_id_t client_id);
DR_API
/**
* Sets information presented to users in diagnostic messages.
* Only one name is supported, regardless of how many clients are in use.
* If this routine is called a second time, the new values supersede
* the original.
* The \p report_URL is meant to be a bug tracker location where users
* should go to report errors in the client end-user tool.
*/
bool
dr_set_client_name(const char *name, const char *report_URL);
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);
#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
/* DR_API EXPORT BEGIN */
#ifdef WINDOWS
/** Windows versions */
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx */
typedef enum {
/** 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;
} dr_os_version_info_t;
/* DR_API EXPORT END */
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);
/* DR_API EXPORT BEGIN */
#endif
/* DR_API EXPORT END */
DR_API
/** Retrieves the current time. */
void
dr_get_time(dr_time_t *time);
DR_API
/**
* Returns the number of milliseconds since Jan 1, 1601 (this is
* the current UTC time).
*
* \note This is the Windows standard. UNIX time functions typically
* count from the Epoch (Jan 1, 1970). The Epoch is 11644473600*1000
* milliseconds after Jan 1, 1601.
*/
uint64
dr_get_milliseconds(void);
DR_API
/**
* Returns a pseudo-random number in the range [0..max).
* The pseudo-random sequence can be repeated by passing the seed
* used during a run to the next run via the -prng_seed runtime option.
*/
uint
dr_get_random_value(uint max);
DR_API
/**
* Sets the seed used for dr_get_random_value(). Generally this would
* only be called during client initialization.
*/
void
dr_set_random_seed(uint seed);
DR_API
/** Returns the seed used for dr_get_random_value(). */
uint
dr_get_random_seed(void);
DR_API
/**
* Aborts the process immediately without any cleanup (i.e., the exit event
* will not be called).
*/
void
dr_abort(void);
DR_API
/**
* Exits the process, first performing a full cleanup that will
* trigger the exit event (dr_register_exit_event()). The process
* exit code is set to \p exit_code.
*
* On Linux, only the bottom 8 bits of \p exit_code will be honored
* for a normal exit. If bits 9..16 are not all zero, DR will send an
* unhandled signal of that signal number instead of performing a normal
* exit.
*
* \note Calling this from \p dr_init or from the primary thread's
* initialization event is not guaranteed to always work, as DR may
* invoke a thread exit event where a thread init event was never
* called. We recommend using dr_abort() or waiting for full
* initialization prior to use of this routine.
*/
void
dr_exit_process(int exit_code);
/* DR_API EXPORT BEGIN */
/** Indicates the type of memory dump for dr_create_memory_dump(). */
typedef enum {
/**
* A "livedump", or "ldmp", DynamoRIO's own custom memory dump format.
* The ldmp format does not currently support specifying a context
* for the calling thread, so it will always include the call frames
* to dr_create_memory_dump(). The \p ldmp.exe tool can be used to
* create a dummy process (using the \p dummy.exe executable) which
* can then be attached to by the debugger (use a non-invasive attach)
* in order to view the memory dump contents.
*
* \note Windows only.
*/
DR_MEMORY_DUMP_LDMP = 0x0001,
} dr_memory_dump_flags_t;
/** Indicates the type of memory dump for dr_create_memory_dump(). */
typedef struct _dr_memory_dump_spec_t {
/** The size of this structure. Set this to sizeof(dr_memory_dump_spec_t). */
size_t size;
/** The type of memory dump requested. */
dr_memory_dump_flags_t flags;
/**
* This field only applies to DR_MEMORY_DUMP_LDMP. This string is
* stored inside the ldmp as the reason for the dump.
*/
const char *label;
/**
* This field only applies to DR_MEMORY_DUMP_LDMP. This is an optional output
* field that, if non-NULL, will be written with the path to the created file.
*/
char *ldmp_path;
/**
* This field only applies to DR_MEMORY_DUMP_LDMP. This is the maximum size,
* in bytes, of ldmp_path.
*/
size_t ldmp_path_size;
} dr_memory_dump_spec_t;
/* DR_API EXPORT END */
DR_API
/**
* Requests that DR create a memory dump file of the current process.
* The type of dump is specified by \p spec.
*
* \return whether successful.
*
* \note this function is only supported on Windows for now.
*/
bool
dr_create_memory_dump(dr_memory_dump_spec_t *spec);
/* DR_API EXPORT BEGIN */
/**************************************************
* APPLICATION-INDEPENDENT MEMORY ALLOCATION
*/
/** Flags used with dr_custom_alloc() */
typedef enum {
/**
* If this flag is not specified, dr_custom_alloc() uses a managed
* heap to allocate the memory, just like dr_thread_alloc() or
* dr_global_alloc(). In that case, it ignores any requested
* protection bits (\p prot parameter), and the location (\p addr
* parameter) must be NULL. If this flag is specified, a
* page-aligned, separate block of memory is allocated, in a
* similar fashion to dr_nonheap_alloc().
*/
DR_ALLOC_NON_HEAP = 0x0001,
/**
* This flag only applies to heap memory (i.e., when
* #DR_ALLOC_NON_HEAP is not specified). If this flag is not
* specified, global heap is used (just like dr_global_alloc())
* and the \p drcontext parameter is ignored. If it is specified,
* thread-private heap specific to \p drcontext is used, just like
* dr_thread_alloc().
*/
DR_ALLOC_THREAD_PRIVATE = 0x0002,
/**
* Allocate memory that is 32-bit-displacement reachable from the
* code caches and from the client library. Memory allocated
* through dr_thread_alloc(), dr_global_alloc(), and
* dr_nonheap_alloc() is also reachable, but for
* dr_custom_alloc(), the resulting memory is not reachable unless
* this flag is specified. If this flag is passed, the requested
* location (\p addr parameter) must be NULL. This flag is not
* compatible with #DR_ALLOC_LOW_2GB, #DR_ALLOC_FIXED_LOCATION, or
* #DR_ALLOC_NON_DR.
*/
DR_ALLOC_CACHE_REACHABLE = 0x0004,
/**
* This flag only applies to non-heap memory (i.e., when
* #DR_ALLOC_NON_HEAP is specified). The flag requests that
* memory be allocated at a specific address, given in the \p addr
* parameter. Without this flag, the \p addr parameter is not
* honored. This flag is not compatible with #DR_ALLOC_LOW_2GB or
* #DR_ALLOC_CACHE_REACHABLE.
*/
DR_ALLOC_FIXED_LOCATION = 0x0008,
/**
* This flag only applies to non-heap memory (i.e., when
* #DR_ALLOC_NON_HEAP is specified) in 64-bit mode. The flag
* requests that memory be allocated in the low 2GB of the address
* space. If this flag is passed, the requested location (\p addr
* parameter) must be NULL. This flag is not compatible with
* #DR_ALLOC_FIXED_LOCATION.
*/
DR_ALLOC_LOW_2GB = 0x0010,
/**
* This flag only applies to non-heap memory (i.e., when
* #DR_ALLOC_NON_HEAP is specified). When this flag is specified,
* the allocated memory is not considered to be DynamoRIO or tool
* memory and thus is not kept separate from the application.
* This is similar to dr_raw_mem_alloc(). Use of this memory is
* at the client's own risk. This flag is not compatible with
* #DR_ALLOC_CACHE_REACHABLE.
*/
DR_ALLOC_NON_DR = 0x0020,
#ifdef WINDOWS
/**
* This flag only applies to non-heap, non-DR memory (i.e., when
* both #DR_ALLOC_NON_HEAP and #DR_ALLOC_NON_DR are specified) on
* Windows. When this flag is specified, the allocated memory is
* reserved but not committed, just like the MEM_RESERVE Windows API
* flag (the default is MEM_RESERVE|MEM_COMMIT).
*/
DR_ALLOC_RESERVE_ONLY = 0x0040,
/**
* This flag only applies to non-heap, non-DR memory (i.e., when both
* #DR_ALLOC_NON_HEAP and #DR_ALLOC_NON_DR are specified) on Windows.
* This flag must be combined with DR_ALLOC_FIXED_LOCATION. When this
* flag is specified, previously allocated memory is committed, just
* like the MEM_COMMIT Windows API flag (when this flag is not passed,
* the effect is MEM_RESERVE|MEM_COMMIT). When passed to
* dr_custom_free(), this flag causes a de-commit, just like the
* MEM_DECOMMIT Windows API flag. This flag cannot be combined with
* #DR_ALLOC_LOW_2GB and must include a non-NULL requested location (\p
* addr parameter).
*/
DR_ALLOC_COMMIT_ONLY = 0x0080,
#endif
} dr_alloc_flags_t;
/* DR_API EXPORT END */
DR_API
/**
* Allocates \p size bytes of memory from DR's memory pool specific to the
* thread associated with \p drcontext.
*/
void *
dr_thread_alloc(void *drcontext, size_t size);
DR_API
/**
* Frees thread-specific memory allocated by dr_thread_alloc().
* \p size must be the same as that passed to dr_thread_alloc().
*/
void
dr_thread_free(void *drcontext, void *mem, size_t size);
DR_API
/** Allocates \p size bytes of memory from DR's global memory pool. */
void *
dr_global_alloc(size_t size);
DR_API
/**
* Frees memory allocated by dr_global_alloc().
* \p size must be the same as that passed to dr_global_alloc().
*/
void
dr_global_free(void *mem, size_t size);
DR_API
/**
* Allocates memory with the properties requested by \p flags.
*
* If \p addr is non-NULL (only allowed with certain flags), it must
* be page-aligned.
*
* To make more space available for the code caches when running
* larger applications, or for clients that use a lot of heap memory
* that is not directly referenced from the cache, we recommend that
* dr_custom_alloc() be called to obtain memory that is not guaranteed
* to be reachable from the code cache (by not passing
* #DR_ALLOC_CACHE_REACHABLE). This frees up space in the reachable
* region.
*
* Returns NULL on failure.
*/
void *
dr_custom_alloc(void *drcontext, dr_alloc_flags_t flags, size_t size,
uint prot, void *addr);
DR_API
/**
* Frees memory allocated by dr_custom_alloc(). The same \p flags
* and \p size must be passed here as were passed to dr_custom_alloc().
*/
bool
dr_custom_free(void *drcontext, dr_alloc_flags_t flags, void *addr, size_t size);
DR_API
/**
* Allocates \p size bytes of memory as a separate allocation from DR's
* heap, allowing for separate protection.
* The \p prot protection should use the DR_MEMPROT_READ,
* DR_MEMPROT_WRITE, and DR_MEMPROT_EXEC bits.
* When creating a region to hold dynamically generated code, use
* this routine in order to create executable memory.
*/
void *
dr_nonheap_alloc(size_t size, uint prot);
DR_API
/**
* Frees memory allocated by dr_nonheap_alloc().
* \p size must be the same as that passed to dr_nonheap_alloc().
*/
void
dr_nonheap_free(void *mem, size_t size);
DR_API
/**
* \warning This raw memory allocation interface is in flux and is subject to
* change in the next release. Consider it experimental in this release.
*
* Allocates \p size bytes (page size aligned) of memory as a separate
* allocation at preferred base \p addr that must be page size aligned,
* allowing for separate protection.
* If \p addr is NULL, an arbitrary address is picked.
*
* The \p prot protection should use the DR_MEMPROT_READ,
* DR_MEMPROT_WRITE, and DR_MEMPROT_EXEC bits.
* The allocated memory is not considered to be DynamoRIO or tool memory and
* thus is not kept separate from the application. Use of this memory is at the
* client's own risk.
*
* Returns the actual address allocated or NULL if memory allocation at
* preferred base fails.
*/
void *
dr_raw_mem_alloc(size_t size, uint prot, void *addr);
DR_API
/**
* Frees memory allocated by dr_raw_mem_alloc().
* \p addr and \p size must be the same as that passed to dr_raw_mem_alloc()
* on Windows.
*/
bool
dr_raw_mem_free(void *addr, size_t size);
#ifdef LINUX
DR_API
/**
* Calls mremap with the specified parameters and returns the result.
* The old memory must be non-DR memory, and the new memory is also
* considered to be non-DR memory (see #DR_ALLOC_NON_DR).
* \note Linux-only.
*/
void *
dr_raw_mremap(void *old_address, size_t old_size, size_t new_size,
int flags, void *new_address);
DR_API
/**
* Sets the program break to the specified value. Invokes the SYS_brk
* system call and returns the result. This is the application's
* program break, so use this system call only when deliberately
* changing the application's behavior.
* \note Linux-only.
*/
void *
dr_raw_brk(void *new_address);
#endif
#ifdef UNIX
DR_API
/**
* Allocates memory from DR's global memory pool, but mimics the
* behavior of malloc. Memory must be freed with __wrap_free(). The
* __wrap routines are intended to be used with ld's -wrap option to
* replace a client's use of malloc, realloc, and free with internal
* versions that allocate memory from DR's private pool. With -wrap,
* clients can link to libraries that allocate heap memory without
* interfering with application allocations.
* \note Currently Linux only.
*/
void *
__wrap_malloc(size_t size);
DR_API
/**
* Reallocates memory from DR's global memory pool, but mimics the
* behavior of realloc. Memory must be freed with __wrap_free(). The
* __wrap routines are intended to be used with ld's -wrap option; see
* __wrap_malloc() for more information.
* \note Currently Linux only.
*/
void *
__wrap_realloc(void *mem, size_t size);
DR_API
/**
* Allocates memory from DR's global memory pool, but mimics the
* behavior of calloc. Memory must be freed with __wrap_free(). The
* __wrap routines are intended to be used with ld's -wrap option; see
* __wrap_malloc() for more information.
* \note Currently Linux only.
*/
void *
__wrap_calloc(size_t nmemb, size_t size);
DR_API
/**
* Frees memory from DR's global memory pool. Memory must have been
* allocated with __wrap_malloc(). The __wrap routines are intended to
* be used with ld's -wrap option; see __wrap_malloc() for more
* information.
* \note Currently Linux only.
*/
void
__wrap_free(void *mem);
#endif
/* DR_API EXPORT BEGIN */
/**************************************************
* MEMORY QUERY/ACCESS ROUTINES
*/
/* DR_API EXPORT END */
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, OUT dr_mem_info_t *info);
/* DR_API EXPORT BEGIN */
#ifdef WINDOWS
/* DR_API EXPORT END */
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);
/* DR_API EXPORT BEGIN */
#endif
/* DR_API EXPORT END */
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. Optionally returns the actual number of bytes copied
* into \p bytes_read. Returns true if successful.
* \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. Optionally returns the actual number of bytes copied
* into \p bytes_written. Returns true if successful.
* \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);
/* DR_API EXPORT BEGIN */
/**
* 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 EXPORT END */
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);
/* DR_API EXPORT BEGIN */
/**************************************************
* CLIENT AUXILIARY LIBRARIES
*/
/* DR_API EXPORT END */
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);
/* DR_API EXPORT BEGIN */
#if defined(WINDOWS) && !defined(X64)
/* DR_API EXPORT END */
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.
*/
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, ...);
/* DR_API EXPORT BEGIN */
#endif /* WINDOWS && !X64 */
/* DR_API EXPORT END */
/* DR_API EXPORT BEGIN */
/**************************************************
* LOCK SUPPORT
*/
/* DR_API EXPORT END */
DR_API
/**
* Initializes a mutex.
*
* Warning: there are restrictions on when DR-provided mutexes, and
* locks in general, can be held by a client: no lock should be held
* while application code is executing in the code cache. Locks can
* be used while inside client code reached from clean calls out of
* the code cache, but they must be released before returning to the
* cache. Failing to follow these restrictions can lead to deadlocks.
*/
void *
dr_mutex_create(void);
DR_API
/** Deletes \p mutex. */
void
dr_mutex_destroy(void *mutex);
DR_API
/** Locks \p mutex. Waits until the mutex is successfully held. */
void
dr_mutex_lock(void *mutex);
DR_API
/** Unlocks \p mutex. Asserts that mutex is currently locked. */
void
dr_mutex_unlock(void *mutex);
DR_API
/** Tries once to lock \p mutex, returns whether or not successful. */
bool
dr_mutex_trylock(void *mutex);
DR_API
/**
* Returns true iff \p mutex is owned by the calling thread.
* This routine is only available in debug builds.
* In release builds it always returns true.
*/
bool
dr_mutex_self_owns(void *mutex);
DR_API
/**
* Instructs DR to treat this lock as an application lock. Primarily
* this avoids debug-build checks that no DR locks are held in situations
* where locks are disallowed.
*
* \warning Any one lock should either be a DR lock or an application lock.
* Use this routine with caution and do not call it on a DR lock that is
* used in DR contexts, as it disables debug checks.
*
* \return whether successful.
*/
bool
dr_mutex_mark_as_app(void *mutex);
DR_API
/**
* Creates and initializes a read-write lock. A read-write lock allows
* multiple readers or alternatively a single writer. The lock
* restrictions for mutexes apply (see dr_mutex_create()).
*/
void *
dr_rwlock_create(void);
DR_API
/** Deletes \p rwlock. */
void
dr_rwlock_destroy(void *rwlock);
DR_API
/** Acquires a read lock on \p rwlock. */
void
dr_rwlock_read_lock(void *rwlock);
DR_API
/** Releases a read lock on \p rwlock. */
void
dr_rwlock_read_unlock(void *rwlock);
DR_API
/** Acquires a write lock on \p rwlock. */
void
dr_rwlock_write_lock(void *rwlock);
DR_API
/** Releases a write lock on \p rwlock. */
void
dr_rwlock_write_unlock(void *rwlock);
DR_API
/** Tries once to acquire a write lock on \p rwlock and returns whether successful. */
bool
dr_rwlock_write_trylock(void *rwlock);
DR_API
/** Returns whether the calling thread owns the write lock on \p rwlock. */
bool
dr_rwlock_self_owns_write_lock(void *rwlock);
DR_API
/**
* Instructs DR to treat this lock as an application lock. Primarily
* this avoids debug-build checks that no DR locks are held in situations
* where locks are disallowed.
*
* \warning Any one lock should either be a DR lock or an application lock.
* Use this routine with caution and do not call it on a DR lock that is
* used in DR contexts, as it disables debug checks.
*
* \return whether successful.
*/
bool
dr_rwlock_mark_as_app(void *rwlock);
DR_API
/**
* Creates and initializes a recursive lock. A recursive lock allows
* the same thread to acquire it multiple times. The lock
* restrictions for mutexes apply (see dr_mutex_create()).
*/
void *
dr_recurlock_create(void);
DR_API
/** Deletes \p reclock. */
void
dr_recurlock_destroy(void *reclock);
DR_API
/** Acquires \p reclock, or increments the ownership count if already owned. */
void
dr_recurlock_lock(void *reclock);
DR_API
/** Decrements the ownership count of \p reclock and releases if zero. */
void
dr_recurlock_unlock(void *reclock);
DR_API
/** Tries once to acquire \p reclock and returns whether successful. */
bool
dr_recurlock_trylock(void *reclock);
DR_API
/** Returns whether the calling thread owns \p reclock. */
bool
dr_recurlock_self_owns(void *reclock);
DR_API
/**
* Instructs DR to treat this lock as an application lock. Primarily
* this avoids debug-build checks that no DR locks are held in situations
* where locks are disallowed.
*
* \warning Any one lock should either be a DR lock or an application lock.
* Use this routine with caution and do not call it on a DR lock that is
* used in DR contexts, as it disables debug checks.
*
* \return whether successful.
*/
bool
dr_recurlock_mark_as_app(void *reclock);
DR_API
/**
* Use this function to mark a region of code as safe for DR to suspend
* the client while inside the region. DR will not relocate the client
* from the region and will resume it at precisely the suspend point.
*
* This function must be used in client code that acquires application locks.
* Use this feature with care! Do not mark code as safe to suspend that has
* a code cache return point. I.e., do not call this routine from a clean
* call.
*
* No DR locks can be held while in a safe region. Consequently, do
* not call this routine from any DR event callback. It may only be used
* from natively executing code.
*
* Always invoke this routine in pairs, with the first passing true
* for \p enter and the second passing false, thus delimiting the
* region.
*/
bool
dr_mark_safe_to_suspend(void *drcontext, bool enter);
DR_API
/** Atomically adds \p *x and \p val and returns the sum. */
int
dr_atomic_add32_return_sum(volatile int *x, int val);
/* DR_API EXPORT BEGIN */
/**************************************************
* MODULE INFORMATION ROUTINES
*/
/** For dr_module_iterator_* interface */
typedef void * dr_module_iterator_t;
#ifdef AVOID_API_EXPORT
/* We always give copies of the module_area_t information to clients (in the form
* of a module_data_t defined below) to avoid locking issues (see PR 225020). */
/* i#160/PR 562667: support non-contiguous library mappings. While we're at
* it we go ahead and store info on each segment whether contiguous or not.
*/
#endif
#ifdef UNIX
/** Holds information on a segment of a loaded module. */
typedef struct _module_segment_data_t {
app_pc start; /**< Start address of the segment, page-aligned backward. */
app_pc end; /**< End address of the segment, page-aligned forward. */
uint prot; /**< Protection attributes of the segment */
} module_segment_data_t;
#endif
/**
* Holds information about a loaded module. \note On Linux the start address can be
* cast to an Elf32_Ehdr or Elf64_Ehdr. \note On Windows the start address can be cast to
* an IMAGE_DOS_HEADER for use in finding the IMAGE_NT_HEADER and its OptionalHeader.
* The OptionalHeader can be used to walk the module sections (among other things).
* See WINNT.H. \note On MacOS the start address can be cast to mach_header or
* mach_header_64.
* \note When accessing any memory inside the module (including header fields)
* user is responsible for guarding against corruption and the possibility of the module
* being unmapped.
*/
struct _module_data_t {
union {
app_pc start; /**< starting address of this module */
module_handle_t handle; /**< module_handle for use with dr_get_proc_address() */
} ; /* anonymous union of start address and module handle */
/**
* Ending address of this module. If the module is not contiguous
* (which is common on MacOS, and can happen on Linux), this is the
* highest address of the module, but there can be gaps in between start
* and end that are either unmapped or that contain other mappings or
* libraries. Use the segments array to examine each mapped region,
* and use dr_module_contains_addr() as a convenience routine, rather than
* checking against [start..end).
*/
app_pc end;
app_pc entry_point; /**< entry point for this module as specified in the headers */
uint flags; /**< Reserved, set to 0 */
module_names_t names; /**< struct containing name(s) for this module; use
* dr_module_preferred_name() to get the preferred name for
* this module */
char *full_path; /**< full path to the file backing this module */
#ifdef WINDOWS
version_number_t file_version; /**< file version number from .rsrc section */
version_number_t product_version; /**< product version number from .rsrc section */
uint checksum; /**< module checksum from the PE headers */
uint timestamp; /**< module timestamp from the PE headers */
size_t module_internal_size; /**< module internal size (from PE headers SizeOfImage) */
#else
bool contiguous; /**< whether there are no gaps between segments */
uint num_segments; /**< number of segments */
/**
* Array of num_segments entries, one per segment. The array is sorted
* by the start address of each segment.
*/
module_segment_data_t *segments;
uint timestamp; /**< Timestamp from ELF Mach-O headers. */
# ifdef MACOS
uint current_version; /**< Current version from Mach-O headers. */
uint compatibility_version; /**< Compatibility version from Mach-O headers. */
byte uuid[16]; /**< UUID from Mach-O headers. */
# endif
#endif
#ifdef AVOID_API_EXPORT
/* FIXME: PR 215890: ELF64 size? Anything else? */
/* We can add additional fields to the end without breaking compatibility */
#endif
};
/* DR_API EXPORT END */
DR_API
/**
* Looks up the module containing \p pc. If a module containing \p pc is found
* returns a module_data_t describing that module. Returns NULL if \p pc is
* outside all known modules, which is the case for most dynamically generated
* code. Can be used to obtain a module_handle_t for dr_lookup_module_section()
* or dr_get_proc_address() via the \p handle field inside module_data_t.
*
* \note Returned module_data_t must be freed with dr_free_module_data().
*/
module_data_t *
dr_lookup_module(byte *pc);
DR_API
/**
* Looks up the module with name \p name ignoring case. If an exact name match is found
* returns a module_data_t describing that module else returns NULL. User must call
* dr_free_module_data() on the returned module_data_t once finished. Can be used to
* obtain a module_handle_t for dr_get_proc_address().
* \note Returned module_data_t must be freed with dr_free_module_data().
*/
module_data_t *
dr_lookup_module_by_name(const char *name);
DR_API
/**
* Looks up module data for the main executable.
* \note Returned module_data_t must be freed with dr_free_module_data().
*/
module_data_t *
dr_get_main_module(void);
DR_API
/**
* Initialize a new module iterator. The returned module iterator contains a snapshot
* of the modules loaded at the time it was created. Use dr_module_iterator_hasnext()
* and dr_module_iterator_next() to walk the loaded modules. Call
* dr_module_iterator_stop() when finished to release the iterator. \note The iterator
* does not prevent modules from being loaded or unloaded while the iterator is being
* walked.
*/
dr_module_iterator_t *
dr_module_iterator_start(void);
DR_API
/**
* Returns true if there is another loaded module in the iterator.
*/
bool
dr_module_iterator_hasnext(dr_module_iterator_t *mi);
DR_API
/**
* Retrieves the module_data_t for the next loaded module in the iterator. User must call
* dr_free_module_data() on the returned module_data_t once finished.
* \note Returned module_data_t must be freed with dr_free_module_data().
*/
module_data_t *
dr_module_iterator_next(dr_module_iterator_t *mi);
DR_API
/**
* User should call this routine to free the module iterator.
*/
void
dr_module_iterator_stop(dr_module_iterator_t *mi);
DR_API
/**
* Makes a copy of \p data. Copy must be freed with dr_free_module_data().
* Useful for making persistent copies of module_data_t's received as part of
* image load and unload event callbacks.
*/
module_data_t *
dr_copy_module_data(const module_data_t *data);
DR_API
/**
* Frees a module_data_t returned by dr_module_iterator_next(), dr_lookup_module(),
* dr_lookup_module_by_name(), or dr_copy_module_data(). \note Should NOT be used with
* a module_data_t obtained as part of a module load or unload event.
*/
void
dr_free_module_data(module_data_t *data);
DR_API
/**
* Returns the preferred name for the module described by \p data from
* \p data->module_names.
*/
const char *
dr_module_preferred_name(const module_data_t *data);
DR_API
/**
* Returns whether \p addr is contained inside any segment of the module \p data.
* We recommend using this routine rather than checking against the \p start
* and \p end fields of \p data, as modules are not always contiguous.
*/
bool
dr_module_contains_addr(const module_data_t *data, app_pc addr);
/* DR_API EXPORT BEGIN */
/**
* Iterator over the list of modules that a given module imports from. Created
* by calling dr_module_import_iterator_start() and must be freed by calling
* dr_module_import_iterator_stop().
*
* \note On Windows, delay-loaded DLLs are not included yet.
*
* \note ELF does not import directly from other modules.
*/
struct _dr_module_import_iterator_t;
typedef struct _dr_module_import_iterator_t dr_module_import_iterator_t;
/**
* Descriptor used to iterate the symbols imported from a specific module.
*/
struct _dr_module_import_desc_t;
typedef struct _dr_module_import_desc_t dr_module_import_desc_t;
/**
* Module import data returned from dr_module_import_iterator_next().
*
* String fields point into the importing module image. Robust clients should
* use DR_TRY_EXCEPT while inspecting the strings in case the module is
* partially mapped or the app racily unmaps it. The iterator routines
* themselves handle faults by stopping the iteration.
*
* \note ELF does not import directly from other modules.
*/
typedef struct _dr_module_import_t {
/**
* Specified name of the imported module or API set.
*/
const char *modname;
/**
* Opaque handle that can be passed to dr_symbol_import_iterator_start().
* Valid until the original module is unmapped.
*/
dr_module_import_desc_t *module_import_desc;
} dr_module_import_t;
/* DR_API EXPORT END */
DR_API
/**
* Creates a module import iterator. Iterates over the list of modules that a
* given module imports from.
*
* \note ELF does not import directly from other modules.
*/
dr_module_import_iterator_t *
dr_module_import_iterator_start(module_handle_t handle);
DR_API
/**
* Returns true if there is another module import in the iterator.
*
* \note ELF does not import directly from other modules.
*/
bool
dr_module_import_iterator_hasnext(dr_module_import_iterator_t *iter);
DR_API
/**
* Advances the passed-in iterator and returns the current module import in the
* iterator. The pointer returned is only valid until the next call to
* dr_module_import_iterator_next() or dr_module_import_iterator_stop().
*
* \note ELF does not import directly from other modules.
*/
dr_module_import_t *
dr_module_import_iterator_next(dr_module_import_iterator_t *iter);
DR_API
/**
* Stops import iteration and frees a module import iterator.
*
* \note ELF does not import directly from other modules.
*/
void
dr_module_import_iterator_stop(dr_module_import_iterator_t *iter);
/* DR_API EXPORT BEGIN */
/**
* Symbol import iterator data type. Can be created by calling
* dr_symbol_import_iterator_start() and must be freed by calling
* dr_symbol_import_iterator_stop().
*/
struct _dr_symbol_import_iterator_t;
typedef struct _dr_symbol_import_iterator_t dr_symbol_import_iterator_t;
/**
* Symbol import data returned from dr_symbol_import_iterator_next().
*
* String fields point into the importing module image. Robust clients should
* use DR_TRY_EXCEPT while inspecting the strings in case the module is
* partially mapped or the app racily unmaps it.
*/
typedef struct _dr_symbol_import_t {
const char *name; /**< Name of imported symbol, if available. */
const char *modname; /**< Preferred name of module (Windows only). */
bool delay_load; /**< This import is delay-loaded (Windows only). */
bool by_ordinal; /**< Import is by ordinal, not name (Windows only). */
ptr_uint_t ordinal; /**< Ordinal value (Windows only). */
/* DR_API EXPORT END */
/* We never ask the client to allocate this struct, so we can go ahead and
* add fields here without breaking ABI compat.
*/
/* DR_API EXPORT BEGIN */
} dr_symbol_import_t;
/* DR_API EXPORT END */
DR_API
/**
* Creates an iterator over symbols imported by a module. If \p from_module is
* NULL, all imported symbols are yielded, regardless of which module they were
* imported from.
*
* On Windows, from_module is obtained from a \p dr_module_import_t and used to
* iterate over all of the imports from a specific module.
*
* The iterator returned is invalid until after the first call to
* dr_symbol_import_iterator_next().
*
* \note On Windows, symbols imported from delay-loaded DLLs are not included
* yet.
*/
dr_symbol_import_iterator_t *
dr_symbol_import_iterator_start(module_handle_t handle,
dr_module_import_desc_t *from_module);
DR_API
/**
* Returns true if there is another imported symbol in the iterator.
*/
bool
dr_symbol_import_iterator_hasnext(dr_symbol_import_iterator_t *iter);
DR_API
/**
* Returns the next imported symbol. The returned pointer is valid until the
* next call to dr_symbol_import_iterator_next() or
* dr_symbol_import_iterator_stop().
*/
dr_symbol_import_t *
dr_symbol_import_iterator_next(dr_symbol_import_iterator_t *iter);
DR_API
/**
* Stops symbol import iteration and frees the iterator.
*/
void
dr_symbol_import_iterator_stop(dr_symbol_import_iterator_t *iter);
/* DR_API EXPORT BEGIN */
/**
* Symbol export iterator data type. Can be created by calling
* dr_symbol_export_iterator_start() and must be freed by calling
* dr_symbol_export_iterator_stop().
*/
struct _dr_symbol_export_iterator_t;
typedef struct _dr_symbol_export_iterator_t dr_symbol_export_iterator_t;
/**
* Symbol export data returned from dr_symbol_export_iterator_next().
*
* String fields point into the exporting module image. Robust clients should
* use DR_TRY_EXCEPT while inspecting the strings in case the module is
* partially mapped or the app racily unmaps it.
*
* On Windows, the address in \p addr may not be inside the exporting module if
* it is a forward and has been patched by the loader. In that case, \p forward
* will be NULL.
*/
typedef struct _dr_symbol_export_t {
const char *name; /**< Name of exported symbol, if available. */
app_pc addr; /**< Address of the exported symbol. */
const char *forward; /**< Forward name, or NULL if not forwarded (Windows only). */
ptr_uint_t ordinal; /**< Ordinal value (Windows only). */
/**
* Whether an indirect code object (see dr_export_info_t). (Linux only).
*/
bool is_indirect_code;
bool is_code; /**< Whether code as opposed to exported data (Linux only). */
/* DR_API EXPORT END */
/* We never ask the client to allocate this struct, so we can go ahead and
* add fields here without breaking ABI compat.
*/
/* DR_API EXPORT BEGIN */
} dr_symbol_export_t;
/* DR_API EXPORT END */
DR_API
/**
* Creates an iterator over symbols exported by a module.
* The iterator returned is invalid until after the first call to
* dr_symbol_export_iterator_next().
*
* \note To iterate over all symbols in a module and not just those exported,
* use the \ref page_drsyms.
*/
dr_symbol_export_iterator_t *
dr_symbol_export_iterator_start(module_handle_t handle);
DR_API
/**
* Returns true if there is another exported symbol in the iterator.
*/
bool
dr_symbol_export_iterator_hasnext(dr_symbol_export_iterator_t *iter);
DR_API
/**
* Returns the next exported symbol. The returned pointer is valid until the
* next call to dr_symbol_export_iterator_next() or
* dr_symbol_export_iterator_stop().
*/
dr_symbol_export_t *
dr_symbol_export_iterator_next(dr_symbol_export_iterator_t *iter);
DR_API
/**
* Stops symbol export iteration and frees the iterator.
*/
void
dr_symbol_export_iterator_stop(dr_symbol_export_iterator_t *iter);
/* DR_API EXPORT BEGIN */
#ifdef WINDOWS
/* DR_API EXPORT END */
DR_API
/**
* Returns whether \p pc is within a section within the module in \p section_found and
* information about that section in \p section_out. \note Not yet available on Linux.
*/
bool
dr_lookup_module_section(module_handle_t lib,
byte *pc, IMAGE_SECTION_HEADER *section_out);
/* DR_API EXPORT BEGIN */
#endif /* WINDOWS */
/* DR_API EXPORT END */
DR_API
/**
* Set whether or not the module referred to by \p handle should be
* instrumented. If \p should_instrument is false, code from the module will
* not be passed to the basic block event. If traces are enabled, code from the
* module will still reach the trace event. Must be called from the module load
* event for the module referred to by \p handle.
* \return whether successful.
*
* \warning Turning off instrumentation for modules breaks clients and
* extensions, such as drwrap, that expect to see every instruction.
*/
bool
dr_module_set_should_instrument(module_handle_t handle, bool should_instrument);
DR_API
/**
* Return whether code from the module should be instrumented, meaning passed
* to the basic block event.
*/
bool
dr_module_should_instrument(module_handle_t handle);
DR_API
/**
* Returns the entry point of the exported function with the given
* name in the module with the given base. Returns NULL on failure.
*
* On Linux, when we say "exported" we mean present in the dynamic
* symbol table (.dynsym). Global functions and variables in an
* executable (as opposed to a library) are not exported by default.
* If an executable is built with the \p -rdynamic flag to \p gcc, its
* global symbols will be present in .dynsym and dr_get_proc_address()
* will locate them. Otherwise, the drsyms Extension (see \ref
* page_drsyms) must be used to locate the symbols. drsyms searches
* the debug symbol table (.symtab) in addition to .dynsym.
*
* \note On Linux this ignores symbol preemption by other modules and only
* examines the specified module.
* \note On Linux, in order to handle indirect code objects, use
* dr_get_proc_address_ex().
*/
generic_func_t
dr_get_proc_address(module_handle_t lib, const char *name);
/* DR_API EXPORT BEGIN */
/**
* Data structure used by dr_get_proc_address_ex() to retrieve information
* about an exported symbol.
*/
typedef struct _dr_export_info_t {
/**
* The entry point of the export as an absolute address located
* within the queried module. This address is identical to what
* dr_get_proc_address_ex() returns.
*/
generic_func_t address;
/**
* Relevant for Linux only. Set to true iff this export is an
* indirect code object, which is a new ELF extension allowing
* runtime selection of which implementation to use for an
* exported symbol. The address of such an export is a function
* that takes no arguments and returns the address of the selected
* implementation.
*/
bool is_indirect_code;
} dr_export_info_t;
/* DR_API EXPORT END */
DR_API
/**
* Returns information in \p info about the symbol \p name exported
* by the module \p lib. Returns false if the symbol is not found.
* See the information in dr_get_proc_address() about what an
* "exported" function is on Linux.
*
* \note On Linux this ignores symbol preemption by other modules and only
* examines the specified module.
*/
bool
dr_get_proc_address_ex(module_handle_t lib, const char *name,
dr_export_info_t *info OUT, size_t info_len);
/* DR_API EXPORT BEGIN */
/**************************************************
* SYSTEM CALL PROCESSING ROUTINES
*/
/**
* Data structure used to obtain or modify the result of an application
* system call by dr_syscall_get_result_ex() and dr_syscall_set_result_ex().
*/
typedef struct _dr_syscall_result_info_t {
/** The caller should set this to the size of the structure. */
size_t size;
/**
* Indicates whether the system call succeeded or failed. For
* dr_syscall_set_result_ex(), this requests that DR set any
* additional machine state, if any, used by the particular
* plaform that is not part of \p value to indicate success or
* failure (e.g., on MacOS the carry flag is used to indicate
* success).
*
* For Windows, the success result from dr_syscall_get_result_ex()
* should only be relied upon for ntoskrnl system calls. For
* other Windows system calls (such as win32k.sys graphical
* (NtGdi) or user (NtUser) system calls), computing success
* depends on each particular call semantics and is beyond the
* scope of this routine (consider using the "drsyscall" Extension
* instead).
*
* For Mach syscalls on MacOS, the success result from
* dr_syscall_get_result_ex() should not be relied upon.
* Computing success depends on each particular call semantics and
* is beyond the scope of this routine (consider using the
* "drsyscall" Extension instead).
*/
bool succeeded;
/**
* The raw main value returned by the system call.
* See also the \p high field.
*/
reg_t value;
/**
* On some platforms (such as MacOS), a 32-bit application's
* system call can return a 64-bit value. For such calls,
* this field will hold the top 32 bit bits, if requested
* by \p use_high. It is up to the caller to know which
* system calls have 64-bit return values. System calls that
* return only 32-bit values do not clear the upper bits.
* Consider using the "drsyscall" Extension in order to obtain
* per-system-call semantic information, including return type.
*/
reg_t high;
/**
* This should be set by the caller, and only applies to 32-bit
* system calls. For dr_syscall_get_result_ex(), this requests
* that DR fill in the \p high field. For
* dr_syscall_set_result_ex(), this requests that DR set the high
* 32 bits of the application-facing result to the value in the \p
* high field.
*/
bool use_high;
/**
* This should be set by the caller. For dr_syscall_get_result_ex(),
* this requests that DR fill in the \p errno_value field.
* For dr_syscall_set_result_ex(), this requests that DR set the
* \p value to indicate the particular error code in \p errno_value.
*/
bool use_errno;
/**
* If requested by \p use_errno, if a system call fails (i.e., \p
* succeeded is false) dr_syscall_get_result_ex() will set this
* field to the absolute value of the error code returned (i.e.,
* on Linux, it will be inverted from what the kernel directly
* returns, in order to facilitate cross-platform clients that
* operate on both Linux and MacOS). For Linux and Macos, when
* \p succeeded is true, \p errno_value is set to 0.
*
* If \p use_errno is set for dr_syscall_set_result_ex(), then
* this value will be stored as the system call's return value,
* negated if necessary for the underlying platform. In that
* case, \p value will be ignored.
*/
uint errno_value;
} dr_syscall_result_info_t;
/* DR_API EXPORT END */
DR_API
/**
* Usable only from a pre-syscall (dr_register_pre_syscall_event())
* event. Returns the value of system call parameter number \p param_num.
*
* It is up to the caller to ensure that reading this parameter is
* safe: this routine does not know the number of parameters for each
* system call, nor does it check whether this might read off the base
* of the stack.
*
* \note On some platforms, notably MacOS, a 32-bit application's
* system call can still take a 64-bit parameter (typically on the
* stack). In that situation, this routine will consider the 64-bit
* parameter to be split into high and low parts, each with its own
* parameter number.
*/
reg_t
dr_syscall_get_param(void *drcontext, int param_num);
DR_API
/**
* Usable only from a pre-syscall (dr_register_pre_syscall_event())
* event, or from a post-syscall (dr_register_post_syscall_event())
* event when also using dr_syscall_invoke_another(). Sets the value
* of system call parameter number \p param_num to \p new_value.
*
* It is up to the caller to ensure that writing this parameter is
* safe: this routine does not know the number of parameters for each
* system call, nor does it check whether this might write beyond the
* base of the stack.
*
* \note On some platforms, notably MacOS, a 32-bit application's
* system call can still take a 64-bit parameter (typically on the
* stack). In that situation, this routine will consider the 64-bit
* parameter to be split into high and low parts, each with its own
* parameter number.
*/
void
dr_syscall_set_param(void *drcontext, int param_num, reg_t new_value);
DR_API
/**
* Usable only from a post-syscall (dr_register_post_syscall_event())
* event. Returns the return value of the system call that will be
* presented to the application.
*
* \note On some platforms (such as MacOS), a 32-bit application's
* system call can return a 64-bit value. Use dr_syscall_get_result_ex()
* to obtain the upper bits in that case.
*
* \note On some platforms (such as MacOS), whether a system call
* succeeded or failed cannot be determined from the main result
* value. Use dr_syscall_get_result_ex() to obtain the success result
* in such cases.
*/
reg_t
dr_syscall_get_result(void *drcontext);
DR_API
/**
* Usable only from a post-syscall (dr_register_post_syscall_event())
* event. Returns whether it successfully retrieved the results
* of the system call into \p info.
*
* The caller should set the \p size, \p use_high, and \p use_errno fields
* of \p info prior to calling this routine.
* See the fields of #dr_syscall_result_info_t for details.
*/
bool
dr_syscall_get_result_ex(void *drcontext, dr_syscall_result_info_t *info INOUT);
DR_API
/**
* Usable only from a pre-syscall (dr_register_pre_syscall_event()) or
* post-syscall (dr_register_post_syscall_event()) event.
* For pre-syscall, should only be used when skipping the system call.
* This sets the return value of the system call that the application sees
* to \p value.
*
* \note On MacOS, do not use this function as it fails to set the
* carry flag and thus fails to properly indicate whether the system
* call succeeded or failed: use dr_syscall_set_result_ex() instead.
*/
void
dr_syscall_set_result(void *drcontext, reg_t value);
DR_API
/**
* Usable only from a pre-syscall (dr_register_pre_syscall_event()) or
* post-syscall (dr_register_post_syscall_event()) event.
* For pre-syscall, should only be used when skipping the system call.
*
* This sets the returned results of the system call as specified in
* \p info. Returns whether it successfully did so.
* See the fields of #dr_syscall_result_info_t for details.
*/
bool
dr_syscall_set_result_ex(void *drcontext, dr_syscall_result_info_t *info);
DR_API
/**
* Usable only from a pre-syscall (dr_register_pre_syscall_event())
* event, or from a post-syscall (dr_register_post_syscall_event())
* event when also using dr_syscall_invoke_another(). Sets the system
* call number of the system call about to be invoked to \p new_num.
*/
void
dr_syscall_set_sysnum(void *drcontext, int new_num);
DR_API
/**
* Usable only from a post-syscall (dr_register_post_syscall_event())
* event. An additional system call will be invoked immediately,
* using the current values of the parameters, which can be set with
* dr_syscall_set_param(). The system call to be invoked should be
* specified with dr_syscall_set_sysnum().
*
* Use this routine with caution. Especially on Windows, care must be
* taken if the application is expected to continue afterward. When
* system call parameters are stored on the stack, modifying them can
* result in incorrect application behavior, particularly when setting
* more parameters than were present in the original system call,
* which will result in corruption of the application stack.
*
* On Windows, when the first system call is interruptible
* (alertable), the additional system call may be delayed.
*
* DR will set key registers such as r10 for 64-bit or xdx for
* sysenter or WOW64 system calls. However, DR will not set ecx for
* WOW64; that is up to the client.
*/
void
dr_syscall_invoke_another(void *drcontext);
#ifdef WINDOWS
DR_API
/**
* Must be invoked from dr_init(). Requests that the named ntoskrnl
* system call be intercepted even when threads are native (e.g., due
* to #DR_EMIT_GO_NATIVE). Only a limited number of system calls
* being intercepted while native are supported. This routine will
* fail once that limit is reached.
*
* @param[in] name The system call name. The name must match an exported
* system call wrapper in \p ntdll.dll.
* @param[in] sysnum The system call number (the value placed in the eax register).
* @param[in] num_args The number of arguments to the system call.
* @param[in] wow64_index The value placed in the ecx register when this system
* call is executed in a WOW64 process. This value should be obtainable
* by examining the system call wrapper.
*
* \note Windows only.
*/
bool
dr_syscall_intercept_natively(const char *name, int sysnum, int num_args,
int wow64_index);
#endif
/* DR_API EXPORT BEGIN */
/**************************************************
* PLATFORM-INDEPENDENT FILE SUPPORT
*
* Since a FILE cannot be used outside of the DLL it was created in,
* we have to use HANDLE on Windows.
* We hide the distinction behind the file_t type
*/
/* DR_API EXPORT END */
DR_API
/**
* Creates a new directory. Fails if the directory already exists
* or if it can't be created.
* Relative path support on Windows is identical to that described in dr_open_file().
*/
bool
dr_create_dir(const char *fname);
DR_API
/**
* Deletes the given directory. Fails if the directory is not empty.
* Relative path support on Windows is identical to that described in dr_open_file().
*/
bool
dr_delete_dir(const char *fname);
DR_API
/**
* Returns the current directory for this process in \p buf.
* On Windows, reading the current directory is considered unsafe
* except during initialization, as it is stored in user memory and
* access is not controlled via any standard synchronization.
*/
bool
dr_get_current_directory(char *buf, size_t bufsz);
DR_API
/**
* Checks for the existence of a directory.
* Relative path support on Windows is identical to that described in dr_open_file().
*/
bool
dr_directory_exists(const char *fname);
DR_API
/**
* Checks the existence of a file.
* Relative path support on Windows is identical to that described in dr_open_file().
*/
bool
dr_file_exists(const char *fname);
/* The extra BEGIN END is to get spacing nice. */
/* DR_API EXPORT BEGIN */
/* DR_API EXPORT END */
/* DR_API EXPORT BEGIN */
/* flags for use with dr_open_file() */
/** Open with read access. */
#define DR_FILE_READ 0x1
/** Open with write access, but do not open if the file already exists. */
#define DR_FILE_WRITE_REQUIRE_NEW 0x2
/**
* Open with write access. If the file already exists, set the file position to the
* end of the file.
*/
#define DR_FILE_WRITE_APPEND 0x4
/**
* Open with write access. If the file already exists, truncate the
* file to zero length.
*/
#define DR_FILE_WRITE_OVERWRITE 0x8
/**
* Open with large (>2GB) file support. Only applicable on 32-bit Linux.
* \note DR's log files and tracedump files are all created with this flag.
*/
#define DR_FILE_ALLOW_LARGE 0x10
/** Linux-only. This file will be closed in the child of a fork. */
#define DR_FILE_CLOSE_ON_FORK 0x20
/* DR_API EXPORT END */
DR_API
/**
* Opens the file \p fname. If no such file exists then one is created.
* The file access mode is set by the \p mode_flags argument which is drawn from
* the DR_FILE_* defines ORed together. Returns INVALID_FILE if unsuccessful.
*
* On Windows, \p fname is safest as an absolute path (when using Windows system
* calls directly there is no such thing as a relative path). A relative path
* passed to this routine will be converted to absolute on a best-effort basis
* using the current directory that was set at process initialization time.
* (The most recently set current directory can be retrieved (albeit with no
* safety guarantees) with dr_get_current_directory().) Drive-implied-absolute
* paths ("\foo.txt") and other-drive-relative paths ("c:foo.txt") are not
* supported.
*
* On Linux, the file descriptor will be marked as close-on-exec. The
* DR_FILE_CLOSE_ON_FORK flag can be used to automatically close a
* file on a fork.
*
* \note No more then one write mode flag can be specified.
*
* \note On Linux, DR hides files opened by clients from the
* application by using file descriptors that are separate from the
* application's and preventing the application from closing
* client-opened files.
*/
file_t
dr_open_file(const char *fname, uint mode_flags);
DR_API
/** Closes file \p f. */
void
dr_close_file(file_t f);
DR_API
/**
* Renames the file \p src to \p dst, replacing an existing file named \p dst if
* \p replace is true.
* Atomic if \p src and \p dst are on the same filesystem.
* Returns true if successful.
*/
bool
dr_rename_file(const char *src, const char *dst, bool replace);
DR_API
/**
* Deletes the file referred to by \p filename.
* Returns true if successful.
* On both Linux and Windows, if filename refers to a symlink, the symlink will
* be deleted and not the target of the symlink.
* On Windows, this will fail to delete any file that was not opened with
* FILE_SHARE_DELETE and is still open.
* Relative path support on Windows is identical to that described in dr_open_file().
*/
bool
dr_delete_file(const char *filename);
DR_API
/** Flushes any buffers for file \p f. */
void
dr_flush_file(file_t f);
DR_API
/**
* Writes \p count bytes from \p buf to file \p f.
* Returns the actual number written.
*/
ssize_t
dr_write_file(file_t f, const void *buf, size_t count);
DR_API
/**
* Reads up to \p count bytes from file \p f into \p buf.
* Returns the actual number read.
*/
ssize_t
dr_read_file(file_t f, void *buf, size_t count);
/* NOTE - keep in synch with OS_SEEK_* in os_shared.h and SEEK_* from Linux headers.
* The extra BEGIN END is to get spacing nice. Once we have more control over the layout
* of the API header files share with os_shared.h. */
/* DR_API EXPORT BEGIN */
/* DR_API EXPORT END */
/* DR_API EXPORT BEGIN */
/* For use with dr_file_seek(), specifies the origin at which to apply the offset. */
#define DR_SEEK_SET 0 /**< start of file */
#define DR_SEEK_CUR 1 /**< current file position */
#define DR_SEEK_END 2 /**< end of file */
/* DR_API EXPORT END */
DR_API
/**
* Sets the current file position for file \p f to \p offset bytes
* from the specified origin, where \p origin is one of the DR_SEEK_*
* values. Returns true if successful.
*/
bool
dr_file_seek(file_t f, int64 offset, int origin);
DR_API
/**
* Returns the current position for the file \p f in bytes from the start of the file.
* Returns -1 on an error.
*/
int64
dr_file_tell(file_t f);
DR_API
/**
* Returns a new copy of the file handle \p f.
* Returns INVALID_FILE on error.
*/
file_t
dr_dup_file_handle(file_t f);
DR_API
/**
* Determines the size of the file \p fd.
* On success, returns the size in \p size.
* \return whether successful.
*/
bool
dr_file_size(file_t fd, OUT uint64 *size);
/* The extra BEGIN END is to get spacing nice. */
/* DR_API EXPORT BEGIN */
/* DR_API EXPORT END */
/* DR_API EXPORT BEGIN */
/* flags for use with dr_map_file() */
enum {
/**
* If set, changes to mapped memory are private to the mapping process and
* are not reflected in the underlying file. If not set, changes are visible
* to other processes that map the same file, and will be propagated
* to the file itself.
*/
DR_MAP_PRIVATE = 0x0001,
#ifdef UNIX
/**
* If set, indicates that the passed-in start address is required rather than a
* hint. On Linux, this has the same semantics as mmap with MAP_FIXED: i.e.,
* any existing mapping in [addr,addr+size) will be unmapped. This flag is not
* supported on Windows.
*/
DR_MAP_FIXED = 0x0002,
#endif
#ifdef WINDOWS
/**
* If set, loads the specified file as an executable image, rather than a data
* file. This flag is not supported on Linux.
*/
DR_MAP_IMAGE = 0x0004,
#endif
/**
* If set, loads the specified file at a location that is reachable from
* the code cache and client libraries by a 32-bit displacement. If not
* set, the mapped file is not guaranteed to be reachable from the cache.
*/
DR_MAP_CACHE_REACHABLE = 0x0008,
};
/* DR_API EXPORT END */
DR_API
/**
* Memory-maps \p size bytes starting at offset \p offs from the file \p f
* at address \p addr with privileges \p prot.
*
* @param[in] f The file to map.
* @param[in,out] size The requested size to map. Upon successful return,
* contains the actual mapped size.
* @param[in] offs The offset within the file at which to start the map.
* @param[in] addr The requested start address of the map. Unless \p fixed
* is true, this is just a hint and may not be honored.
* @param[in] prot The access privileges of the mapping, composed of
* the DR_MEMPROT_READ, DR_MEMPROT_WRITE, and DR_MEMPROT_EXEC bits.
* @param[in] flags Optional DR_MAP_* flags.
*
* \note Mapping image files for execution is not supported.
*
* \return the start address of the mapping, or NULL if unsuccessful.
*/
void *
dr_map_file(file_t f, INOUT size_t *size, uint64 offs, app_pc addr, uint prot,
uint flags);
DR_API
/**
* Unmaps a portion of a file mapping previously created by dr_map_file().
* \return whether successful.
*
* @param[in] map The base address to be unmapped. Must be page size aligned.
* @param[in] size The size to be unmapped.
* All pages overlapping with the range are unmapped.
*
* \note On Windows, the whole file will be unmapped instead.
*
*/
bool
dr_unmap_file(void *map, size_t size);
/* TODO add copy_file, truncate_file etc.
* All should be easy though at some point should perhaps tell people to just use the raw
* systemcalls, esp for linux where they're documented and let them provide their own
* wrappers. */
/* DR_API EXPORT BEGIN */
/**************************************************
* PRINTING
*/
/* DR_API EXPORT END */
DR_API
/**
* Writes to DR's log file for the thread with drcontext \p drcontext if the current
* loglevel is >= \p level and the current \p logmask & \p mask != 0.
* The mask constants are below.
* Logging is disabled for the release build.
* If \p drcontext is NULL, writes to the main log file.
*/
void
dr_log(void *drcontext, uint mask, uint level, const char *fmt, ...);
/* hack to get these constants in the right place in dr_ir_api.h */
#if 0 /* now skip a line to prevent gen_api.pl from removing this */
/* DR_API EXPORT BEGIN */
/* The log mask constants */
#define LOG_NONE 0x00000000 /**< Log no data. */
#define LOG_STATS 0x00000001 /**< Log per-thread and global statistics. */
#define LOG_TOP 0x00000002 /**< Log top-level information. */
#define LOG_THREADS 0x00000004 /**< Log data related to threads. */
#define LOG_SYSCALLS 0x00000008 /**< Log data related to system calls. */
#define LOG_ASYNCH 0x00000010 /**< Log data related to signals/callbacks/etc. */
#define LOG_INTERP 0x00000020 /**< Log data related to app interpretation. */
#define LOG_EMIT 0x00000040 /**< Log data related to emitting code. */
#define LOG_LINKS 0x00000080 /**< Log data related to linking code. */
#define LOG_CACHE 0x00000100 /**< Log data related to code cache management. */
#define LOG_FRAGMENT 0x00000200 /**< Log data related to app code fragments. */
#define LOG_DISPATCH 0x00000400 /**< Log data on every context switch dispatch. */
#define LOG_MONITOR 0x00000800 /**< Log data related to trace building. */
#define LOG_HEAP 0x00001000 /**< Log data related to memory management. */
#define LOG_VMAREAS 0x00002000 /**< Log data related to address space regions. */
#define LOG_SYNCH 0x00004000 /**< Log data related to synchronization. */
#define LOG_MEMSTATS 0x00008000 /**< Log data related to memory statistics. */