blob: 1b33709e710f8a61827afe14ab373ab77f7bd4ec [file] [edit]
/* ******************************************************************************
* Copyright (c) 2010-2017 Google, Inc. All rights reserved.
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2007-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.
*/
/**
****************************************************************************
****************************************************************************
****************************************************************************
\if vmsafe
\mainpage VMsafe In-Process API
\section VMsafe_intro Introduction
This document describes a component of the VMsafe model that provides control
at a process level and explains how to use it. For the rest of the document
this component shall be referred to as the VMsafe In-Process Runtime or VIPER.
VIPER allows a user specified (via a Guest Agent) in-process agent (referred to
as client from now on) to monitor and modify the execution of any given
process. VIPER is different from the security agent on the security monitor VM
or an in-guest agent as neither of them provides direct control at the
process level because they are unaware of processes. VIPER on the other hand
is fully aware of process and resides within the address space of each one that
is intended to be monitored or controlled. It provides a finer grain of
control as it allows the user to decide which processes and what aspects of the
processes' execution to monitor and control. Also, a client is an optional
component for any VMsafe-based solution. The figure below gives an idea of how
VIPER fits in with other VMsafe components. All user- or ISV-provided parts of a
VMsafe solution are shown in blue and the VMsafe components in gray.
\image html viper.png
\image rtf viper.png
\image latex viper.eps
\else
\mainpage The DynamoRIO API
\endif
\image html drlogo.png
\image rtf drlogo.png
DynamoRIO is a <em>runtime code manipulation system</em> that supports
code transformations on any part of a program, <em>while it executes</em>.
DynamoRIO gives complete control over the runtime code stream and does not
limit transformations to trampoline insertion. DynamoRIO exports an
interface for building dynamic tools for a wide variety of uses: program
analysis and understanding, profiling, instrumentation, optimization,
translation, etc. DynamoRIO provides efficient, transparent, and
comprehensive manipulation of an unmodified application running on a stock
operating system (Windows, Linux, or Android) and commodity IA-32, AMD64,
ARM, and AArch64 hardware. See \ref sec_limit_platforms for details of
which platform combinations are fully supported.
This document describes the DynamoRIO system and the various API's that it
exports for building custom tools. It is divided into the following
sections:
- \subpage page_deploy
<br>How to run DynamoRIO.
- \subpage using
<br>How to make use of DynamoRIO.
\if vmsafe
- \subpage API_security
<br>An interface for customizing and applying the award-winning Memory
Firewall security software.
- \subpage API_probe
<br>A powerful probe insertion interface that can operate with the code cache
or in a lighter-weight but more restrictive mode without code cache.
\endif
- \subpage API_BT
<br>DynamoRIO's full runtime code manipulation interface.
\ifnot vmsafe
- \subpage page_standalone
<br>DynamoRIO can be used as a standalone library for IA-32/AMD64/ARM/AArch64
disassembly, decoding, encoding, and general instruction manipulation.
A separate static library is provided for this purpose.
\endif
- \subpage API_tutorial
<br>Gives a few short tutorials on using DynamoRIO.
- \subpage API_samples
<br>Shows some sample use cases and reference implementations.
- \subpage overview
<br>A description of the implementation of the DynamoRIO system.
- \subpage release_notes
<br>Release notes for this release, including changes since prior
releases \ifnot vmsafe and plans for future releases \endif.
- \subpage page_license
<br>
***************************************************************************
***************************************************************************
\page overview DynamoRIO System Details
DynamoRIO is a system for runtime code manipulation that is efficient,
transparent, and comprehensive, able to observe and manipulate every
executed instruction in an unmodified application running on a stock
operating system and commodity hardware.
***************************************************************************
\section sec_intro Introduction
DynamoRIO operates in user mode on a target process. It acts as a
<em>process virtual machine</em>, interposing between the application and
the operating system. It has a complete view of the application code
stream and acts as a runtime control point, allowing custom tools to be
embedded inside it:
\image html interpose.png
\image rtf interpose.png
\image latex interpose.eps "Flow chart" width=10cm
The application itself, along with the underlying operating system and
hardware, remain unchanged. DynamoRIO operates in native (non-virtual)
environments as well as inside guest operating systems running on virtual
machines. Tools created on top of DynamoRIO will operate without change
whether the underlying operating system is native or a virtual machine
guest.
***************************************************************************
\section sec_system System Operation
DynamoRIO operates by shifting an application's execution from its original
instructions to a <em>code cache</em>, where the instructions can be freely
modified. DynamoRIO occupies the address space with the application and has
full control over execution, taking over whenever control leaves the code
cache or when the operating system directly transfers control to the
application (<em>kernel-mediated control transfers</em>):
\image html flow-highlevel.png
\image rtf flow-highlevel.png
\image latex flow-highlevel.eps "Flow chart" width=10cm
DynamoRIO copies the application code one <em>dynamic basic block</em> at a
time into its basic block code cache. A block that directly targets another
block already resident in the cache is linked to that block to avoid the
cost of returning to the DynamoRIO dispatcher.
Frequently executed sequences of basic blocks are combined into
<em>traces</em>, which are placed in a separate code cache. DynamoRIO makes
these traces available via its interface for convenient access to hot
application code streams.
The following figure shows the flow of control between the components of
DynamoRIO and its code caches:
\image html flow.png
\image rtf flow.png
\image latex flow.eps "Flow chart" width=15cm
The context switch is between DynamoRIO's operational state and the machine
state of the application: both are still within the same process.
Indirect branches require dynamic resolution of their targets, which is
performed via an inlined table lookup or a compare to a known target
inlined into a trace.
\section sec_sys_transp Transparency
Transparency is an important requirement for DynamoRIO and its clients.
The subject is fully covered in \subpage transparency.
\ifnot vmsafe
***************************************************************************
\section sec_refs References
The canonical reference for DynamoRIO is:
- Derek Bruening.<br>
<a href="http://www.burningcutlery.com/derek/phd.html">
Efficient, Transparent, and Comprehensive Runtime Code Manipulation</a>.<br>
Ph.D. Thesis, MIT, September 2004.
Other publications describing DynamoRIO include:
- Derek Bruening and Vladimir Kiriansky.<br>
<a href="http://www.burningcutlery.com/derek/docs/procshared-VEE08.pdf">
Process-Shared and Persistent Code Caches</a>.<br>
International Conference on Virtual Execution Environments (VEE-08), March 2008.<br>
- Derek Bruening, Vladimir Kiriansky, Timothy Garnett, and Sanjeev Banerji.<br>
<a href="http://www.burningcutlery.com/derek/docs/threadshared-CGO06.pdf">
Thread-Shared Software Code Caches</a>.<br>
International Symposium on Code Generation and Optimization (CGO-06), March 2006.<br>
- Derek Bruening and Saman Amarasinghe. <br>
<a href="http://www.burningcutlery.com/derek/docs/cacheconscap-CGO05.pdf">
Maintaining Consistency and Bounding Capacity of Software Code Caches</a>.<br>
International Symposium on Code Generation and Optimization (CGO-05), March 2005. <br>
- Gregory Sullivan, Derek Bruening, Iris Baron, Timothy Garnett, and
Saman Amarasinghe. <br>
<a href="http://www.burningcutlery.com/derek/docs/IVME03.pdf">
Dynamic Native Optimization of Interpreters</a>. <br>
ACM Workshop on Interpreters, Virtual Machines and Emulators (IVME-03), June 2003.<br>
- Derek Bruening, Timothy Garnett, and Saman Amarasinghe. <br>
<a href="http://www.burningcutlery.com/derek/docs/adaptive-CGO03.pdf">
An Infrastructure for Adaptive Dynamic Optimization</a>. <br>
International Symposium on Code Generation and Optimization (CGO-03), March 2003. <br>
- Derek Bruening, Evelyn Duesterwald, and Saman Amarasinghe.<br>
<a href="http://www.burningcutlery.com/derek/docs/win32-FDDO.pdf">
Design and Implementation of a Dynamic Optimization Framework for Windows</a>.<br>
4th ACM Workshop on Feedback-Directed and Dynamic
Optimization (FDDO-4), December 2001.<br>
\endif
\image html favicon.ico
\page page_deploy Deployment
\if vmsafe
A DynamoRIO application consists of a guest agent and one or more clients. Each of
these must be linked against the necessary DynamoRIO dynamic libraries, which
are provided as part of the SDK. These DynamoRIO dynamic libraries must be
installed when the DynamoRIO application is installed on a guest OS.
Any DynamoRIO application wanting to get control of a process must
first register a client (which is a self-contained executable
library) for that process. Otherwise DynamoRIO will not be
initialized for that process. This is done by the guest agent, which
can either be a service or a standalone executable. The guest agent
should use dr_register_process() and dr_register_client() to register
a process name for which control is desired, which clients to use for
each process, and which mode to run the clients in (more on this
below). DynamoRIO will be initialized in the specified mode for
registered processes started subsequently. DynamoRIO will then load
the corresponding clients into such processes and call each client's
initialization routine, dr_client_main(). There are three modes of operation
for DynamoRIO which map to the three API's provided by DynamoRIO
(see below). Depending upon the mode chosen the usage model will
change.
In addition to registering the processes for which control is desired, the
guest agent can also unregister them as needed using dr_unregister_process().
The guest agent can also send update messages to processes currently
initialized with DynamoRIO and a client using dr_nudge_process().
For example, this can be used by the guest agent when it has obtained new
information (data, libraries, etc.), from a management server or over the
internet from a security vendor, to let clients know about them.
Process registration, unregistration, and nudging require administrative
privileges. On Windows Vista or higher, if UAC is enabled, process registration must be
performed by an elevated (runas admin) process. When using the -syswide_on
parameter, be sure that the cmd shell being used was started with elevated
permissions.
\else
Once the DynamoRIO distribution contents are unpacked (see \ref
sec_package), configuration and execution of applications under DynamoRIO
is handled by a set of libraries and tools. On Windows, the
tools are \c drconfig.exe, \c drrun.exe, and \c drinject.exe. The
corresponding libraries (whose APIs are exposed by the tools) are \c
drconfiglib.dll and \c drinjectlib.dll with header files \c dr_config.h and
\c dr_inject.h. On Linux, the tools are named \c drconfig, \c drrun, and \c
drinject, and the libraries are \c libdrconfiglib.a and \c
libdrinjectlib.a.
\ifnot vmsafe
When using DynamoRIO as a third-party disassembly library (see \ref
page_standalone), no deployment is needed, as DynamoRIO does not control a
target application when used as a regular library.
\endif
\section win_deploy Windows Deployment
There are two methods for running a process under DynamoRIO: the one-time
configure-and-run, and the two-step separate configuration and execution.
The \c drrun.exe tool supports the first, simpler model, while the \c
drconfig.exe and \c drinject.exe tools support the second, more powerful
model. The \c drconfig.exe tool, or the corresponding the \c
drconfiglib.dll library, can also be used to \ref sec_comm "nudge" running
processes.
Configuration information is stored in files in the current user's profile
directory, which is obtained from the environment variable \c USERPROFILE.
Thus, configurations are persistent across reboots and are private to each
user. If the <tt>DYNAMORIO_CONFIGDIR</tt> environment variable is set,
its value is used instead of \c USERPROFILE.
If neither is set, a temp directory will be used when creating new
configuration files for configure-and-run execution.
DynamoRIO also supports global configurations, which are stored in
the "config" subdirectory of the directory specified by the \c
DYNAMORIO_HOME registry value in the registry key \c
\\HKLM\\SOFTWARE\\DynamoRIO\\DynamoRIO (or for 32-bit on 64-bit Windows
(WOW64) \c \\HKLM\\SOFTWARE\\Wow6432Node\\DynamoRIO\\DynamoRIO). Setting
that \c DYNAMORIO_HOME value and creating the directory it points to must
be done manually. The provided tools support reading and writing both
local and global configuration files, and automatically creating the local
directory. DynamoRIO gives local files precedence when both exist. Note
that applications that do not have a \c USEPROFILE environment variable can
be controlled using <tt>DYNAMORIO_CONFIGDIR</tt> or global configurations.
Also note that by default \c USERPROFILE is not set over cygwin ssh and
must be explicitly set in the shell startup files.
Configurations are per-process, with the basename of the process used for
identification (e.g., \c notepad.exe). One-time configuration also uses the
process id to specify that the configuration is for that process instance
only.
As an example, assume you have unpacked the DynamoRIO distribution and
your current directory is its base directory. Run \c notepad.exe with the
bbsize sample client using the following configure-and-run command:
\if vmsafe
\code
bin32/drrun.exe -mode code -c samples/bin32/bbsize.dll -- notepad
\endcode
\else
\code
bin32/drrun.exe -c samples/bin32/bbsize.dll -- notepad
\endcode
\endif
To use system-wide injection, allowing for an application to be run
under DynamoRIO regardless of how it is invoked, configure the application
first (-syswide_on requires administrative privileges):
\if vmsafe
\code
bin32/drconfig.exe -reg notepad.exe -syswide_on -mode code -c samples/bin32/bbsize.dll
\endcode
\else
\code
bin32/drconfig.exe -reg notepad.exe -syswide_on -c samples/bin32/bbsize.dll
\endcode
\endif
The next time \c notepad.exe is started by the current user, it will run under
DynamoRIO with the bbsize client.
To unregister \c notepad.exe, issue the following command:
\code
bin32/drconfig.exe -unreg notepad.exe
\endcode
Invoke any of the \c drconfig.exe, \c drrun.exe, or \c drinject.exe tools
with no arguments to see the full list of options available.
By default, DynamoRIO follows into all child processes, with the parent's
settings inherited by the child if there is no configuration set up ahead
of time for the child application. To instead only
follow children that are configured (via \c drconfig.exe), use the
\ref op_children "-no_follow_children" runtime option.
To \ref sec_comm "nudge" all instances of \c notepad.exe running under
DynamoRIO with argument "5", use:
\code
bin32/drconfig.exe -nudge notepad.exe 0 5
\endcode
This will result in a nudge event with argument=5 delivered to the
client callback registered with dr_register_nudge_event() in all
\c notepad.exe processes running under DynamoRIO. The third argument,
0, is an ID supplied at registration which uniquely identifies the
target client (see dr_deploy.h for details).
To view 32-bit or WOW64 processes running under DynamoRIO the
\c drview.exe tool can be used. The bin64 version will display both 32-bit
and 64-bit processes and will indicate which are 32-bit. The bin32 version
will display 64-bit processes but is unable to determine whether DynamoRIO
is present.
\attention
Note that on Windows NT a reboot is required after using -syswide_on or -syswide_off.
DynamoRIO uses the
<tt>\\HKLM\\SOFTWARE\\Microsoft\\Windows\\Windows NT\\CurrentVersion\\AppInit_DLLs</tt>
key
(for 32-bit on 64-bit Windows (WOW64),
<tt>\\HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\AppInit_DLLs</tt>)
for -syswide_on to inject into new processes without having to directly
launch them \c drrun.exe or \c drinject.exe. For injection to work, the
registered process must statically link to user32.dll (only a few small
non-graphical windows applications don't link user32.dll). If a target
application does not link to user32.dll, DynamoRIO can still inject if the
process is launched with \c drinject.exe or if the parent process (usually
cmd.exe or explorer.exe for user launched processes) is running under
DynamoRIO. The drinject.exe tool uses the configuration information set
by \c drconfig.exe for the target application.
\attention
The -syswide_on, -syswide_off, use of global configuration files, and
nudging certain processes may require administrative privileges. On
Windows Vista or higher, if UAC is enabled, use an elevated (runas admin)
process. When using \c drconfig.exe and \c drrun.exe in these scenarios, be
sure that the cmd shell being used was started with elevated permissions.
An alternative method to run an application under DynamoRIO is the \ref
sec_startstop "app_start()/app_stop()" interface, which requires modifying
application source code.
\section lin_deploy Linux Deployment
Once DynamoRIO has been unpacked, the same set of helper binaries as on
Windows provide flexibility in configuring and executing applications.
There are two methods for invoking an application under DynamoRIO:
-# Configure and launch in one step via \p drrun
-# Configure via \p drconfig and launch via \p drinject
As an example of the simpler method, the following command runs \c ls
under DynamoRIO with the bbsize sample client:
\code
% bin32/drrun -c samples/bin32/libbbsize.so -- ls
\endcode
Run \c drrun with no options to get a list of the options and
environment variable shortcuts it supports. To disable following across
child execve calls, use the \ref op_children "-no_follow_children" runtime
option.
Use the tools in \c bin32/ for 32-bit applications and the tools in \c
bin64/ for 64-bit applications.
The two-step method allows for greater control over child processes. The
\p drconfig tool writes a configuration file for a given application
name. DynamoRIO reads its options from the configuration file at runtime.
Once each process name is configured, the \p drinject tool can be used to
invoke the parent process. The \p drrun tool can also be used but it
creates a temporary configuration file that will override settings
requested via \p drconfig. The configuration file for each application is
stored in <tt>$DYNAMORIO_CONFIGDIR/.dynamorio/&lt;appname&gt;.config32</tt>
(or a \p config64 suffix for 64-bit). If <tt>DYNAMORIO_CONFIGDIR</tt> is
not set, <tt>$HOME/.dynamorio/&lt;appname&gt;.config32</tt> is used;
if neither is set, a temp directory will be used when creating new
configuration files for configure-and-run execution. On Android, if
neither <tt>/data/local/tmp</tt> nor the current working directory are
writable, you will need to specify a writable directory by setting the
<tt>DYNAMORIO_CONFIGDIR</tt> environment variable.
DynamoRIO also supports global configuration
files in <tt>/etc/dynamorio/&lt;appname&gt;.config32</tt> when a local
configuration file is not found. \p drconfig does not support directly
writing a global config file but such files can be copied from or modeled
on local files.
If a target application executes an \c execve that discards the \c HOME
environment variable, the resulting process will still run under DynamoRIO
control with the same settings as the parent process.
Use <tt>DYNAMORIO_CONFIGDIR</tt> or global configuration files to
specify separate options for such a child process.
When running scripts it is best to explicitly invoke the interpreter rather
than invoking the script directly:
\code
% bin64/drrun -- /bin/bash myscript.sh
\endcode
To \ref sec_comm "nudge" a process with pid \c targetpid running under
DynamoRIO and pass argument "5" to the nudge callback, use the \c
nudgeunix tool:
\code
bin32/nudgeunix -pid targetpid -client 0 5
\endcode
This will result in a nudge event with argument=5 delivered to the
client callback registered with dr_register_nudge_event() in the
target process. The 0 argument is an ID supplied at registration which
uniquely identifies the target client (see dr_deploy.h for details).
If you used the -c argument to drrun or drconfig to register the client, the
client's id defaults to 0.
An alternative method to run an application under DynamoRIO is the \ref
sec_startstop "app_start()/app_stop()" interface, which requires modifying
application source code.
\section android_deploy Android Deployment
Android deployment is generally the same as \ref lin_deploy except for the
following differences.
For pure native applications, the default configuration file location (if
<tt>DYNAMORIO_CONFIGDIR</tt> is not explicitly set) is usually (depending
on whether <tt>$HOME</tt> happens to be writable) <tt>/data/local/tmp</tt>.
For Android applications on recent versions of Android, SELinux prevents
writing to <tt>/data/local/tmp</tt>. The application's data directory
should be pointed at in the \p TMPDIR or <tt>DYNAMORIO_CONFIGDIR</tt>
environment variables, as shown below in the example wrapper script. We
recommend using \p TMPDIR as its value will also be used by tools such as
Dr. Memory for their log files.
To launch an Android application under DynamoRIO, use a wrapper script and
point at the script via the \p logwrapper property set on your
application's name prefixed by \p <tt>wrap.</tt>. For example, if your
application's name is <tt>com.myco.appname</tt>, set the property for
<tt>wrap.com.myco.appname</tt>, truncating to 31 characters:
\code
setprop wrap.com.myco.appname "logwrapper /system/xbin/wrap.sh"
\endcode
The wrapper shell script should contain the command line prefix you wish to
use to launch your application under DynamoRIO:
\code
#!/system/bin/sh
export TMPDIR=/data/data/com.myco.appname
exec /system/xbin/dynamorio/bin32/drrun -- $@
\endcode
Be sure to place the DynamoRIO binaries and the wrapper script in an
executable location, such as <tt>/system/xbin</tt>. Alternatively, disable
SELinux via <tt>setenforce 0</tt>.
If you run into problems with configuration files being created due to
SELinux denials (look in the logs for such denials), it may be simplest to
disable SELinux via <tt>setenforce 0</tt>. We have attempted to get
everything to work without this step, but we are not able to test on all
versions or configurations of Android.
\endif
\section client_ops Passing Options to Clients
All of the earlier examples did not need to pass any arguments to the client.
When using the -c argument to set the client, all arguments between the client
path and the double dash are passed to the client. When using the -client
argument to drrun, the third argument following -client is passed through to
the client. For example, all these invocations of drrun pass '-op1
-op2 "value with spaces"' to the client:
\code
bin32/drrun.exe -c libmyclient.dll -op1 -op2 \"value with spaces\" -- notepad
bin32/drrun.exe -client myclient.dll 0 '-op1 -op2 "value with spaces"' -- notepad
\endcode
On Linux:
\code
bin32/drrun -c libmyclient.so -op1 -op2 \"value with spaces\" -- ls
bin32/drrun -client libmyclient.so 0 '-op1 -op2 "value with spaces"' -- ls
\endcode
When using a two-step model, the options are passed to \p drconfig:
\code
bin32/drconfig.exe -reg notepad.exe -c myclient.dll -op1 -op2 \"value with spaces\"
bin32/drconfig.exe -reg notepad.exe -client myclient.dll 0 '-op1 -op2 "value with spaces"'
\endcode
The client's options are passed directly to its \p dr_client_main()
initialization routine, in the same manner as arguments are passed to a
regular application's \p main() routine. To match standalone application
conventions, \p argv[0] is set to the client library path, with the actual
parameters starting at index 1. The client can also optionally call
dr_get_option_array() to retrieve the options passed to it. C++ clients
can use the convenience of the \ref page_droption.
Client options are not allowed to contain semicolons. Additionally, the
client option string combined with the path to the client library cannot
contain all three quote characters (', ", `) simultaneously.
\section multi_client Multiple Clients
DynamoRIO does support multiple clients. It is each client's
responsibility, however, to ensure compatibility with other clients.
DynamoRIO makes no attempt to force cooperation among clients. For
example, instruction stream modifcations made by one client are
visible to other clients. Systems employing multiple clients must
be aware of such interactions and design accordingly.
Client registration requires users to specify the \em priority of each
client. DynamoRIO calls each client's
dr_client_main() routine sequentially according to this priority. Clients
with a numerically lower priority value are called first and therefore
given the first opportunity to register callbacks (the client with
priority 0 is called first). Since DynamoRIO delivers event
callbacks sequentially, client priority and the order of event
registration is important. For a given event, the \em first
registered callback is called \em last. This scheme gives precedence
to the first registered callback since that callback is given the final
opportunity to modify the instruction stream or influence DynamoRIO's
operation.
\section tool_frontend End-User Tools
A client can be packaged up with DynamoRIO to create an end-user tool. For
many tools, a separate front-end executable is not necessary, and \p drrun
is sufficient. Using \p drrun for a tool is made simpler by the \p -t
option. To use the option, first create a file in the \p tools
subdirectory of the root of the DynamoRIO installation called \p
toolname.drrun32 or \p toolname.drrun64, depending on the target
architecture. Here, \p toolname is the desired external name of the tool.
This file should contain one of the following lines:
\code
CLIENT_ABS=/absolute/path/to/client
\endcode
or
\code
CLIENT_REL=relative/path/to/client/from/DynamoRIO/root
\endcode
This enables \p drrun to locate the tool's client library.
The file can also modify the default DynamoRIO runtime options (see \ref
sec_options) via \p DR_OP= lines. Each line contains only one option string
token. For example:
\code
DR_OP=-persist
DR_OP=-persist_dir
DR_OP=c:\\path with spaces\\subdir
\endcode
Tool options can also be specified, but normally the defaults should be set
up appropriately in the client itself:
\code
TOOL_OP=-custom_op1
TOOL_OP=-custom_op2
\endcode
Lines beginning with \p # are considered comments.
When \p drrun is passed the option string <tt>-t toolname</tt>, it looks
for <tt>tools/toolname.drrun64</tt> or <tt>tools/toolname.drrun32</tt> and
reads the file to determine the client library to use and the default
DynamoRIO options. This makes for a simpler launching command, rather than
the end user needing to name the exact location of the client library. For
example, this command:
\code
bin64/drrun -t mytool -tool_option1 -tool_option2 -- myapp
\endcode
can be made to expand to this equivalent command:
\code
bin64/drrun -mytool_dr_option1 -mytool_dr_option2 -c tools/mytool/libmytool.so -tool_option1 -tool_option2 -- myapp
\endcode
For more extensive actions on launching the tool, a custom front-end
executable can be created that replaces \p drrun by using \p drinjectlib,
\p drconfiglib, and \p drfrontendlib. These three libraries facilitate
creating cross-platform tools for configuring and launching applications
under Dr. Memory. For more information about the interfaces they provide,
see their header files: dr_inject.h, dr_config.h, dr_frontend.h.
A custom front-end executable can be invoked via a \p drrun \p -t
configuration file using one of the following lines:
\code
FRONTEND_ABS=/absolute/path/to/front-end
\endcode
or
\code
FRONTEND_REL=relative/path/to/front-end/from/DynamoRIO/root
\endcode
This will cause \p drrun to transfer control to the specified front-end
executable, passing any tool arguments (including a client path, if \p
CLIENT_ABS or \p CLIENT_REL appears after the \p FRONTEND_* command)
followed by "--" and the target application command line.
The path to the DynamoRIO install base can be included in the front-end
options via this line
\code
TOOL_OP_DR_PATH
\endcode
The DynamoRIO runtime options can be included in a single token, preceded by a prefix,
via this line, using "-dr_ops" as an example prefix:
\code
TOOL_OP_DR_BUNDLE=-dr_ops
\endcode
A warning message can be presented up front to the user with:
\code
USER_NOTICE=This tool is currently experimental. Please report issues to mytool.com/issues.
\endcode
****************************************************************************
****************************************************************************
*/
/* It's good to use separate C comments: we've hit some sort of doxygen
* internal buffering error before if one comment gets too long.
*/
/**
***************************************************************************
***************************************************************************
\page using Usage Model for DynamoRIO
This section gives an overview of how to use DynamoRIO, divided into the
following sub-sections:
\if vmsafe
- \ref dr_api
- \ref dr_modes
- \ref sec_events
- \ref sec_utils
- \ref sec_extlibs
- \ref sec_comm
- \ref sec_annotations
- \ref sec_options
- \ref sec_debugging
\else
- \ref sec_events
- \ref sec_utils
- \ref sec_build
- \ref sec_extlibs
- \ref sec_extensions
- \ref sec_comm
- \ref sec_annotations
- \ref sec_64bit_reach
- \ref sec_utf8
- \ref sec_options
- \ref sec_debugging
\endif
\ifnot vmsafe
DynamoRIO exports a rich Application Programming Interface (API) to the
user for building a DynamoRIO <em>client</em>. A DynamoRIO client is a
library that is coupled with DynamoRIO in order to jointly operate on an
input program binary:
\image html client.png
\image rtf client.png
\image latex client.eps "DynamoRIO client" width=10cm
To interact with the client, DynamoRIO provides specific events that a
client can intercept. Event interception functions, if supplied by a user
client, are called by DynamoRIO at appropriate times.
DynamoRIO can alternatively be used as a third-party disassembly library
(see \ref page_standalone).
\endif
\if vmsafe
***************************************************************************
\section dr_api API
DynamoRIO's API is divided into the following interfaces:
- \ref API_security
<br>An interface for customizing and applying the award-winning Memory
Firewall security software.
- \ref API_probe
<br>A powerful probe insertion interface that can operate with the code cache
(\ref DR_MODE_CODE_MANIPULATION) or in a lighter-weight but more restrictive
mode without the code cache (\ref DR_MODE_PROBE).
- \ref API_BT
<br>The full runtime code manipulation interface. This includes the Probe
API, i.e., probes in the code cache.
\endif
\if vmsafe
***************************************************************************
\section dr_modes Modes
The different modes a client can request DynamoRIO to operate in are listed
below. These are not to be confused with the different \ref dr_api provided by
DynamoRIO. Each mode of DynamoRIO's operation maps to one or more API.
- The Memory Firewall mode (#DR_MODE_MEMORY_FIREWALL) maps exclusively to the Memory Firewall API.
- The Probe mode maps to the Probe API (#DR_MODE_PROBE) without code cache, i.e., a lighter-weight but restrictive mode.
- The Code Manipulation mode maps to the Code Manipulation API (#DR_MODE_CODE_MANIPULATION) and the Probe API (#DR_MODE_PROBE) with code cache.
.
Below we describe parts of the system that are common to all modes and
interfaces. Each interface adds its own events and utilities, described in
the section for that interface.
\endif
***************************************************************************
\section sec_events Common Events
A client's primary interaction with the DynamoRIO system is via a
set of event callbacks. These events include the following:
- Basic block and trace creation or deletion
(dr_register_bb_event(), dr_register_trace_event(), dr_register_delete_event())
- Process initialization and exit
(dr_client_main(), dr_register_exit_event())
- Thread initialization and exit
(dr_register_thread_init_event(), dr_register_thread_exit_event())
- Fork child initialization (Linux-only); meant to be used for
re-initialization of data structures and creation of new log files
(dr_register_fork_init_event())
- Application library load and unload
(dr_register_module_load_event(), dr_register_module_unload_event())
\ifnot NYI_kernel_mediated_transfer_events
- Application fault or exception (signal on Linux)
(dr_register_exception_event(), dr_register_signal_event())
\else
- Kernel-mediated control transfers:
- Application fault or exception
- Application APC (Asynchronous Procedure Call) or callback (Windows)
- Application signal (Linux)
\endif
- System call interception: pre-system call, post-system call, and system
call filtering by number
(dr_register_pre_syscall_event(), dr_register_post_syscall_event(),
dr_register_filter_syscall_event())
- Signal interception (Linux-only)
(dr_register_signal_event())
- Nudge received - see \ref sec_comm
(dr_register_nudge_event())
Typically, a client will register for the desired events at
initialization in its dr_client_main() routine. DynamoRIO then calls the
registered functions at the appropriate times. Each event has a
specific registration routine (e.g., dr_register_thread_init_event(): see
the names in parentheses in the list above)
and an associated unregistration routine. The header file dr_events.h
contains the declarations for all registration and unregistration
routines.
Note that clients are allowed to register multiple callbacks for the
same event. DynamoRIO also supports mutiple clients, each of which
can register for the same event. In this case, DynamoRIO sequences
event callbacks in reverse order of when they were registered. In
other words, the first registered callback receives event notification
last. This scheme gives priority to a callback registered earlier,
since it can override or modify the actions of clients registered
later. Note that DynamoRIO calls each client's dr_client_main() routine
according to the client's priority (see \ref multi_client and
dr_register_client() in the deployment API).
Systems registering multiple callbacks for a single event should be
aware that client modifications are visible in subsequent callbacks.
DynamoRIO makes no attempt to mitigate interference among callback
functions. It is the responsibility of a client to ensure
compatibility among its callback functions and the callback functions
of other clients.
Clients can also unregister a callback using the appropriate
unregister routine (see dr_events.h). While unusual, it is possible for
one callback routine to unregister another. In this case, DynamoRIO
still calls routines that were registered before the event.
Unregistration takes effect before the next event.
On Linux, an exec (SYS_execve) does NOT result in an exit event, but it
WILL result in the client library being reloaded and its dr_client_main() routine
being called again. The system call events can be used for notification of
SYS_execve.
***************************************************************************
\section sec_utils Common Utilities
DynamoRIO provides clients with a powerful library of utilities for
custom runtime code transformations. The interface includes explicit
support for creating \e transparent clients. See the section on
\ref transparency for a full discussion of the importance of remaining
transparent when operating in the same process as the application.
DynamoRIO provides common resources clients can use to avoid reliance on
shared libraries that may be in use by the application. The client should
only use external resources through DynamoRIO's own API, through
DynamoRIO Extensions (see \ref sec_extensions), through direct
system calls, or via an external agent in a separate process that
communicates with the client (see \ref sec_comm). Third-party libraries
can be used if they are linked statically or loaded privately and there is
no possibility of global resource conflicts (e.g., a third-party library's
memory allocation must be wrapped): see \ref sec_extlibs for more details.
\if vmsafe For the Probe API, these restrictions can be relaxed (see \ref
sec_trans_probe). \endif
DynamoRIO's API provides:
- Memory allocation: both thread-private (faster as it incurs no
synchronization costs) and thread-shared
- Thread-local storage
- Thread-local stack separate from the application stack
- Simple mutexes
- File creation, reading, and writing
- Address space querying
- Application module iterator
- Processor feature identification
- Extra thread creation
- Symbol lookup (currently Windows-only)
- Auxiliary library loading
See dr_tools.h and dr_proc.h for specifics of each routine.
Another class of utilities provided by DynamoRIO are structures and
routines for decoding, encoding, and manipulating IA-32, AMD64, ARM, and AArch64
instructions. These are described in \ref sec_IR.
\anchor subsec_forwards
In addition, on Windows, DynamoRIO provides a number
of utility functions that it fowards to a core Windows system library
that we believe to be safe for clients to use:
- wcstoul
- wcstombs
- wcstol
- wcsstr
- wcsspn
- wcsrchr
- wcspbrk
- wcsncpy
- wcsncmp
- wcsncat
- wcslen
- wcscspn
- wcscpy
- wcscmp
- wcschr
- wcscat
- towupper
- towlower
- toupper
- tolower
- tan
- strtoul
- strtol
- strstr
- strspn
- strrchr
- strpbrk
- strncpy
- strncmp
- strncat
- strlen
- strcspn
- strcmp
- strchr
- sscanf
- sqrt
- sprintf
- sin
- qsort
- pow
- memset
- memmove
- memcpy
- memcmp
- memchr
- mbstowcs
- log
- labs
- isxdigit
- iswxdigit
- iswspace
- iswlower
- iswdigit
- iswctype
- iswalpha
- isupper
- isspace
- ispunct
- isprint
- islower
- isgraph
- isdigit
- iscntrl
- isalpha
- isalnum
- floor
- fabs
- cos
- ceil
- atol
- atoi
- atan
- abs
- _wtol
- _wtoi64
- _wtoi
- _wcsupr
- _wcsnicmp
- _wcslwr
- _wcsicmp
- _vsnprintf
- _ultow
- _ultoa
- _ui64toa
- _toupper
- _tolower
- _strupr
- _strnicmp
- _strlwr
- _stricmp
- _strcmpi
- _snwprintf
- _snprintf
- _memicmp
- _memccpy
- _ltow
- _ltoa
- _itow
- _itoa
- _i64tow
- _i64toa
- _ftol
- _fltused
- _chkstk
- _aullshr
- _aullrem
- _aulldiv
- _atoi64
- _allshr
- _allshl
- _allrem
- _allmul
- _alldiv
- __toascii
- __iscsymf
- __iscsym
- __isascii
In general, these routines match their standard C library counterparts. However, be
warned that some of these may be more limited. In particular, _vsnprintf
and _snprintf do not support floating-point values. DynamoRIO provides
its own dr_snprintf() that does support floating-point values, but does
not support printing wide characters. When printing floating-point values
be sure to \ref sec_trans_floating_point
"save the application's floating point state"
so as to avoid corrupting it.
***************************************************************************
\section sec_64bit_reach 64-Bit Reachability
To simplify reachability in a 64-bit address space, DynamoRIO guarantees
that all of its code caches are located within a single 2GB memory region.
It also places all client memory allocated through dr_thread_alloc(),
dr_global_alloc(), dr_nonheap_alloc(), or dr_custom_alloc() with
#DR_ALLOC_CACHE_REACHABLE in the same region.
DynamoRIO loads client libraries and Extensions (but not copies of system
libraries) within 32-bit reachability of its code caches. Typically, the
code cache region is located in the low 4GB of the address space; thus, to
avoid relocations at client library load time, it is recommended to set a
preferred client library base in the low 4GB.
The net result is that any static data or code in a client library, or any
data allocated using DynamoRIO's API routines (except dr_raw_mem_alloc() or
dr_custom_alloc()), is guaranteed to be directly reachable from code cache
code. However, memory allocated through system libraries (including
malloc, operator new, and HeapAlloc), as well as DynamoRIO's own
internally-used heap memory, is *not* guaranteed to be reachable: only
memory directly allocated via DynamoRIO's API. The \ref op_reachable_heap
"-reachable_heap runtime option" can be used to guarantee that all memory
is reachable, at the risk of running out memory due to the smaller space
of available memory.
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.
When inserting calls, dr_insert_call() and dr_insert_clean_call() assume
that the call is destined for encoding into the code cache-reachable memory
region, when determining whether a direct or indirect call is needed.
An indirect call will clobber r11. Use dr_insert_clean_call_ex()
with #DR_CLEANCALL_INDIRECT to ensure reachability when encoding to
a location other than DR's regular code region, or when a clean call is not
needed, dr_insert_call_ex() takes in a target encode location for more
flexible determination of direct versus indirect.
DynamoRIO does not guarantee that any of its memory is allocated in the
lower 4GB of the address space. However, it provides several features to
make it easier to reference addresses absolutely:
- For directly referencing a global variable \p var in a client library, the
client can create an operand with the address \p &var and it will
auto-magically turn into a pc-relative addressing mode.
OPND_CREATE_ABSMEM() directly creates a pc-relative operand, while
opnd_create_abs_addr() will convert to a pc-relative operand when an
absolute reference will not encode. An opnd_create_rel_addr() operand
will also convert to an absolute reference when that will reach but a
pc-relative reference will not.
- When using an address as an immediate, use the routines
instrlist_insert_mov_immed_ptrsz() or
instrlist_insert_push_immed_ptrsz() to conveniently insert either one or
two instructions depending on whether the address is in the lower 4GB or
not.
- When using an \p instr_t pointer as an immediate, use the routines
instrlist_insert_mov_instr_addr() or instrlist_insert_push_instr_addr()
to conveniently insert either one or two instructions depending on
whether the resulting instr_t encoded address is in the lower 4GB or
not.
***************************************************************************
\section sec_utf8 String Encoding
All strings in the DynamoRIO API, whether input or output parameters, are
encoded as UTF-8. DynamoRIO will internally convert to UTF-16 when
interacting with the Windows kernel. A client can use #dr_snprintf() or
#dr_snwprintf() with the \p S format code to convert between UTF-8 and
UTF-16 on its own. (The _snprintf() function forwarded to ntdll does not
perform that conversion.)
***************************************************************************
\section sec_build Building a Client
To use the DynamoRIO API, a client should include the main DynamoRIO
header file:
\code
#include "dr_api.h"
\endcode
The client's target operating system and architecture must
be specified by setting pre-processor defines before including the
DynamoRIO header files. The appropriate library must then be linked
with. The define choices are:
-# \p WINDOWS, \p LINUX, or (coming soon) \p MACOS
-# \p X86_32, \p X86_64, \p ARM_32, or \p ARM_64
Currently we provide a private loader for both Windows and Linux.
With private loading, clients use a separate copy of each library
from any copy used by the application.
If the private loader is deliberately disabled, for transparency reasons
(see \ref transparency), clients should be
self-contained and should not share libraries with the application.
Without the private loader, 64-bit clients must take care to try and load
themselves within reachable range of DynamoRIO's code caches by setting a
preferred base address, although this may not always be honored by the
system loader.
The DynamoRIO release supplies <a href="http://www.cmake.org">CMake</a>
configuration files to facilitate building clients with the proper
compiler and linker flags. CMake is a cross-platform build system that
generates Makefiles or other development system project files. A \p
DynamoRIOConfig.cmake configuration file, along with supporting files, is
distributed in the \p cmake/ directory.
In its \p CMakeLists.txt file, a client should first invoke a \p
find_package(DynamoRIO) command. This can optionally take a version
parameter. This adds DynamoRIO as an imported target. If found, the
client should then invoke the \p configure_DynamoRIO_client() function in
order to configure build settings. Here is an example:
\code
add_library(myclient SHARED myclient.c)
find_package(DynamoRIO)
if (NOT DynamoRIO_FOUND)
message(FATAL_ERROR "DynamoRIO package required to build")
endif(NOT DynamoRIO_FOUND)
configure_DynamoRIO_client(myclient)
\endcode
Note that when building a 32-bit client in Linux using \p gcc, the stack
alignment should be 4-byte only.
Using the function \p configure_DynamoRIO_client() will configure the
build settings correctly.
Otherwise, appropriate options should be passed to the compiler: e.g.,
\p -mpreferred-stack-boundary=2.
The \p samples/CMakeLists.txt file in the release package serves as another
example. The top of \p DynamoRIOConfig.cmake contains detailed
instructions as well.
When configuring, the \p DynamoRIO_DIR CMake variable can be passed in to
identify the directory that contains the \p DynamoRIOConfig.cmake file. For
example:
\code
mkdir ../build
cd ../build
cmake -DDynamoRIO_DIR=$DYNAMORIO_HOME/cmake ../myclient
make
\endcode
The compiler needs to be configured prior to invoking cmake. If using gcc
with a non-default target platform, the \p CFLAGS and \p CXXFLAGS
environment variables should be set prior to invoking cmake. For example,
to configure a 32-bit client when gcc's default is 64-bit:
\code
mkdir ../build
cd ../build
CFLAGS=-m32 cmake -DDynamoRIO_DIR=$DYNAMORIO_HOME/cmake ../myclient
make
\endcode
Note that \p CXXFLAGS should be set instead for a C++ client, and both should
be set when building both types of clients from the same configuration
(e.g., \p samples/CMakeLists.txt).
To improve clean call performance (see \ref sec_clean_call and \ref
op_cleancall "-opt_cleancall"), we recommend high levels of optimization
when building a client.
If a client is not using CMake, the appropriate compiler and linker flags
can be gleaned from \p DynamoRIOConfig.cmake. One method is to invoke CMake to
generate a Makefile and then build with \p VERBOSE=1. We also summarize
here the key flags required for 32-bit clients for \p gcc:
\code
gcc -fPIC -shared -lgcc -DLINUX -DX86_32 -I$DYNAMORIO_HOME/include my-client.c
\endcode
And for \p cl:
\code
cl my-client.c /I$DYNAMORIO_HOME/include /GS- /DWINDOWS /DX86_32
/link /libpath:$DYNAMORIO_HOME/bin dynamorio.lib /dll /out:my-client.dll
\endcode
For a 64-bit client with \p cl:
\code
cl my-client.c /I$DYNAMORIO_HOME/include /GS- /DWINDOWS /DX86_64
/link /libpath:$DYNAMORIO_HOME/bin dynamorio.lib /dll /out:my-client.dll
/base:0x72000000 /fixed
\endcode
For 64-bit Linux clients, setting the preferred base takes several steps.
Refer to \p DynamoRIOConfig.cmake for details.
To make clean call sequences more likely to be optimized, it is recommended
to compile the client with optimizations, \p -O2 for gcc or \p /O2 for cl.
***************************************************************************
\section sec_extensions DynamoRIO Extensions
DynamoRIO supports extending the API presented to clients through
separate libraries called DynamoRIO Extensions. Extensions are meant to
include features that may be too costly to make available by default or
features contributed by third parties whose licensing requires using a
separate library. Extensions can be either static libraries linked with
clients at build time or dynamic libraries loaded at runtime. A private
loader is used to load dynamic Extensions.
Current Extensions provide symbol access and container data structures.
Each Extension has its own documentation and has its functions and data
structures documented separately from the main API.
See the full list of Extensions here: \ref page_ext.
Be aware that some of the DynamoRIO Extensions have LGPL licenses instead
of the BSD license of the rest of DynamoRIO. Such Extensions are built as
shared libraries, have their own license.txt files, and clearly identify
their license in their documentation. (We also provide static versions of
such libraries, but take care in using them that their LGPL licenses match
your requirements.)
***************************************************************************
\section sec_extlibs Using External Libraries
Clients are free to use external libraries as long as those libraries do
not use any global user-mode resources that would interfere with the
running application, and as long as no alertable system calls are invoked
on Windows (see \ref sec_alertable). While most non-graphical
non-alertable Windows API routines are supported, native threading libraries
such as \p libpthread.so on Linux are known to cause problems.
Currently we provide a private loader for both Windows and Linux.
Clients must either link statically to all libraries or load them using
our private loader, which will happen automatically for shared libraries
loaded in a typical manner.
With private loading, the client
uses a separate copy of each library from any copy used by the application.
This helps to prevent re-entrancy problems (see \ref sec_trans_resource).
Even with this separation, if these libraries use global resources there
can still be conflicts. Our private loader redirects heap
allocation in the main process heap to instead use DynamoRIO's internal
heap. The loader also attempts to isolate other global resource usage and
global callbacks. Please file reports on any transparency problems
observed when using the private loader.
By default, all Windows clients link with libc. To instead
use the libc subset of routines forwarded from the DynamoRIO library to \p
ntdll.dll (which keeps clients more lightweight and is usually sufficient
for most C code), set this variable prior to invoking
configure_DynamoRIO_client():
\code
set(DynamoRIO_USE_LIBC OFF)
\endcode
C++ clients and standalone clients link with libc by default.
**************************************************
\subsection sec_alertable Avoid Alertable System Calls
On Windows, DynamoRIO does not support a client (or a library used by a
client) making alertable system calls. These are system calls that can be
interrupted for delivery of callbacks or asynchronous procedure calls. At
the Windows API layer, they include many graphical routines, any Wait
function invoked with \p alertable=TRUE (e.g., WaitForSingleObjectEx or
WaitForMultipleObjectsEx), any Windows message queue function (GetMessage,
SendMessage, ReplyMessage), and asynchronous i/o. In general, avoiding
graphical, windowing, or asynchronous i/o library or system calls is
advisable. DynamoRIO does not guarantee correct execution when a callback
arrives during client code execution.
**************************************************
\subsection sec_rpath DynamoRIO Library Search Paths
DynamoRIO's loader searches for libraries in approximately the same manner
as the system loader. It also has support for automatically locating
Extension libraries that are packaged in the usual place in the DynamoRIO
file hierarchy.
DynamoRIO supports setting DT_RPATH for ELF clients, via setting the
DynamoRIO_RPATH variable to ON prior to invoking
configure_DynamoRIO_client(). On Windows, setting that variable will
create a "<client_basename>.drpath" text file that contains a list of
paths. At runtime, DynamoRIO's loader will parse this file and add each
newline-separated path to its list of search paths. This file is honored
on Linux as well, though it is not automatically created there. This
allows clients a cross-platform mechanism to use third-party libraries in
locations of their choosing.
**************************************************
\subsection subsec_avoid_redir Deliberately Invoking Application Routines
Sometimes, a client wishes to invoke system library routines with the
application context, rather than having them redirected and isolated by
DynamoRIO. This can be accomplished using dynamic binding rather than
static: dynamically looking up each desired library routine via DR's own
routines (such as dr_get_proc_address()). (Using \p GetProcAddress will not
work for this purpose as the result will be redirected.)
**************************************************
\subsection subsec_no_loader When Private Loader is Disabled
On Linux, if the private loader is deliberately disabled, ld provides the -wrap
option, which allows us to override the C library's memory heap allocation
routines with our own. For convenience, DynamoRIO exports
__wrap_malloc(), __wrap_realloc(), and __wrap_free() for this purpose.
These routines behave like their C library counterparts, but operate on
DynamoRIO's global memory pool. Use the -Xlinker flag with gcc to replace
the libc routines with DynamoRIO's _wrap routines, e.g.,
\code
gcc -Xlinker -wrap=malloc -Xlinker -wrap=realloc -Xlinker -wrap=free ...
\endcode
The ability to override the memory allocation routines makes it
convenient to develop C++ clients that use the \em new and \em delete
operators (as long as those operators are implemented using malloc and
free). In particular, heap allocation is required to use the C++
Standard Template Library containers. When developing a C++ client,
we recommend linking statically to the C++ runtime library if not using
the provided private loader.
On Linux, this is most easily accomplished by specifying the path to the
static version of the library on the gcc command line. gcc's
-print-file-name option is useful for discovering this path, e.g.,
\code
g++ -print-file-name=libstdc++.a
\endcode
A full gcc command line for building a C++ client when disabling the
private loader (which is not the default) might look something like this
(note that this requires static versions of the standard libraries that
were built PIC, which is not the case in modern binary distributions and
often requires building from source):
\code
g++ -o my-client.so -I<header dir> \
-fPIC -shared -nodefaultlibs \
-Xlinker -wrap=malloc -Xlinker -wrap=realloc -Xlinker -wrap=free \
`g++ -print-file-name=libstdc++.a` \
`g++ -print-file-name=libgcc.a` \
`g++ -print-file-name=libgcc_eh.a` \
my-client.cpp
\endcode
**************************************************
\subsection subsec_cpp C++ Clients
The 3.0 version of DynamoRIO added experimental full support for C++
clients using the STL and other libraries.
On Windows, when using the Microsoft Visual C++ compiler, we recommend
using the \p /MT compiler flag to request a static C library. The client
will still use the \p kernel32.dll library but our private loader will load
a separate copy of that library and redirect heap allocation automatically.
Our private loader does not yet support locating SxS (side-by-side)
libraries, so using \p /MD will most likely not work unless using a
version of the Visual Studio compiler other than 2005 or 2008.
We do not recommend that a client or its libraries invoke their own system
calls as this bypasses DynamoRIO's monitoring of changes to the process
address space and changes to threads or control flow. Such system calls
will also not work properly on Linux when using sysenter on some systems.
If you see an assert to that effect in debug build on Linux, try the \ref
op_sysenter "-sysenter_is_int80" option.
***************************************************************************
\section sec_comm Communication
Due to transparency limitations (see \ref transparency),
DynamoRIO can only support certain communication channels in and out of the
target application process. These include:
- DynamoRIO deployment control and runtime options: see \ref page_deploy
and \ref sec_options. In particular, the deployment API allows users to
pass up-front runtime information to the client.
- Nudges: Since polling requires extra threads, and DynamoRIO tries not
to create permanent extra threads (see \ref sec_trans_thread
"Thread Transparency"), a mechanism called \e nudges are the preferred mechanism
for pushing data into the process. Nudges are used to notify DynamoRIO
that it needs to re-read its options, or perform some other action.
DynamoRIO also provides a custom nudge event that can be used by
clients. See dr_nudge_process() and dr_register_nudge_event().
- Files can be used to send data out. An external process can wait on
the file.
- Shared memory can be used for bi-directional communication. For an
example of this on Windows, see the stats sample (see \ref sec_drstats).
***************************************************************************
\section sec_annotations Annotations
DynamoRIO provides a binary annotation mechanism which allows the target application to
communicate directly with the DynamoRIO client, or with DynamoRIO itself. A binary
annotation is generated from a macro that can be manually inserted into the source code of
the target program. When compiled, the resulting sequence of assembly instructions has no
effect on native execution (i.e., it is a nop, or resolves to a static default value),
but during execution under DynamoRIO, each annotation is detected and transformed into a
function call to a set of registered handlers. Currently DynamoRIO provides 2 simple
annotations:
- <b>DYNAMORIO_ANNOTATE_RUNNING_ON_DYNAMORIO()</b>
Indicates by its return value whether the target app is running under DynamoRIO,
- <b>DYNAMORIO_ANNOTATE_LOG(format, ...)</b>
Writes a message to the DynamoRIO log, when the target app is running under DynamoRIO
and logging is enabled.
An annotation may be declared void, as in DYNAMORIO_ANNOTATE_LOG(), or it may have a
return value, as in the boolean DYNAMORIO_ANNOTATE_RUNNING_ON_DYNAMORIO(). The return
value can be used in a branch predicate, such that some of the target app's code only
executes under DynamoRIO, or it can be used for in-process communication to obtain data
from DynamoRIO or its client that is only available during binary translation.
\subsection subsec_annotate_app Annotating an Application
Adding an annotation to a target application is primarily a simple matter of invoking the
annotation macro at the desired program location. The macros are declared in the C header
file <b>include/annotations/dr_annotations.h</b>, and each macro operates syntactically
like a function call. An annotation having a return value can be used as an expression.
DynamoRIO provides a module which defines the annotations, and clients may also provide
modules containing custom annotations. Each compilation unit that uses annotations must be
statically linked with the corresponding annotation module(s). For projects using cmake, a
convenience function \b use_DynamoRIO_annotations(target, srcs) will configure the
specified \b srcs to be linked with the annotation module.
\subsection subsec_instr_annotations Instrumenting Annotations
When DynamoRIO encounters an annotation in the target app, it instruments that program
location in one of two ways:
- Return value substitution: DynamoRIO replaces the annotation with a constant return
value (this instrumentation is only valid for annotations having a return value),
- Handler invocation: DynamoRIO replaces the annotation with a call to each handler that
is currently registered for the annotation. For annotations having a return value, the
return value of the last registered handler will be the value to take effect at the
target program location.
Annotation handlers are registered using API functions \b dr_annotation_register_call()
and \b dr_annotation_register_return(). Note that changes to handler registration will
have no effect on annotations that have already been translated by DynamoRIO into the
code cache (until the annotated basic blocks are removed from the cache and retranslated).
The annotation instrumentation invokes the handlers using a separate clean call for each
handler. The return value for an annotation can be set within a handler function using
the API function \b dr_annotation_set_return_value().
\subsection subsec_create_annotations Creating Custom Annotations
DynamoRIO client developers may wish to create new annotations to facilitate
client-specific communication with the target application. For example, a client that
inspects memory usage may have false positives for variables in the target app that are
never referenced after initialization. The \ref API_tutorial_annotation1 walks
through the process of creating a new annotation that allows target application
developers to explicitly mark any variable as defined.
***************************************************************************
\section sec_options Fine-Tuning DynamoRIO: Runtime Parameters
DynamoRIO's behavior can be fine-tuned using runtime parameters. Options
are specified via \c drconfig, \c drrun, or dr_register_process(). See
\ref page_deploy.
- \b -no_follow_children: \anchor op_children
By default, DynamoRIO follows all child processes. When this option
is disabled via \p -no_follow_children, DynamoRIO follows only
into child processes for which a configuration file exists (typically
created by \c drconfig; see \ref page_deploy). On Linux,
forked children are always followed and this option only affects execve.
To follow all children in general but exclude certain children, leave \p
-follow_children on (the default) and create config files that exclude
the desired applications by running \c drconfig with the \c -norun
option.
- \b -opt_memory: \anchor op_memory
Reduce memory usage, but potentially at the cost of performance. This
option can result in memory savings as high as 20%, and usually incurs
no noticable performance degradation. However, it conflicts with the
\ref op_enable "-enable_full_api option" and cannot be used with
dr_unlink_flush_region().
- \b -opt_cleancall \e \<number\>: \anchor op_cleancall
Optimize (shrink or inline) the clean call sequences (see \ref sec_clean_call).
When DynamoRIO analyzes the callee and optimizes each clean call invocation,
it assumes that a client will not modify the clean call callee or application
instructions after the inserted clean call.
If a client changes application instructions after an inserted clean call,
the client may need to reduce the -opt_cleancall level to preserve correct
execution.
The clean call will only be optimized if it is a leaf function.
Currently, the callee will be inlined only if it is small, has at most
one argument, and has no control flow other than for the PIC base.
Compiling the client with optimizations makes clean call sequences more likely
to be optimized.
The optimization results (e.g. whether the inserted clean call is inlined or not,
and which registers were saved on each context switch) are logged.
Users can run DynamoRIO debug build with the runtime option
"-loglevel 2 -logmask 0x02000000" (the logmask is optional but reduces the
logfile size significantly) and grep for
"CLEANCALL" in the log file to retrieve the information
about clean call optimization.
There are four optimization levels.
By default, the clean call optimization level is 2.
- 0: no optimization.
- 1: callee register usage analysis and optimization on context switch.
- 2: simple callee inline optimization, callee-save register analysis,
and aflags usage analysis on the instruction list to be inserted.
- 3: more aggressive, but potentially unsafe, optimizations.
- \b -opt_speed: \anchor op_speed
By default, DynamoRIO provides a more straightforward code stream to
clients in lieu of performance optimizations. This option attempts
to obtain higher performance with potential loss of client simplicity.
In particular, unconditional branches (both jumps and calls) and in some
cases indirect calls may be elided in basic blocks. See also \ref sec_limit_perf.
Note that dr_insert_mbr_instrumentation() is not supported when -opt_speed
is specified.
- \b -stack_size \e \<number\>: \anchor op_stack_size
DynamoRIO's per-thread stack is limited to 56KB by default (this may
seem small, but this is much larger than its size when no client is
present). This parameter can be used to increase the size; however,
larger stack sizes use significantly more memory when targeting
applications with hundreds of threads. The parameter can take a 'K'
suffix, and must be a multiple of the page size (4K). This stack is
used \if vmsafe for probe callbacks and by the Code Manipulation
API \else by the \endif routines dr_insert_clean_call(),
dr_swap_to_clean_stack(), dr_prepare_for_call(),
dr_insert_call_instrumentation(), dr_insert_mbr_instrumentation(),
dr_insert_cbr_instrumentation(), and dr_insert_ubr_instrumentation().
The stack is started fresh for each use, so <em>no persistent state may be
stored on it</em>.
\if vmsafe
Options available only in Code Manipulation mode and Memory Firewall mode
(see \ref dr_modes):
\endif
- \b -thread_private: \anchor op_thread_priv
By default, DynamoRIO's code caches are shared across threads. This
option requests code caches that are private to each thread. For
applications with many threads, thread-private code caches use more
memory. However, they can be more efficient, particularly when
inserting thread-specific instrumentation.
- \b -disable_traces:
By default, DynamoRIO builds both a <em>basic block</em> code cache and
a <em>trace</em> code cache (see \ref sec_IR). This option disables
trace building, which can have a negative performance impact.
When running large, short-running applications, however, disabling
traces can improve performance.
When traces are disabled, dr_register_trace_event() has no effect.
DynamoRIO tries to keep traces transparent to a client who is
interested in all code and not only hot code, so there is rarely a
reason to disable traces.
\if internal_comment
if we expose -enable_traces, note that it must be specified BEFORE
-thread_private as today it turns on -shared_traces
\endif
- \b -enable_full_api: \anchor op_enable
DynamoRIO's default internal options balance performance with API
usability. A few API functions, such as dr_unlink_flush_region(),
are incompatible with this default mode. Client users can gain
access to the entire set of API functions with -enable_full_api.
Note that this option may result in a small performance degradation.
- \b -reachable_heap: \anchor op_reachable_heap
By default, DynamoRIO guarantees that heap allocated directly through
its API routines dr_thread_alloc(), dr_global_alloc(),
dr_nonheap_alloc(), or dr_custom_alloc() with #DR_ALLOC_CACHE_REACHABLE
is reachable by a 32-bit displacement from the code cache. However, it
does not guarantee that memory allocated through system libraries
(including malloc, operator new, and HeapAlloc) or DynamoRIO's own
internal memory is reachable. Turning this option on combines all of
the heap memory such that it is all guaranteed to be reachable from the
code cache, at the risk of running out memory due to the smaller space
of available memory.
- \b -max_bb_instrs:
DynamoRIO stops building a basic block if it hits this application
instruction count limit before hitting control flow or other block
termination conditions. The default value is 1024; lower it if
extensive client instrumentation is running into code cache size
limit asserts.
- \b -max_trace_bbs:
DynamoRIO will not build a trace with larger than this number of
constituent basic block. The default value is 128; lower it if
extensive client instrumentation is running into code cache size
limit asserts.
- \b -sysenter_is_int80: \anchor op_sysenter
This option only applies to Linux. If sysenter is the system call
gateway, DynamoRIO normally hooks the vsyscall vdso page when it can.
This option requests that DynamoRIO convert sysenter into int 0x80
instead. See \ref sec_extlibs.
- \b -multi_thread_exit:
By default, DynamoRIO synchronizes with all remaining threads
at process exit time and the process exit event executes with only
one live thread. This option requests that in release build the
synchronization be avoided. The process exit event must be written
in a thread-safe manner. Note that if thread exit events are
registered, to avoid the synchronization the -skip_thread_exit_at_exit
option must also be set. These options can also be enabled
programmatically via dr_set_process_exit_behavior().
- \b -skip_thread_exit_at_exit:
By default, DynamoRIO synchronizes with all remaining threads at
process exit time in order to safely call each thread exit event. This
option requests that in release build the synchronization be avoided by
removing the invocation of thread exit events at process exit time.
Note that if the process exit event is registered, to avoid the
synchronization the -multi_thread_exit option must also be set. These
options can also be enabled programmatically via
dr_set_process_exit_behavior().
- \b -persist:\anchor op_persist
Enables persisting of code caches to disk and re-use on subsequent runs.
Caches are persisted in units that correspond to application libraries,
or sometimes smaller units. Each unit is persisted to its own file
in a subdirectory of the base directory specified by \p -persist_dir.
See \ref sec_pcache for more details.
- \b -persist_dir \e \<path\>:
Sets the base directory for persistent code cache files. If unset,
the default base directory is the log directory. A different
sub-directory will be created for each user inside the specified
directory.
- \b -translate_fpu_pc:\anchor op_translate_fpu_pc
Enables translation of the last floating-point instruction address when
the last floating-point instruction is not in the same basic block as
the instruction saving the FPU state. This is off by default as it
incurs significant performance penalties and few applications require
this feature.
\if cache_sizing
FIXME: users may want control over adaptive wset cache management,
particularly for thread-private to avoid deletions, but also for shared if
they want to shrink memory usage
\endif
- \b -syntax_intel: \anchor op_syntax_intel
This option causes DynamoRIO to output all disassembly using Intel
syntax rather than the default show-implicit-operands syntax. This can also be set
using disassemble_set_syntax().
- \b -syntax_att: \anchor op_syntax_att
This option causes DynamoRIO to output all disassembly using AT&T
syntax rather than the default show-implicit-operands syntax. This can also be set
using disassemble_set_syntax().
- \b -syntax_arm: \anchor op_syntax_arm
This option causes DynamoRIO to output all disassembly using standard
ARM assembler syntax rather than the default show-implicit-operands
syntax. This can also be set using disassemble_set_syntax().
- \b -disasm_mask:
This option sets the disassembly style to the specified bitmask of
dr_disasm_flags_t values. This option overlaps with -syntax_intel,
-syntax_att, and -syntax_arm. The style can also be set using
disassemble_set_syntax().
\ifnot vmsafe
- \b -tracedump_text and \b -tracedump_binary:
These options cause DynamoRIO to output all traces that were created
to the log file \e traces-shared.0.TID.html, where \e
TID is the thread id of the initial thread; any thread-private traces
(see \ref op_thread_priv "-thread_private option") produce per-thread
files \e traces.TID.html.
Traces are logged whenever they are flushed from the cache (which can
be during execution or at the latest at program termination). The two
options select either a text dump or a binary dump. The text dump
takes up considerable room and time to dump, while the binary dump
requires more effort to examine. The binary trace dump format is
documented in dr_tools.h, and a sample reader is provided with this
distribution.
- \b -tracedump_origins
When selected by itself with neither -tracedump_text nor
-tracedump_binary, dumps only a text list of the constituent basic block
tags of each trace to the trace log file. When combined with either of
-tracedump_text or -tracedump_binary, adds a full disassembly of the
constituent basic blocks to the selected dump.
\endif
\if profiling
FIXME PR 225255: profiling options
\endif
Options controlling notifications from DynamoRIO:
- \b -msgbox_mask \e 0xN: \anchor op_msgbox_mask
Controls whether DynamoRIO uses pop-up message boxes on Windows,
or waits for a key press on Linux, when presenting information.
The mask takes the following bitfields:
- INFORMATION = 0x1
- WARNING = 0x2
- ERROR = 0x4
- CRITICAL = 0x8
.
dr_messagebox() is not affected by -msgbox_mask. For the
provided Windows debug build -msgbox_mask defaults to 0xC.
On Linux the default is 0, as this feature reads from standard input and
might conflict with some applications. On Linux the pause can be
changed to use an infinite loop rather than reading from standard input
by passing the \b -pause_via_loop runtime option, which allows attaching
a debugger.
\attention
On Vista or higher most Windows services are currently unable to display
message boxes (see \ref limits_vista_service_messagebox
"Limitations"). Since these services also don't have an associated
console for stderr printing, the \ref op_loglevel "-loglevel"
and \ref op_logmask "-logmask" options should be used
instead. For the messages that would be displayed by -msgbox_mask,
setting any bit in -logmask is sufficient for the message to be
included in the logfile.
- \b -stderr_mask \e 0xN:
Parallel to -msgbox_mask, but controls DynamoRIO's output to standard
error. This option takes the same bitfields as -msgbox_mask. The API
routine dr_is_notify_on() can be used to determine if -stderr_mask is
non-zero. Messages printed to stderr will only be visible for
applications that have an attached console. They will not be visible
in the \p cmd console on Windows 7 or earlier or on any Windows version
when running a graphical application in \p cmd (even with dr_enable_console_printing(),
as that only affects clients calling dr_printf() or dr_fprintf()) but
the output can be viewed from \p cmd by redirecting to a file.
For the provided Linux
debug builds, -stderr_mask defaults to 0xF; for the Linux release
builds, its default is 0xE. The default on Windows is 0.
\ifnot vmsafe
Options aiding in debugging:
- \b -no_hide: \anchor op_no_hide
By default, DynamoRIO hides itself from the Windows module list, for
transparency. However, this makes it more difficult to debug a process
under DynamoRIO's control. The option -no_hide turns off this module
hiding. However, the client library and any libraries it imports from
will still be hidden. We provide a windbg script that can locate
DynamoRIO, the client library, and all of its dependences, so this
option should no longer be necessary (see \ref sec_debugging).
This option is for Windows only.
\endif
Options available only in the debug build of DynamoRIO:
\anchor op_loglevel
- \b -loglevel \e N:
If N is greater than 0, DynamoRIO prints out a log of its actions.
The greater the value of N, the more information DynamoRIO prints.
Useful ranges are from 1 to 6. Verbosity is set to 0 by default, i.e.,
no log written. All log files are kept in a log directory. There is
one directory per address space per run. The directories are named \e
app.NNN, where \e app is the application name and \e NNN is a number
that is incremented with each directory created. On
Windows the directories are located by default in
a subdirectory \e logs of the DynamoRIO home directory as
specified in the dr_register_process(), \c drconfig, or \c drrun
configuration for the target application.
The runtime option \ref op_logdir "-logdir" can be used to override the
default directory.
There is one main log file per directory named
\e app.0.TID.html, where \e TID is the thread identifier of the initial
thread. There is also a log file per thread, named \e log.N.TID.html,
where \e N is the thread's creation ordinal and \e TID is its thread
identifier. The loglevel may be changed during program execution, but
if it began at 0 then it cannot be raised later. The -logmask
parameter can be used to control which DynamoRIO modules output data
to the log files. dr_log() allows the client to write to the above
logfiles.
\anchor op_logmask
- \b -logmask \e 0xN:
Selects which DynamoRIO modules print out logging information, at the
-loglevel level. The mask is a combination of the LOG_ bitfields
listed in dr_tools.h (#LOG_ALL selects all modules).
\anchor op_logdir
- \b -logdir \e \<path\>:
Specifies the directory to use for log files. See the documentation
for \ref op_loglevel "-loglevel" for a description of the default
log directory.
- \b -ignore_assert_list \b '*': \anchor op_ignore_assert
Ignores all DynamoRIO asserts of the form "<file>:1234". * may be
replaced by a ; separated list of individual asserts to ignore
"foo.c:333;bar.c:12".
***************************************************************************
\section sec_debugging Diagnosing and Reporting Problems
When using a complex system like DynamoRIO, problems can be challenging to
diagnose. This section contains some debugging tips and shows how to get
help.
\subsection sec_reporting Obtaining Help and Reporting Problems
For questions and discussion, join the <a
href="http://groups.google.com/group/dynamorio-users/">DynamoRIO Users
group</a>.
For bug reports, use the <a
href="https://github.com/DynamoRIO/dynamorio/issues">Issue Tracker</a>.
Please include <a
href="https://github.com/DynamoRIO/dynamorio/wiki/Bug-Reporting">a detailed
description</a> of the problem (is it an application crash? a DynamoRIO
crash? a hang? a debug build assert?) and how to reproduce it.
\subsection sec_diagnosing Troubleshooting
- DynamoRIO disables itself when Windows is booted in safe mode (without
networking). Thus, if a crash occurs in a Windows service under
DynamoRIO, rebooting in safe mode will allow recovery.
- If the client library doesn't seem to function for a given process, it is
likely that the client library wasn't loaded due to errors.
\par
One of the common situations where this happens is when the target
application runs as a different user than the user who created the client
library. This results in the application process not having the right
permissions to access the client library.
\par
Try running the process under the debug mode of DynamoRIO (see
dr_register_process()), where diagnostic messages are raised on errors like
client library permissions. To see all messages, set the notification
options like -msgbox_mask and -stderr_mask options to 0xf (see \ref
sec_options). This will alert you to the problem.
- DynamoRIO asserts of the form "<file>:1234" can be suppressed with
the \ref op_ignore_assert "-ignore_assert_list '*'" option. * may
be replaced by a ; separated lists of individual asserts to
suppress as so "-ignore_assert_list 'foo.c:333;bar.c:12'".
- The DynamoRIO header files have typedefs that may conflict with other
header files wrapped in ifndef DR_DO_NOT_DEFINE_<type> to make it
easier to work around such conflicts.
\ifnot vmsafe
\subsection sec_using_debugger Using Debuggers
A process under control of DynamoRIO can be executed within a debugger.
For debugging on Windows we recommend using windbg version 6.3.0017 (\b not
the newer versions, as they have problems displaying callstacks involving
DynamoRIO code).
Normally, the debugger will not be aware of the DynamoRIO library or the
client library. We provide a windbg script that locates the DynamoRIO
library, the client library, and any privately-loaded dependent libraries.
The script is in \c bin32/load_syms.txt and \c bin64/load_syms64.txt. To
load it from windbg, execute the following command:
\code
$><c:\path\to\DR\bin32\load_syms.txt
\endcode
When debugging often, modify the shortcut that launches windbg
to include this command as a -c argument. E.g.:
\code
"C:\Program Files (x86)\Debugging Tools for Windows\windbg.exe" -pt 1 -c "$><c:\tools\DynamoRIO\bin32\load_syms.txt"
\endcode
On Windows, the \ref op_no_hide "-no_hide" option can alternatively be
used so the debugger can see the DynamoRIO library, but the debugger
will still not be able to see the client library or any of its
dependent libraries. We recommend using our script.
To attach to a process on Windows, use the \ref op_msgbox_mask
"-msgbox_mask" option and attach the debugger while the dialog box has
paused the application. On Linux, the same option can be used and
the debugger attached while the application waits for enter to be
pressed. Since this may not work for applications that themselves
read from standard input, we also provide the \b -pause_via_loop runtime
option which sits in an infinite loop rather than waiting for a keypress.
To run an application on Linux under a debugger from process start you
can launch drrun under gdb as you would normally:
\code
gdb --args path/to/drrun <options> -- path/to/app
\endcode
Because the executable changes from drrun to the app, the app cannot be
re-run from gdb's prompt.
On Linux, the main drawback of debugging from application start rather
than attaching is that breakpoint instructions (\c int3) inserted by
the debugger get copied into the code cache. This includes internal
debugger breakpoints automatically placed in the loader, as well as
user-defined breakpoints. For example, gdb puts a breakpoint on
__nptl_create_event, which is called by pthread_create and related
calls. See https://github.com/DynamoRIO/dynamorio/issues/490.
The debugger will handle these traps, but the user must tell it to
continue, which is an annoyance. For user breakpoints, consider using
read watchpoints on the code in question instead.
On Windows, if an application invokes OutputDebugString() while under a
debugger, DynamoRIO can end up losing control of the application.
For additional tips, check the DynamoRIO wiki page on debugging:
https://github.com/DynamoRIO/dynamorio/wiki/Debugging
\endif
****************************************************************************
****************************************************************************
*/
/* It's good to use separate C comments: we've hit some sort of doxygen
* internal buffering error before if one comment gets too long.
*/
/**
***************************************************************************
***************************************************************************
\ifnot vmsafe
\page page_standalone IA-32/AMD64/ARM/AArch64 Disassembly Library
DynamoRIO can be used as a standalone library for IA-32/AMD64/ARM/AArch64
disassembly, decoding, encoding, and general instruction manipulation,
independently of controlling a target application. When used in this way,
all aspects of DynamoRIO's API routines that apply to instrumentation or
application control are not applicable; however, the full, rich instruction
set API is enabled. For further information on the instruction set API see
the following sections of the Code Manipulation API:
- \ref sec_IR
- \ref sec_decode
\section sec_standalone Using DynamoRIO as a Standalone Library
DynamoRIO can be used as a regular third-party library for a standalone
application (instead of a client that operates on a target program). Two
options are provided: using the regular DynamoRIO shared library, or using
a special static library \p drdecode. The shared library provides not only
decoding routines but also cross-platform resources such as file
manipulation.
When using the DynamoRIO shared library, this initialization routine must
be called prior to using any API routines:
\code dr_standalone_init() \endcode
This routine returns a dummy context that can be passed to API routines.
When using \p drdecode, the special context \p GLOBAL_DCONTEXT should be
used whenever a context is required. The \p drdecode library does not
require initialization.
Neither the context returned by dr_standalone_init() nor \p
GLOBAL_DCONTEXT can be used as the drcontext for a thread running under
DynamoRIO control! It is only for standalone programs that wish to use
DynamoRIO as a library of routines for IA-32 instruction manipulation or
other purposes.
In standalone mode, the dr_set_isa_mode() routine operates globally rather
than per-thread.
Runtime options are ignored in standalone mode. Disassembly style can be
controlled via disassemble_set_syntax(). The processor to use will not be
automatically set and will be assumed to be \p VENDOR_INTEL. Use
proc_set_vendor() to set to \p VENDOR_AMD instead.
Some DynamoRIO API routines are not supported in standalone mode. These
include all event registration routines, module iteration,
dr_memory_protect(), dr_messagebox(), dr_get_current_drcontext(),
dr_get_thread_id(), tls fields, dr_thread_yield(), dr_sleep(), client
threads, suspending threads, itimers, register spilling and restoring,
dr_redirect_execution(), try/except, and code cache routines (e.g.,
dr_delete_fragment() or flush routines).
When using the \p drdecode library, no API routines other than those
involving decoding, encoding, disassembling, instruction lists,
instructions, or operands are supported. The various compute_address
routines can be used by manually filling in \p dr_mcontext_t, although far
memory references will have their segment base ignored. Other API routines
are simply not present in the static library. There is no separate set of
headers for use with \p drdecode.
When using DynamoRIO's CMake support, use the configure_DynamoRIO_decoder()
function to set up include directories and to link with \p drdecode. The
next section describes how to link with the DynamoRIO shared library.
\subsection sec_relativize Re-Relativization of Jumps and Calls
When encoding a relative jump or call to a different location than it was
decoded from while in standalone mode, a re-encode must be forced in order
to work around an issue where DynamoRIO does not re-relativize the target:
\code
instr_set_raw_bits_valid(instr, false)
\endcode
When not in standalone mode, all branches are mangled and thus this is
never an issue. This should be fixed in a future release.
\section sec_standalone_shared DynamoRIO Shared Library Issues
Since the DynamoRIO library on Windows includes or forwards
implementations of certain C library routines (see
\ref subsec_forwards "C library utilities"), standalone applications
linking to both DynamoRIO and the C library may experience linker errors
when building and floating point problems when running. To avoid these
problems, explicitly list the C runtime library on the command line:
\code /link /nodefaultlib libcmt.lib dynamorio.lib \endcode
DynamoRIO writes to stderr and stdout using raw system calls, which can
interfere with the buffering of library routines. When mixing use of
printf or fprintf with DynamoRIO output (including not only dr_printf()
and dr_fprintf() but also passing STDOUT or STDERR to routines like
disassemble()), you may need to flush between library printing and
DynamoRIO printing (e.g., using fflush(stdout)) to ensure that the library
output is visible.
The binary tracedump reader (\ref sec_ex8) is an example of use of
DynamoRIO as a standalone library.
When building an application that uses DynamoRIO as a standalone library,
follow the steps for \ref sec_build to include the header files and link
with the DynamoRIO library, but omit the linker flags requesting no
standard libraries or startup files. DynamoRIO's CMake support does this
automatically via the configure_DynamoRIO_standalone() function.
\endif
*/