blob: 955dcb219d763264b6f4c5d472194fc8c295fbe5 [file] [edit]
/* **********************************************************
* Copyright (c) 2012-2021 Google, Inc. All rights reserved.
* Copyright (c) 2007-2009 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.
*/
/**
\page API_samples Sample Tools
We provide several examples in the <tt>samples</tt> directory of the
release package to illustrate how the DynamoRIO API is used to build a
DynamoRIO client.
There are also samples for the Dr. Memory Framework located in the
<tt>drmemory/drmf/samples</tt> directory of the release package.
For larger examples of clients, see the provided \ref page_tool, which are
larger and more polished end-user clients than these samples.
********************
\section sample_list List of Samples
Each sample below is in the <tt>api/samples</tt> directory. The links point to
the corresponding source file in the Git repository.
\subsection sec_sample_bbbuf bbbuf.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/bbbuf.c">bbbuf.c</a> records each basic block’s start PC into a per-thread fast circular buffer (default 64KB) by inserting inline instrumentation at the first instruction of each basic block using the drx_buf extension.
\par DynamoRIO concepts demonstrated
\li TLS-backed per-thread buffers via \ref page_drx (Buffer Filling API)
\li Basic block instrumentation at block entry
\li Scratch register management with \ref page_drreg
\par Typical use cases
\li Hot path profiling based on basic block history
\li Lightweight execution tracing for debugging
\subsection sec_sample_bbcount bbcount.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/bbcount.c">bbcount.c</a> counts dynamic basic block executions by inserting a non-atomic global counter update at the start of each basic block using \ref page_drx counter helpers.
\par DynamoRIO concepts demonstrated
\li Basic block instrumentation
\li Inline counter updates with \ref page_drx
\li AFLAGS liveness checks via \ref page_drreg
\par Typical use cases
\li Measuring overall execution volume
\li Comparing workloads by basic block activity
\subsection sec_sample_bbsize bbsize.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/bbsize.c">bbsize.c</a> computes the number, maximum size, and average size of basic blocks using a basic-block analysis callback and explicit floating-point state save/restore.
\par DynamoRIO concepts demonstrated
\li Basic block analysis callbacks
\li Floating-point state preservation in callbacks
\li Shared statistics protected by a mutex
\par Typical use cases
\li Characterizing code layout behavior
\li Comparing compiler output across binaries
\subsection sec_sample_callstack callstack.cpp
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/callstack.cpp">callstack.cpp</a> wraps a configurable function (default: malloc) and prints a symbolized call stack on each call using \ref page_drwrap, \ref page_drcallstack, and \ref page_drsyms.
\par DynamoRIO concepts demonstrated
\li Function wrapping with \ref page_drwrap
\li Call stack walking via the \ref page_drcallstack extension
\li Symbol lookup with \ref page_drsyms
\li Runtime options via \ref page_droption
\par Typical use cases
\li Debugging unexpected call paths
\li Capturing stack traces at selected points
\subsection sec_sample_cbr cbr.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/cbr.c">cbr.c</a> instruments conditional branches with separate taken/not-taken clean calls, records which edges execute, and flushes and redirects execution to remove instrumentation during execution once each edge has been seen.
\par DynamoRIO concepts demonstrated
\li Conditional branch instrumentation with clean calls
\li Fragment flushing and execution redirection
\li Per-branch state tracking with a hash table
\par Typical use cases
\li Building dynamic control-flow graphs
\li Reducing overhead after edge discovery
\subsection sec_sample_cbrtrace cbrtrace.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/cbrtrace.c">cbrtrace.c</a> logs each conditional branch’s address, fall-through, target, and taken direction to per-thread log files using dr_insert_cbr_instrumentation_ex().
\par DynamoRIO concepts demonstrated
\li Conditional branch instrumentation
\li Thread-local storage via drmgr TLS fields (\ref page_drmgr)
\li Per-thread log file output
\par Typical use cases
\li Debugging branch behavior
\li Building branch outcome traces
\subsection sec_sample_countcalls countcalls.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/countcalls.c">countcalls.c</a> counts dynamic direct calls, indirect calls, and returns using per-thread TLS data and inline counter updates with flag preservation.
\par DynamoRIO concepts demonstrated
\li TLS-based per-thread data via drmgr (\ref page_drmgr)
\li Instruction classification for calls and returns
\li Inline counter updates with \ref page_drreg
\par Typical use cases
\li Profiling call/return behavior
\li Comparing indirect call frequency across inputs
\subsection sec_sample_div div.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/div.c">div.c</a> counts unsigned division instructions and how often the runtime divisor is a power of two, using a clean call to read the divisor value.
\par DynamoRIO concepts demonstrated
\li Clean calls for operand inspection
\li Runtime operand value extraction
\li Thread-safe counters with a mutex
\par Typical use cases
\li Identifying optimization opportunities
\li Finding expensive divisions in hot code
\subsection sec_sample_empty empty.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/empty.c">empty.c</a> is a minimal client that only registers an exit event and performs no instrumentation.
\par DynamoRIO concepts demonstrated
\li Client initialization
\li Exit event handling
\par Typical use cases
\li Starting point for new clients
\li Verifying build and load pipelines
\subsection sec_sample_hot_bbcount hot_bbcount.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/hot_bbcount.c">hot_bbcount.c</a> uses \ref page_drbbdup to create cold and hot versions of basic block instrumentation, switching to inline counter updates after a per-block hit threshold is reached.
\par DynamoRIO concepts demonstrated
\li Basic block duplication (\ref page_drbbdup)
\li Clean calls versus inline counter updates
\li Runtime case encoding stored in raw TLS
\par Typical use cases
\li Hot path profiling with reduced overhead
\li Tiered instrumentation strategies
\subsection sec_sample_inc2add inc2add.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/inc2add.c">inc2add.c</a> performs an app2app transformation that replaces inc/dec with add/sub in trace blocks when the carry flag is not live, using drreg liveness analysis to preserve correctness.
\par DynamoRIO concepts demonstrated
\li App2app transformations
\li Instruction replacement
\li Flag liveness checks with \ref page_drreg
\par Typical use cases
\li Exploring micro-architecture-specific optimizations
\li Testing transformation pipelines
\subsection sec_sample_inline inline.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/inline.c">inline.c</a> customizes trace formation to inline callees into traces by marking call sites as trace heads and ending traces after returns or size limits.
\par DynamoRIO concepts demonstrated
\li Custom trace control via end-trace events
\li Trace head tracking with \ref page_drmgr and dr_mark_trace_head()
\li Fragment lifecycle handling on deletion
\par Typical use cases
\li Dynamic inlining experiments
\li Trace-level performance research
\subsection sec_sample_inscount inscount.cpp
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/inscount.cpp">inscount.cpp</a> counts executed instructions by computing per-basic-block instruction counts in analysis and adding them via an auto-inlined clean call, with an option to count only application code.
\par DynamoRIO concepts demonstrated
\li Clean calls optimized by DynamoRIO
\li Runtime options via \ref page_droption
\li Emulation-aware instruction counting with drmgr (\ref page_drmgr)
\par Typical use cases
\li Instruction count profiling
\li Validating instrumentation overhead
\subsection sec_sample_instrace_simple instrace_simple.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/instrace_simple.c">instrace_simple.c</a> records a per-thread instruction trace (PC and opcode) into a raw TLS buffer with inline instrumentation and flushes it to a text file using clean calls.
\par DynamoRIO concepts demonstrated
\li Raw TLS buffer management
\li Inline per-instruction instrumentation
\li Clean calls to flush per-thread buffers
\par Typical use cases
\li Building simple instruction traces
\li Validating instrumentation correctness
\li For a full-featured instruction and data address tracing tool, see \ref page_drcachesim.
\subsection sec_sample_instrace_x86 instrace_x86.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/instrace_x86.c">instrace_x86.c</a> captures a per-thread instruction trace on x86 using inline buffer filling and a local code cache for lean clean calls when the buffer fills.
\par DynamoRIO concepts demonstrated
\li Local code cache generation
\li Lean clean calls
\li Per-thread buffering and file output
\par Typical use cases
\li High-performance instruction tracing
\li Producing binary traces for offline analysis
\li For a full-featured instruction and data address tracing tool, see \ref page_drcachesim.
\subsection sec_sample_instrcalls instrcalls.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/instrcalls.c">instrcalls.c</a> logs each direct call, indirect call, and return with target information to per-thread files, with optional symbolization via drsyms (\ref page_drsyms).
\par DynamoRIO concepts demonstrated
\li Call and return instrumentation
\li Per-thread logging
\li Optional symbol lookup with drsyms
\par Typical use cases
\li Building call flow traces
\li Investigating indirect call behavior
\subsection sec_sample_memtrace_simple memtrace_simple.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/memtrace_simple.c">memtrace_simple.c</a> records instruction and memory-reference entries (type, size, address) into a per-thread buffer and dumps them to a text file using clean calls.
\par DynamoRIO concepts demonstrated
\li Memory operand analysis
\li \ref page_drutil helpers for address and size
\li \ref page_drx expansion of string and scatter/gather operations
\par Typical use cases
\li Studying memory access patterns
\li Validating memory reference instrumentation
\li For a full-featured instruction and data address tracing tool, see \ref page_drcachesim.
\subsection sec_sample_memtrace_x86 memtrace_x86.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/memtrace_x86.c">memtrace_x86.c</a> captures memory references on x86 with inline buffer filling and a local code cache for lean clean calls, writing binary or text traces per thread.
\par DynamoRIO concepts demonstrated
\li \ref page_drutil string and scatter/gather expansion
\li Local code cache generation
\li Per-thread buffering with lean clean calls
\par Typical use cases
\li High-performance memory tracing
\li Generating binary traces for offline analysis
\li For a full-featured instruction and data address tracing tool, see \ref page_drcachesim.
\subsection sec_sample_memval_simple memval_simple.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/memval_simple.c">memval_simple.c</a> records memory write addresses and the written bytes using drx_buf trace and circular buffers, flushing via a trace-buffer fault handler to per-thread log files.
\par DynamoRIO concepts demonstrated
\li Post-instruction instrumentation for write values
\li \ref page_drx trace and circular buffers with a fault handler (Buffer Filling API)
\li Memory operand address calculation with \ref page_drutil
\par Typical use cases
\li Tracking data writes for debugging
\li Building lightweight memory value traces
\subsection sec_sample_modxfer modxfer.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/modxfer.c">modxfer.c</a> counts instructions per module and tracks cross-module indirect branch transfers between any modules, logging summary statistics at exit.
\par DynamoRIO concepts demonstrated
\li Module load and unload tracking
\li Indirect branch instrumentation
\li Per-module counters with \ref page_drx
\par Typical use cases
\li Studying inter-module call patterns
\li Identifying frequent cross-module transfers
\subsection sec_sample_modxfer_app2lib modxfer_app2lib.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/modxfer_app2lib.c">modxfer_app2lib.c</a> counts instructions in the main application versus libraries and tracks indirect call/jump transfers between them using per-basic-block clean calls.
\par DynamoRIO concepts demonstrated
\li Module range checks for app vs. library code
\li Clean call updates of per-basic-block counts
\li Indirect branch instrumentation for cross-module transfers
\par Typical use cases
\li Measuring time spent in app vs. libraries
\li Detecting app-to-lib transition frequency
\subsection sec_sample_opcode_count opcode_count.cpp
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/opcode_count.cpp">opcode_count.cpp</a> counts executions of a selected opcode and the total instruction count using drmgr opcode instrumentation events and drx counter updates.
\par DynamoRIO concepts demonstrated
\li Opcode instrumentation events via \ref page_drmgr
\li Inline counter updates with \ref page_drx
\li Runtime options via \ref page_droption
\par Typical use cases
\li Focused opcode profiling
\li Regression checks for specific instruction patterns
\subsection sec_sample_opcodes opcodes.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/opcodes.c">opcodes.c</a> counts dynamic instruction executions by opcode, grouped by ISA mode, and reports the top opcode counts at exit.
\par DynamoRIO concepts demonstrated
\li Basic block instrumentation
\li Inline counter updates with \ref page_drx
\li ISA mode awareness
\par Typical use cases
\li Opcode mix profiling
\li Comparing dynamic behavior across workloads
\subsection sec_sample_prefetch prefetch.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/prefetch.c">prefetch.c</a> removes prefetch and prefetchw instructions on Intel CPUs using an app2app pass, counting the removals for reporting.
\par DynamoRIO concepts demonstrated
\li App2app instruction removal
\li CPU vendor detection
\li Thread-safe counting with a mutex
\par Typical use cases
\li Running AMD-optimized binaries on Intel CPUs
\li Testing instruction stream sanitization
\subsection sec_sample_signal signal.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/signal.c">signal.c</a> monitors UNIX signals, suppressing SIGTERM and redirecting SIGSEGV by skipping the faulting instruction while counting signals seen.
\par DynamoRIO concepts demonstrated
\li Signal event callbacks (UNIX)
\li Signal suppression and redirection
\li Atomic counters
\par Typical use cases
\li Observing crash signals in a controlled way
\li Prototyping signal-based fault handling
\subsection sec_sample_ssljack ssljack.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/ssljack.c">ssljack.c</a> wraps OpenSSL and GnuTLS read/write functions on module load and logs plaintext data to per-SSL-context files.
\par DynamoRIO concepts demonstrated
\li Module load events
\li Function wrapping (\ref page_drwrap)
\li Per-context file logging
\par Typical use cases
\li Inspecting decrypted SSL/TLS traffic
\li Debugging application-level crypto usage
\subsection sec_sample_statecmp statecmp.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/statecmp.c">statecmp.c</a> uses \ref page_drstatecmp to detect instrumentation-induced state mismatches by intentionally clobbering flags and handling mismatches via a user callback.
\par DynamoRIO concepts demonstrated
\li \ref page_drstatecmp integration
\li Instrumentation correctness checking
\li Custom mismatch callbacks
\par Typical use cases
\li Validating new instrumentation passes
\li Debugging subtle state clobbers
\subsection sec_sample_stats stats.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/stats.c">stats.c</a> (Windows-only) exports instruction, floating-point, and syscall counters via shared memory for the stats viewer, using drx counter updates per basic block.
\par DynamoRIO concepts demonstrated
\li Shared memory usage for client stats
\li Inline counters with \ref page_drx
\li Windows-specific API interactions
\par Typical use cases
\li Live statistics dashboards
\li Comparing runs without heavy logging
\subsection sec_sample_strace strace.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/strace.c">strace.c</a> prints the name and result of every system call using the \ref page_drsyscall extension from DRMF.
\par DynamoRIO concepts demonstrated
\li Syscall event callbacks via \ref page_drsyscall
\li Syscall name lookup with DRMF
\li Result decoding
\par Typical use cases
\li Debugging unexpected syscalls
\li Building basic syscall traces
\subsection sec_sample_stl_test stl_test.cpp
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/stl_test.cpp">stl_test.cpp</a> is a C++ client that exercises STL containers (vector, list, map) and optionally uses a TLS variable on UNIX when SHOW_RESULTS is enabled.
\par DynamoRIO concepts demonstrated
\li C++ client setup
\li STL usage in a client
\li Exit event registration
\par Typical use cases
\li C++ client scaffolding
\li Validating STL usage in DynamoRIO clients
\subsection sec_sample_syscall syscall.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/syscall.c">syscall.c</a> monitors system calls, counts them, and modifies write syscalls (SYS_write/NtWriteFile) using drmgr’s pre/post syscall events and thread-context-local storage (\ref page_drmgr).
\par DynamoRIO concepts demonstrated
\li Syscall interception events
\li Thread-context-local storage via drmgr CLS (\ref page_drmgr)
\li Platform-specific syscall handling and parameter modification
\par Typical use cases
\li Auditing syscall activity
\li Prototyping syscall rewriting
\subsection sec_sample_tracedump tracedump.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/tracedump.c">tracedump.c</a> uses the standalone API to parse and disassemble binary trace dump files produced by the -tracedump_binary option.
\par DynamoRIO concepts demonstrated
\li Standalone API usage
\li Trace dump file parsing
\li Disassembly of cached code
\par Typical use cases
\li Inspecting trace dumps offline
\li Debugging code cache behavior
\subsection sec_sample_utils utils.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/utils.c">utils.c</a> provides shared logging helpers for samples, including unique per-process log file creation and FILE* stream helpers.
\par DynamoRIO concepts demonstrated
\li Client path discovery
\li Log file creation helpers via \ref page_drx
\li Stream helper utilities
\par Typical use cases
\li Reusing logging utilities across sample clients
\li Standardizing output file naming
\subsection sec_sample_wrap wrap.c
The sample <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/wrap.c">wrap.c</a> wraps malloc (Linux) or HeapAlloc (Windows) to track the maximum allocation size and optionally force occasional allocation failures.
\par DynamoRIO concepts demonstrated
\li Module load callbacks
\li Function wrapping (\ref page_drwrap)
\li Return value modification
\par Typical use cases
\li Testing error handling paths
\li Tracking allocation patterns
\section bt_examples Discussion of Selected Samples
********************
\subsection sec_ex1 Instruction Counting
We now illustrate how to use the above API to implement a simple
instrumentation client for counting the number of executed call and
return instructions in the input program. Full code for this example is
in the file <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/countcalls.c">countcalls.c</a>.
The client maintains set of three counters: num_direct_calls,
num_indirect_calls, and num_returns to count three different
types of instructions during execution. It keeps both thread-private
and global versions of these counters. The client initializes
everything by supplying the following \p dr_client_main routine:
\code
DR_EXPORT void
dr_client_main(client_id_t id, int argc, const char *argv[])
{
/* register events */
dr_register_exit_event(event_exit);
dr_register_thread_init_event(event_thread_init);
dr_register_thread_exit_event(event_thread_exit);
dr_register_bb_event(event_basic_block);
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, DR_LOG_ALL, 1, "Client 'countcalls' initializing\n");
}
\endcode
The client provides an event_exit routine that displays the final
values of the global counters as well as a thread_exit routine that
shows the counter totals on a per-thread basis.
The client keeps track of each thread's instruction counts separately.
To do this, it creates a data structure that will be separately allocated
for each thread:
\code
typedef struct {
int num_direct_calls;
int num_indirect_calls;
int num_returns;
} per_thread_t;
\endcode
Now the thread hooks are used to initialize the data structure and to
display the thread-private totals :
\code
static void event_thread_init(void *drcontext)
{
/* create an instance of our data structure for this thread */
per_thread *data = (per_thread *)
dr_thread_alloc(drcontext, sizeof(per_thread));
/* store it in the slot provided in the drcontext */
dr_set_tls_field(drcontext, data);
data->num_direct_calls = 0;
data->num_indirect_calls = 0;
data->num_returns = 0;
dr_log(drcontext, DR_LOG_ALL, 1, "countcalls: set up for thread "TIDFMT"\n",
dr_get_thread_id(drcontext));
}
static void event_thread_exit(void *drcontext)
{
per_thread *data = (per_thread *) dr_get_tls_field(drcontext);
... // string formatting and displaying
/* clean up memory */
dr_thread_free(drcontext, data, sizeof(per_thread));
}
\endcode
The real work is done in the basic block hook. We simply look for
the instructions we're interested in and insert an increment of the
appropriate thread-local and global counters, remembering to save the
flags, of course. This sample has separate paths for incrementing the
thread private counts for shared vs. thread-private caches (see the
-thread_private option) to illustrate the differences in targeting
for them. Note that the shared path would work fine with private
caches.
\code
static void
insert_counter_update(void *drcontext, instrlist_t *bb, instr_t *where, int offset)
{
/* Since the inc instruction clobbers 5 of the arithmetic eflags,
* we have to save them around the inc. We could be more efficient
* by not bothering to save the overflow flag and constructing our
* own sequence of instructions to save the other 5 flags (using
* lahf) or by doing a liveness analysis on the flags and saving
* only if live.
*/
dr_save_arith_flags(drcontext, bb, where, SPILL_SLOT_1);
/* Increment the global counter using the lock prefix to make it atomic
* across threads. It would be cheaper to aggregate the thread counters
* in the exit events, but this sample is intended to illustrate inserted
* instrumentation.
*/
instrlist_meta_preinsert(bb, where, LOCK(INSTR_CREATE_inc
(drcontext, OPND_CREATE_ABSMEM(((byte *)&global_count) + offset, OPSZ_4))));
/* Increment the thread private counter. */
if (dr_using_all_private_caches()) {
per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext);
/* private caches - we can use an absolute address */
instrlist_meta_preinsert(bb, where, INSTR_CREATE_inc(drcontext,
OPND_CREATE_ABSMEM(((byte *)&data) + offset, OPSZ_4)));
} else {
/* shared caches - we must indirect via thread local storage */
/* We spill xbx to use a scratch register (we could do a liveness
* analysis to try and find a dead register to use). Note that xax
* is currently holding the saved eflags. */
dr_save_reg(drcontext, bb, where, REG_XBX, SPILL_SLOT_2);
dr_insert_read_tls_field(drcontext, bb, where, REG_XBX);
instrlist_meta_preinsert(bb, where,
INSTR_CREATE_inc(drcontext, OPND_CREATE_MEM32(REG_XBX, offset)));
dr_restore_reg(drcontext, bb, where, REG_XBX, SPILL_SLOT_2);
}
/* restore flags */
dr_restore_arith_flags(drcontext, bb, where, SPILL_SLOT_1);
}
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating)
{
instr_t *instr, *next_instr;
... // some logging
for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
/* grab next now so we don't go over instructions we insert */
next_instr = instr_get_next(instr);
/* instrument calls and returns -- ignore far calls/rets */
if (instr_is_call_direct(instr)) {
insert_counter_update(drcontext, bb, instr,
offsetof(per_thread_t, num_direct_calls));
} else if (instr_is_call_indirect(instr)) {
insert_counter_update(drcontext, bb, instr,
offsetof(per_thread_t, num_indirect_calls));
} else if (instr_is_return(instr)) {
insert_counter_update(drcontext, bb, instr,
offsetof(per_thread_t, num_returns));
}
}
... // some logging
return DR_EMIT_DEFAULT;
}
\endcode
\par Building the Example
For general instructions on building a client, see \ref page_build_client.
To build the \p instrcalls.c client using CMake, if \p DYNAMORIO_HOME is
set to the base of the DynamoRIO release package:
\code
mkdir build
cd build
cmake -DDynamoRIO_DIR=$DYNAMORIO_HOME/cmake $DYNAMORIO_HOME/samples
make instrcalls
\endcode
To build 32-bit samples when using gcc with a default of 64-bit, use:
\code
mkdir build
cd build
CFLAGS=-m32 CXXFLAGS=-m32 cmake -DDynamoRIO_DIR=$DYNAMORIO_HOME/cmake $DYNAMORIO_HOME/samples
make instrcalls
\endcode
The result is a shared library instrcalls.dll or libinstrcalls.so. To
invoke the client library, follow the instructions under \ref page_deploy.
********************
\subsection sec_ex2 Instruction Profiling
The next example shows how to use the provided control flow
instrumentation routines, which allow more sophisticated profiling than
simply counting instructions. Full code for this example is
in the file <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/instrcalls.c">instrcalls.c</a>.
As in the previous example, the client is interested in direct and
indirect calls and returns. The client wants to analyze the target
address of each dynamic instance of a call or return. For our example,
we simply dump the data in text format to a separate file for each
thread. Since FILE cannot be exported from a DLL on Windows, we use the
DynamoRIO-provided file_t type that hides the distinction between FILE and
HANDLE to allow the same code to work on Linux and Windows.
We make use of the thread initialization and exit routines to
open and close the file. We store the file for a thread in the user
slot in the drcontext.
\code
static void event_thread_init(void *drcontext)
{
/* we're going to dump our data to a per-thread file */
file_t f;
char logname[512];
... // filename generation
f = dr_open_file(fname, false/*write*/);
DR_ASSERT(f != INVALID_FILE);
/* store it in the slot provided in the drcontext */
dr_set_tls_field(drcontext, (void *)f);
... // logging
}
static void event_thread_exit(void *drcontext)
{
file_t f = (file_t)(ptr_uint_t) dr_get_tls_field(drcontext);
dr_close_file(f);
}
\endcode
The basic block hook inserts a call to a procedure for each
type of instruction, using the API-provided
dr_insert_call_instrumentation and dr_insert_mbr_instrumentation
routines, which insert calls to procedures with a certain signature.
\code
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating)
{
instr_t *instr, *next_instr;
... // logging
for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
next_instr = instr_get_next(instr);
if (!instr_opcode_valid(instr))
continue;
/* instrument calls and returns -- ignore far calls/rets */
if (instr_is_call_direct(instr)) {
dr_insert_call_instrumentation(drcontext, bb, instr, (app_pc)at_call);
} else if (instr_is_call_indirect(instr)) {
dr_insert_mbr_instrumentation(drcontext, bb, instr, (app_pc)at_call_ind,
SPILL_SLOT_1);
} else if (instr_is_return(instr)) {
dr_insert_mbr_instrumentation(drcontext, bb, instr, (app_pc)at_return,
SPILL_SLOT_1);
}
}
return DR_EMIT_DEFAULT;
}
\endcode
These procedures look like this :
\code
static void
at_call(app_pc instr_addr, app_pc target_addr)
{
file_t f = (file_t)(ptr_uint_t) dr_get_tls_field(dr_get_current_drcontext());
dr_mcontext_t mc;
dr_get_mcontext(dr_get_current_drcontext(), &mc, NULL);
dr_fprintf(f, "CALL @ "PFX" to "PFX", TOS is "PFX"\n",
instr_addr, target_addr, mc.xsp);
}
static void
at_call_ind(app_pc instr_addr, app_pc target_addr)
{
file_t f = (file_t)(ptr_uint_t) dr_get_tls_field(dr_get_current_drcontext());
dr_fprintf(f, "CALL INDIRECT @ "PFX" to "PFX"\n", instr_addr, target_addr);
}
static void
at_return(app_pc instr_addr, app_pc target_addr)
{
file_t f = (file_t)(ptr_uint_t) dr_get_tls_field(dr_get_current_drcontext());
dr_fprintf(f, "RETURN @ "PFX" to "PFX"\n", instr_addr, target_addr);
}
\endcode
The address of the instruction and the address of its target are both
provided. These routines could perform some sort of analysis based on
these addresses. In our example we simply print out the data.
********************
\subsection sec_ex3 Modifying Existing Instrumentation
In this example, we show how to update or replace existing
instrumentation after it executes. This ability is useful for clients
performing adaptive optimization. In this example, however, we are
interested in recording the direction of all conditional branches, but
wish to remove the overhead of instrumentation once we've gathered
that information. This code could form part of a dynamic CFG builder,
where we want to observe the control-flow edges that execute at
runtime, but remove the instrumentation after it executes.
While DynamoRIO supports direct fragment replacement, another method
for re-instrumentation is to flush the fragment from the code cache
and rebuild it in the basic block event callback. In other words, we
take the following approach:
-# In the basic block event callback, insert separate instrumentation
for the taken and fall-through edges.
-# When the basic block executes, note the direction taken and flush
the fragment from the code cache.
-# When the basic block event triggers again, insert instrumentation
only for the unseen edge. After both edges have triggered, remove
all instrumentation for the cbr.
We insert separate clean calls for the taken and fall-through cases.
In each clean call, we record the observed direction and immediately
flush the basic block using dr_flush_region(). Since that routine
removes the calling block, we redirect execution to the target or
fall-through address with dr_redirect_execution(). The file <a
href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/cbr.c">cbr.c</a> contains the full code for this
sample.
********************
\subsection sec_ex4 Optimization
For the next example we consider a client application for a simple
optimization. The optimizer replaces every increment/decrement operation
with a corresponding add/subtract operation if running on a Pentium 4,
where the add/subtract is less expensive. For optimizations, we are
less concerned with covering all the code that is executed; on the
contrary, in order to amortize the optimization overhead, we only want
to apply the optimization to hot code. Thus, we apply the optimization
at the trace level rather than the basic block level. Full code for
this example is in the file <a
href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/inc2add.c">inc2add.c</a>.
********************
\subsection sec_ex5 Custom Tracing
This example demonstrates the custom tracing interface. It changes
DynamoRIO's tracing behavior to favor making traces that start at a call
and end right after a return. It demonstrates the use of both custom trace
API elements :
\code
int query_end_trace(void *drcontext, void *trace_tag, void *next_tag);
bool dr_mark_trace_head(void *drcontext, void *tag);
\endcode
Full code for this example is in the file <a
href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/inline.c">inline.c</a>.
********************
\subsection sec_ex6 Use of x87 Floating Point Operation in a Client
Because saving the x87 floating point state is very expensive, on x86 DynamoRIO
seeks to do so on an as needed basis. If a client wishes to use floating point
operations and is unsure whether its compiler will use x87 or not, or if it
wishes to use MMX registers, it must
save and restore the application's floating point state
around the usage. For an inserted clean call out of the code cache, this
can be conveniently done using dr_insert_clean_call() and passing true for
the save_fpstate parameter. It can also be done explicitly using these
routines:
\code
void proc_save_fpstate(byte *buf);
void proc_restore_fpstate(byte *buf);
\endcode
These routines must be used if x87 floating point operations are performed in
non-inserted-call locations, such as event callbacks. Note that there are
restrictions on how these methods may be called: see the documentation in
the header files for additional information. Note also that the floating
point state must be saved around calls to our provided printing routines
when they are used to print floats. However, it is not necessary to save
and restore the floating point state around floating point operations if
they are being used in the initialization or termination routines.
On ARM and AArch64 the SIMD/FP registers are always saved, so
proc_save_fpstate and proc_restore_fpstate are no-ops.
On x86, modern compilers typically do not use x87 operations, but to be
safe clients are still advised to either avoid floating-point operations
or use the preservation routines listed here.
This example client counts the number of basic blocks processed and keeps
statistics on their average size using floating point operations. Full code
for this example is in the file <a
href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/bbsize.c">bbsize.c</a>.
********************
\subsection sec_drstats Use of Custom Client Statistics with the Windows GUI
The new Windows GUI will display custom client statistics, if they are
placed in shared memory with a certain name. The sample <a
href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/stats.c">stats.c</a> gives code for the
protocol used in the form of a sample client that counts total
instructions, floating-point instructions, and system calls.
Note that the stats.c example client and the Windows GUI must both be run
within the same session in order for the statistics to be shared
properly. They can be modified to use a "Global" prefix instead of "Local"
for cross-session sharing, though this requires running with administrative
privileges.
********************
\subsection sec_ex8 Use of Standalone API
The binary tracedump reader also functions as an example of
\ref page_standalone : <a href="https://github.com/DynamoRIO/dynamorio/tree/master/api/samples/tracedump.c">tracedump.c</a>.
*/