initial open source import from formerly proprietary VMware sources

SVN-Revision: 1
This commit is contained in:
DynamoRIO Developers
2009-02-10 21:30:46 +00:00
commit 1d3f9ce2a5
821 changed files with 327675 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2000-2009 VMware, Inc. licensed under the terms of the BSD. All other 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.
+170
View File
@@ -0,0 +1,170 @@
# **********************************************************
# Copyright 2008 VMware, Inc. All rights reserved. -- VMware Confidential
# **********************************************************
###########################################################################
###########################################################################
###
### Top-level Makefile for building DynamoRIO
###
### Default build is a GoVirtual release package.
###
### The build directory is NOT automatically updated:
### the user should invoke as "make clean zip" (or just "make")
### in order to update an existing build directory.
###
### WARNING: do NOT include any shell-invoking values prior to
### the currently-under-cygwin test below!
.PHONY: default zip clean dynamorio-all
default: clean dynamorio-all
# Only Windows shoud have the OS env var set
ifeq ($(OS),)
MACHINE := linux
else
MACHINE := win32
endif
# build team provides these:
# OBJDIR = ignored
# BUILD_ROOT = pass to makezip.sh
# PUBLISH_DIR = pass to makezip.sh
# BUILD_NUMBER = -DUNIQUE_BUILD_NUMBER via makezip.sh
# PRODUCT_BUILD_NUMBER = -DBUILD_NUMBER via makezip.sh
# we no longer support viper
BUILD_TYPE := vmap
BUILD_ROOT := $(CURDIR)/zipbuild
# used if invoker doesn't specify
NO_BUILD_NUMBER := 16
# our BUILD_NUMBER goes into the windows x.y.z.w version and so must
# be <64K, which is vmware's PRODUCT_BUILD_NUMBER. but we're supposed
# to record the potentially-larger unique BUILD_NUMBER somewhere as well,
# requiring us to pass in two build numbers to makezip.sh.
ifneq ($(BUILD_NUMBER),)
UNIQUE_BUILD_NUMBER := $(BUILD_NUMBER)
else
UNIQUE_BUILD_NUMBER := $(NO_BUILD_NUMBER)
endif
# part-of-version build number: must be <64K
ifneq ($(PRODUCT_BUILD_NUMBER),)
VER_BUILD_NUMBER := $(PRODUCT_BUILD_NUMBER)
else
VER_BUILD_NUMBER := $(NO_BUILD_NUMBER)
endif
# keep in sync with CURRENT_API_VERSION in core/x86/instrument.h
# and _USES_DR_VERSION_ in dr_api.h (PR 250952) and compatibility
# check in core/x86/instrument.c (OLDEST_COMPATIBLE_VERSION, etc.)
# and api/docs/footer.html
# and tools/DRgui/DynamoRIO.rc
VERSION_NUMBER := 1.3.1
MAKEZIP_ARGS := $(BUILD_TYPE) $(BUILD_ROOT) $(VER_BUILD_NUMBER) \
$(UNIQUE_BUILD_NUMBER) $(VERSION_NUMBER) $(PUBLISH_DIR)
ifndef DYNAMORIO_TOOLS
DYNAMORIO_TOOLS := tools
endif
##################################################
ifeq ($(MACHINE), win32)
# To support building with either a local cygwin
# or a toolchain cygwin, we do NOT
# invoke any commands that require sh or bash to avoid cygwin
# conflicts before we've identified whether we're using local
# cygwin or need to invoke our batch file to set up
# for toolchain cygwin.
#
# The standard VMware Windows build uses a non-cygwin make.exe
# from toolchain, with the path set such that it finds
# toolchain/win32/bin/sh.exe as its shell. We do NOT want
# to execute that shell and want to use our toolchain cygwin
# instead. But, for invocations on a machine that
# has a local cygwin, we want to use that. Fundamentally
# we want to know whether there is a local cygwin install
# that we can use, not whether the make.exe is cygwin or not.
# That's difficult to check w/o invoking utility programs.
# Next best would be to identify whether any other running
# processes are cygwin, since those can conflict with toolchain
# cygwin. That's also hard to do, so we settle for checking
# whether make.exe was invoked from a cygwin shell.
# Unfortunately $OSTYPE and $MACHTYPE are not exported, so
# we instead check whether cmd's %ComSpec% is set (it is even if
# invoking make.exe from the Run box).
# Note that we can't check whether PATH uses ; or : since
# toolchain make.exe converts a Unix PATH to Windows format.
ifeq ($(ComSpec),)
LOCAL_CYGWIN := 1
else
LOCAL_CYGWIN := 0
endif
ifeq ($(LOCAL_CYGWIN),1)
# Currently under cygwin: keep using that cygwin.
# We assume all utilities are on the PATH.
zip:
$(DYNAMORIO_TOOLS)/makezip.sh $(MAKEZIP_ARGS)
clean:
$(RM) -rf $(BUILD_ROOT) $(PUBLISH_DIR)
else
# No local cygwin: set up for toolchain cygwin.
SHELL := cmd.exe
ifndef DYNAMORIO_BATCH
DYNAMORIO_BATCH := batch
endif
zip:
$(DYNAMORIO_BATCH)\makezip.bat $(MAKEZIP_ARGS)
# For some reason I can't get direct invocation of rd to
# work with toolchain make: it messes up its CreateProcess
# invocation.
clean:
-$(DYNAMORIO_BATCH)\rmtree.bat $(subst /,\,$(BUILD_ROOT))
-$(DYNAMORIO_BATCH)\rmtree.bat $(subst /,\,$(PUBLISH_DIR))
endif
##################################################
else
ifndef DYNAMORIO_MAKE
DYNAMORIO_MAKE := make
endif
# we need the x64 version of strip in order to operate on x64 libs
ARCH := x64
include $(DYNAMORIO_MAKE)/compiler.mk
# Set up for scripts like makezip.sh and for auto-generated
# api/docs/latex/Makefile to use toolchain utils.
# For scripts we could set env vars whenever make invokes a script
# TAR=$(TAR) PERL=$(PERL) ... <script>
# and then have the script explicitly invoke $TAR, but it's less work
# to set up the path (esp. for auto-gen latex/Makefile).
#
# PR 340793: this older doxygen doesn't quite match newer local
# doxygen, but it's close enough
#
PATH := $(BINUTILS)/$(BINPREFIX)-linux/bin:$(COREUTILS):$(TC_AWK):$(TC_DIFF):$(TC_GREP):$(TC_PERL):$(TC_SED):$(TC_XARGS):$(TC_DOXYGEN):$(TC_MOGRIFY):$(TC_FIG2DEV):$(TC_GS):$(TC_TETEX):$(TC_TAR):$(TC_GZIP):$(TC_ZIP):$(TC_MAKE):$(TC_FIND)
zip:
$(DYNAMORIO_TOOLS)/makezip.sh $(MAKEZIP_ARGS)
clean:
$(RM) -rf $(BUILD_ROOT) $(PUBLISH_DIR)
endif
##################################################
dynamorio-all: zip
+41
View File
@@ -0,0 +1,41 @@
Copyright (c) 2000-2009 VMware, Inc. licensed under the terms of the BSD. All other 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.
**********************************************************
DynamoRIO is a runtime code manipulation system that supports code
transformations on any part of a program, while it executes. DynamoRIO
exports an interface for building dynamic tools for a wide variety of uses:
program analysis and understanding, profiling, instrumentation,
optimization, translation, etc. Unlike many dynamic tool systems, DynamoRIO
is not limited to insertion of callouts/trampolines and allows arbitrary
modifications to application instructions via a powerful IA-32/AMD64
instruction manipulation library. DynamoRIO provides efficient,
transparent, and comprehensive manipulation of unmodified applications
running on stock operating systems (Windows or Linux) and commodity IA-32
and AMD64 hardware.
+707
View File
@@ -0,0 +1,707 @@
<!doctype html public "-//IETF//DTD HTML//EN">
<html>
<head>
<title>DynamoRIO Coding Standards</title>
</head>
<!--------------------------------------------------------------------------
Copyright (c) 2003-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.
-------------------------------------------------------------------------->
<body bgcolor="ffffff" text="000000" link="000088" vlink="006600">
<h1>DynamoRIO Coding Standards</h1>
<ul>
<li><a href="#Style">Coding Style</a></li>
<li><a href="#Content">Code Content</a></li>
</ul>
<!--------------------------------------------------------------------------->
<a name="Style">&nbsp;</a>
<table bgcolor="#6699cc" width=100% cellspacing=0 cellpadding=5 border=0>
<tr><td>&nbsp;<font size=+2>
<strong>Coding Style</strong>
</font></td></tr></table>
<!--------------------------------------------------------------------------->
<p>The overall goal is to <strong>make the source code as readable and
as self-documenting as possible</strong>. Everyone following the same
style guidelines is an important part of keeping the code consistent and
maintainable.</p>
<h3>Naming Conventions</h3>
<ol>
<li><p>Variable and function names use only lowercase letters. Multi-word
function and variable names are all lowercase with underscores delimiting
words. Do not use CamelCase for names, unless mirroring Windows-defined
data structures.
<pre>
<em>GOOD</em>: instr_get_target()
<font color=gray><em>BAD</em>: instrGetTarget()</font>
</pre>
</p></li>
<li><p>Type names are all lowercase, with underscores dividing words, and
ending in <tt>_t</tt>:
<pre>
instr_t
build_bb_t
</pre>
</p></li>
<li><p>The name of a struct in a typedef should be the type name with an
underscore prefixed:
<pre>
typedef struct _build_bb_t {
...
} build_bb_t;
</pre>
</p></li>
<li><p>Constants should be in all capital letters, with underscores dividing
words. Enum members should use a common descriptive prefix.
<pre>
static const int MAX_SIZE = 256;
enum {
DUMPCORE_DEADLOCK = 0x0004,
DUMPCORE_ASSERTION = 0x0008,
};
</pre>
</p></li>
<li><p>Preprocessor defines and macros should be in all capital letters, with
underscores dividing words.
<pre>
#ifdef WINDOWS
# define IF_WINDOWS(x) x
#else
# define IF_WINDOWS(x)
#endif
</pre>
</p></li>
<li><p>Functions that operate on a data structure should contain that
structure as a prefix. For example, all of the routines that operate on
the <tt>instr_t</tt> struct begin with <tt>instr_</tt>.
</p></li>
<li><p>Use <tt>static</tt> when possible for every function or variable
that is not needed outside of its own file.
</p></li>
</ol>
<h3>Types</h3>
<ol>
<li><p>See above for naming conventions for types.
</p></li>
<li><p>When declaring a function with no arguments, always explicitly use
the <tt>void</tt> keyword. Otherwise the compiler will not be able to
check whether you are incorrectly passing arguments to that function.
<pre>
<em>GOOD</em>: int foo(void);
<font color=gray><em>BAD</em>: int foo();</font>
</pre>
</p></li>
<li><p>Use the <tt>IN</tt>, <tt>OUT</tt>, and <tt>INOUT</tt> labels to
describe function parameters. This is a recent addition to DynamoRIO so
you will see many older functions without these labels, but use them on all
new functions.
<pre>
<em>GOOD</em>: int foo(IN int length, OUT char *buf);
<font color=gray><em>BAD</em>: int foo(int length, char *buf);</font>
</pre>
</p></li>
<li><p>Only use boolean types as conditionals. This means using explicit NULL
comparisons and result comparisons. In particular with functions like
strcmp() and memcmp(), the use of ! is counter-intuitive.
<pre>
<em>GOOD</em>: if (p == NULL) ...
<font color=gray><em>BAD</em>: if (p)</font>
<em>GOOD</em>: if (p != NULL) ...
<font color=gray><em>BAD</em>: if (!p)</font>
<em>GOOD</em>: if (strncmp(...) == 0) ...
<font color=gray><em>BAD</em>: if (!strncmp(...))</font>
</pre>
</p></li>
<li><p>It's much easier to read <tt>if (i == 0)</tt> than <tt>if (0 == i)
</tt>. The compiler, with all warnings turned on (which we have), will
warn you if you use assignment rather than equality.
<pre>
<em>GOOD</em>: if (i == 0) ...
<font color=gray><em>BAD</em>: if (0 == i)</font>
</pre>
</p></li>
<li><p>Use the <tt>TEST</tt> and related macros for testing bits.
<pre>
<em>GOOD</em>: if (TEST(BITMASK, x))
<font color=gray><em>BAD</em>: if ((x & BITMASK) != 0)</font>
</pre>
</p></li>
<li><p>Write code that is 32-bit and 64-bit aware:
<ul>
<li><p>Use int and uint for 32-bit integers. Do not use long as its size is
64-bit for Linux but 32-bit for Windows. We assume that int is a 32-bit
type.
<li><p>Use int64 and uint64 for 64-bit integers. Use <tt>INT64_FORMAT</tt>
and related macros for printing 64-bit integers.
<li><p>Use ptr_uint_t and ptr_int_t for pointer-sized integers.
<li><p>Use size_t for sizes of memory regions.
<li><p>Use reg_t for register-sized values.
<li><p>Use <tt>ASSERT_TRUNCATE</tt> macros when casting to a smaller type.
<li><p>Use <tt>PFX</tt> and other printf macros for printing pointer-sized variables.
</ul>
</p></li>
<li><p>Invalid addresses, either pointers to our data structures or
application addresses that we're manipulating, have the value NULL, not 0.
0 is only for arithmetic types.
</p></li>
<li><p><tt>const</tt> makes code easier to read and lets the compiler complain
about errors and generate better code. It is also required for the most
efficient self-protection. Use whenever possible.
</p></li>
<li><p>Place * prefixing variable names (C style), not suffixing type names
(Java style):
<pre>
<em>GOOD</em>: char *foo;
<font color=gray><em>BAD</em>: char* foo;</font>
</pre>
</p></li>
</ol>
<h3>Commenting Conventions</h3>
<ol>
<li><p>This is C, so <tt>/* */</tt> comments are preferable to <tt>//</tt>.
Put stars on each line of a multi-line comment, like this:
<pre>
/* multi-line
* comment
* with stars
*/
</pre>
Generally the trailing <tt>*/</tt> should be on its own line, but it can
optionally be on the end of the precending line.
</p></li>
<li><p>Make liberal use of comments. However, too many comments can impair
readability. Choose self-descriptive function and variable names to reduce
the number of comments needed.
</p></li>
<li><p>Do not use large, clunky function headers that simply duplicate
information in the code itself. Such headers tend to contain stale,
incorrect information, for two reasons: the code is often updated without
maintaining the header, and since the headers are a pain to type they are
often copied from other functions and not completely modified for their new
home. They also make it harder to see the code or to group related
functions, as they take up so much screen space. It is better to have
leaner, more maintainable, and more readable implementation files by using
self-descriptive function and parameter names and placing comments for
function parameters next to the parameters themselves.
<pre>
<em>GOOD</em>: /* Retrieves the name of the logfile for a particular thread.
* Returns false if no such thread exists.
*/
bool get_logfile(IN thread_id_t thread,
OUT char *fname,
IN size_t fname_len)
<font color=gray><em>BAD</em>: /*------------------------------------------------------
* Name: get_logfile
*
* Purpose:
* Retrieves the name of the logfile for a particular thread.
*
* Parameters:
* [IN] thread = which thread
* [OUT] fname = where to store the logfile name
* [IN] fname_len = the size of the fname buffer
*
* Returns:
* True if successful.
* False if no such thread exists.
*
* Side effects:
* None.
* ------------------------------------------------------
*/
bool get_logfile(thread_id_t thread, char *fname, size_t fname_len)
</font>
</pre>
</p></li>
<li><p>Use doxygen comments on all function and type declarations that are
exported as part of the API. For comments starting with <tt>/**</tt>,
leave the rest of the first line empty, unless the entire comment is a
single line. Some examples:
<pre>
DR_API
/**
* Returns the entry point of the function with the given name in the module
* with the given base. Returns NULL on failure.
* \note Currently Windows only.
*/
generic_func_t
dr_get_proc_address(IN module_handle_t lib, IN const char *name);
/**
* Data structure passed with a signal event. Contains the machine
* context at the signal interruption point and other signal
* information.
*/
typedef struct _dr_siginfo_t {
int sig; /**< The signal number. */
void *drcontext; /**< The context of the thread receiving the signal. */
dr_mcontext_t mcontext; /**< The machine state at the signal interruption point. */
siginfo_t siginfo; /**< The signal information provided by the kernel. */
} dr_siginfo_t;
</pre>
</p></li>
<li><p><strong>NEVER</strong> check in commented-out code. This is
unacceptable. If you feel strongly that you need to leave code in that is
disabled, use conditional compilation (e.g., <tt>#if
DISABLED_UNTIL_BUG_812_IS_FIXED</tt>), and explain why the code is
disabled.
</p></li>
<li><p>Sloppy comments full of misspelled words, etc. are an indication of
carelessness. We do not want carelessly written code, and we do not
want carelessly written comments.
</p></li>
<li><p>Use <tt>FIXME</tt> in comments to indicate missing features, code that
could be optimized, or anything else that may warrant re-examination later.
</p></li>
</ol>
<h3>Warnings Are Errors</h3>
<ol>
<li><p> Uninitialized variables warning (W4701 for cl): Don't initialize
variables when you don't need to, so that we can still have good warnings
about uninitialized variables in the future. Only if the compiler can't
analyze code properly is it better to err on the side of a deterministic
bug and set to 0 or {0}.
<p> Use do {} while () loops to help the compiler figure out that variables
will get initialized. The generated code on those constructs is faster and
better predicted (although optimizations should be able to transform simple
loops).
</p></li>
<li><p> For suggested use of static analysis tools: PreFAST or /analyze for
new code, refer to case 3966.
</p></li>
</ol>
<h3>Program Structure</h3>
<ol>
<li><p>Keep the line length to 90 characters or less.
</p></li>
<li><p>Use an indentation level of 4 spaces (no tabs, always expand them to
spaces when saving the file). <strong>WARNING</strong>: Emacs defaults are
not always correct here. Make sure your .emacs contains the following:
<pre>
; always expand tabs to spaces
(setq-default indent-tabs-mode 'nil)
; want "gnu" style but indent of 4:
(setq c-basic-offset 4)
(add-hook 'c-mode-hook '(lambda ()
(setq c-basic-offset 4)))
</pre>
</p></li>
<li><p>K&amp;R-style braces: opening braces at the end of the line preceding
the new code block, closing braces on their own line at the same
indentation as the line preceding the code block. Functions are an
exception -- see below.
</p></li>
<li><p>Functions should have their type on a separate line from their name.
Place the function's opening brace on a line by itself at zero
indentation.
<br><em>Example</em>:<br>
<pre>
int
foo(int x, int y)
{
return 42;
}
</pre>
</p></li>
<li><p>Put spaces after commas in parameter and argument lists
<pre>
<em>GOOD</em>: foo(x, y, z);
<font color=gray><em>BAD</em>: foo(x,y,z);</font>
</pre>
</p></li>
<li><p>Do not put spaces between a function name or a <tt>for</tt>,
<tt>if</tt>, <tt>while</tt>, <tt>do</tt>, or <tt>switch</tt> and the
following parenthesis, or before the closing parenthesis.<br>
<pre>
<em>GOOD</em>: if (x == 6)
<font color=gray><em>BAD</em>: if( x==6 )</font>
</pre>
</p></li>
<li><p>Always put the body of an if or loop on a separate line from the
line containing the keyword.
<pre>
<em>GOOD</em>: if (x == 6)
y = 5;
<font color=gray><em>BAD</em>: if (x==6) y = 5;</font>
</pre>
</p></li>
<li><p>A multi-line (not just multi-statement) body (of an if, loop, etc.)
should always be surrounded with braces (to avoid errors in later
statements arising from indentation mistakes).
</p></li>
<li><p>Statements should always begin on a new line (do not put multiple
statements on the same line).
</p></li>
<li><p>Indent nested preprocessor statements. The # character must be in
the first column, but the rest of the statement can be indented.
<br><em>Example:</em></br>
<pre>
#ifdef OUTERDEF
# ifdef INNERDEF
# define INSIDE
# endif
#else
# define OUTSIDE
#endif
</pre>
</p></li>
<li><p>To make the code easier to read, use the <tt>DODEBUG</tt>,
<tt>DOSTATS</tt>, or <tt>DOLOG</tt> macros, or the <tt>IF_WINDOWS</tt> and
related macros, rather than ifdefs, for common defines.
</p></li>
<li><p> Do not use DO_ONCE(SYSLOG_INTERNAL. Instead use two new macros:
DODEBUG_ONCE and SYSLOG_INTERNAL_*_ONCE.
</p></li>
<li><p>Use <em>make ugly</em> to examine the code for known poor coding
patterns.
</p></li>
</ol>
<h3>File Organization</h3>
<ol>
<li><p>Write OS-independent code as much as possible and keep it in the
base <tt>core/</tt> directory. If code must diverge for Windows versus
Linux, provide an OS-independent interface documented
in <tt>core/os_shared.h</tt> and implemented separately
in <tt>core/linux/</tt> and <tt>core/windows/</tt>.
</p></li>
</ol>
<!--------------------------------------------------------------------------->
<a name="Content">&nbsp;</a>
<table bgcolor="#6699cc" width=100% cellspacing=0 cellpadding=5 border=0>
<tr><td>&nbsp;<font size=+2>
<strong>Code Content</strong>
</font></td></tr></table>
<!--------------------------------------------------------------------------->
<h3>Adding New Features</h3>
<ol>
<li><p>A new feature should be added under its own preprocessor define as well
as under its own off-by-default runtime option, to facilitate incremental
development and testing. Once it is working properly, the ifdefs can be
removed. Once it is proven to be worthwhile and robust, the option can be
turned on by default.
</p></li>
<li><p>Code reviews are required for any commit, regardless of how trivial.
</p></li>
<li><p>Use assertions whenever an assumption is made. We have several types
of ASSERT macros: use the appropriate one. For any API-visible function,
use CLIENT_ASSERT to provide an understandable string to the user.
</p></li>
<li><p>Add a new statistic to <tt>core/lib/statsx.h</tt> for anything we might
want to keep track of.
</p></li>
<li><p>Be careful with locks. Make sure to follow our deadlock-avoidance
scheme when adding a new lock: add it to the list in <tt>core/utils.h</tt>.
</p></li>
</ol>
<h3>Security</h3>
<ol>
<li><p>Be security aware. Carefully watch your buffers and input validation to
avoid introducing vulnerabilities.
</p></li>
<li><p>Do not use unsafe string routines. E.g., use <tt>snprintf</tt> instead
of <tt>sprintf</tt>.
</p></li>
<li><p>Variable placement: <strong>.data is read-only!</strong>
</p></li>
<p>
For self-protection from inadvertent or malicious application activity,
DynamoRIO uses a non-standard data section layout with five separate
sections:
<ol></p></li>
<li><p><em>.rdata</em> = read-only data<br> Mark all non-written
variables as <tt>const</tt> to get them into this section.
</p></li>
<li><p><em>.data</em> = rarely-written data<br> Variables that are
written only during initialization, cleanup, or a handful of times during
execution. This section is write-protected by default and only
unprotected for small, infrequent windows of time. This is the default
location for a variable (even if in .bss, if on Windows, though not on
Linux currently due to PR 213296), so if you write to your new
default-location variable after initialization <strong>DynamoRIO will
crash</strong>! In debug builds a special self-protection message will
alert you to crashes coming from attempts to write to .data.
</p><p>If you must write to a variable after initialization,
you can either unprotect it with this pair of macros (however, see the
next item):
<pre>
SELF_UNPROTECT_DATASEC(DATASEC_RARELY_PROT);
SELF_PROTECT_DATASEC(DATASEC_RARELY_PROT);
</pre>
Or you can move it to another section, probably .fspdata, like this:
<pre>
DECLARE_FREQPROT_VAR(static vartype myvar, initial-value);
</pre>
</p>
</p><p>
Only unprotect if you write <strong>very infrequently</strong>, as in
zero times on any critical path. Keep an eye on the stats for
unprotection calls and make sure you're not affecting performance and not
opening up too many windows where the entire .data section is
unprotected.
</p><p> Do not keep pointers in a data section other than .data. If they
must be writable, use indirection and keep them on the heap.
</p><p> Think about whether non-pointers (booleans, counters) can be
exploited before throwing them into unprotected sections. Can an
overwrite of the variable in question cause us to stop protecting the
application, or to lose control of the application?
</p><p> Place all locks in .cspdata.
</p><p> Be aware that DO_ONCE introduces a window where .data is unprotected
(see PR 212510).
</p></li>
<li><p><em>.fspdata</em> = frequently-written self-protected data<br>
Variables that are written enough that we do not want to unprotect .data
every time. We place them in a separate section called .fspdata (for
"frequently self-protected data", referring to the number of times we
need to change the page protections, which is proportional to the number
of post-init writes) both for security and performance reasons. We moved
any pointers in this category into structures on the heap, enabling us to
move their base pointers into .data. Currently the heap is better
protected than our data sections due to its better randomization and its
guard pages. Try not to put new variables here as we hope to eventually
eliminate this section. Note that this is not yet protected at all: PR
212508.
</p></li>
<li><p><em>.cspdata</em> = context-switch-written self-protected data<br>
This is our section for locks, which are written so frequently that
unprotecting them is best done at each context switch. Note that this is
not yet protected at all: PR 212508.
</p></li>
<li><p><em>.nspdata</em> = not self-protected data<br> Debug-build-only
variables, statistics, or data that is not persistent across code cache
execution fall into this category of variables that we never
protect. This section is always writable.
</p></li>
</ol>
</p><p>DynamoRIO has several other features for self-protection:
<ol>
<li><p>The base of its heap is randomized. This is why we consider
writable pointers in the heap to be safer than writable pointers in a
data section.
</p></li>
<li><p>Guard pages protect both ends of every stack and heap unit to
protect against sequential overwrites.
</p></li>
<li><p>No state is kept on the DynamoRIO stack across code cache
execution: execution starts from a clean slate at the base of the stack
on every exit from the code cache.
</p></li>
<li><p>Generated code is made read-only after initialization.
</p></li>
<li><p>The options are made read-only after initialization.
Now that we have .data read-only, this is simply part of that feature.
</p></li>
<li><p>The base of the dynamorio.dll library is randomized.
</p></li>
</ol>
</p></li>
</ol>
<h3>Transparency</h3>
<p>
The DynamoRIO core must be absolutely transparent. It cannot interfere
with the application's semantics. This means that extra care must be taken
when using <strong>any</strong> operating system or shared library
resources that might interact with the application's use of those
resources. See the API documentation for more details. The following
guidelines list some common mistakes to avoid.
</p>
<ol>
<li><p>Do not introduce new user library dependencies. On Windows we only
use ntdll.dll, and there we only call routines that we are sure are
re-entrant. On Linux we're not quite there yet: we still use some C
library routines. But we're working toward libc independence, so avoid
adding any new library calls.
</p></li>
<li><p> Never call any potentially non-reentrant library routines. These
include malloc, calloc, fprintf, etc., and everything that calls these
routines, such as strdup. Usually you'll be violating the prior point if
you use these, but keep in mind that many ntdll.dll routines are
non-reentrant because they acquire locks or allocate memory. Use raw
system calls instead of library routines (yes we have hit many bugs due to
using library routines).
</p></li>
<li><p>Do not make any alertable system calls on Windows.
This includes any Wait* API routine. Use the system calls instead, which
let you specify whether it should be alertable or not.
</p></li>
<li><p> For memory allocation, use either the local heap (via
<tt>heap_alloc</tt>) or the global heap (via
<tt>global_heap_alloc</tt>). (In certain circumstances, such as inside
signal handlers, other heaps should be used.) Always de-allocate
memory. We cannot assume we will last as long as the application, since
we may be detached before the application exits.
</p></li>
<li><p> For I/O, use the interfaces exported by the OS subdirectories. Do not
use <tt>stderr</tt> or <tt>stdout</tt> -- due to <tt>FILE</tt> problems on windows we use
<tt>HANDLE</tt> on windows and hide the distinction behind the
<tt>file_t</tt> type. Use the <tt>STDERR</tt> and <tt>STDOUT</tt> macros.
</p></li>
<li><p>DO NOT USE FLOATING-POINT OPERATIONS!
DynamoRIO does not save or restore floating-point state on context
switches. You can use the routines <tt>save_fpstate</tt> and
<tt>restore_fpstate</tt> (includes mmx & sse state) around your code if
you really need floating point operations.
</p></li>
<li><p>DO NOT HOLD LOCKS ACROSS CODE CACHE EXECUTION!
Doing so violates the assumptions of our synchronization algorithms.
</p></li>
</ol>
<!--------------------------------------------------------------------------->
<table bgcolor="#6699cc" width=100% cellspacing=0 cellpadding=5 border=0>
<tr><td>&nbsp;</td></tr></table>
<!--------------------------------------------------------------------------->
</body>
</html>
+257
View File
@@ -0,0 +1,257 @@
# **********************************************************
# Copyright (c) 2007-2008 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.
# Doxyfile 1.5.1
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = "DynamoRIO API"
PROJECT_NUMBER =
OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = NO
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = YES
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
# if you add/change aliases make sure you also change the sed lines in the Makefile
ALIASES = DynamoRIO=DynamoRIO Client=Client Clients=Clients client=client clients=clients
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
BUILTIN_STL_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = YES
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
# choices: linux, VMsafe, NYI_kernel_mediated_transfer_events
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = .
FILE_PATTERNS = dr_*.h *.dox
RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH = genimages images
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
USE_HTAGS = NO
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER = header.html
HTML_FOOTER = footer.html
HTML_STYLESHEET = htmlstyle.css
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = YES
DISABLE_INDEX = YES
ENUM_VALUES_PER_LINE = 1
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = YES
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = letter
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = YES
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = YES
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = WINDOWS LINUX X64
EXPAND_AS_DEFINED = IF_X64_ELSE
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = YES
+243
View File
@@ -0,0 +1,243 @@
# **********************************************************
# 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.
.PHONY: all clean mkimages
ifndef DYNAMORIO_MAKE
DYNAMORIO_MAKE := ../../make
endif
include $(DYNAMORIO_MAKE)/compiler.mk
ifndef DYNAMORIO_HOME
DYNAMORIO_HOME := ../..
endif
ifndef DYNAMORIO_LIBUTIL
DYNAMORIO_LIBUTIL := ../../libutil
endif
ifeq ($(MACHINE), linux)
DYNAMORIO_DIR_BASE := $(DYNAMORIO_HOME)/exports/x86_$(MACHINE)_
else
DYNAMORIO_DIR_BASE := $(DYNAMORIO_HOME)/exports/x86_$(MACHINE)_
endif
# allow yes or 1 for DEBUG or INTERNAL
USE_DEBUG=$(DEBUG)
ifeq ($(DEBUG),yes)
USE_DEBUG := 1
endif
USE_INTERNAL=$(INTERNAL)
ifeq ($(INTERNAL),yes)
USE_INTERNAL := 1
endif
INTERNAL_EXISTS := $(wildcard $(DYNAMORIO_DIR_BASE)intr/dr_api.h)
RELEASE_EXISTS := $(wildcard $(DYNAMORIO_DIR_BASE)rel/dr_api.h)
DEBUG_EXISTS := $(wildcard $(DYNAMORIO_DIR_BASE)dbg/dr_api.h)
ifeq ($(USE_DEBUG),1)
RELEASE_EXISTS := ""
INTERNAL_EXISTS := ""
else
ifeq ($(USE_INTERNAL),1)
RELEASE_EXISTS := ""
DEBUG_EXISTS := ""
endif
endif
ifeq ($(RELEASE_EXISTS), $(DYNAMORIO_DIR_BASE)rel/dr_api.h)
BUILD := rel
else
ifeq ($(INTERNAL_EXISTS), $(DYNAMORIO_DIR_BASE)intr/dr_api.h)
BUILD := intr
else
ifeq ($(DEBUG_EXISTS), $(DYNAMORIO_DIR_BASE)dbg/dr_api.h)
BUILD := dbg
else
$(error API header files do not exist)
endif
endif
endif
ifeq ($(MACHINE), linux)
EXPORT_DIR := $(DYNAMORIO_DIR_BASE)$(BUILD)
else
EXPORT_DIR := $(shell $(CYGPATH) -u $(DYNAMORIO_DIR_BASE)$(BUILD))
endif
HEADERS := $(wildcard $(EXPORT_DIR)/dr_*.h)
# We need to escape EXPORT_DIR so we can pass it to sed.
# Use sed to put in the escape characters.
EXPORT_ESC := $(shell $(ECHO) "$(EXPORT_DIR)" | $(SED) 's/\./\\\./g')
EXPORT_ESC := $(shell $(ECHO) "$(EXPORT_ESC)" | $(SED) 's/\//\\\//g')
EXPORT_SED := "s/\(INPUT[ \t]*=\)/\1 $(EXPORT_ESC)/g"
# We also need to escape the path to libutil
LIBUTIL_DIR := $(DYNAMORIO_LIBUTIL)
ifeq ($(MACHINE), win32)
LIBUTIL_DIR := $(shell $(CYGPATH) -u $(DYNAMORIO_LIBUTIL))
endif
LIBUTIL_ESC := $(shell $(ECHO) "$(LIBUTIL_DIR)" | $(SED) 's/\./\\\./g')
LIBUTIL_ESC := $(shell $(ECHO) "$(LIBUTIL_ESC)" | $(SED) 's/\//\\\//g')
LIBUTIL_SED := "s/\(INPUT[ \t]*=\)/\1 $(LIBUTIL_ESC)/g"
all: $(HEADERS) mkimages Doxyfile
@$(ECHO) "** Using headers in $(EXPORT_DIR) **"
ifdef VMSAFE
@$(ECHO) "Use the macro \\DynamoRIO to allow name substitution"
# we don't do -i to allow function names and macros
$(GREP) -E -n -H "(^|[^\\])DynamoRIO" *.dox; if [ $$? == 0 ]; then false; fi
$(GREP) -E -n -i -H "(^|[^_\\-])client($$|[^_])" *.dox; if [ $$? == 0 ]; then false; fi
endif
# run doxygen and fail on warnings
$(DOXYGEN) 2>&1 | $(TEE) doxygen.out
$(GREP) -i warning doxygen.out; if [ $$? == 0 ]; then false; fi
$(RM) doxygen.out
# doxygen does not put header.html on the top-level frame so we add favicon manually
$(SED) -i 's/<title>/<link rel="shortcut icon" type="image\/x-icon" href="favicon.ico" \/>\n<title>/' html/index.html
# add our logo to treeview pane (yes there is no closing </body></html>)
$(ECHO) '<p>&nbsp;<br><img src="drlogo.png"></p>' >> html/tree.html
# workaround for doxygen bug
$(CP) html/htmlstyle.css html/doxygen.css
# get our samples in place
$(MKDIR) -p html/samples
$(CP) -a ../samples/*.c html/samples/
# not exporting custom stats for VMsafe, security api for VMAP
# FIXME: these exclusions are duplicated in tools/makezip.sh: combine somehow?
ifdef VMSAFE
# -f because of perforce file protections being carried over
$(RM) html/samples/stats.c html/samples/tracedump.c
$(CP) -a ../samples/MF_moduledb-sample.config html/samples/
$(CP) -a ../samples/VIPA_test.exe html/samples/
else
$(RM) html/samples/MF_moduledb*
ifeq ($(MACHINE), linux)
# no stats sample on linux
$(RM) html/samples/stats.c
endif
endif
$(CP) -a ../samples/Makefile html/samples/
# IE for some reason won't initially load an .ico in a web page from a server,
# though will show it via file: or after pointing straight at image from server.
# doxygen fails to copy image referenced only in footer.html
$(CP) images/favicon.png html/
pdf: all
-$(CP) images/vmware-logo-crop.png latex/vmware-logo.png
./fix-latex.pl
$(MAKE) -C latex
# note that we can have "a" vs "an" issues
# thus, going w/ a consonant-onset acronym:
# VIPER = VMsafe In-ProcEss Runtime
VMSAFE_NAME=VIPER
# Viper In-Process Agent: again, starting w/ a consonant
VMSAFE_CLIENT=VIPA
Doxyfile: API.doxy Makefile
$(SED) $(EXPORT_SED) $< > $@
$(SED) -i $(LIBUTIL_SED) $@
ifdef VMSAFE
$(SED) -i 's/\(PROJECT_NAME[ \t]*=\).*/\1 "VMsafe In-Process API"/' $@
$(SED) -i 's/\(ENABLED_SECTIONS[ \t]*=\)/\1 vmsafe/' $@
$(SED) -i 's/DynamoRIO=DynamoRIO/DynamoRIO=${VMSAFE_NAME}/' $@
$(SED) -i 's/client=client/client=${VMSAFE_CLIENT}/' $@
$(SED) -i 's/clients=clients/clients=${VMSAFE_CLIENT}s/' $@
$(SED) -i 's/Client=Client/Client=${VMSAFE_CLIENT}/' $@
$(SED) -i 's/Clients=Clients/Clients=${VMSAFE_CLIENT}s/' $@
else
$(SED) -i 's/\(ENABLED_SECTIONS[ \t]*=\)/\1 linux/' $@
endif
# "doxygen -u" seems to preserve our non-default settings, while eliminating
# warnings about deprecated options due to differing versions of doxygen
$(DOXYGEN) -u
ifndef HEADER_DIR
update_headers:
@$(ECHO) "must set HEADER_DIR variable"; false
else
update_headers:
# even w/ no extension given, my cygwin perl makes .bak files!
cd $(HEADER_DIR); \
$(PERL) -pi -e 's|\bDynamoRIO\b|${VMSAFE_NAME}|g' *.h; \
$(PERL) -pi -e 's|\bDR\b|${VMSAFE_NAME}|g' *.h; \
$(PERL) -pi -e 's|\bclient(s?)\b|${VMSAFE_CLIENT}\1|gi' *.h; \
$(RM) *.bak
endif
####################
# Figures from xfig
#
# Requires fig2dev from the transfig package and mogrify from the ImageMagick
# package to be installed.
ifdef VMSAFE
FIGXL8 := $(SED) 's|DynamoRIO|${VMSAFE_NAME}|g'
else
FIGXL8 := $(CAT)
endif
GENIMGDIR := genimages
FIGS := $(wildcard *.fig)
FIG_IMAGES := $(patsubst %.fig,$(GENIMGDIR)/%.eps,$(FIGS)) \
$(patsubst %.fig,$(GENIMGDIR)/%.png,$(FIGS))
mkimages: $(GENIMGDIR) $(FIG_IMAGES)
$(GENIMGDIR):
if ! test -d $(GENIMGDIR); then $(MKDIR) -p $(GENIMGDIR); fi
# fig2dev w/ pipe or redirect crashes sometimes on cygwin so
# we use ugly temp files
$(GENIMGDIR)/%.post.fig: %.fig
${FIGXL8} $< > $@
$(GENIMGDIR)/%.eps: $(GENIMGDIR)/%.post.fig
$(FIG2DEV) -L eps $< $@
# Because fig2dev does not perform anti-aliasing, converting directly
# to an image format can result in very poor quality lines and text.
# This problem is compounded if that image is subsequently resized
# without any anti-aliasing, such as by your web browser. The
# solution is to magnify the vector data to at least 4x and then
# generate a lossless bitmap format such as TIFF; then have a real
# image manipulator resize it to the final size (cannot make
# browser-resizable vector graphics).
# See also http://www.burningcutlery.com/derek/bargraph/
%.png: %.tiff
$(MOGRIFY) -resize 33% -format png $<
# ImageMagick 6.0.4 produces foo.png.0 while 6.3.0 creates foo-0.png
@(if test -e $*-1.png; then $(RM) $*-1.png; $(MV) $*-0.png $@; else \
$(RM) $*.png.1; $(MV) $*.png.0 $@; fi)
$(GENIMGDIR)/%.tiff: $(GENIMGDIR)/%.post.fig
$(FIG2DEV) -L tiff -m 4 $< $@
####################
clean:
$(RM) -r html latex rtf Doxyfile $(GENIMGDIR)
+978
View File
@@ -0,0 +1,978 @@
/* **********************************************************
* 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_BT Code Manipulation API
The Code Manipulation API exposes the full power of \DynamoRIO, allowing
tools to observe and modify the application's actual code stream as it
executes. Modifications are not limited to trampoline insertion and can
include arbitrary changes. We divide the API description into the
following sections:
- \ref sec_IR
- \ref sec_events_bt
- \ref sec_decode
- \ref sec_64bit
- \ref sec_IR_utils
- \ref sec_translation
- \ref bt_examples
\ifnot vmsafe - \ref sec_startstop
\endif
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_IR Instruction Representation
The primary data structures involved in instruction manipulation are
the \c instr_t, which represents a single IA-32 instruction, and the \c
instrlist_t, which is a linked list of instructions. The header files
dr_ir_instrlist.h and dr_ir_instr.h list a number of functions that
operate on these data structures, including:
- Routines to create new instructions.
- Routines to iterate over an instruction's operands.
- Routines to iterate over an \c instrlist_t.
- Routines to insert and remove an \c instr_t from an \c instrlist_t.
As we will see in the the \ref sec_events_bt section that follows, a
\client usually interacts with \c instrlist_t's in the form of \e basic \e
blocks or \e traces. A basic block is a sequence of instructions that
terminates with a control transfer operation. Traces are
frequently-executed sequences of basic blocks that \DynamoRIO forms
dynamically as the application executes, i.e., \e hot code.
Collectively, we refer to basic blocks and traces as \e fragments.
Both basic blocks and traces present a linear view of control flow.
In other words, instruction sequences have a single entrance and one
or more exits. This representation greatly simplifies analysis and is
a primary contributor to \DynamoRIO's efficiency.
\if level_of_detail
********************
\subsection sec_IR_adaptive Adaptive Level of Detail
It is costly to decode IA-32 instructions. Fortunately, \DynamoRIO is
often only interested in high-level information for a subset of
instructions, such as just the control-flow instructions. Each
instruction can be at one of five levels of detail. To simplify \clients,
\DynamoRIO only passes them instructions at Level 3 or Level 4.
Internally, \DynamoRIO uses all five levels:
\par Level 0: Raw Bundle
At Level 0, the \c instr_t data structure holds raw bytes for group of
instructions decoded only enough to determine the final instruction
boundary:
<table border=0 cellpadding=2 cellspacing=1>
<tr bgcolor="ffcc99"><td><tt>
8d 34 01 8b 46 0c 2b 46 1c 0f b7 4e 08 c1 e1 07 3b c1 0f 8d a2 0a 00 00
</tt></td></tr>
</table>
\par Level 1: Raw Individual
At Level 1, each \c instr_t holds only one instruction, but has no more
information than raw bytes:
<table border=0 cellpadding=2 cellspacing=1>
<tr><td bgcolor="ffcc99"><tt>8d 34 01</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>8b 46 0c</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>2b 46 1c</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>0f b7 4e 08</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>c1 e1 07</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>3b c1</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>0f 8d a2 0a 00 00</tt></td></tr>
</table>
\par Level 2: Opcode and Eflags
At Level 2, \c instr_t has been decoded just enough to determine opcode and
flags effects (flags are important when analyzing IA-32 code). Raw bytes
are still used for encoding. The flags effects below are only shown for
reading (R) or writing (W) the six arithmetic flags (Carry, Parity, Adjust,
Zero, Sign, and Overflow).
<table border=0 cellpadding=2 cellspacing=1>
<tr><td bgcolor="ffcc99"><tt>8d 34 01</tt></td>
<td bgcolor="ccccff"><tt>lea</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>8b 46 0c</tt></td>
<td bgcolor="ccccff"><tt>mov</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>2b 46 1c</tt></td>
<td bgcolor="ccccff"><tt>sub</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>0f b7 4e 08</tt></td>
<td bgcolor="ccccff"><tt>movzx</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>c1 e1 07</tt></td>
<td bgcolor="ccccff"><tt>shl</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>3b c1</tt></td>
<td bgcolor="ccccff"><tt>cmp</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>0f 8d a2 0a 00 00</tt></td>
<td bgcolor="ccccff"><tt>jnl</tt></td>
<td bgcolor="ccccff" align="middle"><tt>RSO</tt></td></tr>
</table>
\par Level 3: Operands
A Level 3 \c instr_t contains dynamically allocated arrays of source and
destination operands (dynamic because IA-32 is so variable) that are now
filled in. Raw bytes are still valid and are used for encoding. This
level combines high-level information with quick encoding.
<table border=0 cellpadding=2 cellspacing=1>
<tr><td bgcolor="ffcc99"><tt>8d 34 01</tt></td>
<td bgcolor="ccccff"><tt>lea</tt></td>
<td bgcolor="ccff66"><tt>(%ecx,%eax,1) => %esi</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>8b 46 0c</tt></td>
<td bgcolor="ccccff"><tt>mov</tt></td>
<td bgcolor="ccff66"><tt>0xc(%esi) => %eax</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>2b 46 1c</tt></td>
<td bgcolor="ccccff"><tt>sub</tt></td>
<td bgcolor="ccff66"><tt>0x1c(%esi) %eax => %eax</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>0f b7 4e 08</tt></td>
<td bgcolor="ccccff"><tt>movzx</tt></td>
<td bgcolor="ccff66"><tt>0x8(%esi) => %ecx</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>c1 e1 07</tt></td>
<td bgcolor="ccccff"><tt>shl</tt></td>
<td bgcolor="ccff66"><tt>$0x07 %ecx => %ecx</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>3b c1</tt></td>
<td bgcolor="ccccff"><tt>cmp</tt></td>
<td bgcolor="ccff66"><tt>%eax %ecx</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>0f 8d a2 0a 00 00</tt></td>
<td bgcolor="ccccff"><tt>jnl</tt></td>
<td bgcolor="ccff66"><tt>$0x77f52269</tt></td>
<td bgcolor="ccccff" align="middle"><tt>RSO</tt></td></tr>
</table>
\par Level 4: Modified Operands
At the highest level, \c instr_t has been modified at the operand level, or
has been created from operands, such that the raw bytes are no longer
valid. The \c instr_t must be fully encoded from its operands.
<table border=0 cellpadding=2 cellspacing=1>
<tr><td>&nbsp;</td>
<td bgcolor="ccccff"><tt>lea</tt></td>
<td bgcolor="ccff66"><tt>(%ecx,%eax,1) => \e %edi</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td>&nbsp;</td>
<td bgcolor="ccccff"><tt>mov</tt></td>
<td bgcolor="ccff66"><tt>0xc(\e %edi) => %eax</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td>&nbsp;</td>
<td bgcolor="ccccff"><tt>sub</tt></td>
<td bgcolor="ccff66"><tt>0x1c(\e %edi) %eax => %eax</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td>&nbsp;</td>
<td bgcolor="ccccff"><tt>movzx</tt></td>
<td bgcolor="ccff66"><tt>0x8(\e %edi) => %ecx</tt></td>
<td bgcolor="ccccff" align="middle"><tt>-</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>c1 e1 07</tt></td>
<td bgcolor="ccccff"><tt>shl</tt></td>
<td bgcolor="ccff66"><tt>$0x07 %ecx => %ecx</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>3b c1</tt></td>
<td bgcolor="ccccff"><tt>cmp</tt></td>
<td bgcolor="ccff66"><tt>%eax %ecx</tt></td>
<td bgcolor="ccccff" align="middle"><tt>WCPAZSO</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;</td><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>0f 8d a2 0a 00 00</tt></td>
<td bgcolor="ccccff"><tt>jnl</tt></td>
<td bgcolor="ccff66"><tt>$0x77f52269</tt></td>
<td bgcolor="ccccff" align="middle"><tt>RSO</tt></td></tr>
</table>
\par Basic Block Example
As an example of using different levels of detail, a basic block in
\DynamoRIO is represented using a Level 0 \c instr_t for all non-control-flow
instructions, and a Level 3 \c instr_t for the block-ending control-flow
instruction:
<table border=0 cellpadding=2 cellspacing=1>
<tr bgcolor="ffcc99"><td colspan=4><tt>
8d 34 01 8b 46 0c 2b 46 1c 0f b7 4e 08 c1 e1 07 3b c1
</tt></td></tr>
<tr align="middle" bgcolor="ffffff"><td>&nbsp;|</td></tr>
<tr><td bgcolor="ffcc99"><tt>0f 8d a2 0a 00 00</tt></td>
<td bgcolor="ccccff"><tt>jnl&nbsp;&nbsp;&nbsp;&nbsp;</tt></td>
<td bgcolor="ccff66"><tt>$0x77f52269&nbsp;&nbsp;&nbsp;&nbsp;</tt></td>
<td bgcolor="ccccff" align="middle"><tt>&nbsp;&nbsp;RSO&nbsp;&nbsp;</tt></td></tr>
</table>
However, when a \client registers for the basic block event, \DynamoRIO
passes an \c instrlist_t of all Level 3 \c instr_t's, for simplicity.
\endif
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_events_bt Events
The core of a \client's interaction with \DynamoRIO occurs through <em>
event hooks</em>: the \client registers its own callback routine (or \e
hook) for each event it is interested in. \DynamoRIO calls the
\client's event hooks at appropriate times, giving the \client access to
key actions during execution of the application. The \ref sec_events
section describes events common to the entire \DynamoRIO API. Here we
discuss the events specific to the Code Manipulation portion.
\DynamoRIO provides two events related to fragment creation: one for
basic blocks and one for traces (see dr_register_bb_event() and
dr_register_trace_event()). Through these fragment-creation hooks,
the \client has the ability to inspect and modify any piece of code
that \DynamoRIO emits before it executes. Using the basic block hook,
a \client sees \e all application code. The trace-creation hook
provides a mechanism for \clients to instrument only
frequently-executed code paths.
The code manipulation API is highly efficient in that fragment
creation comprises a small part of \DynamoRIO's overhead. A \client's
analysis time rarely impacts execution time; only instrumentation code
inserted by the \client affects efficiency.
******************** \subsection sec_events_bb Basic Block Creation
Through the basic block creation event, registered via
dr_register_bb_event(), the \client has the ability to inspect and transform
any piece of code prior to its execution. The \client's hook receives
three parameters:
\code
dr_emit_flags_t new_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
\endcode
- \c drcontext is a pointer to the input program's machine context.
\Clients should not inspect or modify the context; it is provided as
an opaque pointer (i.e., <tt>void *</tt>) to be passed to API
routines that require access to this internal data.
- \c tag is a unique identifier for the basic block fragment.
- \c bb is a pointer to the list of instructions that comprise the
basic block. \Clients can examine, manipulate, or completely
replace the instructions in the list.
- \c for_trace indicates whether this callback is for a new basic block
(false) or for adding a basic block to a trace being created (true).
The \client has the opportunity to either include the same modifications
made to the standalone basic block, or to use different modifications,
for the code in the trace.
- \c translating indicates whether this callback is for basic block
creation (false) or is for address translation (true). This is further
explained in \ref sec_translation.
The return value of the basic block callback should generally be
DR_EMIT_DEFAULT; however, time-varying instrumentation or complex code
transformations may need to return DR_EMIT_STORE_TRANSLATIONS. See \ref
sec_translation for further details.
To iterate over instructions in an \c instrlist_t, use the \ref
instrlist_first(), \ref instrlist_last(), and \ref instr_get_next()
routines. For example:
\code
dr_emit_flags_t new_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating)
{
instr_t *instr, *next;
for (instr = instrlist_first(bb);
instr != instrlist_last(bb);
instr = next) {
next = instr_get_next(instr);
/* do some processing on instr */
}
return DR_EMIT_DEFAULT;
}
\endcode
********************
\subsection sec_Meta Meta-Instructions
\DynamoRIO performs some processing on the basic block after the
\client has finished with it, primarily modifying branches to ensure
that \DynamoRIO retains control after execution. It is important that
the \client mark any control-flow instructions it does not want treated
as application instructions as \e meta-instructions. Doing so informs
\DynamoRIO that these instructions should execute natively rather than
being trapped and redirected to new basic block fragments.
Meta instructions are marked using these API routines:
\code
instr_set_ok_to_mangle()
instrlist_meta_preinsert()
instrlist_meta_postinsert()
instrlist_meta_append()
\endcode
Through meta instructions, a \client can add its own internal control flow
or make a call to a native routine that will not be brought into the code
cache by \DynamoRIO. However, such native calls need to be careful to
remain transparent (see \ref sec_clean_call).
While \DynamoRIO attempts to support arbitrary code transformations, its
internal operation requires that we impose the following limitations:
- If there is more than one non-meta branch, only the last can be
conditional.
- A non-meta conditional branch must be the final instruction in the
block.
- There can only be one indirect branch (call, jump, or return) in
a basic block, and it must be the final non-meta branch in the block.
- The exit control-flow of a block ending in a system call cannot be
changed.
********************
\subsection sec_events_trace Trace Creation
\DynamoRIO provides access to traces primarily through the trace-creation
event, registered via dr_register_trace_event(). It is important to note
that \clients are not
required to employ the trace-creation event to ensure full instrumentation.
Rather, it is sufficient to perform all code modification using the basic
block event. Any basic blocks that \DynamoRIO chooses to place in a trace
will contain all \client modifications (unless the \client behaves
differently in the basic block hook when its \c for_trace parameter is
true). The trace-creation event provides
a mechanism for \clients to instrument \e hot code separately.
The parameters to the trace-creation event hook are nearly identical
to those of the basic block hook:
\code
dr_emit_flags_t new_trace(void *drcontext, void *tag, instrlist_t *trace,
bool translating);
\endcode
- \c drcontext is a pointer to the input program's machine context.
\Clients should not inspect or modify the context; it is provided as
an opaque pointer (i.e., <tt>void *</tt>) to be passed to API
routines that require access to this internal data.
- \c tag is a unique identifier for the trace fragment.
- \c bb is a pointer to the list of instructions that comprise the
trace. \Clients can examine, manipulate, or completely replace the
instructions in the list.
- \c translating indicates whether this callback is for trace creation
(false) or is for address translation (true). This is further explained
in \ref sec_translation.
The return value of the trace callback should generally be DR_EMIT_DEFAULT;
however, time-varying instrumentation or complex code transformations may
need to return DR_EMIT_STORE_TRANSLATIONS. See \ref sec_translation for
further details.
\DynamoRIO calls the \client-supplied event hook each time a trace is
created, just before the trace is emitted into the code cache.
Additionally, as each constituent basic block is added to the trace,
\DynamoRIO calls the basic block creation hook with the \p for_trace
parameter set to true. In order to preserve basic block instrumentation
inside of traces, a \client need only act identically with respect to the
\p for_trace parameter; it can ignore the trace event if its goal is to
place instrumentation on all code.
The constituent basic blocks will be stitched together prior to insertion
in the code cache: conditional branches will be realigned so that their
fall-through target remains on the trace, and inlined indirect branches
will be preceded by a comparison against the on-trace target.
If the basic block callback behaves differently based on the \p for_trace
parameter, different instrumentation will exist in the trace as opposed to
the standalone basic block. If the basic block corresponds to the
application code at the start of the trace (i.e., it is a trace head), the
trace will shadow the basic block and the trace will be executed
preferentially. If #dr_delete_fragment() is called, it will also delete
the trace first and may leave the basic block in place. The flush routines
(#dr_flush_region(), #dr_delay_flush_region(), #dr_unlink_flush_region()),
however, will delete traces and basic blocks alike.
********************
\subsection sec_events_translation State Restoration
If a \client is only adding instrumentation (meta instructions) that do not
reference application memory, and is not reordering or removing application
instructions, then it need not register for this event. If, however, a
\client is modifying application code or adding instructions that could
fault, the \client must be capable of restoring the original context.
\DynamoRIO calls the state restoration event, registered via
dr_register_restore_state_event(), whenever it needs to translate a code
cache context to an original application context:
\code
void restore_state(void *drcontext, void *tag, dr_mcontext_t *mcontext,
bool restore_memory, bool app_code_consistent)
\endcode
See \ref sec_translation for further details.
********************
\subsection sec_events_del Basic Block and Trace Deletion
\DynamoRIO can also provide notification of fragment deletion via
dr_register_delete_event(). The signature for this event callback is:
\code
void fragment_deleted(void *drcontext, void *tag);
\endcode
\DynamoRIO calls this event hook each time it deletes a fragment from
the code cache. Such information may be needed if the \client
maintains its own data structures about emitted fragment code that
must be consistent across fragment deletions.
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_decode Decoding and Encoding
As discussed in \ref sec_events_bb and \ref sec_events_trace, a
\client's primary interface to code inspection and manipulation is via
the basic block and trace hooks. However, \DynamoRIO also
exports a rich set of functions and data structures to decode and
encode instructions directly. The following subsections overview this
functionality.
********************
\subsection sec_Decoding Decoding
\DynamoRIO provides several routines for decoding and disassembling
IA-32 instructions. The most common method for decoding is the
decode() routine, which populates an \c instr_t data structure with all
information about the instruction (e.g., opcode and operand
information).
When decoding instructions, \clients must explicitly manage the \c
instr_t data structure. For example, the following code shows how to
use the instr_init(), instr_reset(), and instr_free() routines to
decode a sequence of arbritrary instructions:
\code
instr_t instr;
instr_init(&instr);
do {
instr_reset(dcontext, &instr);
pc = decode(dcontext, pc, &instr);
/* check for invalid instr */
if (pc == NULL)
break;
if (instr_writes_memory(&instr)) {
/* do some processing */
}
} while (pc < stop_pc);
instr_free(dcontext, &instr);
\endcode
The 64-bit build of \DynamoRIO is capable of decoding 32-bit code as well.
See \ref sec_64bit for full details.
\subsection sec_InstrGen Instruction Generation
\Clients can construct instructions from scratch in two different ways:
-# Using the INSTR_CREATE_opcode macros that fill
in implicit operands automatically:
\code
instr_t *instr = INSTR_CREATE_dec(dcontext, opnd_create_reg(REG_EDX));
\endcode
-# Specifying the opcode and all operands (including implicit
operands):
\code
instr_t *instr = instr_create(dcontext);
instr_set_opcode(instr, OP_dec);
instr_set_num_opnds(dcontext, instr, 1, 1);
instr_set_dst(instr, 0, opnd_create_reg(REG_EDX));
instr_set_src(instr, 0, opnd_create_reg(REG_EDX));
\endcode
When using the second method, the exact order of operands and their
sizes must match the templates that \DynamoRIO uses. The
INSTR_CREATE_ macros in dr_ir_macros.h should be consulted to
determine the order.
\subsection sec_Encoding Encoding
\DynamoRIO's encoding routines take an instruction or list of
instructions and encode them into the corresponding IA-32 bit pattern:
\code instr_encode(), instrlist_encode() \endcode
When encoding a control transfer instruction that targets another
instruction, two encoding passes are performed: one to find the offset
of the target instruction, and the other to link the control transfer
to the proper target offset.
The 64-bit build of \DynamoRIO is capable of encoding 32-bit code as well.
See \ref sec_64bit for details.
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_64bit 64-bit Versus 32-bit Instructions
The 64-bit build of \DynamoRIO uses 64-bit decoding and encoding by
default, while the 32-bit build uses 32-bit. The 64-bit build is also
capable of decoding and encoding 32-bit instructions. Each thread has a
current mode that is used to determine how to interpret instructions while
decoding, whose default matches the \DynamoRIO build. The set_x86_mode()
routine changes the current mode, while get_x86_mode() queries the current
mode.
Each instruction contains a flag indicating whether it should be encoded in
32-bit or 64-bit mode. When an instruction is created or decoded, the
instruction's flag is set to the thread's current mode. It can be queried
with instr_get_x86_mode() and changed with instr_set_x86_mode().
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_IR_utils Utilities
In addition to instruction decoding and encoding, the API includes
several higher-level routines to facilitate code instrumentation.
These include the following:
- Routines to insert clean calls to \client-defined functions.
- Routines to instrument control-flow instructions.
- Routines to spill registers to \DynamoRIO's thread-private spill
slots.
- Routines to quickly save and restore arithmetic flags,
floating-point state, and MMX/SSE registers.
The following subsections describe these routines in more detail.
********************
\subsection sec_clean_call Clean Calls
To make it easy to insert code into the application instruction
stream, \DynamoRIO provides a <em>clean call</em> mechanism, which
allows insertion of a transparent call to a \client routine.
The dr_insert_clean_call() routine takes care of switching to a clean
stack, setting up arguments to a call and making the call, optionally
preserving floating point state, and preserving application state across
the entire sequence.
Here is an example of inserting a clean call to the \c at_mbr function:
\code
if (instr_is_mbr(instr)) {
app_pc address = instr_get_app_pc(instr);
uint opcode = instr_get_opcode(instr);
instr_t *nxt = instr_get_next(instr);
dr_insert_clean_call(drcontext, ilist, nxt, (void *) at_mbr,
false/*don't need to save fp state*/,
2 /* 2 parameters */,
/* opcode is 1st parameter */
OPND_CREATE_INT32(opcode),
/* address is 2nd parameter */
OPND_CREATE_INTPTR(address));
}
\endcode
Through this mechanism, \clients can write analysis code in C or other
high-level languages and easily insert calls to these routines in the
instruction stream. Note, however, that saving and restoring machine state
is an expensive operation. Performance-critical operations should be
inlined for maximum efficiency.
The stack that \DynamoRIO switches to for clean calls is relatively small:
only 20KB by default. \Clients can increase the size of the stack with the
\ref op_stack_size "-stack_size" runtime option. \Clients should also
avoid keeping persistent state on the clean call stack, as it is wiped
clean at the start of each clean call.
The saved interrupted application state can be accessed using
dr_get_mcontext() and modified using dr_set_mcontext().
For performance reasons, clean calls do not save or restore floating point,
MMX, or SSE state by default. If the clean callee is using floating point
or multimedia operations, it should request that the clean call mechanism
preserve the floating point state through the appropriate parameter to
dr_insert_clean_call(). See also
\ref sec_trans_floating_point "Floating Point State, MMX, and SSE Transparency".
If more detailed control over the call sequence is desired, it can be
broken down into its constituent pieces:
- dr_prepare_for_call()
- Optionally, dr_insert_save_fpstate()
- dr_insert_call()
- Optionally, dr_insert_restore_fpstate()
- dr_cleanup_after_call()
********************
\subsection sec_state State Preservation
To facilitate code transformations, \DynamoRIO makes available its register
spill slots and other state preservation functionality. It exports API
routines for saving and restoring registers to and from thread-local spill
slots:
\code dr_save_reg(), dr_restore_reg(), and dr_reg_spill_slot_opnd() \endcode
The values stored in these spill slots remain valid until the next non-meta
(i.e. application) instruction and as such can be accessed from clean calls using:
\code dr_read_saved_reg(), dr_write_saved_reg() \endcode
For longer term persistance \DynamoRIO also provides a generic dedicated
thread-local storage field for use by \clients, making it easy to write
thread-aware \clients. From C code, use:
\code dr_get_tls_field(), dr_set_tls_field() \endcode
To access this thread-local field from the code cache, use the following
routines to generate the necessary code:
\code dr_insert_read_tls_field(), dr_insert_write_tls_field() \endcode
Since saving and restoring the \c eflags register is required for almost
all code transformations, and since it is difficult to do so efficiently,
we export routines that use our efficient method of arithmetic flag
preservation:
\code dr_save_arith_flags(), dr_restore_arith_flags() \endcode
As just discussed in \ref sec_clean_call, we also export convenience
routines for making \e clean (i.e., transparent) native calls from the code
cache, as well as floating point and multimedia state preservation.
********************
\subsection sec_branch_instru Branch Instrumentation
\DynamoRIO provides explicit support for instrumenting call
instructions, direct (or unconditional) branches, indirect (or
multi-way) branches, and conditional branches. These convenience
routines insert clean calls to \client-provided methods, passing as
arguments the instruction pc and target pc of each control transfer,
along with taken or not taken information for conditional branches:
\code
dr_insert_call_instrumentation()
dr_insert_ubr_instrumentation()
dr_insert_mbr_instrumentation()
dr_insert_cbr_instrumentation()
\endcode
********************
\subsection sec_adaptive Dynamic Instrumentation
\DynamoRIO allows a \client to dynamically adjust its instrumentation
by providing routines to flush all cached fragments corresponding to
an application code region:
\code
dr_flush_region()
dr_unlink_flush_region()
dr_delay_flush_region()
\endcode
In order to directly modify the instrumentation on a particular fragment
(as opposed to replacing instrumentation on all copies of fragments
corresponding to particular application code), \DynamoRIO also supports
directly replacing an existing fragment with a new \c instrlist_t:
\code
dr_replace_fragment()
\endcode
However, this routine is only supported when running with the \ref
op_thread_priv "-thread_private" runtime option, and it replaces the
fragment for the current thread only. A \client can call this routine even
while inside the to-be-replaced fragment (e.g., in a clean call from inside
the fragment). In this scenario, the old fragment is executed to
completion and the new code is inserted before the next execution.
For example usage, see the \client sample \ref sec_ex3.
********************
\subsection sec_custom_traces Custom Traces
\DynamoRIO combines frequently executed sequences of basic blocks into
<em>traces</em>. It uses a simple profiling scheme based on <em>trace
heads</em>, which are the targets of backward branches or exits from
existing traces. Execution counters are kept for each trace head. Once a
head crosses a threshold, the next sequence of basic blocks that are
executed becomes a new trace.
\DynamoRIO allows a \client to build custom traces by marking its own trace
heads (<em>in addition</em> to \DynamoRIO's normal trace heads) and
deciding when to end traces. If a \client registers for the following
event, \DynamoRIO will call its hook before extending a trace (with tag \c
trace_tag) with a new basic block (with tag \c next_tag):
\code
int query_end_trace(void *drcontext, void *trace_tag, void *next_tag);
\endcode
The \client hook returns one of these values:
- CUSTOM_TRACE_DR_DECIDES = use standard termination criteria
- CUSTOM_TRACE_END_NOW = end trace now
- CUSTOM_TRACE_CONTINUE = do not end trace
If using standard termination criteria, \DynamoRIO ends the trace if it
reaches a trace head or another trace (or certain corner-case basic blocks
that cannot be part of a trace).
The \client can also mark any basic block as a trace head with
\code dr_mark_trace_head() \endcode
For example usage, see the callee-inlining \client sample \ref sec_ex5.
\if custom_stubs
********************
\subsection sec_custom_stubs Custom Exit Stubs
An exit cti can be given an instrlist_t to be prepended to the standard
exit stub. There are set and get methods for this custom exit stub code:
\code
void instr_set_exit_stub_code(instr_t *instr, instrlist_t *stub);
instrlist_t *instr_exit_stub_code(instr_t *instr);
\endcode
When a fragment is re-decoded, e.g. when being appended to a trace or when
re-decoded using dr_decode_fragment, the custom stubs are regenerated and
added to the owning exit cti's.
\endif
\if prefixes
********************
\subsection sec_prefixes Prefixes
Some code manipulations need to store a target address in a register and
then jump there, but need the register to be restored as well. \DynamoRIO
provides a single-instruction prefix that is placed on all fragments (basic
blocks as well as traces) that restores ecx. It is on traces for internal
\DynamoRIO use. To have it added to basic blocks as well, call this routine
during initialization:
\code
void dr_add_prefixes_to_basic_blocks();
\endcode
To have a cti target the prefix rather than the normal entry, use these set
and get routines:
\code
bool instr_branch_targets_prefix(instr_t *instr);
void instr_branch_set_prefix_target(instr_t *instr, bool val);
\endcode
\endif
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_translation State Translation
To support transparent fault handling, \DynamoRIO must translate a fault in
the code cache into a fault at the corresponding application address.
\DynamoRIO must also be able to translate when a suspended thread is
examined by the application or by \DynamoRIO itself for internal
synchronization purposes.
If a \client is only adding observational instrumentation (i.e., \ref
sec_Meta) (which should not fault) and is not modifying, reordering, or
removing application instructions, these details can be ignored. In that
case the \client's basic block and trace callbacks should return
#DR_EMIT_DEFAULT in addition to being deterministic and idempotent (i.e.,
\DynamoRIO should be able to repeatedly call the callback and receive back
the same resulting instruction list, with no net state changes to the
\client).
If a \client is performing modifications, then in order for \DynamoRIO to
properly translate a code cache address the \client must use
instr_set_translation() (chainable via INSTR_XL8()) in the basic block and
trace creation callbacks to set the corresponding application address for
each modified instruction and each added non-meta instruction. The
translation value is the application address that should be presented to
the application as the faulting address, or the application address that
should be restarted after a suspend.
There are two methods for using the translated addresses:
-# Return #DR_EMIT_STORE_TRANSLATIONS from the basic block creation
callback. DR will then store the translation addresses and use
the stored information on a fault. The basic block callback for
\p tag will not be called with \p translating set to true. Note
that unless #DR_EMIT_STORE_TRANSLATIONS is also returned for \p
for_trace calls (or #DR_EMIT_STORE_TRANSLATIONS is returned in
the trace callback), each constituent block comprising the trace
will need to be re-created with both \p for_trace and \p
translating set to true. Storing translations uses additional
memory that can be significant: up to 20% in some cases, as it
prevents DR from using its simple data structures and forces it
to fall back to its complex, corner-case design. This is why DR
does not store all translations by default.
-# Return #DR_EMIT_DEFAULT from the basic block or trace creation callback.
\DynamoRIO will then call the callback again during fault translation
with \p translating set to true. All modifications to the instruction
list that were performed on the creation callback must be repeated on
the translating callback. This option is only posible when basic block
modifications are deterministic and idempotent, but it saves memory.
Naturally, global state changes triggered by block creation should be
wrapped in checks for \p translating being false. Even in this case,
instr_set_translation() should be called for non-meta instructions even
when \p translating is false, as \DynamoRIO may decide to store the
translations at creation time for reasons of its own.
Furthermore, if the \client's modifications change any part of the machine
state besides the program counter, the \client should use
dr_register_restore_state_event() (see \ref sec_events_translation) to
restore the registers to their original application values.
For meta instructions that do not reference application memory (i.e., they
should not fault), leave the translation field as NULL. A NULL value
instructs \DynamoRIO to use the subsequent non-meta instruction's
translation as the application address, and to fail when translating the
full state. Since the full state will only be needed when relocating a
thread (as stated, there will not be a fault here), failure indicates that
this is not a valid relocation point, and \DynamoRIO's thread
synchronization scheme will use another spot. If the translation field is
set to a non-NULL value, the \client should be willing to also restore the
rest of the machine state at that point (restore spilled registers, etc.)
via #dr_register_restore_state_event(). This is necessary for meta
instructions that reference application memory. \DynamoRIO takes care of
such potentially-faulting instructions added by its own API routines
(#dr_insert_clean_call() arguments that reference application data,
#dr_insert_mbr_instrumentation()'s read of application indirect branch
data, etc.)
\ifnot vmsafe
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_startstop Running a Subset of an Application
An alternative to running an entire application under \DynamoRIO control is to
use the Application Interface to specify a portion of the application to
run. This interface consists of the following routines:
\code
dr_app_setup()
dr_app_start()
dr_app_stop()
dr_app_cleanup()
dr_app_take_over()
\endcode
When building an executable that links with the \DynamoRIO library, you may
need to explicitly link with the C library prior to the \DynamoRIO library:
\code /link /nodefaultlib libcmt.lib dynamorio.lib \endcode
\endif
***************************************************************************
****************************************************************************
****************************************************************************
*/
+40
View File
@@ -0,0 +1,40 @@
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
0 32 #000000
0 33 #eeeeee
0 34 #ffffaa
0 35 #0000ff
0 36 #6666ff
0 37 #aaaaff
0 38 #00ffff
0 39 #77ff00
0 40 #aaffaa
0 41 #dd00ff
0 42 #ffaaaa
0 43 #cccccc
0 44 #aaaaaa
2 2 0 1 0 33 54 0 20 0.000 0 0 -1 0 0 5
600 750 3600 750 3600 0 600 0 600 750
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
2100 750 2100 1200
2 2 0 1 0 34 51 0 20 0.000 0 0 -1 0 0 5
2775 1950 3600 1950 3600 1200 2775 1200 2775 1950
2 2 0 1 0 42 51 0 20 0.000 0 0 -1 0 0 5
600 1950 2775 1950 2775 1200 600 1200 600 1950
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
2100 1950 2100 2400
2 2 0 1 0 44 54 0 20 0.000 0 0 -1 0 0 5
600 3150 3600 3150 3600 2400 600 2400 600 3150
4 0 0 50 0 0 12 0.0000 4 180 1425 1425 375 running application\001
4 0 0 50 0 0 12 0.0000 4 180 945 1275 1575 DynamoRIO\001
4 0 0 50 0 0 12 0.0000 4 135 420 3000 1575 client\001
4 0 0 50 0 0 12 0.0000 4 180 1380 1425 2850 hardware platform\001
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/perl
# **********************************************************
# Copyright (c) 2007 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.
# Script to post-process the latex auto-generated with doxygen. It
# looks like doxygen is pretty rigid about where it puts chapters and
# sections; we'll clean up the latex ourselves before generating the
# pdf. Our approach is to try to replicate the structure of the html
# output.
$html_dir = "./html";
$latex_dir = "./latex";
$html_file = "$html_dir/tree.html";
$latex_file = "$latex_dir/refman.tex";
$latex_style = "$latex_dir/doxygen.sty";
#
# Read the first part of the current latex file, up until the first
# \chapter declaration. That portion will remain the same.
#
$latex = "";
open (IN, $latex_file) || die "ERROR: can't open $latex_file\n";
while (<IN>) {
last if ($_ =~ /^\\chapter/);
if (/Generated by Doxygen/) {
$latex .= "{\\small VMware Proprietary and Confidential}\\\\\n";
# eat the next two lines
$_ = <IN>; # vspace line
$_ = <IN>;
die "ERROR: unexpected line" unless (/^{\\small/);
} else {
$latex .= $_;
}
}
close (IN);
open (OUT, ">$latex_file") || die "ERROR: can't overwrite $latex_file\n";
print OUT $latex;
#
# Now parse the html file and match its layout.
#
open (IN, $html_file) || die "ERROR: can't open $html_file\n";
$level = -1;
while (<IN>) {
if ($_ =~ /<p>.*href=\"(.+)\.html\".*>(.*)<\/a><\/p>/) {
if (-e "$latex_dir/$1.tex") {
if ($level == 1) {
print OUT "\\chapter{$2}\n";
}
print OUT "\\input{$1}\n";
}
}
elsif ($_ =~ /<div/) {
$level++;
}
elsif ($_ =~ /<\/div/) {
$level--;
}
}
print OUT "\\printindex\n\\end{document}\n";
close (IN);
close (OUT);
# now process the style file
$latex = "";
open (IN, $latex_style) || die "ERROR: can't open $latex_style\n";
while (<IN>) {
# put in our logo and statement in the footers
if (/^\\rfoot/) {
$latex .= "\\rfoot[\\fancyplain{}{\\bfseries\\scriptsize \\raisebox{1ex}{VMware Proprietary and Confidential\\ \\ \\ } \\includegraphics[width=13ex]{vmware-logo} }]{}\n";
} elsif (/^\\lfoot/) {
$latex .= "\\lfoot[]{\\fancyplain{}{\\bfseries\\scriptsize \\includegraphics[width=13ex]{vmware-logo} \\raisebox{1ex}{\\ \\ \\ VMware Proprietary and Confidential} }}\n";
} else {
$latex .= $_;
}
}
close (IN);
open (OUT, ">$latex_style") || die "ERROR: can't overwrite $latex_style\n";
print OUT $latex;
close (OUT);
+103
View File
@@ -0,0 +1,103 @@
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
0 32 #000000
0 33 #dfdfdf
0 34 #ffffae
0 35 #0000ff
0 36 #6165ff
0 37 #aeaaff
0 38 #00ffff
0 39 #71ff00
0 40 #aeffae
0 41 #df00ff
0 42 #ffaaae
0 43 #cfcfcf
0 44 #aeaaae
0 45 #efefef
2 1 1 1 0 7 52 0 -1 4.000 1 0 -1 1 0 2
1 0 1.00 60.00 120.00
675 1275 675 450
2 1 0 1 0 7 52 0 -1 0.000 0 0 -1 1 0 3
1 1 1.00 60.00 120.00
675 3450 675 1275 1725 1275
2 1 0 1 0 7 52 0 -1 0.000 0 0 -1 1 0 3
1 1 1.00 60.00 120.00
825 3450 825 1425 1725 1425
2 1 1 1 0 7 52 0 -1 4.000 1 0 -1 1 0 2
1 0 1.00 60.00 120.00
825 1425 1875 450
2 1 1 1 0 7 52 0 -1 4.000 1 0 -1 1 0 2
1 0 1.00 60.00 120.00
975 1575 3075 450
2 1 0 1 0 7 52 0 -1 0.000 0 0 -1 1 0 3
1 1 1.00 60.00 120.00
975 3450 975 1575 1725 1575
2 1 0 1 0 7 52 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 60.00 120.00
1050 450 2100 1200
2 1 0 1 0 7 52 0 -1 0.000 1 0 -1 0 1 2
1 1 1.00 60.00 120.00
2250 1200 2250 450
2 1 0 1 0 7 52 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 60.00 120.00
3450 450 2400 1200
2 2 0 1 0 45 54 0 20 0.000 0 0 -1 0 0 5
300 450 4200 450 4200 0 300 0 300 450
2 1 0 1 0 7 52 0 -1 0.000 0 0 -1 0 0 2
2925 0 2925 450
2 1 0 1 0 7 52 0 -1 0.000 0 0 -1 0 0 2
1575 0 1575 450
2 2 0 1 0 43 54 0 20 0.000 0 0 -1 0 0 5
4200 3900 300 3900 300 3450 4200 3450 4200 3900
2 2 0 1 0 44 54 0 20 0.000 0 0 -1 0 0 5
4200 4350 300 4350 300 3900 4200 3900 4200 4350
2 1 0 1 0 7 52 0 -1 0.000 1 0 -1 0 1 2
1 1 1.00 60.00 120.00
3150 1350 2775 1350
2 1 0 1 0 42 52 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 60.00 120.00
3150 1500 2775 1500
2 1 0 1 0 42 52 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 60.00 120.00
2175 1650 2175 2250
2 1 0 1 0 42 52 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 60.00 120.00
2325 2250 2325 1650
2 1 0 1 0 42 52 0 -1 0.000 0 0 -1 1 0 4
1 1 1.00 60.00 120.00
1725 2550 1425 2550 1425 2400 1725 2400
2 2 0 1 0 37 54 0 20 0.000 0 0 -1 0 0 5
1725 2700 2775 2700 2775 2250 1725 2250 1725 2700
2 2 0 1 0 40 54 0 20 0.000 0 0 -1 0 0 5
3150 1650 4200 1650 4200 1200 3150 1200 3150 1650
2 2 0 1 0 34 54 0 20 0.000 0 0 -1 0 0 5
1725 1650 2775 1650 2775 1200 1725 1200 1725 1650
2 2 2 1 0 33 54 0 20 3.000 0 0 -1 0 0 5
1725 1800 4200 1800 4200 2100 1725 2100 1725 1800
2 2 0 1 0 42 56 0 20 0.000 0 0 -1 0 0 5
75 975 4425 975 4425 2925 75 2925 75 975
2 1 0 1 0 42 52 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 60.00 120.00
2175 2700 2175 3450
2 1 0 1 0 42 52 0 -1 0.000 0 0 -1 1 0 2
1 1 1.00 60.00 120.00
2325 3450 2325 2700
4 0 0 50 0 0 12 0.0000 4 180 1965 1275 300 multi-threaded application\001
4 0 0 50 0 0 12 0.0000 4 180 1305 1650 3750 operating system\001
4 0 0 50 0 0 12 0.0000 4 135 705 1950 4200 hardware\001
4 0 0 50 0 0 12 0.0000 4 180 645 1950 1500 dispatch\001
4 0 0 50 0 0 12 0.0000 4 135 855 3300 1425 basic block\001
4 0 0 50 0 0 12 0.0000 4 135 510 3375 1575 builder\001
4 0 0 50 0 0 12 0.0000 4 135 855 1875 2550 code cache\001
4 0 0 50 0 0 12 0.0000 4 135 1125 2475 2025 context switch\001
4 0 0 56 0 2 14 0.0000 4 195 1200 3075 2550 DynamoRIO\001
4 0 0 50 0 0 12 0.0000 4 180 960 2475 3225 system calls\001
4 0 0 50 0 0 12 1.5708 4 135 1215 375 2550 kernel-mediated\001
4 0 0 50 0 0 12 1.5708 4 135 1260 525 2550 control transfers\001
+112
View File
@@ -0,0 +1,112 @@
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
0 32 #000000
0 33 #dddddd
0 34 #ffffaa
0 35 #0000ff
0 36 #6666ff
0 37 #aaaaff
0 38 #00ffff
0 39 #77ff00
0 40 #aaffaa
0 41 #dd00ff
0 42 #ffaaaa
0 43 #cccccc
0 44 #aaaaaa
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
3750 750 3750 450
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
4050 450 4050 750
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
5250 450 5250 750
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
4950 750 4950 450
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
1950 2250 4350 2250
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 4
1 1 1.00 60.00 90.00
7050 2850 7050 3225 3150 3225 3150 2850
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 4
1 1 1.00 60.00 90.00
1200 2850 1200 3075 750 3075 750 2850
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 4
1 1 1.00 60.00 90.00
5400 2850 5400 3075 4950 3075 4950 2850
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 3
1 1 1.00 60.00 90.00
3000 975 1575 975 1575 2100
2 1 0 1 0 7 52 0 -1 4.000 1 0 -1 1 0 4
1 1 1.00 60.00 90.00
4575 2850 4575 3075 3825 3075 3825 2850
2 1 0 1 0 7 52 0 -1 4.000 1 0 -1 1 0 4
1 1 1.00 60.00 90.00
6450 2850 6450 3075 5700 3075 5700 2850
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
4050 2625 4350 2625
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
1950 2625 2250 2625
2 1 0 1 0 7 51 0 -1 4.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
5925 2625 6225 2625
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
5475 1200 5475 2100
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 3
1 1 1.00 60.00 90.00
1875 450 1875 825 3000 825
2 2 0 1 0 34 51 0 20 0.000 0 0 -1 0 0 5
3000 1200 5775 1200 5775 750 3000 750 3000 1200
2 2 0 1 0 37 54 0 20 0.000 0 0 -1 0 0 5
0 2850 0 2100 1950 2100 1950 2850 0 2850
2 2 0 1 0 42 54 0 20 0.000 0 0 -1 0 0 5
4050 2850 2250 2850 2250 2400 4050 2400 4050 2850
2 2 0 1 0 37 54 0 20 0.000 0 0 -1 0 0 5
4350 2850 4350 2100 5925 2100 5925 2850 4350 2850
2 2 0 1 0 42 54 0 20 0.000 0 0 -1 0 0 5
6225 2850 7800 2850 7800 2400 6225 2400 6225 2850
2 2 0 1 0 40 54 0 20 0.000 0 0 -1 0 0 5
2850 450 4500 450 4500 0 2850 0 2850 450
2 2 0 1 0 40 54 0 20 0.000 0 0 -1 0 0 5
6075 0 4800 0 4800 450 6075 450 6075 0
2 2 0 0 7 33 54 0 20 0.000 0 0 -1 0 0 5
0 1800 7800 1800 7800 1500 0 1500 0 1800
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 3
1 1 1.00 60.00 90.00
1875 2100 1875 1125 3000 1125
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
3150 2400 3150 1200
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
5625 2100 5625 1200
2 1 0 1 0 7 52 0 -1 4.000 1 0 -1 1 0 4
1 1 1.00 60.00 90.00
2475 2850 2475 3075 1725 3075 1725 2850
4 0 0 50 0 0 12 0.0000 4 135 1875 75 2400 BASIC BLOCK CACHE\001
4 0 0 50 0 0 12 0.0000 4 135 1245 300 2550 non-control-flow\001
4 0 0 50 0 0 12 0.0000 4 135 900 525 2700 instructions\001
4 0 0 50 0 0 12 0.0000 4 135 1275 4500 2400 TRACE CACHE\001
4 0 0 50 0 0 12 0.0000 4 135 1245 4500 2550 non-control-flow\001
4 0 0 50 0 0 12 0.0000 4 135 900 4725 2700 instructions\001
4 0 0 50 0 0 12 0.0000 4 135 570 1575 375 START\001
4 0 0 50 0 0 12 0.0000 4 135 1410 3000 278 basic block builder\001
4 0 0 50 0 0 12 0.0000 4 180 645 4050 1012 dispatch\001
4 0 0 50 0 0 12 0.0000 4 135 1050 4950 278 trace selector\001
4 0 0 50 0 0 12 0.0000 4 135 1125 3750 1725 context switch\001
4 0 0 50 0 0 12 0.0000 4 180 1665 2325 2677 indirect branch lookup\001
4 0 0 50 0 0 12 0.0000 4 135 1125 6480 2602 indirect branch\001
4 0 0 50 0 0 12 0.0000 4 180 1155 6495 2767 stays on trace?\001
+5
View File
@@ -0,0 +1,5 @@
<hr size="1"><address style="text-align: center;"><small>
<img border=0 src="favicon.png"> &nbsp; $projectname version 1.3.1 --- $datetime
&nbsp; <img border=0 src="favicon.png">
</body>
</html>
+7
View File
@@ -0,0 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<title>$title</title>
<link href="$relpath$doxygen.css" rel="stylesheet" type="text/css">
<link href="$relpath$tabs.css" rel="stylesheet" type="text/css">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
</head><body>
+359
View File
@@ -0,0 +1,359 @@
BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
font-family: Geneva, Arial, Helvetica, sans-serif;
}
BODY,TD {
font-size: 90%;
}
H1 {
text-align: center;
font-size: 160%;
}
H2 {
font-size: 130%;
}
H3 {
font-size: 110%;
}
CAPTION { font-weight: bold }
DIV.qindex {
width: 100%;
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
padding: 2px;
line-height: 140%;
}
DIV.nav {
width: 100%;
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
padding: 2px;
line-height: 140%;
}
DIV.navtab {
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
margin-right: 15px;
padding: 2px;
}
TD.navtab {
font-size: 70%;
}
A.qindex {
text-decoration: none;
font-weight: bold;
color: #1A419D;
}
A.qindex:visited {
text-decoration: none;
font-weight: bold;
color: #1A419D
}
A.qindex:hover {
text-decoration: none;
background-color: #ddddff;
}
A.qindexHL {
text-decoration: none;
font-weight: bold;
background-color: #6666cc;
color: #ffffff;
border: 1px double #9295C2;
}
A.qindexHL:hover {
text-decoration: none;
background-color: #6666cc;
color: #ffffff;
}
A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff }
A.el { text-decoration: none; font-weight: bold }
A.elRef { font-weight: bold }
A.code:link { text-decoration: none; font-weight: normal; color: #0000FF}
A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF}
A.codeRef:link { font-weight: normal; color: #0000FF}
A.codeRef:visited { font-weight: normal; color: #0000FF}
A:hover { text-decoration: none; background-color: #f2f2ff }
DL.el { margin-left: -1cm }
.fragment {
font-family: monospace, fixed;
font-size: 95%;
}
PRE.fragment {
border: 1px solid #CCCCCC;
background-color: #f5f5f5;
margin-top: 4px;
margin-bottom: 4px;
margin-left: 2px;
margin-right: 8px;
padding-left: 6px;
padding-right: 6px;
padding-top: 4px;
padding-bottom: 4px;
}
DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px }
DIV.groupHeader {
margin-left: 16px;
margin-top: 12px;
margin-bottom: 6px;
font-weight: bold;
}
DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% }
BODY {
background: white;
color: black;
margin-right: 20px;
margin-left: 20px;
}
TD.indexkey {
background-color: #e8eef2;
font-weight: bold;
padding-right : 10px;
padding-top : 2px;
padding-left : 10px;
padding-bottom : 2px;
margin-left : 0px;
margin-right : 0px;
margin-top : 2px;
margin-bottom : 2px;
border: 1px solid #CCCCCC;
}
TD.indexvalue {
background-color: #e8eef2;
font-style: italic;
padding-right : 10px;
padding-top : 2px;
padding-left : 10px;
padding-bottom : 2px;
margin-left : 0px;
margin-right : 0px;
margin-top : 2px;
margin-bottom : 2px;
border: 1px solid #CCCCCC;
}
TR.memlist {
background-color: #f0f0f0;
}
P.formulaDsp { text-align: center; }
IMG.formulaDsp { }
IMG.formulaInl { vertical-align: middle; }
SPAN.keyword { color: #008000 }
SPAN.keywordtype { color: #604020 }
SPAN.keywordflow { color: #e08000 }
SPAN.comment { color: #800000 }
SPAN.preprocessor { color: #806020 }
SPAN.stringliteral { color: #002080 }
SPAN.charliteral { color: #008080 }
.mdescLeft {
padding: 0px 8px 4px 8px;
font-size: 80%;
font-style: italic;
background-color: #FAFAFA;
border-top: 1px none #E0E0E0;
border-right: 1px none #E0E0E0;
border-bottom: 1px none #E0E0E0;
border-left: 1px none #E0E0E0;
margin: 0px;
}
.mdescRight {
padding: 0px 8px 4px 8px;
font-size: 80%;
font-style: italic;
background-color: #FAFAFA;
border-top: 1px none #E0E0E0;
border-right: 1px none #E0E0E0;
border-bottom: 1px none #E0E0E0;
border-left: 1px none #E0E0E0;
margin: 0px;
}
.memItemLeft {
padding: 1px 0px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: solid;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-size: 80%;
}
.memItemRight {
padding: 1px 8px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: solid;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-size: 80%;
}
.memTemplItemLeft {
padding: 1px 0px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: none;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-size: 80%;
}
.memTemplItemRight {
padding: 1px 8px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: none;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-size: 80%;
}
.memTemplParams {
padding: 1px 0px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: solid;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
color: #606060;
background-color: #FAFAFA;
font-size: 80%;
}
.search { color: #003399;
font-weight: bold;
}
FORM.search {
margin-bottom: 0px;
margin-top: 0px;
}
INPUT.search { font-size: 75%;
color: #000080;
font-weight: normal;
background-color: #e8eef2;
}
TD.tiny { font-size: 75%;
}
a {
color: #1A41A8;
}
a:visited {
color: #2A3798;
}
.dirtab { padding: 4px;
border-collapse: collapse;
border: 1px solid #84b0c7;
}
TH.dirtab { background: #e8eef2;
font-weight: bold;
}
HR { height: 1px;
border: none;
border-top: 1px solid black;
}
/* Style for detailed member documentation */
.memtemplate {
font-size: 80%;
color: #606060;
font-weight: normal;
margin-left: 3px;
}
.memnav {
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
margin-right: 15px;
padding: 2px;
}
.memitem {
padding: 4px;
background-color: #eef3f5;
border-width: 1px;
border-style: solid;
border-color: #dedeee;
-moz-border-radius: 8px 8px 8px 8px;
}
.memname {
white-space: nowrap;
font-weight: bold;
}
.memdoc{
padding-left: 10px;
}
.memproto {
background-color: #d5e1e8;
width: 100%;
border-width: 1px;
border-style: solid;
border-color: #84b0c7;
font-weight: bold;
-moz-border-radius: 8px 8px 8px 8px;
}
.paramkey {
text-align: right;
}
.paramtype {
white-space: nowrap;
}
.paramname {
color: #602020;
font-style: italic;
white-space: nowrap;
}
/* End Styling for detailed member documentation */
/* for the tree view */
.ftvtree {
font-family: sans-serif;
margin:0.5em;
}
.directory { font-size: 9pt; font-weight: bold; }
.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; }
.directory > h3 { margin-top: 0; }
.directory p { margin: 0px; white-space: nowrap; }
.directory div { display: none; margin: 0px; }
.directory img { vertical-align: -30%; }
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

+39
View File
@@ -0,0 +1,39 @@
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
0 32 #000000
0 33 #eeeeee
0 34 #ffffaa
0 35 #0000ff
0 36 #6666ff
0 37 #aaaaff
0 38 #00ffff
0 39 #77ff00
0 40 #aaffaa
0 41 #dd00ff
0 42 #ffaaaa
0 43 #cccccc
0 44 #aaaaaa
2 2 0 1 0 42 51 0 20 0.000 0 0 -1 0 0 5
600 1950 3600 1950 3600 1200 600 1200 600 1950
2 2 0 1 0 44 54 0 20 0.000 0 0 -1 0 0 5
600 3150 3600 3150 3600 2400 600 2400 600 3150
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
2100 750 2100 1200
2 1 0 1 0 7 50 0 -1 0.000 1 0 -1 1 0 2
1 1 1.00 60.00 90.00
2100 1950 2100 2400
2 2 0 1 0 33 54 0 20 0.000 0 0 -1 0 0 5
600 750 3600 750 3600 0 600 0 600 750
4 0 0 50 0 0 12 0.0000 4 180 1425 1425 375 running application\001
4 0 0 50 0 0 12 0.0000 4 180 1380 1425 2775 hardware platform\001
4 0 0 50 0 0 12 0.0000 4 180 2790 750 1650 observe/manipulate every instruction\001
4 0 0 50 0 0 12 0.0000 4 180 1890 1125 1800 in the running application\001
4 0 0 50 0 0 12 0.0000 4 180 1950 1125 1425 runtime code manipulator:\001
+1250
View File
File diff suppressed because it is too large Load Diff
+69
View File
@@ -0,0 +1,69 @@
/* **********************************************************
* Copyright (c) 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 page_license License
Copyright (c) 2000-2009 VMware, Inc. licensed under the terms of the BSD. All other 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.
*/
+165
View File
@@ -0,0 +1,165 @@
/* **********************************************************
* Copyright (c) 2007-2008 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
\page API_security Memory Firewall API
The Memory Firewall API provides an interface for using and
customizing the award-winning Memory Firewall software originally
developed by Determina, Inc. Memory Firewall is a security technique
that leverages the \DynamoRIO runtime code manipulation system
to control what code is allowed to execute ("Restricted Code Origins"
or RCO) and how said code can be reached ("Restricted Control
Transfers" or RCT). The former provides protection against code
injection attacks while the latter provides protection against code
reuse attacks. Together these types of attacks account for most
critical exploits seen in the wild.
The Memory Firewall API comes with a built in set of policies and
exemptions based off of a simplified version of those used in
Determina's VPS product. These policies and exemptions are not
configurable and should be suitable for most applications. Some
applications or modules may use code constructs that violate these
policies and in these cases a \client can be used to exempt these
violations. The \client is also given control over the remediation
taken when a violation occurs. Most standard windows services
(other than winlogon.exe: see \ref limits_winlogon "Limitations") and
applications shouldn't receive violations in
and of themselves. However, poorly written 3rd party plugins (such as
printer drivers in the spoolsv.exe service and plugins to explorer.exe
and Internet Explorer) can be a source of violations. Third party
software that is injected into all processes (such as certain
anti-virus and anti-cheating products) can also be a source of
violations.
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_MF_events Events
The security violation event occurs when a violation of the built in
policies is detected. The \client registers a callback routine (or
hook) to receive notification of this event (see
dr_register_security_event()). The hook routine receives seven
parameters that describe the violation and give control over the
remediation actions taken :
\code
void security_violation(void *drcontext, void *source_tag,
app_pc source_pc, app_pc target_pc,
dr_security_violation_type_t violation,
dr_mcontext_t *mcontext,
dr_security_violation_action_t *action);
\endcode
- \c drcontext is a pointer to the input program's binary translation
context. It is critical for correct program execution that the
input program's context remains intact. Thus, the user is not expected
to inspect or modify the context and it is passed as an opaque pointer
(i.e., <tt>void *</tt>).
- \c source_tag is the unique tag of the fragment of code in the
code cache that was the source of the violations. Each fragment of
code within \DynamoRIO's code cache is identified by a unique \e
tag which is the application starting address of that block of
code.
- \c source_pc is the address of the source instruction for the violation.
- \c target_pc is the address of the target instruction for the violation.
- \c violation is a value from the \c dr_security_violation_type_t enum in
dr_events.h that describes the type of violation that occurred
including whether the violation is from the RCO or RCT policies.
See the enum for a fuller description of the violation types.
- \c mcontext is the application's context at the time of the
violation. This is an IN/OUT parameter to allow the application's
state to be changed as part of the remediation.
- \c action is an IN/OUT parameter that selects the remediation action
to take. The remediations are drawn from the \c
dr_security_violation_action_t enum in dr_events.h and include such
actions as continuing as if no violation occurred, throwing an
exception at the target, etc. See the enum for a fuller
description of possible remediations.
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_MF_utils Utilities
The Memory Firewall API also includes the ability to generate a
forensics report when a violation is received that includes detailed
information about the source and target addresses, as well as general
information on the process and machine as a whole. The forensics
report is generated in an xml block described by
dr_forensics-1.0.dtd.
\code
void dr_write_forensics_report(void *dcontext, (file_t) file,
dr_security_violation_type_t violation,
dr_security_violation_action_t action,
const char *violation_name);
\endcode
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_MF_examples Examples
An example Memory Firewall \client implementation is provided at <a
href="samples/MF_moduledb.c">samples/MF_moduledb.c</a>. See \ref
sec_mf_samples for a description.
\endif
****************************************************************************
****************************************************************************
*/
+101
View File
@@ -0,0 +1,101 @@
/* **********************************************************
* Copyright (c) 2007-2008 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
\page API_probe Probe API
The Probe API provides an interface that enables a \client to insert
instructions at any arbitrary point in the executable instructions of a
process. This allows for monitoring and changing program behavior. The usage
model for the Probe API is described below.
In dr_init(), a \client should call dr_register_probes() to register (with
\DynamoRIO) all the points in the current proces at which it would like to
insert a probe. A probe insertion point may be a raw virtual address, an
executable library name and an exported address or an executable library name
and offset. For each probe insertion point the \client should provide
a callback function. If a probe or its callback function is invalid, the
registration will faill for that probe (see dr_register_probes() for details).
After successful registration, \DynamoRIO will invoke a probe's callback
function using an alternate stack whenever that probe's insertion point
executes. With the callback, \DynamoRIO passes a pointer argument of type \ref
dr_mcontext_t (the process's register context at that point of execution).
Within the callback function, the \client can perform its monitoring and
control operations using a subset of \DynamoRIO's API routines (e.g., functions
to collect information about the process, communicate with external processes,
etc.). See \ref sec_utils and \ref sec_comm.
When a callback function completes, it returns a code to indicate its
status and to request that \DynamoRIO perform certain actions on its
behalf. Example actions include: sending messages to an event log,
killing the current thread or process, raising an exception, or
changing control flow. These capabilities enable a callback function to have
more influence over the process's control flow. Once the callback function
exits and \DynamoRIO has finished the requested actions, the process continues
execution.
\Clients can determine the status of each probe by calling
dr_get_probe_status() at any time during process execution. \Clients can also
add, remove or update probes at any time during process execution via
subsequent calls to dr_register_probes(). A new list of probes completely
replaces the existing probes. That is, existing probes not specified in the
new list are removed from the process.
The flexibility of doing probe registration at any time during execution means
that probe registration is not a synchronous operation. In other words, probes
may not yet be registered when dr_register_probes() returns. After an update,
the \client should use dr_get_probe_status() to ascertain the status of the
requested probe registrations.
Probe updates can be used by the \client as part of an internally or an
externally triggered event. An internal event is triggered by the \client
itself, based on analysis of process behavior for example. Here the \client
might decide to change callback functions to another one or remove a probe or
add a new one. An externally triggered event is caused by the Guest Agent via
dr_nudge_process(). The Guest Agent might have downloaded new versions of some
callback functions, have obtained data regarding new probes, etc. It notifies
the \client which may choose use the new callbacks or probes using
dr_register_probes().
At process exit all probes are removed automatically. Probes are removed
automatically at a few other scenarios too (see dr_register_probes()) for
details.
\endif
****************************************************************************
****************************************************************************
*/
+546
View File
@@ -0,0 +1,546 @@
/* **********************************************************
* Copyright (c) 2008-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 release_notes Release Notes for Version 1.3.1
This section is divided into the following subsections:
- \ref sec_package
\ifnot vmsafe
- \ref sec_changes
\endif
- \ref sec_limits
\ifnot vmsafe
- \ref sec_future
\endif
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_package Distribution Contents
The following are part of the \DynamoRIO release distribution:
\if profiling
FIXME PR 225255: profile library too
\endif
- Four different \DynamoRIO libraries: debug and release for each of
32-bit and 64-bit.
The debug library enables assertion messages to more easily diagnose
API usage errors.
- The \DynamoRIO deployment library and command-line utility
\c drdeploy.exe, for configuring applications to execute under
\DynamoRIO control. \if linux Windows package only. \endif
- A utility \c drinject.exe to launch applications under \DynamoRIO
control. \if linux Windows package only. \endif
- A utility \c drview.exe for viewing which 32-bit or WOW64 processes
are running under \DynamoRIO control. Note that the tool does
not yet support showing the status of 64-bit applications.
\if linux Windows package only. \endif
\if linux
- The \c drdeploy script for configuring and running applications under
\DynamoRIO on Linux (Linux package only).
\endif
- Header files for the \DynamoRIO APIs.
- This documentation.
- \ref API_samples "Sample \clients".
\ifnot vmsafe
- A graphical statistics viewer, usable with the \DynamoRIO debug
library to see internal statistics as well as custom statistics defined
by a \client (see \ref sec_ex7). \if linux Windows package only. \endif
\endif
\ifnot vmsafe
- A binary tracedump reader, which also functions as a sample
\client using \DynamoRIO as a standalone library (see \ref
sec_standalone).
\endif
\ifnot vmsafe
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_changes Changes Since Prior Releases
We have re-numbered the \DynamoRIO versions as follows:
- 1.0.0 = 0.9.6 build 9600
- 1.1.0 = 0.9.6 build 9601
- 1.2.0 = 0.9.6 build 9602
The current version is 1.3.1 and is backward compatible with the 0.9.6
releases. 1.3.1 is identical to 1.3.0 but is under a BSD license (see \ref
page_license).
The changes between version 1.3.0 and version 1.2.0 (0.9.6 9602) are:
- Version numbering shift to 1.x.y instead of 0.9.6 960x
- New system call pre, post, and filter events, and new system call
parameter and result access, along with a feature to chain system calls:
- dr_register_pre_syscall_event()
- dr_register_post_syscall_event()
- dr_register_filter_syscall_event()
- dr_syscall_get_param()
- dr_syscall_set_param()
- dr_syscall_set_sysnum()
- dr_syscall_get_result()
- dr_syscall_set_result()
- dr_syscall_invoke_another()
- dr_is_wow64()
- New signal event for Linux
- dr_register_signal_event()
- New option \ref op_pause "-pause_on_error", and error messages to
stdout by default for release builds, to improve Linux debugging
- New routines for memory allocation and memory manipulation:
- dr_nonheap_alloc()
- dr_nonheap_free()
- dr_memory_protect()
- New option \ref op_syntax_intel "-syntax_intel" for Intel-style disassembly
- New option \ref op_sysenter "-sysenter_is_int80"
- The parameter to an application's system call (normally kept in the eax
register) can now be freely changed in basic blocks on all platforms
- Added support for 64-bit -thread_private
- Added corner-case undocumented IA-32 opcode support
- Fixed bug running multi-threaded 64-bit Linux apps
- Fixed bugs in 64-bit Linux signal handling
- Fixed bug running -thread_private debug build
- Fixed bug running 32-bit apps on 64-bit Linux on AMD processors
- Fixed bug where OS_OPEN_APPEND overwrote instead of appending on Windows
The changes between the 0.9.6 release builds 9602 and 9601 are:
- Performance improvements for both the base \DynamoRIO system and for
\client instrumentation when running on Pentium M, Core, and Core 2
processors.
- 64-bit bug fixes
- Added several convenience routines:
- get_register_name()
- reg_to_pointer_sized()
- reg_is_gpr()
- reg_is_segment()
- reg_32_to_8()
- Disassembly now expands immed sizes to match operands
- Fixed bug in instr_is_nop()
The changes between the 0.9.6 release builds 9601 and 9600 are:
- The Windows registry key used is now "VMware, Inc." instead of "VMware"
- Added large file support (see #DR_FILE_ALLOW_LARGE)
- Added support for decoding from a copy of code: decode_from_copy() and
disassemble_from_copy().
- Changed the default options to favor performance, and added the
\ref op_memory "-opt_memory" runtime option to prioritize memory instead.
Release 0.9.6 is \b not backward compatible with prior releases 0.9.1-0.9.5.
The major changes between the 0.9.6 and 0.9.5 releases include 64-bit
support, multiple \clients, state translation, trace contents, and Linux
module events and fast system calls:
- 64-bit applications and \clients are now supported. This changed
several function signatures:
- instr_encode()
- decode_next_pc()
- decode_sizeof()
- decode_eflags_usage()
- instr_init()
- The binary trace dump format changed.
.
Several new functions were added:
- set_x86_mode()
- get_x86_mode()
- instr_set_x86_mode()
- instr_get_x86_mode()
- opnd_create_rel_addr()
- opnd_create_far_rel_addr()
- opnd_is_rel_addr()
- opnd_is_near_rel_addr()
- opnd_is_far_rel_addr()
- instr_has_rel_addr_reference()
- instr_get_rel_addr_target()
- instr_get_rel_addr_dst_idx()
- instr_get_rel_addr_src_idx()
- instr_shrink_to_32_bits()
- opnd_shrink_to_32_bits()
- reg_32_to_64()
- reg_64_to_32()
- reg_is_extended()
- reg_parameter_num()
.
To build a 64-bit \client, set the \p X86_64 preprocessor define before
including the \DynamoRIO header files, and link with the 64-bit build of
\DynamoRIO (for a 32-bit \client, set \p X86_32).
- Multiple \clients are now supported. This changed the signatures of
dr_init(), dr_get_options(), and dr_get_client_path(). It also changed
how \clients are deployed and nudged, and how events are unregistered:
explicit unregistration routines are now used.
- State translation in the presence of \clients is now fully supported.
This changed the signature for the basic block and trace event callbacks
(see dr_register_bb_event() and dr_register_trace_event()), added a
new event dr_register_restore_state_event(), and added new functions
instr_set_translation(), instr_set_meta_no_translation(), and INSTR_XL8().
- The trace callback (#dr_register_trace_event()) now presents original
application code to the \client, rather than code that has already
been modified for execution in the code cache. The \client also has
flexibility in which instrumentation is included from constituent
basic blocks added to a trace (the \p for_trace parameter: see
#dr_register_bb_event()).
- Fast system calls (syscall and sysenter) are now supported on Linux.
- Module load/unload events and module iteration are now supported on Linux.
- System calls for 32-bit applications on 64-bit kernels are no longer
hidden by vsyscall; related functions were removed:
instr_is_lol64_syscall(), instr_is_32on64_syscall().
- Due to both 64-bit support and full WOW64 (32-bit applications on 64-bit
Windows) support, xmm registers were added to dr_mcontext_t, and a
new function dr_mcontext_xmm_fields_valid() was added.
- Far instr-type operands are now supported: opnd_create_far_instr(),
opnd_is_near_instr(), opnd_is_far_instr().
- Miscellaneous new functions were added:
- instr_convert_short_meta_jmp_to_long()
- instr_reads_from_reg()
- LOCK()
- OPND_CREATE_INT_32OR8()
- OPND_CREATE_INT_16OR8()
- instrlist_meta_append()
- dr_using_all_private_caches()
- The type of nudge arguments was changed from (void *) to uint64.
- The signature of dr_lookup_module() changed. It no longer has an
IMAGE_SECTION_HEADER out argument. See dr_lookup_module_section()
for that functionality.
- The disassemble-from-address routines now return NULL when pointed at
invalid instructions (matching the decode routines).
- The routines to access \DynamoRIO tls slots from the cache were changed.
dr_insert_write_temp_tls was eliminated in favor of a generalized #dr_save_reg
with more flexibility on which slot can be used. #dr_save_arith_flags was
similarly generalized. Slots are now guaranteed to remain valid until the
next non-meta instruction allowing access to saved registers during clean
calls via #dr_read_saved_reg and #dr_write_saved_reg. #dr_insert_mbr_instrumentation
also now requires caller to specify the spill slot to be clobbered
which must be less than dr_max_opnd_accessible_spill_slot().
The major changes between the 0.9.5 and 0.9.4 releases are:
- The basic block hook (\ref sec_events_bb) passes completely unmodified
application code to the \client (no mangling or elision).
- The old \client hook exports have been replaced with an explicit event
registration model.
- Instruction representation simplification: the \client only sees fully
decoded instructions.
- Easier-to-use clean calls (see #dr_insert_clean_call).
- Library support (-wrap on linux, ntdll on windows: see \ref sec_extlibs
and \ref sec_utils).
- Some features have been removed (these are easily implemented by a
\client): there is no more edge-counting profile build, no more
custom exit stubs, and no more prefixes.
- Infrastructure improvements:
- Thread-shared caches (can still request thread-private: \ref
op_thread_priv "-thread_private option"). Note that there are
some subtle changes stemming from using thread-shared: in particular,
note that the context passed to the deletion event may be NULL
(see #dr_register_delete_event).
- Direct access to TLS slots (#dr_save_reg, dr_insert_write_temp_tls,
#dr_insert_write_tls_field).
- Module events (#dr_register_module_load_event),
module iteration (#dr_module_iterator_start, #dr_lookup_module, etc.),
and memory querying (#dr_query_memory, #dr_virtual_query).
- The full API is now documented in html and pdf for easy browsing.
- Numerous type and routine name changes.
\endif
***************************************************************************
\if future
FIXME not done yet
- see \clients/mit_release/using.html: what's included, etc.
- DRcontrol: specify target app and runtime options (TODO: case 10647:
external vs internal ops)
- GUI: just stats viewer, or control too?
- DRview
- native_exec (TODO: specify on module load; TODO: case 10846 eliding problems)
- multiple \clients (TODO: multiple non-mutating, one mutating RIO \client;
multiple probe \clients w/ chaining; one prog shep \client?)
- detach (TODO: ask each \client to clean up)
- updating: load new library
Options for communication in and out of the process are discussed in \ref
sec_comm.
\endif
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_limits Limitations
\subsection sec_limit_clients \Client Limitations
The most important limitation on a \client is that it remain transparent.
This is described fully in \ref transparency.
Here we summarize the key points to remain transparent:
- The \client should be a self-contained library with linkage to nothing
other than \DynamoRIO libraries, unless those other libraries are
statically linked and have all of their own resource usage made transparent
(see \ref sec_extlibs). Linkage to other shared libraries is likely to
result in using the libraries used by the process being controlled, thereby
leading to unpredictable re-entrancy problems.
- Currently communication API provided by \DynamoRIO is limited to file
I/O. The \client should only use this and not any system libraries
directly to avoid non-deterministic and unpredictable re-entrancy problems.
This is because the process can be in the middle of using them. If a
\client has to avail of more system services, it can include its own system
call entry functions, statically link against these or request that these
be added to \DynamoRIO. Non system resource related functionality like
string manipulation, etc. can be statically linked to a \client or by
defining users' own routines.
\if vmsafe
- The security agent on the security monitor VM has no direct
relationship with \DynamoRIO. However, the VMsafe solution provider
can architect their own communication channel between the security
agent on the security monitor VM and the \client by using an agent on
the \client's VM as an intermediary.
\anchor limits_winlogon
- There is a known false positive in the anti-piracy DRM code in the
Windows Genuine Advantage component of winlogon.exe. This code
performs deliberate obfuscation and violations of standard coding
behavior.
\endif
\if vmsafe
- The \client can run in only one mode at a time, which cannot be changed during the
execution of the process. Mode change can be done only on a subsequent
application restart.
- The \client should call only the API corresponding to the mode it was started
in. Mixing API from different modes can lead to unspecified results and is
not supported.
- Probe API allows only one registration of probes, which must occur in
dr_init().
- Probes can be specified only with library names and offsets from the base
of the library in memory (\ref DR_PROBE_ADDR_LIB_OFFS).
- When a probe callback finishes execution it can't request \DynamoRIO to
perform any actions like logging, control flow changes, etc.
- Probe locations can't include system call wrappers in ntdll.dll, i.e.,
ntdll!Nt* routines can't be probe locations.
\endif
\subsection sec_limit_platforms Platform Limitations
- \DynamoRIO currently supports the following NT-based 32-bit
Windows systems : NT (all service packs), 2000 (all service
packs), XP (32-bit, service packs 0-3), 2003 (32-bit, service
packs 0-2), and Vista (32-bit, service packs 0-1). It does not
support Windows 95, 98, ME or Server 2008.
- This release of \DynamoRIO has limited support for running 32-bit
Windows applications on the following 64-bit Windows operating
systems : Windows XP Professional x64 (service pack 2), Windows 2003
x64 (service pack 2), Vista x64 (service packs 0-1). Only the 32-bit
code will be seen, and children processes created will not be injected
into. On 64-bit Windows 32-bit applications are automatically run
through the Windows-On-Windows or WOW64 emulator so system call and
indirect call processing \clients must be aware of
#instr_is_wow64_syscall().
- This release of \DynamoRIO has experimental support for running
64-bit Windows applications, using the 64-bit \DynamoRIO build, on
the following 64-bit Windows systems: Windows XP Professional x64
(service pack 2), Windows 2003
x64 (service pack 2), Vista x64 (service packs 0-1). It does not
support any Itanium based Windows systems. For 64-bit
applications \clients must be compiled for 64-bit with a
fixed preferred address in the lower 2GB of the address space (e.g.,
with the link options /base:"0x72000000" /FIXED), and multiple
\clients with conflicting base addresses aren't supported. See <a
href="samples/Makefile">samples/Makefile</a> for an example. The
target application may fail to initialize properly or load
\DynamoRIO if there is an address conflict with the preferred
bases of the \client or \DynamoRIO dlls, but given the choice of
bases and the fact that \DynamoRIO is loaded quite early we expect
this to only very rarely be a problem. This limitation will be
addressed in future releases. This release also does not support
thread-private caches with 64-bit applications.
- This release does not fully support applications that mix 32-bit and
64-bit code. Future releases will support such mixtures.
- When running a cygwin application under control of \DynamoRIO,
stderr and stdout output from \DynamoRIO or its \clients may not
be visible.
\if linux
- This release of \DynamoRIO has limited support for most 32-bit Linux
distributions running on Intel-compatible hardware, including
Ubuntu 7.04, Ubuntu 8.04, and Fedora 9. It may not support
applications using segment registers beyond the standard threading
library usage. Future releases will match the Windows version in
comprehensive support.
- This release of \DynamoRIO has limited support for running 32-bit
Linux applications on 64-bit Linux operating systems on
AMD64-compatible hardware.
- This release of \DynamoRIO has experimental support for running 64-bit
Linux applications, using the 64-bit \DynamoRIO build. Similarly to
64-bit Windows, \clients must set a preferred base address in the lower
2GB of the address space, and multiple \clients with conflicting base
addresses aren't supported. See <a
href="samples/Makefile">samples/Makefile</a> for an example.
This limitation will be addressed in future releases.
\endif
\subsection sec_limit_perf Performance Limitations
- In order to present a more straightforward code stream to \clients,
\DynamoRIO has several optimizations disabled in this release.
System-call-heavy applications are the ones most likely to be affected.
Future releases may allow \clients to choose performance versus
visibility. This release does provide the \ref op_memory "-opt_memory option"
to enable prioritizing memory usage.
- The performance \if vmsafe of Code Manipulation Mode and Memory
Firewall Mode \endif when starting up large desktop applications
may be noticeably worse than native. Upcoming releases will
address this issue. \if vmsafe Note that Probe Mode incurs
significantly less overhead than the other modes. \endif
- The performance \if vmsafe of Code Manipulation Mode \endif when
running Java, .Net, Flash or similar managed execution
applications can be noticeably worse then native. This can
include applications that load these components as in-process
plugins (such as Internet Explorer). Upcoming releases will
address this issue. \if vmsafe Probe Mode and Memory Firewall
Mode are not affected. \endif
- When using \if vmsafe Code Manipulation Mode or Memory Firewall
Mode \else \DynamoRIO \endif on all or many processes on a system
simultaneously, memory usage may become a factor. Upcoming
releases will address this issue. \if vmsafe Note that Probe Mode
incurs significantly less overhead than the other modes. \endif
\subsection sec_limit_deploy Deployment Limitations
- The dr_config.lib library is not multi-thread safe. Users of the
library should ensure that no more then one thread accesses the
library at a time.
- Other installed software that uses hooks may not always be
interoperable with \DynamoRIO.
- Other installed software may conflict with \DynamoRIO's use of the
\c \\HKLM\\SOFTWARE\\Microsoft\\Windows\\WindowsNT\\CurrentVersion\\AppInit_DLLs
registry key (only very rarely an issue).
- Cygwin processes do not work with \DynamoRIO due to cygwin's
implementation of fork being incompatible with \DynamoRIO.
- Though \DynamoRIO supports running on Windows NT, the provided
installer will only run on Windows 2000 and higher. After
installation on a 2000 or higher machine the \ref sec_package may
be copied to the NT machine for use there.
- On Windows NT, a reboot is required after the initial
dr_register_process() in order for \DynamoRIO to take control of any
applications. The reboot will not change or undo the registration.
- A Windows application that does not statically link with
user32.dll will not be run under control of \DynamoRIO unless its
parent process (typically cmd.exe or explorer.exe, for manually
launched applications) is already under \DynamoRIO control
\if vmsafe (the parent can be in any mode)\endif or the drinject.exe
utility is used to launch the application. Only some small
non-graphical applications do not link with user32.dll.
- When invoking an application in any way that is not from a parent
process under \DynamoRIO control, \DynamoRIO takes control a little
later and in some rare cases the application has already created a new
thread. This is in violation of the Windows specficiations, but cygwin
processes do this. This new thread will not be under \DynamoRIO
control and can cause a variety of problems. In such cases it is best
to invoke from a parent process under \DynamoRIO control. However, for
32-bit applications on 64-bit Windows operating systems, \DynamoRIO
takes over later even from the parent. Future releases will address
this limitation.
- This release does not support running some Windows services under
control of \DynamoRIO: System, smss.exe, csrss.exe, and protected
processes on Windows Vista.
- This release does not support nudging 64-bit processes.
\anchor limits_vista_service_messagebox
- On Windows Vista most services are run in a separate session as a
security feature. This means that neither \DynamoRIO nor its
\client will be able to display a messagebox when running in said
services (they have no associated visible window station). See
dr_messagebox().
- On Windows Vista \if vmsafe in Code Manipulation Mode \endif the code from
certain dlls (found mostly in services) and the code subsequently
called from those dlls is run natively and is not visible to the
instrumentation APIs. This only applies to dlls that have a .pexe
section (only 13 dlls have such a section is a standard Vista
install) which seems to be associated with a likely obfuscation
method involving kernel side components that this release has no
other workaround for.
\if linux
\anchor limits_linux_preload
- On Linux, the only provided deployment method in this release (aside
from the \ref sec_startstop "app_start() app_stop()" interface, which
requires soure code modification) is LD_PRELOAD. This means that
static binaries cannot be injected into. Also, suid-root binaries
disallow absolute paths in LD_PRELOAD and ignore LD_LIBRARY_PATH, so
alternate methods of specifying the path are needed there. One method
is to place libdrpreload.so's full path in /etc/ld.so.preload and copy
libdynamorio.so to /usr/lib or some other system search directory.
\endif
\ifnot vmsafe
***************************************************************************
\htmlonly
<table width=100% bgcolor="#000000" cellspacing=0 cellpadding=2 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td><table width=100% bgcolor="#0000C0" cellspacing=0 cellpadding=1 border=0>
<tr><td></td></tr></table></td></tr></table></td></tr></table>
\endhtmlonly
\section sec_future Plans for Future Releases
We hope to include the following major features in future releases:
- Persistent and process-shared code caches
- Auto-inlining of instrumentation callouts
- \Client threads
We also plan to add a number of secondary features, including:
- More flexible (earlier, or later via attach) Linux injection
- Full control over trace building
- \Client exception event for \client fault recovery/remediation
Send comments or requests to <a
href="mailto:[email protected]">[email protected]</a>.
\endif
*/
+526
View File
@@ -0,0 +1,526 @@
/* **********************************************************
* 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 Use Cases
We provide several examples to illustrate how the \DynamoRIO API is used to
build a \DynamoRIO \client.
\if vmsafe
\section probe_samples Probe API Examples
Not available yet.
\endif
\if vmsafe
\anchor sec_mf_samples
\section mf_samples Memory Firewall Examples
An example Memory Firewall \client implementation is provided at <a
href="samples/MF_moduledb.c">samples/MF_moduledb.c</a> (see that file
for additional documentation). The MF_moduledb sample \client reads in
a list of module names and options from a config file and exempts security
violations associated with those modules based on the type of
violation and the options in the file. In this manner violations from
dlls known to have certain types of false positives can be avoided.
It also supports dynamically changing its exemptions with a nudge
handler that triggers re-reading the config file.
The MF_moduledb sample \client is provided with a configuration file <a
href="samples/MF_moduledb-sample.config">samples/MF_moduledb-sample.config</a>
and a violation generating executable <a
href="samples/VIPA_test.exe">samples/VIPA_test.exe.c</a> for easy
testing. To use :
Use drdeploy.exe to configure VIPA_test.exe to run under security_api mode with
the appropriate options.
drdeploy.exe -reg VIPA_test.exe -root \<root path\> -mode security_api -client \<path
to MF_moduledb.dll\> -ops "-client_ops \<path to MF_moduledb-sample.config\>"
Then run VIPA_test.exe. Clicking on the heap attack button should produce messages
that a potential security violation is being allowed. Clicking on the stack attack
button should produce a message that a potential security violation is being blocked
by killing the process.
Use 'drdeploy.exe -nudge VIPA_text.exe' to nudge the process to re-read the
configuration file.
\endif
\section bt_examples Code Manipulation API Examples
********************
\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="samples/countcalls.c">samples/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 dr_init routine:
\code
DR_EXPORT void
dr_init(client_id_t id)
{
/* 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, 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, LOG_ALL, 1, "countcalls: set up for thread %d\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
To build the \client instrumentation application, the
\client program file (say instrcalls.c) should include the main 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 or \p LINUX
-# \p X86_32 or \p X86_64
We can then build the \client shared library in Windows:
\code
> cl instrcalls.c /I$DYNAMORIO_HOME/include /link /NODEFAULTLIB /NOENTRY /libpath:$DYNAMORIO_HOME/bin dynamorio.lib /dll /out:instrcalls.dll
\endcode
Be sure to include /NODEFAULTLIB and /NOENTRY! Not including them will
result in an unsafe \client library with the potential to deadlock or
crash. See \ref transparency for further information on transparency.
\if linux
To build in Linux:
\code
> gcc -shared -nostartfiles -DLINUX -I$DYNAMORIO_HOME/include instrcalls.c -o instrcalls.so
\endcode
\endif
The result is a shared library instrcalls.dll. To invoke the \client library,
follow the instructions under \ref sec_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="samples/instrcalls.c">samples/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 \if linux to allow the same code to work on Linux and Windows
\endif. 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="samples/cbr.c">samples/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="samples/inc2add.c">samples/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="samples/inline.c">samples/inline.c</a>.
********************
\subsection sec_ex6 Use of Floating Point Operation in a \Client
Because saving the floating point state is very expensive, \DynamoRIO seeks
to do so on an as needed basis. If a \client wishes to use floating point
operations 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 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.
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="samples/bbsize.c">samples/bbsize.c</a>.
\ifnot vmsafe
********************
\subsection sec_ex7 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="samples/stats.c">samples/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.
\endif
\ifnot vmsafe
********************
\subsection sec_ex8 Use of Standalone API
The binary tracedump reader also functions as an example of
\ref page_standalone : <a href="samples/tracedump.c">samples/tracedump.c</a>.
\endif
********************
\subsection sec_ex9 Other examples
The sample <a href="samples/strace.c">samples/strace.c</a> displays how to
use the system call events and API routines.
The sample <a href="samples/signal.c">samples/signal.c</a> demonstrates how to
use the signal event.
The sample <a href="samples/prefetch.c">samples/prefetch.c</a> demonstrates
modifying the dynamic code stream for compatibilty between different
processor types.
The sample <a href="samples/div.c">samples/div.c</a> demonstrates
profiling the types of values fed to a particular opcode.
The sample <a href="samples/empty.c">samples/empty.c</a> is provided
as an example \client that does nothing.
*/
+327
View File
@@ -0,0 +1,327 @@
/* **********************************************************
* 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 transparency \Client Transparency
\DynamoRIO must avoid interfering with the semantics of a program while it
executes. Shifting execution from the original application code into a
cache that occupies the application's own address space provides
flexibility but complicates transparency. To achieve transparency,
\DynamoRIO cannot make any assumptions about a program's stack usage, heap
usage, or any of its dependencies on the instruction set architecture or
operating system. \DynamoRIO's transparency restrictions necessarily apply
to a \client as\if vmsafe well (though they are lessened when using the Probe API in
lightweight mode).\else well.\endif
Contents:
- \ref sec_trans_resource
- \ref sec_trans_unmod
- \ref sec_trans_pretend
\if vmsafe
- \ref sec_trans_probe
\endif
We first describe each of the three transparency categories for \DynamoRIO
and their ramifications for \clients using the code cache. \if vmsafe
Finally, we discuss transparency issues for the Probe API, which has
fewer limitations. \endif
***************************************************************************
\section sec_trans_resource Resource Usage Conflicts
Ideally, \DynamoRIO and its \client's resources should be completely disjoint
from the application's, to avoid conflicts in the usage of libraries, heap,
input/output, and locks. Library conflicts are the most relevant to a
\client.
\par Library Transparency
Sharing libraries with the application can cause problems with re-entrancy
and corruption of persistent state like error codes. \DynamoRIO's dispatch
code can execute at arbitrary points in the middle of application code; a
\client's instrumentation is similarly executed. If both the application
and \DynamoRIO use the same non-re-entrant library routine, \DynamoRIO might
call the routine while the application is inside it, causing incorrect
behavior. We have learned this lesson the hard way, having run into it
several times. The solution is for \DynamoRIO's external resources to come
only from system calls and never from user libraries. This is
straightforward to accomplish on Linux, and most operating systems, where
the system call interface is a standard mechanism for requesting services
(\e a in the figure below). However, on Windows, the documented method of
interacting with the operating system is not via system calls but instead
through an application programming interface (the {\em Win32 API}) built
with user libraries on top of the system call interface (\e b in the
figure). If \DynamoRIO uses this interface, re-entrancy and other resource
usage conflicts can, and will, occur. To achieve full transparency on
Windows, the system call interface (\e c in the figure) must be used,
rather than the API layer.
\image html windows.png
\image rtf windows.png
\image latex windows.eps "Native API" width=10cm
\DynamoRIO provides access to resources to \clients via a cross-platform
API. We do not recommend that a \client invoke its own system calls as
this bypasses \DynamoRIO's monitoring of changes to the process address
space and changes to threads or control flow.
We provide limited support to assist in using statically linked libraries
in a \client: see \ref sec_extlibs.
In addition to Library Transparency, several other types of transparency
are of concern to a \client:
\par Heap Transparency
Sharing heap allocation routines with the application violates Library
Transparency. Most heap allocation routines are not re-entrant
(they are thread-safe, but not re-entrant). Additionally, \DynamoRIO
should not interfere with the data layout of the application (Data
Transparency: see below) or with application memory bugs (Error
Transparency: see below). \DynamoRIO obtains its memory directly from
system calls and parcels it out internally with a custom memory manager.
It exports its heap allocation routines through its API to ensure that
\clients maintain Heap Transparency (see \ref sec_utils).
\par Input/Output Transparency
\DynamoRIO uses its own input/output routines to avoid interfering with
the application's buffering. As with heap transparency, \DynamoRIO
exports its input/output routines to \clients to ensure that transparency
is not violated (see \ref sec_utils).
\par Synchronization Transparency
\DynamoRIO and its \clients must avoid acquiring locks that the application
also acquires, such as the \p LoaderLock on Windows. Additionally, there
are restrictions imposed by \DynamoRIO on when its own locks can be
acquired, to allow it to safely synchronize with multiple threads:
***************************************************************************
\section sec_trans_unmod Leaving the Application Unchanged When Possible
As many aspects of the application as possible should be left unchanged:
\anchor sec_trans_floating_point
\par Floating Point State, MMX, and SSE Transparency
Because it is expensive to do so and rarely necessary, \DynamoRIO does
\e NOT save or restore the floating point state or MMX (64-bit) registers
during a context switch away from the application. If at any time a
\client wishes to use floating point or multimedia operations, it
must explicitly preserve the state. The dr_insert_clean_call() routine
takes a boolean indicating whether floating point state should be preserved
across the call; this is the most convenient method for saving the state.
The state can alternatively be saved explicitly from C code using:
\code
proc_save_fpstate(byte *buf)
proc_restore_fpstate(byte *buf)
\endcode
Saving can be done from inlined code in the code cache using:
\code dr_insert_save_fpstate(), dr_insert_restore_fpstate() \endcode
These routines require a buffer that is 16-byte-aligned and of a certain
size (512 bytes for processors with the FXSR feature, and 108 bytes for
those without). Here is a sample usage:
\code
byte fp_raw[512 + 16];
byte *fp_align = (byte *) ( (((ptr_uint_t)fp_raw) + 16) & ((ptr_uint_t)-16) );
proc_save_fpstate(fp_align);
\endcode
Note that floating point operations include almost any operation that
acts on a float, even printing one with %%f.
The XMM (128-bit) registers are saved by \DynamoRIO on context switches and
clean calls only for a 64-bit Windows kernel (whether in a 32-bit process
(WOW64) or a 64-bit process) or for 64-bit Linux applications. For a
64-bit Windows kernel, xmm0 through xmm5 are preserved; for a 64-bit Linux
application, xmm0 through xmm15 are preserved. For all other platforms, it
is up to the \client to preserve the xmm registers, and for 64-bit Windows
kernels, to preserve the rest of the xmm registers beyond xmm5, if any code
is invoked that modifies them. See also the dr_mcontext_xmm_fields_valid()
routine.
\anchor sec_trans_thread
\par Thread Transparency
For full transparency, if \DynamoRIO or a \client creates extra threads
they should be hidden from any introspection performed by the
application.
\par Executable Transparency
The program binary and shared library files on disk should not be
modified.
\par Data Transparency
\DynamoRIO leaves application data unmodified, including heap layout.
\par Stack Transparency
The application stack must look exactly like it does natively. It is
tempting to use the application stack for scratch space, but we have seen
applications like Microsoft Office access data beyond the top of the stack
(i.e., the application stores data on the top of the stack, moves the stack
pointer to the previous location, and then accesses the data). Using the
application stack for scratch space would clobber such data. Additionally,
hand-crafted code might use the stack pointer as a general-purpose
register. Other and better options for temporary space are available.
\DynamoRIO provides thread-local storage through its API.
\DynamoRIO provides a separate stack to use for itself and for the \client,
and never assumes even that the application stack is valid. Many
applications examine their stack and may not work properly if something
is slightly different than expected.
***************************************************************************
\section sec_trans_pretend Pretending The Application Is Unchanged When It Is Not
For changes that are necessary (such as executing out of a code cache),
\DynamoRIO must warp events like interrupts, signals, and exceptions such
that they appear to have occurred natively.
\par Cache Consistency
\DynamoRIO must keep its cached copies of the application code consistent
with the actual copy in memory. If the application unloads a shared
library and loads a new one in its place, or modifies its own code,
\DynamoRIO must change its code cache to reflect those changes to avoid
incorrectly executing stale code. If the \client needs to modify
application code, it should do so through the basic block event, rather
than directly.
\if future
FIXME: if we provide routine to modify app memory should
talk about it here.
\endif
\par Address Space Transparency
\DynamoRIO must pretend that it is not perturbing the application's
address space. An application bug that writes to invalid memory and
generates an exception should do the same thing under \DynamoRIO, even if
we have allocated memory at that location that would natively have been
invalid. This requires protecting all \DynamoRIO memory from inadvertent
(or malicious) writes by the application. Furthermore, \DynamoRIO
hides itself from introspection by manipulating memory queries.
\par Application Address Transparency
Although the application's code is moved into a cache, every address
manipulated by the application must remain an original application
address. \DynamoRIO must translate indirect branch targets from
application addresses to code cache addresses, and conversely if a code
cache address is ever exposed to the application, \DynamoRIO must
translate it back to its original application address. The latter occurs
when the operating system hands a machine context to a signal or
exception handler. In that case both the faulting or interrupted address
and the complete register state must be made to look like the signal or
exception occurred natively, rather than inside the code cache where it
actually occurred.
To save space, \DynamoRIO does not store any mappings from code cache
state to application state. Since our cache consistency guarantees that
the original application code cannot have changed since we built a
fragment, we re-create the fragment from the original code, applying all
the same transformations we applied when we first copied it into our code
cache. We then walk through the reproduction and the code cache version
in lockstep until we reach the target instruction. In order to
accomplish this algorithm in code that has been modified or re-arranged
by a \client, \DynamoRIO needs \client support. We have not yet implemented
this support. \if future FIXME: say anything else? \endif
\par Error Transparency
Application errors under \DynamoRIO must occur as they would natively. We
accomplish this by maintaining Heap Transparency, Data Transparency,
Stack Transparency, and Address Space Transparency, We have seen many
cases of applications that access invalid memory natively, handle the
exception, and carry on. Without Error Transparency such applications
would not work properly under \DynamoRIO.
\par Timing Transparency
We would like to make it impossible for the application to determine
whether it is executing inside of \DynamoRIO. However, this may not be
attainable for some aspects of execution, such as the exact timing of
certain operations. This brings efficiency into the transparency
equation.
Changing the timing of multi-threaded applications can uncover behavior
that does not normally happen natively. We have encountered race
conditions while executing under \DynamoRIO that are difficult to
reproduce outside of our system. These are not strictly speaking
transparency violations, as the errors \e could have occurred without
us, but are best avoided.
\par Debugging Transparency
A debugger should be able to attach to a process under \DynamoRIO's
control just like it would natively. Previously discussed transparency
issues overlap with Debugging Transparency. Stack Transparency and Data
Transparency ensure that callstacks and application memory show up
correctly. However, \DynamoRIO can't entirely hide the fact that the
application is running out of a code cache from the debugger. The
debugger will see the wrong eip value when breaking in and execution
break points will not work correctly (and in fact can lead to
corruption of the \DynamoRIO code cache). Debugging Tools for Windows and
\p gdb are known to work with \DynamoRIO with the exception of the
issues noted above.
\if vmsafe
***************************************************************************
\section sec_trans_probe Transparency of Probe API \Clients
For the Probe API, any particular probe routine is interrupting the
application at a single, known point. If the \client is certain that this
is a safe point for invoking shared resources or performing other actions
that are risky when attempted at arbitrary points, then they may be
invoked. However, be warned that it can be difficult to be certain that
library routines are safe, as they may themselves acquire locks or call
other routines that are not safe.
\endif
***************************************************************************
****************************************************************************
****************************************************************************
*/
File diff suppressed because it is too large Load Diff
+106
View File
@@ -0,0 +1,106 @@
#FIG 3.2 Produced by xfig version 3.2.5
Landscape
Center
Inches
A4
100.00
Single
-2
1200 2
0 32 #f7cb66
0 33 #995e3c
0 34 #6f300f
0 35 #969696
0 36 #ccccb1
0 37 #3366ff
6 1725 1050 3075 1950
2 4 0 1 37 37 50 -1 62 0.000 0 0 11 0 0 5
3075 1050 1725 1050 1725 1950 3075 1950 3075 1050
4 1 7 49 -1 18 12 0.0000 4 210 1095 2400 1725 Agent App\001
4 1 7 49 -1 18 12 0.0000 4 210 870 2400 1425 Security\001
-6
6 1725 2700 3075 3600
2 4 0 1 35 35 50 -1 62 0.000 0 0 11 0 0 5
3075 2700 1725 2700 1725 3600 3075 3600 3075 2700
4 1 7 49 -1 18 12 0.0000 4 165 720 2400 3075 VMsafe\001
4 1 7 49 -1 18 12 0.0000 4 165 1035 2400 3375 Front-End\001
-6
6 4200 1200 5550 1950
2 4 0 1 37 37 50 -1 62 0.000 0 0 11 0 0 5
5550 1200 4200 1200 4200 1950 5550 1950 5550 1200
4 1 7 49 -1 18 12 0.0000 4 210 615 4875 1800 Agent\001
4 1 7 49 -1 18 12 0.0000 4 165 615 4875 1500 Guest\001
-6
6 4200 2100 5550 2850
2 4 0 1 37 37 50 -1 62 0.000 0 0 11 0 0 5
5550 2100 4200 2100 4200 2850 5550 2850 5550 2100
4 1 7 49 -1 18 12 0.0000 4 165 810 4875 2700 Handler\001
4 1 7 49 -1 18 12 0.0000 4 165 795 4875 2400 Internal\001
-6
6 5700 750 6900 2550
2 1 0 6 8 8 50 -1 -1 0.000 0 0 -1 1 1 2
1 1 2.00 150.00 75.00
1 1 2.00 150.00 75.00
6300 1350 6300 1800
2 4 0 1 35 35 50 -1 62 0.000 0 0 7 0 0 5
6750 1800 5850 1800 5850 2400 6750 2400 6750 1800
2 4 0 1 37 37 50 -1 62 0.000 0 0 7 0 0 5
6675 1350 5925 1350 5925 900 6675 900 6675 1350
2 4 0 1 36 36 51 -1 62 0.000 0 0 7 0 0 5
6900 750 5700 750 5700 2550 6900 2550 6900 750
4 1 7 49 -1 18 12 0.0000 4 165 660 6300 2175 VIPER\001
4 1 7 49 -1 18 12 0.0000 4 165 510 6300 1200 VIPA\001
-6
6 7050 750 8250 2550
2 1 0 6 8 8 50 -1 -1 0.000 0 0 -1 1 1 2
1 1 2.00 150.00 75.00
1 1 2.00 150.00 75.00
7650 1350 7650 1800
2 4 0 1 36 36 51 -1 62 0.000 0 0 7 0 0 5
8250 750 7050 750 7050 2550 8250 2550 8250 750
2 4 0 1 37 37 50 -1 62 0.000 0 0 7 0 0 5
8025 1350 7275 1350 7275 900 8025 900 8025 1350
2 4 0 1 35 35 50 -1 62 0.000 0 0 7 0 0 5
8100 1800 7200 1800 7200 2400 8100 2400 8100 1800
4 1 7 49 -1 18 12 0.0000 4 165 510 7650 1200 VIPA\001
4 1 7 49 -1 18 12 0.0000 4 165 660 7650 2175 VIPER\001
-6
6 5475 3450 6825 4350
2 4 0 1 35 35 50 -1 62 0.000 0 0 11 0 0 5
6825 3450 5475 3450 5475 4350 6825 4350 6825 3450
4 1 7 49 -1 18 12 0.0000 4 165 720 6150 3825 VMsafe\001
4 1 7 49 -1 18 12 0.0000 4 165 975 6150 4125 Back-End\001
-6
2 4 0 1 34 34 51 -1 62 0.000 0 0 7 0 0 5
8400 3300 4050 3300 4050 2700 8400 2700 8400 3300
2 4 0 1 33 33 51 -1 62 0.000 0 0 7 0 0 5
3600 4500 1200 4500 1200 3900 3600 3900 3600 4500
2 4 1 2 0 7 52 -1 20 9.000 0 0 7 0 0 5
8400 2700 4050 2700 4050 600 8400 600 8400 2700
2 4 0 1 33 33 51 -1 62 0.000 0 0 7 0 0 5
8400 4500 4050 4500 4050 3300 8400 3300 8400 4500
2 1 0 6 8 8 50 -1 -1 0.000 0 0 -1 1 1 2
1 1 2.00 150.00 75.00
1 1 2.00 150.00 75.00
4875 2850 5550 3525
2 4 0 1 32 32 50 -1 62 0.000 0 0 7 0 0 5
8400 5100 1200 5100 1200 4500 8400 4500 8400 5100
2 4 0 1 34 34 51 -1 62 0.000 0 0 7 0 0 5
3600 3900 1200 3900 1200 2250 3600 2250 3600 3900
2 1 0 8 8 8 50 -1 -1 0.000 0 0 -1 1 1 2
1 1 2.00 150.00 75.00
1 1 2.00 150.00 75.00
3075 3150 5475 3900
2 1 0 6 8 8 50 -1 -1 0.000 0 0 -1 1 1 2
1 1 2.00 150.00 75.00
1 1 2.00 150.00 75.00
2400 1950 2400 2700
2 4 0 1 36 36 51 -1 62 0.000 0 0 7 0 0 5
3600 600 1200 600 1200 2250 3600 2250 3600 600
4 1 7 49 -1 18 12 0.0000 4 165 345 2400 4275 VM\001
4 1 0 50 -1 18 12 0.0000 4 165 1095 4800 975 Processes\001
4 1 7 49 -1 18 12 0.0000 4 165 330 6150 3075 OS\001
4 1 0 49 -1 18 12 0.0000 4 210 4065 4725 4875 Virtual Infrastructure (Single ESX Host)\001
4 1 7 50 -1 18 12 0.0000 4 165 555 1800 2550 Linux\001
4 1 0 50 -1 18 12 0.0000 4 210 1755 2400 900 Security Monitor\001
4 1 7 50 -1 18 12 0.0000 4 165 345 7575 3975 VM\001
+74
View File
@@ -0,0 +1,74 @@
#FIG 3.2
Landscape
Center
Inches
Letter
100.00
Single
-2
1200 2
0 32 #000000
0 33 #dddddd
0 34 #ffffaa
0 35 #0000ff
0 36 #6666ff
0 37 #aaaaff
0 38 #ddddff
0 39 #77ff00
0 40 #aaffaa
0 41 #dd00ff
0 42 #ffaaaa
6 0 1350 3150 3525
2 2 0 1 0 37 54 0 20 0.000 0 0 -1 0 0 5
1050 3150 1050 2700 2850 2700 2850 3150 1050 3150
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 1 2
1 1 1.00 60.00 90.00
1 1 1.00 60.00 120.00
1950 1800 1950 2700
2 2 0 0 7 33 54 0 20 0.000 0 0 -1 0 0 5
750 2400 750 2100 3150 2100 3150 2400 750 2400
2 2 0 1 0 38 51 0 20 0.000 0 0 -1 0 0 5
1050 1800 1050 1350 2850 1350 2850 1800 1050 1800
2 1 0 4 41 7 50 0 -1 0.000 0 0 -1 1 0 2
1 1 4.00 120.00 180.00
225 2250 750 2250
4 0 0 50 0 0 12 0.0000 4 180 1305 1350 3000 operating system\001
4 0 0 50 0 0 12 0.0000 4 180 1560 1200 2325 system call gateway\001
4 0 0 50 0 0 12 0.0000 4 180 825 1500 1650 application\001
4 0 0 50 0 0 14 0.0000 4 150 495 1650 3525 Linux\001
4 0 -1 50 0 0 12 0.0000 4 180 165 37 2295 a)\001
-6
6 3600 0 6750 3525
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 1 2
1 1 1.00 60.00 90.00
1 1 1.00 60.00 120.00
5550 450 5550 1350
2 1 0 1 0 7 51 0 -1 0.000 1 0 -1 1 1 2
1 1 1.00 60.00 90.00
1 1 1.00 60.00 120.00
5550 1800 5550 2700
2 2 0 1 0 37 54 0 20 0.000 0 0 -1 0 0 5
4650 3150 4650 2700 6450 2700 6450 3150 4650 3150
2 2 0 0 7 33 54 0 20 0.000 0 0 -1 0 0 5
4350 2400 4350 2100 6750 2100 6750 2400 4350 2400
2 2 0 0 7 33 54 0 20 0.000 0 0 -1 0 0 5
4350 1050 4350 750 6750 750 6750 1050 4350 1050
2 2 0 1 0 42 51 0 20 0.000 0 0 -1 0 0 5
4650 1800 4650 1350 6450 1350 6450 1800 4650 1800
2 2 0 1 0 38 51 0 20 0.000 0 0 -1 0 0 5
4650 450 4650 0 6450 0 6450 450 4650 450
2 1 0 4 41 7 50 0 -1 0.000 0 0 -1 1 0 2
1 1 4.00 120.00 180.00
3825 2250 4350 2250
2 1 0 4 41 7 50 0 -1 0.000 0 0 -1 1 0 2
1 1 4.00 120.00 180.00
3825 900 4350 900
4 0 0 50 0 0 12 0.0000 4 180 825 5100 300 application\001
4 0 0 50 0 0 12 0.0000 4 180 1560 4800 2325 system call gateway\001
4 0 0 50 0 0 12 0.0000 4 180 1305 4950 3000 operating system\001
4 0 0 50 0 0 12 0.0000 4 135 975 5175 1650 Win32 DLLs\001
4 0 0 50 0 0 12 0.0000 4 135 840 5100 975 Win32 API\001
4 0 0 50 0 0 14 0.0000 4 150 810 5175 3525 Windows\001
4 0 -1 50 0 0 12 0.0000 4 180 165 3623 953 b)\001
4 0 -1 50 0 0 12 0.0000 4 180 165 3630 2302 c)\001
-6
+1
View File
@@ -0,0 +1 @@
foo.dll yyybar.dll ynnVIPA_Test.exe nyytest.dll nnn
+341
View File
@@ -0,0 +1,341 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
/* Usage :
* Should be run in DR_MODE_MEMORY_FIREWALL mode.
*
* Expects a single -client_ops option: the full absolute path to a configuration file
* (for example '-client_ops "C:\MF_moduledb_VIPA\MF_moduledb-sample.config"').
*
* The configuration file is specified as a series of table_value_t structures defined
* below with no line breaks or extra padding. Each table_value_t structure consists
* of a module_name padded with spaces to MAXIMUM_PATH in length followed by three
* 'y' or 'n' letters specifying the allow_to_stack, allow_to_heap, and allow_to_here
* modes.
*
* If allow_to_stack is 'y', execution is allowed to go from the module specified to
* a violating location on the stack. If allow_to_heap is 'y', execution is allowed to
* go from the module specified to a violating location on the heap. If allow_to_here is
* 'y', violating transfers targeting the module are allowed.
*
* A sample config file is included: MF_moduledb-sample.config that is set up to work
* with VIPA_test.exe (also in the sample folder). The VIPA_test.exe program has two
* buttons, one to generate a stack overflow attack and one to generate a heap
* overflow attack. The sample config file MF_moduledb-sample.config is set up to
* allow the heap attack, but not the stack attack. To demonstrate :
*
* Use drdeploy.exe to configure VIPA_test.exe to run under security_api mode with
* the appropriate options.
* drdeploy.exe -reg VIPA_test.exe -root <root path> -mode security_api -client <path
* to MF_moduledb.dll> -ops "-client_ops <path to MF_moduledb-sample.config>"
*
* Then run VIPA_test.exe. Clicking on the heap attack button should produce messages
* that a potential security violation is being allowed. Clicking on the stack attack
* button should produce a message that a potential security violation is being blocked
* by killing the process.
*
* Use 'drdeploy.exe -nudge VIPA_text.exe' to nudge the process to re-read the
* configuration file.
*
* The #define VERBOSE and #define VVERBOSE can be adjusted below to generate more
* verbose logging.
*/
#include "dr_api.h"
#define VERBOSE 0
#define VVERBOSE 0
#define USE_MESSAGEBOX 1
#define NAME "MF_moduledb"
#ifdef SHOW_RESULTS
# if defined(WINDOWS) && USE_MESSAGEBOX
# define DISPLAY_FUNC dr_messagebox
# else /* no messageboxes, use dr_printf() instead */
# define DISPLAY_FUNC dr_printf
# endif
#else
# define DISPLAY_FUNC dummy_func
#endif
#if VERBOSE
# define VDISPLAY_FUNC DISPLAY_FUNC
#else
# define VDISPLAY_FUNC dummy_func
#endif
#if VVERBOSE
# define VVDISPLAY_FUNC DISPLAY_FUNC
#else
# define VVDISPLAY_FUNC dummy_func
#endif
/* used to avoid displaying a string */
static void dummy_func(char *fmt, ...) {}
typedef struct {
char module_name[MAXIMUM_PATH];
/* exempt transfers to violating stack regions from this module */
char allow_to_stack; /* either 'y' or 'n' */
/* exempt transfers to violating heap regions from this module */
char allow_to_heap; /* either 'y' or 'n' */
/* exempt violating transfers to this module */
char allow_to_here; /* either 'y' or 'n' */
/* Additional relaxation options such as allowing violating code origins regions
* within this module (some .data sections for ex.) could be added here. */
} table_value_t;
struct _table_entry_t;
typedef struct _table_entry_t table_entry_t;
struct _table_entry_t {
table_value_t value; /* the entry we read out of the config file */
table_entry_t *next; /* table is just a singly linked list */
}; /* table_entry_t */
static const char *table_def_file_name; /* name of configuration file */
static void *table_lock; /* for multithreaded access to the table */
static table_entry_t *table = NULL; /* table of relaxations */
static void event_security_violation(void *drcontext, void *source_tag,
app_pc source_pc, app_pc target_pc,
dr_security_violation_type_t violation,
dr_mcontext_t *mcontext,
dr_security_violation_action_t *action);
static void event_nudge(void *drcontext, uint64 argument);
static void event_about_to_terminate_nudges(int total_non_app_threads,
int live_non_app_threads);
static void event_exit(void);
static table_entry_t * get_entry_for_address(app_pc addr);
static void read_table();
static void free_table();
DR_EXPORT void
dr_init(client_id_t id)
{
VDISPLAY_FUNC(NAME" initializing.");
/* register the events we wish to handle */
dr_register_security_event(event_security_violation);
dr_register_nudge_event(event_nudge, id);
dr_register_exit_event(event_exit);
/* read the client options */
table_def_file_name = dr_get_options(id);
if (table_def_file_name == NULL ||
table_def_file_name[0] == '\0') {
DISPLAY_FUNC(NAME" requires the table name as parameter\n");
dr_abort();
}
/* initialize structures */
table_lock = dr_mutex_create();
read_table();
}
static void
event_exit(void)
{
VDISPLAY_FUNC(NAME" exiting.");
/* free structures */
free_table();
dr_mutex_destroy(table_lock);
}
static void
event_nudge(void *drcontext, uint64 argument)
{
DISPLAY_FUNC(NAME" received nudge event; re-reading config file.");
/* An external process has nudged us with dr_nudge_process() telling us
* to re-read the configuration file. */
dr_mutex_lock(table_lock);
free_table();
read_table();
dr_mutex_unlock(table_lock);
}
#ifdef WINDOWS
/* Lookup the module containing addr and see if we have a table entry for it */
static table_entry_t *
get_entry_for_address(app_pc addr)
{
module_data_t *data = dr_lookup_module(addr);
table_entry_t *entry = NULL;
if (data != NULL) {
entry = table;
while (entry != NULL &&
_stricmp(dr_module_preferred_name(data), entry->value.module_name) != 0) {
entry = entry->next;
}
dr_free_module_data(data);
}
return entry;
}
#endif
static void
event_security_violation(void *drcontext, void *source_tag,
app_pc source_pc, app_pc target_pc,
dr_security_violation_type_t violation,
dr_mcontext_t *mcontext,
dr_security_violation_action_t *action)
{
/* A potential security violation was detected. */
char *violation_str = NULL; /* a name for this violation */
bool allow = false; /* should we let execution continue */
#ifdef WINDOWS
/* find the module we came from */
app_pc source = (source_pc == NULL ? source_tag : source_pc);
table_entry_t *entry;
/* check our source relaxations */
entry = get_entry_for_address(source);
if (entry != NULL) {
/* we have a match, check the relaxations */
if (violation == DR_RCO_STACK_VIOLATION &&
(entry->value.allow_to_stack == 'y' || entry->value.allow_to_stack == 'Y')) {
allow = true;
}
if (violation == DR_RCO_HEAP_VIOLATION &&
(entry->value.allow_to_heap == 'y' || entry->value.allow_to_heap == 'Y')) {
allow = true;
}
}
/* check our target relaxations */
entry = get_entry_for_address(target_pc);
if (entry != NULL) {
/* we have a match, check the relaxations */
if ((violation == DR_RCT_RETURN_VIOLATION ||
violation == DR_RCT_INDIRECT_CALL_VIOLATION ||
violation == DR_RCT_INDIRECT_JUMP_VIOLATION) &&
(entry->value.allow_to_here == 'y' || entry->value.allow_to_here == 'Y')) {
allow = true;
}
}
#endif
switch (violation) {
case DR_RCO_STACK_VIOLATION:
violation_str = "stack execution violation";
break;
case DR_RCO_HEAP_VIOLATION:
violation_str = "heap execution violation";
break;
case DR_RCT_RETURN_VIOLATION:
violation_str = "return target violation";
break;
case DR_RCT_INDIRECT_CALL_VIOLATION:
violation_str = "call transfer violation";
break;
case DR_RCT_INDIRECT_JUMP_VIOLATION:
violation_str = "jump transfer violation";
break;
default:
violation_str = "unknown";
break;
}
if (allow)
*action = DR_VIOLATION_ACTION_CONTINUE;
/* could use dr_write_forensics_report() here to log additional information */
DISPLAY_FUNC("WARNING - possible security violation \"%s\" detected, %s.",
violation_str, allow ? "allowing" : "blocking");
}
static void
read_table()
{
file_t file;
bool read_entry = true;
file = dr_open_file(table_def_file_name, DR_FILE_READ);
if (file == INVALID_FILE) {
DISPLAY_FUNC(NAME" error opening config file \"%s\"\n", table_def_file_name);
return;
}
VVDISPLAY_FUNC(NAME" reading config file: \"%s\"\n", table_def_file_name);
do {
table_entry_t *entry = (table_entry_t *)dr_global_alloc(sizeof(table_entry_t));
if (dr_read_file(file, &entry->value, sizeof(table_value_t)) !=
sizeof(table_value_t)) {
/* end of file */
read_entry = false;
dr_global_free(entry, sizeof(table_entry_t));
} else {
int i;
/* insert NULL termination for module name (including space padding) */
for (i = sizeof(entry->value.module_name) - 1;
i >= 0 && entry->value.module_name[i] == ' '; i--) {
entry->value.module_name[i] = '\0';
}
/* just in case */
entry->value.module_name[sizeof(entry->value.module_name)-1] = '\0';
/* add to the table */
entry->next = table;
table = entry;
VVDISPLAY_FUNC(NAME" read entry for module=\"%s\" to_stack=%s to_heap=%s "
"transfer_to_here=%s\n", entry->value.module_name,
(entry->value.allow_to_stack == 'y' ||
entry->value.allow_to_stack == 'Y') ? "yes" : "no",
(entry->value.allow_to_heap == 'y' ||
entry->value.allow_to_heap == 'Y') ? "yes" : "no",
(entry->value.allow_to_here == 'y' ||
entry->value.allow_to_here == 'Y') ? "yes" : "no");
}
} while (read_entry);
VVDISPLAY_FUNC(NAME" done reading config file.");
}
static void
free_table()
{
/* Free all table entries */
table_entry_t *next;
while (table != NULL) {
next = table->next;
dr_global_free(table, sizeof(table_entry_t));
table = next;
}
}
+221
View File
@@ -0,0 +1,221 @@
# **********************************************************
# Copyright (c) 2008-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.
###########################################################################
###########################################################################
###
### Makefile for DynamoRIO samples
### Requires GNU make for conditionals.
### On Windows requires cygwin cygpath and standard VC command-line setup
### (cl.exe on path, LIB and INCLUDE environment vars set).
### Use ARCH=x64 to build for 64bit.
### Use DEBUG=1 to link with the debug build.
###
.PHONY: clean all
GCC := gcc
GXX := g++
CL := cl
ifndef ARCH
# default is x86 instead of x64
ARCH := x86
endif
ifndef DEBUG
# default is release build
DEBUG := 0
endif
ifndef DYNAMORIO_HOME
# assume we're in docs/html/samples/
DYNAMORIO_HOME := ../../..
endif
ifeq ($(shell uname -s | cut -c1-5), Linux)
MACHINE := linux
WD := $(shell pwd)
else
MACHINE := win32
WD := $(shell cygpath -w $(shell pwd))
# rely on the env vars used for cmd-line building with cl.exe
SYS_INCLUDE := /I$(subst ;, /I, $(INCLUDE))
SYS_LIB := /libpath:$(subst ;, /libpath:,$(LIB))
DYNAMORIO_HOME := $(shell cygpath -ma $(DYNAMORIO_HOME))
endif
ifeq ($(DEBUG), 0)
LIBDIR := release
else
LIBDIR := debug
endif
ifeq ($(ARCH), x64)
DR_LIBPATH := $(DYNAMORIO_HOME)/lib64/$(LIBDIR)
else
DR_LIBPATH := $(DYNAMORIO_HOME)/lib32/$(LIBDIR)
endif
DR_LIB := dynamorio.lib
DR_INCLUDE := $(DYNAMORIO_HOME)/include
ifeq ($(MACHINE), linux)
D := -D
DBG := -g3
SRC_EXCLUDE := stats.c
ifeq ($(ARCH), x64)
CFLAGS := -m64 $(DBG) $(D)LINUX
# Note - it's currently required on 64bit that a client library have a
# preferred base address in the lower 2GB, to be reachable by our
# library and code cache. This is due to limitations in the current
# experimental 64bit release and will be adressed in later releases.
# Naturally for multiple clients different addresses should be used.
PREFERRED_BASE := 0x72000000
LD_SCRIPT := ldscript
LD_USE_SCRIPT := -Xlinker -dT -Xlinker $(LD_SCRIPT)
else
CFLAGS := -m32 $(DBG) $(D)LINUX
LD_USE_SCRIPT :=
endif
SLIB_SUFFIX := .so
SEXE_SUFFIX :=
CXXFLAGS += `$(GXX) -print-file-name=libstdc++.a`
CXXFLAGS += `$(GXX) -print-file-name=libgcc.a`
CXXFLAGS += `$(GXX) -print-file-name=libgcc_eh.a`
CXXFLAGS += -Xlinker -wrap=malloc -Xlinker -wrap=realloc -Xlinker -wrap=free
else
D := /D
DBG := /Zi
CFLAGS := /nologo /GS- $(DBG) $(D)WINDOWS
SRC_EXCLUDE := stl_test.cpp
ifeq ($(ARCH), x64)
# Note - it's currently required on 64bit that /base is used to specify a
# preferred base address such that the resulting instrumentation dll is
# loaded in the range 0x72000000-0x75000000. To ensure that we also add
# /FIXED. This is due to limitations in the current experimental 64bit release
# and will be adressed in later releases.
# Naturally for multiple clients different addresses should be used.
LFLAGS := /machine:X64 /base:"0x72000000" /FIXED
SRC_EXCLUDE += stats.c
else
LFLAGS :=
endif
SLIB_SUFFIX := .dll
SEXE_SUFFIX := .exe
endif
# standalone client isn't easy to run in short regressions
SRCS_STANDALONE := tracedump.c
SEXES := $(subst .c,$(SEXE_SUFFIX),$(SRCS_STANDALONE))
SRCS_LIB := $(filter-out $(SRC_EXCLUDE) $(EXCLUDE) $(SRCS_STANDALONE),$(wildcard *.c *.cpp))
SLIBS := $(subst .c,$(SLIB_SUFFIX),$(subst .cpp,$(SLIB_SUFFIX),$(SRCS_LIB)))
SHOW_RESULTS := 1
ifeq ($(SHOW_RESULTS), 1)
CFLAGS += $(D)SHOW_RESULTS
endif
ifeq ($(ARCH), x64)
CFLAGS += $(D)X86_64
else
CFLAGS += $(D)X86_32
endif
all: $(SLIBS) $(SEXES)
listsrcs:
@echo $(SRCS_LIB)
# shared library clients
ifeq ($(MACHINE), linux)
ifeq ($(ARCH), x64)
$(LD_SCRIPT):
# To set a preferred base address we tweak the default linker script
ld --verbose | sed '/SECTIONS/,/^}/!d' | \
sed 's/0x400000/$(PREFERRED_BASE)/g; /^{/a . = $(PREFERRED_BASE);' > $@
endif
%.so: %.c $(LD_SCRIPT)
# avoid SElinux text relocation security violations by explicitly requesting PIC
$(GCC) $(CFLAGS) -fPIC -shared -nostartfiles -I$(DR_INCLUDE) $(SYS_INCLUDE) \
$< -o $@ $(LD_USE_SCRIPT)
# client libraries need to be executable by all, otherwise the
# client library may not be loaded if run as a different user
chmod ugo+rx "$(WD)/$@"
@echo "---------------------------------------------------------------------------"
@echo "Usage: pass to drdeploy :"
@echo " -client $(WD)/$@ 0 \"\""
%.so: %.cpp $(LD_SCRIPT)
# avoid SElinux text relocation security violations by explicitly requesting PIC
# Note that if we list the source file before the .a files (in CXXFLAGS) we
# get ld warnings on x64 so be sure to list source file last.
$(GXX) $(CFLAGS) $(CXXFLAGS) -fPIC -shared -nostartfiles -I$(DR_INCLUDE) \
$(SYS_INCLUDE) $< -o $@ $(LD_USE_SCRIPT)
else
%.dll: %.c
$(CL) $(CFLAGS) $< /I$(DR_INCLUDE) $(SYS_INCLUDE) /link $(LFLAGS) $(SYS_LIB) \
/libpath:$(DR_LIBPATH) $(DR_LIB) /dll /out:$@ /nodefaultlib /noentry
endif
# client libraries need to be executable by all, otherwise the
# client library may not be loaded if run as a different user
chmod ugo+rx "$(WD)/$@"
@echo "---------------------------------------------------------------------------"
@echo "Usage: pass to drdeploy :"
ifeq ($(MACHINE), linux)
@echo " -client $(WD)/$@ 0 \"\""
else
@echo " -client '$(WD)\\$@' 0 \"\""
endif
# standalone programs
ifeq ($(MACHINE), linux)
%: %.c
$(GCC) $(CFLAGS) -I$(DR_INCLUDE) $(SYS_INCLUDE) -L$(DR_LIBPATH) -ldynamorio \
-Xlinker -rpath -Xlinker $(DR_LIBPATH) $< -o $@
@echo "rpath is set, but if libdynamorio.so is moved, LD_LIBRARY_PATH will need to be set"
else
%.exe: %.c
$(CL) $(CFLAGS) $< /I$(DR_INCLUDE) $(SYS_INCLUDE) /link /nodefaultlib $(SYS_LIB) \
/libpath:$(DR_LIBPATH) libcmt.lib $(DR_LIB) kernel32.lib user32.lib /out:$@
@echo "---------------------------------------------------------------------------"
@echo "Make sure the loader finds dynamorio.dll (e.g., copy to same dir)"
endif
clean:
ifeq ($(MACHINE), linux)
-rm -f *.so
-rm -f *.log
ifeq ($(ARCH), x64)
-rm -f $(LD_SCRIPT)
endif
else
-rm -f *.{dll,exp,lib,obj,pdb,ilk,log}
endif
-rm -f $(SEXES)
BIN
View File
Binary file not shown.
+164
View File
@@ -0,0 +1,164 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
/* Code Manipulation API Sample:
* bbcount.c
*
* Reports the dynamic execution count of all basic blocks.
* Illustrates how to perform performant inline increments with analysis
* on whether flags need to be preserved.
*/
#include <stddef.h> /* for offsetof */
#include "dr_api.h"
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
#endif
#define NULL_TERMINATE(buf) buf[(sizeof(buf)/sizeof(buf[0])) - 1] = '\0'
#define TESTALL(mask, var) (((mask) & (var)) == (mask))
#define TESTANY(mask, var) (((mask) & (var)) != 0)
/* we only have a global count */
static int global_count;
/* If being off a little bit is not important, or the target
* application is single-threaded or spends most of its time in one
* thread, performing a racy inc (i.e., not synchronized among threads)
* is three times faster than synchronizing.
*/
#define RACY_INC 1
#ifdef SHOW_RESULTS
/* some meta-stats: static (not per-execution) */
static int bbs_eflags_saved;
static int bbs_no_eflags_saved;
#endif
static void event_exit(void);
static void event_thread_init(void *drcontext);
static void event_thread_exit(void *drcontext);
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
DR_EXPORT void
dr_init(client_id_t id)
{
/* register events */
dr_register_exit_event(event_exit);
dr_register_bb_event(event_basic_block);
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, LOG_ALL, 1, "Client 'bbcount' initializing\n");
#ifdef SHOW_RESULTS
/* also give notification to stderr */
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client bbcount is running\n");
#endif
}
static void
event_exit(void)
{
#ifdef SHOW_RESULTS
char msg[512];
int len;
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"Instrumentation results:\n"
"%10d basic block executions\n"
"%10d basic blocks needed flag saving\n"
"%10d basic blocks did not\n",
global_count, bbs_eflags_saved, bbs_no_eflags_saved);
DR_ASSERT(len > 0);
NULL_TERMINATE(msg);
DISPLAY_STRING(msg);
#endif /* SHOW_RESULTS */
}
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating)
{
instr_t *instr, *first = instrlist_first(bb);
uint flags;
#ifdef VERBOSE
dr_printf("in dynamorio_basic_block(tag="PFX")\n", tag);
# ifdef VERBOSE_VERBOSE
instrlist_disassemble(drcontext, tag, bb, STDOUT);
# endif
#endif
/* Our inc can go anywhere, so find a spot where flags are dead. */
for (instr = first; instr != NULL; instr = instr_get_next(instr)) {
flags = instr_get_arith_flags(instr);
/* OP_inc doesn't write CF but not worth distinguishing */
if (TESTALL(EFLAGS_WRITE_6, flags) && !TESTANY(EFLAGS_READ_6, flags))
break;
}
if (instr == NULL)
dr_save_arith_flags(drcontext, bb, first, SPILL_SLOT_1);
/* Increment the global counter using the lock prefix to make it atomic
* across threads.
*/
#ifdef RACY_INC
instrlist_meta_preinsert
(bb, (instr == NULL) ? first : instr,
INSTR_CREATE_inc(drcontext, OPND_CREATE_ABSMEM
((byte *)&global_count, OPSZ_4)));
#else
instrlist_meta_preinsert
(bb, (instr == NULL) ? first : instr,
LOCK(INSTR_CREATE_inc(drcontext, OPND_CREATE_ABSMEM
((byte *)&global_count, OPSZ_4))));
#endif
if (instr == NULL)
dr_restore_arith_flags(drcontext, bb, first, SPILL_SLOT_1);
#ifdef SHOW_RESULTS
if (instr == NULL)
bbs_eflags_saved++;
else
bbs_no_eflags_saved++;
#endif
#if defined(VERBOSE) && defined(VERBOSE_VERBOSE)
dr_printf("Finished instrumenting dynamorio_basic_block(tag="PFX")\n", tag);
instrlist_disassemble(drcontext, tag, bb, STDOUT);
#endif
return DR_EMIT_DEFAULT;
}
+131
View File
@@ -0,0 +1,131 @@
/* **********************************************************
* Copyright (c) 2003-2008 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.
*/
/* Code Manipulation API Sample:
* bbsize.c
*
* Reports basic statistics on the sizes of all basic blocks in the
* target application. Illustrates how to preserve floating point
* state in an event callback.
*/
#include "dr_api.h"
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
#endif
static void *stats_mutex; /* for multithread support */
static int num_bb;
static double ave_size;
static int max_size;
static void event_exit(void);
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
DR_EXPORT void
dr_init(client_id_t id)
{
num_bb = 0;
ave_size = 0.;
max_size = 0;
stats_mutex = dr_mutex_create();
dr_register_bb_event(event_basic_block);
dr_register_exit_event(event_exit);
#ifdef SHOW_RESULTS
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client bbsize is running\n");
#endif
}
static void
event_exit(void)
{
#ifdef SHOW_RESULTS
char msg[512];
int len;
/* Note that using %f with dr_printf or dr_fprintf on Windows will print
* garbage as they use ntdll._vsnprintf, so we must use snprintf.
*/
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"Number of basic blocks seen: %d\n"
" Maximum size: %d instructions\n"
" Average size: %5.1f instructions\n",
num_bb, max_size, ave_size);
DR_ASSERT(len > 0);
msg[sizeof(msg)/sizeof(msg[0])-1] = '\0';
DISPLAY_STRING(msg);
#endif /* SHOW_RESULTS */
dr_mutex_destroy(stats_mutex);
}
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating)
{
instr_t *instr;
int cur_size = 0;
/* we use fp ops so we have to save fp state */
byte fp_raw[512 + 16];
byte *fp_align = (byte *) ( (((ptr_uint_t)fp_raw) + 16) & ((ptr_uint_t)-16) );
if (translating)
return DR_EMIT_DEFAULT;
proc_save_fpstate(fp_align);
for (instr = instrlist_first(bb); instr != NULL; instr = instr_get_next(instr))
cur_size++;
dr_mutex_lock(stats_mutex);
#ifdef VERBOSE_VERBOSE
dr_fprintf(STDERR,
"Average: cur=%d, old=%8.1f, num=%d, old*num=%8.1f\n"
"\told*num+cur=%8.1f, new=%8.1f\n",
cur_size, ave_size, num_bb, ave_size*num_bb,
(ave_size * num_bb) + cur_size,
((ave_size * num_bb) + cur_size) / (double) (num_bb+1));
#endif
if (cur_size > max_size)
max_size = cur_size;
ave_size = ((ave_size * num_bb) + cur_size) / (double) (num_bb+1);
num_bb++;
dr_mutex_unlock(stats_mutex);
proc_restore_fpstate(fp_align);
return DR_EMIT_DEFAULT;
}
+432
View File
@@ -0,0 +1,432 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
/* Code Manipulation API Sample:
* cbr.c
*
* This sample shows how to update or replace instrumented code after
* it executes. We focus on cbr instructions, inserting
* instrumentation to record the fallthrough and taken addresses when
* they first execute. After a particular branch first executes, we
* re-instrument the basic block to remove the instrumentation for the
* direction taken. If and when we see the other direction, we remove
* all instrumentation for that branch. We design this sample to
* avoid the instrumentation overhead for a particular direction until
* it is taken. Furthermore, we remove all overhead for that
* direction after it triggers.
*
* This sample might form part of a dynamic CFG builder, where we want
* to record each control-flow edge, but we don't want to pay the
* execution overhead of the instrumentation after we've noted the
* edge.
*
* We use the following replacement scheme:
* 1) In the BB event, insert instrumentation for both the taken and
* fallthrough edges.
* 2) When the BB executes, note the direction taken and flush the
* fragment from the code cache.
* 3) When the BB event triggers again, insert new instrumentation.
*/
#include "dr_api.h"
#define MINSERT instrlist_meta_preinsert
#define ASSERT(x) \
do { \
if (!(x)) { \
dr_printf("ASSERT failed on line %d", __LINE__); \
dr_flush_file(STDOUT); \
dr_abort(); \
} \
} while (0)
/* We need a table to store the state of each cbr (i.e., "seen taken
* edge", "seen fallthrough edge", or "seen both"). We'll use a
* simple hash table.
*/
#define HASH_TABLE_SIZE 7919
/* Possible cbr states */
typedef enum {
CBR_NEITHER = 0x00,
CBR_TAKEN = 0x01,
CBR_NOT_TAKEN = 0x10
} cbr_state_t;
/* Each bucket in the hash table is a list of the following elements.
* For each cbr, we store its address and its state.
*/
typedef struct _elem_t {
struct _elem_t *next;
cbr_state_t state;
app_pc addr;
} elem_t;
typedef struct _list_t {
elem_t *head;
elem_t *tail;
} list_t;
/* We'll use one global hash table */
typedef list_t **hash_table_t;
hash_table_t table = NULL;
static
elem_t *new_elem(app_pc addr, cbr_state_t state)
{
elem_t *elem = (elem_t *)dr_global_alloc(sizeof(elem_t));
ASSERT(elem != NULL);
elem->next = NULL;
elem->addr = addr;
elem->state = state;
return elem;
}
static
void delete_elem(elem_t *elem)
{
dr_global_free(elem, sizeof(elem_t));
}
static
void append_elem(list_t *list, elem_t *elem)
{
if (list->head == NULL) {
ASSERT(list->tail == NULL);
list->head = elem;
list->tail = elem;
}
else {
list->tail->next = elem;
list->tail = elem;
}
}
static
elem_t *find_elem(list_t *list, app_pc addr)
{
elem_t *elem = list->head;
while (elem != NULL) {
if (elem->addr == addr);
return elem;
elem = elem->next;
}
return NULL;
}
static
list_t *new_list()
{
list_t *list = (list_t *)dr_global_alloc(sizeof(list_t));
list->head = NULL;
list->tail = NULL;
return list;
}
static
void delete_list(list_t *list)
{
elem_t *iter = list->head;
while (iter != NULL) {
elem_t *next = iter->next;
delete_elem(iter);
iter = next;
}
dr_global_free(list, sizeof(list_t));
}
hash_table_t new_table()
{
int i;
hash_table_t table = (hash_table_t)dr_global_alloc
(sizeof(list_t *) * HASH_TABLE_SIZE);
for (i=0; i<HASH_TABLE_SIZE; i++) {
table[i] = NULL;
}
return table;
}
void delete_table(hash_table_t table)
{
int i;
for (i=0; i<HASH_TABLE_SIZE; i++) {
if (table[i] != NULL) {
delete_list(table[i]);
}
}
dr_global_free(table, sizeof(list_t *) * HASH_TABLE_SIZE);
}
static
uint hash_func(app_pc addr)
{
return ((uint)(((ptr_uint_t)addr) % HASH_TABLE_SIZE));
}
elem_t *lookup(hash_table_t table, app_pc addr)
{
list_t *list = table[hash_func(addr)];
if (list != NULL)
return find_elem(list, addr);
return NULL;
}
void insert(hash_table_t table, app_pc addr, cbr_state_t state)
{
elem_t *elem = new_elem(addr, state);
uint index = hash_func(addr);
list_t *list = table[index];
if (list == NULL) {
list = new_list();
table[index] = list;
}
append_elem(list, elem);
}
/*
* End hash table implementation
*/
/* Clean call for the 'taken' case */
static void at_taken(app_pc src, app_pc targ)
{
int app_errno;
dr_mcontext_t mcontext;
void *drcontext = dr_get_current_drcontext();
/*
* Record the fact that we've seen the taken case.
*/
elem_t *elem = lookup(table, src);
ASSERT(elem != NULL);
elem->state |= CBR_TAKEN;
/* Remove the bb from the cache so it will be re-built the next
* time it executes.
*/
/* Since the flush will remove the fragment we're already in,
* redirect execution to the target address.
*/
dr_flush_region(src, 1);
dr_get_mcontext(drcontext, &mcontext, &app_errno);
mcontext.pc = targ;
dr_redirect_execution(&mcontext, app_errno);
}
/* Clean call for the 'not taken' case */
static void at_not_taken(app_pc src, app_pc fall)
{
int app_errno;
dr_mcontext_t mcontext;
void *drcontext = dr_get_current_drcontext();
/*
* Record the fact that we've seen the not_taken case.
*/
elem_t *elem = lookup(table, src);
ASSERT(elem != NULL);
elem->state |= CBR_NOT_TAKEN;
/* Remove the bb from the cache so it will be re-built the next
* time it executes.
*/
/* Since the flush will remove the fragment we're already in,
* redirect execution to the fallthrough address.
*/
dr_flush_region(src, 1);
dr_get_mcontext(drcontext, &mcontext, &app_errno);
mcontext.pc = fall;
dr_redirect_execution(&mcontext, app_errno);
}
static dr_emit_flags_t
bb_event(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
instr_t *instr, *next_instr;
for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
next_instr = instr_get_next(instr);
if (instr_is_cbr(instr)) {
/* Conditional branch. We can determine the target and
* fallthrough addresses here, but we want to note the
* edge if and when it actually executes at runtime.
* Instead of using dr_insert_cbr_instrumentation(), we'll
* insert separate instrumentation for the taken and not
* taken cases and remove the instrumentation for an edge
* after it executes.
*/
cbr_state_t state;
bool insert_taken, insert_not_taken;
app_pc src = instr_get_app_pc(instr);
/* First look up the state of this branch so we
* know what instrumentation to insert, if any.
*/
elem_t *elem = lookup(table, src);
if (elem == NULL) {
state = CBR_NEITHER;
insert(table, src, CBR_NEITHER);
}
else {
state = elem->state;
}
insert_taken = (state & CBR_TAKEN) == 0;
insert_not_taken = (state & CBR_NOT_TAKEN) == 0;
if (insert_taken || insert_not_taken) {
app_pc fall = (app_pc)decode_next_pc(drcontext, (byte *)src);
app_pc targ = instr_get_branch_target_pc(instr);
/* Redirect the existing cbr to jump to a callout for
* the 'taken' case. We'll insert a 'not-taken'
* callout at the fallthrough address.
*/
instr_t *label = INSTR_CREATE_label(drcontext);
/* should be meta, and meta-instrs shouldn't have translations */
instr_set_meta_no_translation(instr);
/* it may not reach (in particular for x64) w/ our added clean call */
if (instr_is_cti_short(instr))
instr_convert_short_meta_jmp_to_long(drcontext, bb, instr);
instr_set_target(instr, opnd_create_instr(label));
if (insert_not_taken) {
/* Callout for the not-taken case. Insert after
* the cbr (i.e., 3rd argument is NULL).
*/
dr_insert_clean_call(drcontext, bb, NULL,
(void*)at_not_taken,
false /* don't save fp state */,
2 /* 2 args for at_not_taken */,
OPND_CREATE_INTPTR(src),
OPND_CREATE_INTPTR(fall));
}
/* After the callout, jump to the original fallthrough
* address. Note that this is an exit cti, and should
* not be a meta-instruction. Therefore, we use
* preinsert instead of meta_preinsert, and we must
* set the translation field. On Windows, this jump
* and the final jump below never execute since the
* at_taken and at_not_taken callouts redirect
* execution and never return. However, since the API
* expects clients to produced well-formed code, we
* insert explicit exits from the block for Windows as
* well as Linux.
*/
instrlist_preinsert(bb, NULL,
INSTR_XL8(INSTR_CREATE_jmp
(drcontext, opnd_create_pc(fall)), fall));
/* label goes before the 'taken' callout */
MINSERT(bb, NULL, label);
if (insert_taken) {
/* Callout for the taken case */
dr_insert_clean_call(drcontext, bb, NULL,
(void*)at_taken,
false /* don't save fp state */,
2 /* 2 args for at_taken */,
OPND_CREATE_INTPTR(src),
OPND_CREATE_INTPTR(targ));
}
/* After the callout, jump to the original target
* block (this should not be a meta-instruction).
*/
instrlist_preinsert(bb, NULL,
INSTR_XL8(INSTR_CREATE_jmp
(drcontext, opnd_create_pc(targ)), targ));
}
}
}
/* since our added instrumentation is not constant, we ask to store
* translations now
*/
return DR_EMIT_STORE_TRANSLATIONS;
}
void dr_exit(void)
{
#ifdef SHOW_RESULTS
/* Print all the cbr's seen over the life of the process, and
* whether we saw taken, not taken, or both.
*/
int i;
for (i=0; i<HASH_TABLE_SIZE; i++) {
if (table[i] != NULL) {
elem_t *iter;
for (iter = table[i]->head; iter != NULL; iter = iter->next) {
cbr_state_t state = iter->state;
if (state == CBR_TAKEN) {
dr_printf(""PFX": taken\n", iter->addr);
}
else if (state == CBR_NOT_TAKEN) {
dr_printf(""PFX": not taken\n", iter->addr);
}
else {
ASSERT(state == CBR_TAKEN | CBR_NOT_TAKEN);
dr_printf(""PFX": both\n", iter->addr);
}
}
}
}
#endif
delete_table(table);
}
DR_EXPORT
void dr_init(client_id_t id)
{
table = new_table();
dr_register_bb_event(bb_event);
dr_register_exit_event(dr_exit);
}
+225
View File
@@ -0,0 +1,225 @@
/* **********************************************************
* Copyright (c) 2003-2008 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.
*/
/* Code Manipulation API Sample:
* countcalls.c
*
* Reports the dynamic execution count for direct calls, indirect
* calls, and returns in the target application. Illustrates how to
* perform performant inline increments and use per-thread data
* structures.
*/
#include <stddef.h> /* for offsetof */
#include "dr_api.h"
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
#endif
#define NULL_TERMINATE(buf) buf[(sizeof(buf)/sizeof(buf[0])) - 1] = '\0'
/* keep separate counters for each thread, in this thread-local data
* structure:
*/
typedef struct {
int num_direct_calls;
int num_indirect_calls;
int num_returns;
} per_thread_t;
/* keep a global count as well */
static per_thread_t global_count = {0};
static void event_exit(void);
static void event_thread_init(void *drcontext);
static void event_thread_exit(void *drcontext);
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
DR_EXPORT void
dr_init(client_id_t id)
{
/* 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, LOG_ALL, 1, "Client 'countcalls' initializing\n");
#ifdef SHOW_RESULTS
/* also give notification to stderr */
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client countcalls is running\n");
#endif
}
static void
display_results(per_thread_t *data, char *thread_note)
{
#ifdef SHOW_RESULTS
char msg[512];
int len;
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"%sInstrumentation results:\n"
" saw %d direct calls\n"
" saw %d indirect calls\n"
" saw %d returns\n",
thread_note, data->num_direct_calls,
data->num_indirect_calls, data->num_returns);
DR_ASSERT(len > 0);
NULL_TERMINATE(msg);
DISPLAY_STRING(msg);
#endif /* SHOW_RESULTS */
}
static void
event_exit(void)
{
display_results(&global_count, "");
}
static void
event_thread_init(void *drcontext)
{
/* create an instance of our data structure for this thread */
per_thread_t *data = (per_thread_t *)
dr_thread_alloc(drcontext, sizeof(per_thread_t));
/* 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, LOG_ALL, 1, "countcalls: set up for thread %d\n",
dr_get_thread_id(drcontext));
}
static void
event_thread_exit(void *drcontext)
{
per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext);
char msg[512];
int len;
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"Thread %d exited - ", dr_get_thread_id(drcontext));
DR_ASSERT(len > 0);
NULL_TERMINATE(msg);
/* display thread private counts data */
display_results(data, msg);
/* clean up memory */
dr_thread_free(drcontext, data, sizeof(per_thread_t));
}
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;
#ifdef VERBOSE
dr_printf("in dynamorio_basic_block(tag="PFX")\n", tag);
# ifdef VERBOSE_VERBOSE
instrlist_disassemble(drcontext, tag, bb, STDOUT);
# endif
#endif
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));
}
}
#if defined(VERBOSE) && defined(VERBOSE_VERBOSE)
dr_printf("Finished instrumenting dynamorio_basic_block(tag="PFX")\n", tag);
instrlist_disassemble(drcontext, tag, bb, STDOUT);
#endif
return DR_EMIT_DEFAULT;
}
+118
View File
@@ -0,0 +1,118 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
/* Counts the number of dynamic div instruction for which the
* divisor is a power of 2 (these are cases where div could be
* strength reduced to a simple shift). Demonstrates callout
* based profiling with live operand values. */
#include "dr_api.h"
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
#endif
#define NULL_TERMINATE(buf) buf[(sizeof(buf)/sizeof(buf[0])) - 1] = '\0'
static dr_emit_flags_t bb_event(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
static void exit_event(void);
static int div_count = 0, div_p2_count = 0;
static void *count_mutex; /* for multithread support */
DR_EXPORT void
dr_init(client_id_t id)
{
dr_register_exit_event(exit_event);
dr_register_bb_event(bb_event);
count_mutex = dr_mutex_create();
}
static void
exit_event(void)
{
#ifdef SHOW_RESULTS
char msg[512];
int len;
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"Instrumentation results:\n"
" saw %d div instructions\n"
" of which %d were powers of 2\n",
div_count, div_p2_count);
DR_ASSERT(len > 0);
NULL_TERMINATE(msg);
DISPLAY_STRING(msg);
#endif /* SHOW_RESULTS */
dr_mutex_destroy(count_mutex);
}
static void
callback(app_pc addr, uint divisor)
{
/* instead of a lock could use atomic operations to
* increment the counters */
dr_mutex_lock(count_mutex);
div_count++;
/* check for power of 2 */
if (divisor & (divisor - 1) != 0)
div_p2_count++;
dr_mutex_unlock(count_mutex);
}
static dr_emit_flags_t
bb_event(void* drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
instr_t *instr, *next_instr;
int opcode;
for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
next_instr = instr_get_next(instr);
opcode = instr_get_opcode(instr);
/* if find div, insert a clean call to our instrumentation routine */
if (opcode == OP_div) {
dr_insert_clean_call(drcontext, bb, instr, (void *)callback,
false /*no fp save*/, 2,
OPND_CREATE_INTPTR(instr_get_app_pc(instr)),
instr_get_src(instr, 0) /*divisor is 1st src*/);
}
}
return DR_EMIT_DEFAULT;
}
+55
View File
@@ -0,0 +1,55 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
/* Code Manipulation API Sample:
* empty.c
*
* Serves as an example of an empty client that does nothing but
* register for the exit event.
*/
#include "dr_api.h"
static void event_exit(void);
DR_EXPORT void
dr_init(client_id_t id)
{
/* empty client */
dr_register_exit_event(event_exit);
}
static void
event_exit(void)
{
/* empty client */
}
+214
View File
@@ -0,0 +1,214 @@
/* **********************************************************
* Copyright (c) 2002-2008 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.
*/
/* Code Manipulation API Sample:
* inc2add.c
*
* Performs a dynamic optimization: converts the "inc" instruction to
* "add 1" whenever worthwhile and feasible without perturbing the
* target application's behavior. Illustrates a
* microarchitecture-specific optimization best performed at runtime
* when the underlying processor is known.
*/
#include "dr_api.h"
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
# define ATOMIC_INC(var) _InterlockedIncrement(&var)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
# define ATOMIC_INC(var) __asm__ __volatile__("lock incl %0" : "=m" (var) : : "memory")
#endif
static bool enable;
/* use atomic operations to increment these to avoid the hassle of locking. */
static int num_examined, num_converted;
/* replaces inc with add 1, dec with sub 1
* returns true if successful, false if not
*/
static bool
replace_inc_with_add(void *drcontext, instr_t *inst, instrlist_t *trace);
static dr_emit_flags_t
event_trace(void *drcontext, void *tag, instrlist_t *trace, bool translating);
static void
event_exit(void);
DR_EXPORT void
dr_init(client_id_t id)
{
dr_register_exit_event(event_exit);
dr_register_trace_event(event_trace);
/* this optimization is only worthwhile on the Pentium 4, where
* an add of 1 is faster than an inc
*/
enable = (proc_get_family() == FAMILY_PENTIUM_4);
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, LOG_ALL, 1, "Client 'inc2add' initializing\n");
#ifdef SHOW_RESULTS
/* also give notification to stderr */
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client inc2add is running\n");
#endif
/* initialize our global variables */
num_examined = 0;
num_converted = 0;
}
static void
event_exit(void)
{
#ifdef SHOW_RESULTS
char msg[256];
int len;
if (enable) {
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"converted %d out of %d inc/dec to add/sub\n",
num_converted, num_examined);
} else {
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"decided to keep all original inc/dec\n");
}
DR_ASSERT(len > 0);
msg[sizeof(msg)/sizeof(msg[0])-1] = '\0';
DISPLAY_STRING(msg);
#endif /* SHOW_RESULTS */
}
/* replaces all inc with add 1, dec with sub 1
* if cannot replace (eflags constraints), leaves original instruction alone
*/
static dr_emit_flags_t
event_trace(void *drcontext, void *tag, instrlist_t *trace, bool translating)
{
instr_t *instr, *next_instr;
int opcode;
if (!enable)
return DR_EMIT_DEFAULT;
#ifdef VERBOSE
dr_printf("in dynamorio_trace(tag="PFX")\n", tag);
instrlist_disassemble(drcontext, tag, trace, STDOUT);
#endif
for (instr = instrlist_first(trace); instr != NULL; instr = next_instr) {
/* grab next now so we don't go over instructions we insert */
next_instr = instr_get_next(instr);
opcode = instr_get_opcode(instr);
if (opcode == OP_inc || opcode == OP_dec) {
if (!translating)
ATOMIC_INC(num_examined);
if (replace_inc_with_add(drcontext, instr, trace)) {
if (!translating)
ATOMIC_INC(num_converted);
}
}
}
#ifdef VERBOSE
dr_printf("after dynamorio_trace(tag="PFX"):\n", tag);
instrlist_disassemble(drcontext, tag, trace, STDOUT);
#endif
return DR_EMIT_DEFAULT;
}
/* replaces inc with add 1, dec with sub 1
* returns true if successful, false if not
*/
static bool
replace_inc_with_add(void *drcontext, instr_t *instr, instrlist_t *trace)
{
instr_t *in;
uint eflags;
int opcode = instr_get_opcode(instr);
bool ok_to_replace = false;
DR_ASSERT(opcode == OP_inc || opcode == OP_dec);
#ifdef VERBOSE
dr_print_instr(drcontext, STDOUT, instr, "in replace_inc_with_add:\n\t");
#endif
/* add/sub writes CF, inc/dec does not, make sure that's ok */
for (in = instr; in != NULL; in = instr_get_next(in)) {
eflags = instr_get_eflags(in);
if ((eflags & EFLAGS_READ_CF) != 0) {
#ifdef VERBOSE
dr_print_instr(drcontext, STDOUT, in,
"\treads CF => cannot replace inc with add: ");
#endif
return false;
}
if (instr_is_exit_cti(in)) {
/* to be more sophisticated, examine instructions at
* target of exit cti (if it is a direct branch).
* for this example, we give up if we hit a branch.
*/
return false;
}
/* if writes but doesn't read, ok */
if ((eflags & EFLAGS_WRITE_CF) != 0) {
ok_to_replace = true;
break;
}
}
if (!ok_to_replace) {
#ifdef VERBOSE
dr_printf("\tno write to CF => cannot replace inc with add\n");
#endif
return false;
}
if (opcode == OP_inc) {
#ifdef VERBOSE
dr_printf("\treplacing inc with add\n");
#endif
in = INSTR_CREATE_add(drcontext, instr_get_dst(instr, 0),
OPND_CREATE_INT8(1));
} else {
#ifdef VERBOSE
dr_printf("\treplacing dec with sub\n");
#endif
in = INSTR_CREATE_sub(drcontext, instr_get_dst(instr, 0),
OPND_CREATE_INT8(1));
}
if (instr_get_prefix_flag(instr, PREFIX_LOCK))
instr_set_prefix_flag(in, PREFIX_LOCK);
instr_set_translation(in, instr_get_app_pc(instr));
instrlist_replace(trace, instr, in);
instr_destroy(drcontext, instr);
return true;
}
+361
View File
@@ -0,0 +1,361 @@
/* **********************************************************
* Copyright (c) 2003-2008 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.
*/
/* Code Manipulation API Sample:
* trace-inline.c
*
* Uses the custom trace API to inline entire callees into traces.
*/
#include "dr_api.h"
#include <string.h> /* memset */
#define VERBOSE 1
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
#endif
/****************************************************************************/
/* global */
#ifdef SHOW_RESULTS
static int num_complete_inlines;
#endif
static void *htable_mutex; /* for multithread support */
static void event_exit(void);
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
static void event_fragment_deleted(void *drcontext, void *tag);
static dr_custom_trace_action_t
query_end_trace(void *drcontext, void * trace_tag, void *next_tag);
/****************************************************************************/
/* hashtable so we know if a particular tag is for a call trace or a
* normal back branch trace
*/
typedef struct _trace_head_entry_t {
void *tag;
bool is_trace_head;
bool has_ret;
/* have to end at next block after see return */
int end_next;
/* some callees are too large to inline, so have size limit */
uint size;
struct _trace_head_entry_t *next;
} trace_head_entry_t;
/* global table */
static trace_head_entry_t **htable;
/* max call-trace size */
#define INLINE_SIZE_LIMIT (4*1024)
/* no instruction alignment -> use the lsb! */
#define HASH_MASK(num_bits) ((~0U)>>(32-(num_bits)))
#define HASH_FUNC_BITS(val, num_bits) ((val) & (HASH_MASK(num_bits)))
#define HASH_FUNC(val, mask) ((val) & (mask))
#define HASHTABLE_SIZE(num_bits) (1U << (num_bits))
#define HASH_BITS 13
#define TABLE_SIZE HASHTABLE_SIZE(HASH_BITS) * sizeof(trace_head_entry_t*)
/* if drcontext == NULL uses global memory */
static trace_head_entry_t **
htable_create(void *drcontext)
{
trace_head_entry_t **table = (trace_head_entry_t**) dr_global_alloc(TABLE_SIZE);
/* assume during process init so no lock needed */
memset(table, 0, TABLE_SIZE);
return table;
}
/* if drcontext == NULL uses global memory */
static void
htable_free(void *drcontext, trace_head_entry_t **table)
{
/* assume during process exit so no lock needed */
int i;
/* clean up memory */
for (i = 0; i < HASHTABLE_SIZE(HASH_BITS); i++) {
trace_head_entry_t *e = table[i];
while (e) {
trace_head_entry_t *nexte = e->next;
dr_global_free(e, sizeof(trace_head_entry_t));
e = nexte;
}
table[i] = NULL;
}
dr_global_free(table, TABLE_SIZE);
}
/* Caller must hold htable_mutex if drcontext == NULL. */
static trace_head_entry_t *
add_trace_head_entry(void *drcontext, void *tag)
{
trace_head_entry_t **table = htable;
trace_head_entry_t *e;
uint hindex;
e = (trace_head_entry_t *) dr_global_alloc(sizeof(trace_head_entry_t));
e->tag = tag;
e->end_next = 0;
e->size = 0;
e->has_ret = false;
e->is_trace_head = false;
/* we assume we're masking away top 32 bits for 64-bit, so cast here */
hindex = HASH_FUNC_BITS((uint)(ptr_uint_t)tag, HASH_BITS);
e->next = table[hindex];
table[hindex] = e;
return e;
}
/* Lookup an entry by pc and return a pointer to the corresponding entry .
* Returns NULL if no such entry exists.
* Caller must hold htable_mutex if drcontext == NULL.
*/
static trace_head_entry_t *
lookup_trace_head_entry(void *drcontext, void *tag)
{
trace_head_entry_t **table = htable;
trace_head_entry_t *e;
uint hindex;
/* we assume we're masking away top 32 bits for 64-bit, so cast here */
hindex = HASH_FUNC_BITS((uint)(ptr_uint_t)tag, HASH_BITS);
for (e = table[hindex]; e; e = e->next) {
if (e->tag == tag)
return e;
}
return NULL;
}
/* Lookup an entry by tag and index and delete it.
* Returns false if no such entry exists.
* Caller must hold htable_mutex if drcontext == NULL.
*/
static bool
remove_trace_head_entry(void *drcontext, void *tag)
{
trace_head_entry_t **table = htable;
trace_head_entry_t *e, *prev;
uint hindex;
/* we assume we're masking away top 32 bits for 64-bit, so cast here */
hindex = HASH_FUNC_BITS((uint)(ptr_uint_t)tag, HASH_BITS);
for (prev = NULL, e = table[hindex]; e; prev = e, e = e->next) {
if (e->tag == tag) {
if (prev)
prev->next = e->next;
else
table[hindex] = e->next;
dr_global_free(e, sizeof(trace_head_entry_t));
return true;
}
}
return false;
}
/****************************************************************************/
DR_EXPORT void
dr_init(client_id_t id)
{
htable_mutex = dr_mutex_create();
/* global HASH_BITS-bit addressed hash table */
htable = htable_create(NULL/*global*/);
dr_register_exit_event(event_exit);
dr_register_bb_event(event_basic_block);
dr_register_delete_event(event_fragment_deleted);
dr_register_end_trace_event(query_end_trace);
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, LOG_ALL, 1, "Client 'inline' initializing\n");
#ifdef SHOW_RESULTS
/* also give notification to stderr */
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client inline is running\n");
num_complete_inlines = 0;
#endif
}
static void
event_exit(void)
{
#ifdef SHOW_RESULTS
/* display the results */
char msg[512];
int len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"Inlining results:\n"
" Number of complete inlines: %d\n", num_complete_inlines);
DR_ASSERT(len > 0);
msg[sizeof(msg)/sizeof(msg[0])-1] = '\0';
DISPLAY_STRING(msg);
#endif
htable_free(NULL/*global*/, htable);
dr_mutex_destroy(htable_mutex);
}
/****************************************************************************/
/* the work itself */
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating)
{
instr_t *instr;
trace_head_entry_t *e = NULL;
if (translating)
return DR_EMIT_DEFAULT;
for (instr = instrlist_first(bb); instr != NULL; instr = instr_get_next(instr)) {
/* blocks containing calls are trace heads */
if (instr_is_call(instr)) {
dr_mark_trace_head(drcontext, tag);
dr_mutex_lock(htable_mutex);
e = add_trace_head_entry(NULL, tag);
e->is_trace_head = true;
dr_mutex_unlock(htable_mutex);
#ifdef VERBOSE
dr_log(drcontext, LOG_ALL, 3,
"inline: marking bb "PFX" as trace head\n", tag);
#endif
/* doesn't matter what's in rest of bb */
return DR_EMIT_DEFAULT;
} else if (instr_is_return(instr)) {
dr_mutex_lock(htable_mutex);
e = add_trace_head_entry(NULL, tag);
e->has_ret = true;
dr_mutex_unlock(htable_mutex);
}
}
return DR_EMIT_DEFAULT;
}
/* to keep the size of our hashtable down */
static void
event_fragment_deleted(void *drcontext, void *tag)
{
dr_mutex_lock(htable_mutex);
remove_trace_head_entry(NULL, tag);
dr_mutex_unlock(htable_mutex);
}
/* Ask whether to end trace prior to adding next_tag fragment.
* Return values:
* CUSTOM_TRACE_DR_DECIDES = use standard termination criteria
* CUSTOM_TRACE_END_NOW = end trace
* CUSTOM_TRACE_CONTINUE = do not end trace
*/
static dr_custom_trace_action_t
query_end_trace(void *drcontext, void *trace_tag, void *next_tag)
{
/* if this is a call trace, only end on the block AFTER a return
* (need to get the return inlined!)
* if this is a standard back branch trace, end it if we see a
* block with a call (so that we'll go into the call trace).
* otherwise return 0 and let DynamoRIO determine whether to
* terminate the trace now.
*/
trace_head_entry_t *e;
dr_mutex_lock(htable_mutex);
e = lookup_trace_head_entry(NULL, trace_tag);
if (e == NULL || !e->is_trace_head) {
e = lookup_trace_head_entry(NULL, next_tag);
if (e == NULL || !e->is_trace_head) {
dr_mutex_unlock(htable_mutex);
return CUSTOM_TRACE_DR_DECIDES;
} else {
/* we've found a call, end this trace now so it won't keep going and
* end up never entering the call trace
*/
#ifdef VERBOSE
dr_log(drcontext, LOG_ALL, 3,
"inline: ending trace "PFX" before block "PFX" containing call\n",
trace_tag, next_tag);
#endif
dr_mutex_unlock(htable_mutex);
return CUSTOM_TRACE_END_NOW;
}
} else if (e->end_next > 0) {
e->end_next--;
if (e->end_next == 0) {
#ifdef VERBOSE
dr_log(drcontext, LOG_ALL, 3,
"inline: ending trace "PFX" before "PFX"\n",
trace_tag, next_tag);
#endif
#ifdef SHOW_RESULTS
num_complete_inlines++;
#endif
dr_mutex_unlock(htable_mutex);
return CUSTOM_TRACE_END_NOW;
}
} else {
trace_head_entry_t *nxte = lookup_trace_head_entry(NULL, next_tag);
uint size = dr_fragment_size(drcontext, next_tag);
e->size += size;
if (e->size > INLINE_SIZE_LIMIT) {
#ifdef VERBOSE
dr_log(drcontext, LOG_ALL, 3,
"inline: ending trace "PFX" before "PFX" because reached size limit\n",
trace_tag, next_tag);
#endif
dr_mutex_unlock(htable_mutex);
return CUSTOM_TRACE_END_NOW;
}
if (nxte != NULL && nxte->has_ret && !nxte->is_trace_head) {
/* end trace after NEXT block */
e->end_next = 2;
#ifdef VERBOSE
dr_log(drcontext, LOG_ALL, 3,
"inline: going to be ending trace "PFX" after "PFX"\n",
trace_tag, next_tag);
#endif
dr_mutex_unlock(htable_mutex);
return CUSTOM_TRACE_CONTINUE;
}
}
/* do not end trace */
#ifdef VERBOSE
dr_log(drcontext, LOG_ALL, 3,
"inline: NOT ending trace "PFX" after "PFX"\n", trace_tag, next_tag);
#endif
dr_mutex_unlock(htable_mutex);
return CUSTOM_TRACE_CONTINUE;
}
+163
View File
@@ -0,0 +1,163 @@
/* **********************************************************
* Copyright (c) 2002-2008 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.
*/
/* Code Manipulation API Sample:
* instrcalls.c
*
* Instruments direct calls, indirect calls, and returns in the target
* application. For each dynamic execution, the call target and other
* key information is written to a log file. Note that this log file
* can become quite large, and this client incurs more overhead than
* the other clients due to its log file.
*/
#include "dr_api.h"
static void event_thread_init(void *drcontext);
static void event_thread_exit(void *drcontext);
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
static client_id_t my_id;
DR_EXPORT void
dr_init(client_id_t id)
{
my_id = id;
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, LOG_ALL, 1, "Client 'instrcalls' initializing\n");
/* also give notification to stderr */
#ifdef SHOW_RESULTS
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client instrcalls is running\n");
#endif
dr_register_bb_event(event_basic_block);
dr_register_thread_init_event(event_thread_init);
dr_register_thread_exit_event(event_thread_exit);
}
#ifdef WINDOWS
# define DIRSEP '\\'
#else
# define DIRSEP '/'
#endif
static void
event_thread_init(void *drcontext)
{
file_t f;
char logname[512];
char *dirsep;
int len;
/* We're going to dump our data to a per-thread file.
* On Windows we need an absolute path so we place it in
* the same directory as our library. We could also pass
* in a path and retrieve with dr_get_options().
*/
len = snprintf(logname, sizeof(logname)/sizeof(logname[0]),
"%s", dr_get_client_path(my_id));
DR_ASSERT(len > 0);
for (dirsep = logname + len; *dirsep != DIRSEP; dirsep--)
DR_ASSERT(dirsep > logname);
len = snprintf(dirsep + 1, (sizeof(logname) - (dirsep - logname))/sizeof(logname[0]),
"instrcalls.%d.log", dr_get_thread_id(drcontext));
DR_ASSERT(len > 0);
logname[sizeof(logname)/sizeof(logname[0])-1] = '\0';
f = dr_open_file(logname, DR_FILE_WRITE_OVERWRITE);
DR_ASSERT(f != INVALID_FILE);
/* store it in the slot provided in the drcontext */
dr_set_tls_field(drcontext, (void *)(ptr_uint_t)f);
dr_log(drcontext, LOG_ALL, 1,
"instrcalls: log for thread %d is instrcalls.%03d\n",
dr_get_thread_id(drcontext), dr_get_thread_id(drcontext));
}
static void
event_thread_exit(void *drcontext)
{
file_t f = (file_t)(ptr_uint_t) dr_get_tls_field(drcontext);
dr_close_file(f);
}
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);
}
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;
#ifdef VERBOSE
dr_printf("in dr_basic_block(tag="PFX")\n", tag);
# if VERBOSE_VERBOSE
instrlist_disassemble(drcontext, tag, bb, STDOUT);
# endif
#endif
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;
}
+102
View File
@@ -0,0 +1,102 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
/* Code Manipulation API Sample:
* prefetch.c
*
* Performs a code-stream compatibility modification. Programs optimized for AMD
* processors are likely to use the prefetch and prefetchw instructions (originally
* added as part of the 3D!now extensions). However, these opcodes cause illegal
* instruction faults on most Intel processors. Here we detect if we are on an Intel
* processor and translate (in this case remove) prefetch instructions so the app can
* run.
*/
#include "dr_api.h"
static void event_exit(void);
static dr_emit_flags_t event_bb(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
static void *count_mutex; /* for multithread support */
static int prefetches_removed = 0, prefetchws_removed = 0;
DR_EXPORT void
dr_init(client_id_t id)
{
dr_register_exit_event(event_exit);
/* Only need to remove prefetches for Intel processors. */
if (proc_get_vendor() == VENDOR_INTEL) {
dr_register_bb_event(event_bb);
}
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, LOG_ALL, 1, "Client 'prefetch' initializing\n");
/* must create the counting mutex */
count_mutex = dr_mutex_create();
}
static void
event_exit(void)
{
dr_log(NULL, LOG_ALL, 1, "Removed %d prefetches and %d prefetchws.\n",
prefetches_removed, prefetchws_removed);
dr_mutex_destroy(count_mutex);
}
static dr_emit_flags_t
event_bb(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating)
{
instr_t *instr, *next_instr;
int opcode;
/* look for and remove prefetch[w] instructions */
for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
next_instr = instr_get_next(instr);
opcode = instr_get_opcode(instr);
if (opcode == OP_prefetch || opcode == OP_prefetchw) {
instrlist_remove(bb, instr);
instr_destroy(drcontext, instr);
if (!translating) {
/* count_mutex protects the counter values */
dr_mutex_lock(count_mutex);
if (opcode == OP_prefetch)
prefetches_removed++;
else
prefetchws_removed++;
dr_mutex_unlock(count_mutex);
}
}
}
return DR_EMIT_DEFAULT;
}
+106
View File
@@ -0,0 +1,106 @@
/* **********************************************************
* Copyright (c) 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.
*/
/* Code Manipulation API Sample:
* signal.c
*
* Monitors application signals.
*/
#include "dr_api.h"
#include <signal.h>
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
# define ATOMIC_INC(var) _InterlockedIncrement(&var)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
# define ATOMIC_INC(var) __asm__ __volatile__("lock incl %0" : "=m" (var) : : "memory")
#endif
static int num_signals;
static void event_exit(void);
#ifdef LINUX
static dr_signal_action_t event_signal(void *drcontext, dr_siginfo_t *info);
#endif
DR_EXPORT void
dr_init(client_id_t id)
{
#ifdef LINUX
dr_register_signal_event(event_signal);
#endif
dr_register_exit_event(event_exit);
#ifdef SHOW_RESULTS
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client signal is running\n");
#endif
}
static void
event_exit(void)
{
#ifdef SHOW_RESULTS
char msg[512];
int len;
/* Note that using %f with dr_printf or dr_fprintf on Windows will print
* garbage as they use ntdll._vsnprintf, so we must use snprintf.
*/
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"<Number of signals seen: %d>", num_signals);
DR_ASSERT(len > 0);
msg[sizeof(msg)/sizeof(msg[0])-1] = '\0';
DISPLAY_STRING(msg);
#endif /* SHOW_RESULTS */
}
#ifdef LINUX
static
dr_signal_action_t event_signal(void *drcontext, dr_siginfo_t *info)
{
ATOMIC_INC(num_signals);
if (info->sig == SIGTERM) {
/* Ignore TERM */
return DR_SIGNAL_SUPPRESS;
} else if (info->sig == SIGSEGV) {
/* Skip the faulting instruction. This is a sample only! */
app_pc pc = decode_next_pc(drcontext, info->mcontext.xip);
if (pc != NULL)
info->mcontext.xip = pc;
return DR_SIGNAL_REDIRECT;
}
return DR_SIGNAL_DELIVER;
}
#endif
+657
View File
@@ -0,0 +1,657 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
/* Code Manipulation API Sample:
* stats.c
*
* Serves as an example of how to create custom statistics and export
* them in shared memory (without using any Windows API libraries, and
* thus remaining transparent). These statistics can be viewed using
* the provided statistics viewer. This code also documents the
* official shared memory layout required by the statistics viewer.
*/
#include "dr_api.h"
#include <stddef.h> /* for offsetof */
#ifndef WINDOWS
# error WINDOWS-only!
#endif
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
#endif
/* We export a set of stats in shared memory.
* drgui.exe reads and displays them.
*/
const char *stat_names[] = {
/* drgui.exe displays CLIENTSTAT_NAME_MAX_LEN chars for each name */
"Instructions",
"Floating point instrs",
"System calls",
};
/* Be sure to prefix "Global\" to ensure this is visible across sessions,
* except on NT where Global\ is not supported.
*/
#define CLIENT_SHMEM_KEY_NT_L L"DynamoRIO_Client_Statistics"
#define CLIENT_SHMEM_KEY_L L"Global\\DynamoRIO_Client_Statistics"
#define CLIENTSTAT_NAME_MAX_LEN 50
#define NUM_STATS (sizeof(stat_names)/sizeof(char*))
/* Statistics are all 64-bit for x64. At some point we'll add per-stat
* typing, but for now we have identical types dependent on the platform.
*/
#ifdef X86_64
# error Statistics sample and graphical viewer are not yet supported for 64-bit
typedef int64 stats_int_t;
# define STAT_FORMAT_CODE UINT64_FORMAT_CODE
#else
typedef int stats_int_t;
# define STAT_FORMAT_CODE "d"
#endif
/* we allocate this struct in the shared memory: */
typedef struct _client_stats {
uint num_stats;
bool exited;
uint pid;
/* we need a copy of all the names here */
char names[NUM_STATS][CLIENTSTAT_NAME_MAX_LEN];
stats_int_t num_instrs;
stats_int_t num_flops;
stats_int_t num_syscalls;
} client_stats;
/* we directly increment the global counters using a lock prefix */
static client_stats *stats;
/***************************************************************************/
/* shared memory setup */
/* we have multiple shared memories: one that holds the count of
* statistics instances, and then one per statistics struct */
static HANDLE shared_map_count;
static PVOID shared_view_count;
static int * shared_count;
static HANDLE shared_map;
static PVOID shared_view;
#define KEYNAME_MAXLEN 128
static wchar_t shared_keyname[KEYNAME_MAXLEN];
/* returns current contents of addr and replaces contents with value */
static __declspec(naked) /* no prolog/epilog */
uint
atomic_swap(void *addr, uint value)
{
__asm {
/* cl was using ebp even though naked so we hand-code param access */
mov eax, dword ptr [esp+8] /* value */
mov ecx, dword ptr [esp+4] /* addr */
xchg (ecx), eax
ret
}
}
typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) ((Status) >= 0)
#define NT_CURRENT_PROCESS ( (HANDLE) -1 )
#define NT_CURRENT_THREAD ( (HANDLE) -2 )
/* from DDK2003SP1/3790.1830/inc/wnet/ntdef.h */
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define OBJ_OPENIF 0x00000080L
typedef struct _UNICODE_STRING {
/* Length field is size in bytes not counting final 0 */
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef struct _STRING {
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} ANSI_STRING;
typedef ANSI_STRING *PANSI_STRING;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PSECURITY_DESCRIPTOR SecurityDescriptor;
PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
#define InitializeObjectAttributes( p, n, a, r, s ) { \
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
/* from ntddk.h */
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT;
#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF)
#define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L)
#define GET_NTDLL(NtFunction, signature) NTSYSAPI NTSTATUS NTAPI NtFunction signature
GET_NTDLL(NtCreateSection, (OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PLARGE_INTEGER SectionSize OPTIONAL,
IN ULONG Protect,
IN ULONG Attributes,
IN HANDLE FileHandle));
GET_NTDLL(NtMapViewOfSection, (IN HANDLE SectionHandle,
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN SIZE_T CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PSIZE_T ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect));
GET_NTDLL(NtUnmapViewOfSection, (IN HANDLE ProcessHandle,
IN PVOID BaseAddress));
GET_NTDLL(NtOpenDirectoryObject, (PHANDLE, ACCESS_MASK ,POBJECT_ATTRIBUTES));
typedef struct _PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
BOOLEAN Spare;
HANDLE Mutant;
PVOID ImageBaseAddress;
PVOID LoaderData;
PVOID ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PVOID FastPebLockRoutine;
PVOID FastPebUnlockRoutine;
ULONG EnvironmentUpdateCount;
PVOID KernelCallbackTable;
PVOID EventLogSection;
PVOID EventLog;
PVOID FreeList;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[0x2];
PVOID ReadOnlySharedMemoryBase;
PVOID ReadOnlySharedMemoryHeap;
PVOID ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
BYTE Spare2[0x4];
LARGE_INTEGER CriticalSectionTimeout;
ULONG HeapSegmentReserve;
ULONG HeapSegmentCommit;
ULONG HeapDeCommitTotalFreeThreshold;
ULONG HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID *ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
PVOID GdiDCAttributeList;
PRTL_CRITICAL_SECTION LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
ULONG OSBuildNumber;
ULONG OSPlatformId;
// ...
} PEB;
typedef struct _TEB {
PVOID /* PEXCEPTION_REGISTRATION_RECORD */ ExceptionList;
PVOID StackUserTop;
PVOID StackUserBase;
PVOID SubSystemTib;
ULONG FiberData;
PVOID ArbitraryUser;
struct _TEB *Self;
DWORD EnvironmentPtr;
DWORD ProcessID;
DWORD ThreadID;
DWORD RpcHandle;
PVOID* TLSArray;
PEB* PEBPtr;
DWORD LastErrorValue;
// ...
} TEB;
TEB *
get_TEB(void)
{
return (TEB *) __readfsdword(offsetof(TEB, Self));
}
static uint
getpid(void)
{
return get_TEB()->ProcessID;
}
static int
get_last_error(void)
{
/* RtlGetLastWin32Error is only available on XP+? */
return get_TEB()->LastErrorValue;
}
static void
set_last_error(int val)
{
get_TEB()->LastErrorValue = val;
}
static NTSTATUS
wchar_to_unicode(PUNICODE_STRING dst, PCWSTR src)
{
NTSTATUS res;
GET_NTDLL(RtlInitUnicodeString, (IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString));
res = RtlInitUnicodeString(dst, src);
return res;
}
static bool
is_windows_NT(void)
{
PEB *peb = get_TEB()->PEBPtr;
DR_ASSERT(peb != NULL);
return (peb->OSPlatformId == VER_PLATFORM_WIN32_NT && peb->OSMajorVersion == 4);
}
static HANDLE
get_BNO_handle(void)
{
NTSTATUS res;
HANDLE h;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING name_unicode;
res = wchar_to_unicode(&name_unicode, L"\\BaseNamedObjects");
DR_ASSERT(NT_SUCCESS(res));
InitializeObjectAttributes(&oa, &name_unicode, OBJ_CASE_INSENSITIVE, NULL, NULL);
res = NtOpenDirectoryObject(&h, DIRECTORY_ALL_ACCESS &
~(DELETE | WRITE_DAC | WRITE_OWNER),
&oa);
DR_ASSERT(NT_SUCCESS(res));
return h;
}
static HANDLE
my_CreateFileMappingW(HANDLE file, SECURITY_ATTRIBUTES *attrb,
uint prot, uint size_high, uint size_low, wchar_t *name)
{
NTSTATUS res;
HANDLE section;
UNICODE_STRING section_name_unicode;
OBJECT_ATTRIBUTES section_attributes;
uint access;
LARGE_INTEGER li_size;
li_size.HighPart = size_high;
li_size.LowPart = size_low;
DR_ASSERT(name != NULL);
res = wchar_to_unicode(&section_name_unicode, name);
DR_ASSERT(NT_SUCCESS(res));
if (!NT_SUCCESS(res))
return NULL;
if (file == INVALID_HANDLE_VALUE) {
DR_ASSERT(size_high != 0 || size_low != 0);
file = NULL;
}
/* we ignore dacl for now */
InitializeObjectAttributes(&section_attributes, &section_name_unicode,
OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
get_BNO_handle(), NULL);
access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
if (prot == PAGE_READWRITE)
access |= (SECTION_MAP_WRITE | SECTION_MAP_READ);
res = NtCreateSection(&section, access,
&section_attributes,
(size_high == 0 && size_low == 0) ? NULL /* entire file */
: &li_size,
prot, SEC_COMMIT, file);
if (!NT_SUCCESS(res)) {
dr_fprintf(STDERR, "Error in my_CreateFileMappingW: "PFX"\n", res);
DR_ASSERT(false);
return NULL;
}
if (res == STATUS_OBJECT_NAME_EXISTS) {
set_last_error(ERROR_ALREADY_EXISTS);
} else
set_last_error(ERROR_SUCCESS);
return section;
}
static void *
my_MapViewOfFile(HANDLE section, uint file_prot, uint offs_high, uint offs_low,
size_t size)
{
NTSTATUS res;
void *map = NULL;
uint prot;
LARGE_INTEGER li_offs;
li_offs.HighPart = offs_high;
li_offs.LowPart = offs_low;
/* convert FILE_ flags to PAGE_ flags */
if ((file_prot & FILE_MAP_WRITE) != 0)
prot = PAGE_READWRITE;
else if ((file_prot & FILE_MAP_READ) != 0)
prot = PAGE_READONLY;
else if ((file_prot & FILE_MAP_COPY) != 0)
prot = PAGE_WRITECOPY;
else
prot = PAGE_NOACCESS;
res = NtMapViewOfSection(section, NT_CURRENT_PROCESS, &map, 0,
0 /* no commit */, &li_offs, (PSIZE_T) &size,
ViewUnmap, 0, prot);
if (!NT_SUCCESS(res)) {
dr_fprintf(STDERR, "Error in my_CreateFileMappingW: "PFX"\n", res);
DR_ASSERT(false);
return NULL;
}
return map;
}
static void
my_UnmapViewOfFile(HANDLE base)
{
NTSTATUS res = NtUnmapViewOfSection(NT_CURRENT_PROCESS, base);
DR_ASSERT(NT_SUCCESS(res));
}
static client_stats *
shared_memory_init(void)
{
bool is_NT = is_windows_NT();
int num;
int pos;
SECURITY_ATTRIBUTES attrb;
SECURITY_DESCRIPTOR descrip;
SECURITY_DESCRIPTOR_CONTROL sd_control = SE_DACL_PRESENT;
attrb.nLength = sizeof(SECURITY_ATTRIBUTES);
attrb.bInheritHandle = FALSE;
/* Set security descriptor by hand (WIN32 API routines to do so are
* in advapi). This may not be fully forward compatible.
*/
/* initialize the descriptor */
memset(&descrip, 0, sizeof(SECURITY_DESCRIPTOR));
/* Set the dacl present flag. DACL will be NULL from memset which is as
* desired since will give full acccess to everyone: security
* is not a concern for these stats.
*/
descrip.Control = sd_control;
/* set revision appropriately */
descrip.Revision = SECURITY_DESCRIPTOR_REVISION;
attrb.lpSecurityDescriptor = &descrip;
/* We do not want to rely on the registry.
* Instead, a piece of shared memory with the key base name holds the
* total number of stats instances.
*/
shared_map_count =
my_CreateFileMappingW(INVALID_HANDLE_VALUE, &attrb,
PAGE_READWRITE, 0, sizeof(client_stats),
is_NT ? CLIENT_SHMEM_KEY_NT_L : CLIENT_SHMEM_KEY_L);
DR_ASSERT(shared_map_count != NULL);
shared_view_count =
my_MapViewOfFile(shared_map_count, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 0);
DR_ASSERT(shared_view_count != NULL);
shared_count = (int *) shared_view_count;
/* ASSUMPTION: memory is initialized to 0!
* otherwise our protocol won't work
* it's hard to build a protocol to initialize it to 0 -- if you want
* to add one, feel free, but make sure it's correct
*/
do {
pos = (int) atomic_swap(shared_count, (uint) -1);
/* if get -1 back, someone else is looking at it */
} while (pos == -1);
/* now increment it */
atomic_swap(shared_count, pos+1);
num = 0;
while (1) {
_snwprintf(shared_keyname, KEYNAME_MAXLEN, L"%s.%03d",
is_NT ? CLIENT_SHMEM_KEY_NT_L : CLIENT_SHMEM_KEY_L, num);
shared_map = my_CreateFileMappingW(INVALID_HANDLE_VALUE, &attrb,
PAGE_READWRITE, 0,
sizeof(client_stats),
shared_keyname);
if (shared_map != NULL && get_last_error() == ERROR_ALREADY_EXISTS) {
dr_close_file(shared_map);
shared_map = NULL;
}
if (shared_map != NULL)
break;
num++;
}
dr_log(NULL, LOG_ALL, 1, "Shared memory key is: \"%S\"\n", shared_keyname);
dr_fprintf(STDERR, "Shared memory key is: \"%S\"\n", shared_keyname);
shared_view = my_MapViewOfFile(shared_map, FILE_MAP_READ|FILE_MAP_WRITE,
0, 0, 0);
DR_ASSERT(shared_view != NULL);
return (client_stats *) shared_view;
}
static void
shared_memory_exit(void)
{
int pos;
stats->exited = true;
/* close down statistics */
my_UnmapViewOfFile(shared_view);
dr_close_file(shared_map);
/* decrement count, then unmap */
do {
pos = atomic_swap(shared_count, (uint) -1);
/* if get -1 back, someone else is looking at it */
} while (pos == -1);
/* now increment it */
atomic_swap(shared_count, pos-1);
my_UnmapViewOfFile(shared_view_count);
dr_close_file(shared_map_count);
}
/***************************************************************************/
static void event_exit(void);
static dr_emit_flags_t event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating);
static client_id_t my_id;
DR_EXPORT void
dr_init(client_id_t id)
{
uint i;
my_id = id;
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, LOG_ALL, 1, "Client 'stats' initializing\n");
stats = shared_memory_init();
memset(stats, 0, sizeof(stats));
stats->num_stats = NUM_STATS;
stats->pid = getpid();
for (i=0; i<NUM_STATS; i++) {
strncpy(stats->names[i], stat_names[i], CLIENTSTAT_NAME_MAX_LEN);
stats->names[i][CLIENTSTAT_NAME_MAX_LEN-1] = '\0';
}
dr_register_bb_event(event_basic_block);
dr_register_exit_event(event_exit);
}
#ifdef WINDOWS
# define DIRSEP '\\'
#else
# define DIRSEP '/'
#endif
static void
event_exit(void)
{
file_t f;
/* display the results */
char msg[512];
char fname[512];
char *dirsep;
int len;
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"Instrumentation results:\n"
" saw %" STAT_FORMAT_CODE " flops\n", stats->num_flops);
DR_ASSERT(len > 0);
msg[sizeof(msg)/sizeof(msg[0])-1] = '\0';
#ifdef SHOW_RESULTS
DISPLAY_STRING(msg);
#endif /* SHOW_RESULTS */
/* On Windows we need an absolute path so we place it in
* the same directory as our library.
*/
len = snprintf(fname, sizeof(fname)/sizeof(fname[0]),
"%s", dr_get_client_path(my_id));
DR_ASSERT(len > 0);
for (dirsep = fname + len; *dirsep != DIRSEP; dirsep--)
DR_ASSERT(dirsep > fname);
len = snprintf(dirsep + 1, (sizeof(fname) - (dirsep - fname))/sizeof(fname[0]),
"stats.%d.log", dr_get_process_id());
DR_ASSERT(len > 0);
fname[sizeof(fname)/sizeof(fname[0])-1] = '\0';
f = dr_open_file(fname, DR_FILE_WRITE_OVERWRITE);
DR_ASSERT(f != INVALID_FILE);
dr_fprintf(f, "%s\n", msg);
dr_close_file(f);
shared_memory_exit();
}
static void
insert_inc(void *drcontext, instrlist_t *bb, instr_t *where,
stats_int_t *addr, uint incby)
{
instr_t *inc;
opnd_t immed;
/* FIXME: we're using stats_int_t, but our inc here does not support 64-bit */
if (incby <= 0x7f)
immed = OPND_CREATE_INT8(incby);
else /* unlikely but possible */
immed = OPND_CREATE_INT32(incby);
inc = INSTR_CREATE_add(drcontext, OPND_CREATE_MEM32(REG_NULL, (int)addr), immed);
/* make it thread-safe (only works if it doesn't straddle a cache line) */
instr_set_prefix_flag(inc, PREFIX_LOCK);
DR_ASSERT((((ptr_uint_t)addr) & 0x3) == 0); /* 4-aligned => single cache line */
instrlist_meta_preinsert(bb, where, inc);
}
static dr_emit_flags_t
event_basic_block(void *drcontext, void *tag, instrlist_t *bb,
bool for_trace, bool translating)
{
instr_t *instr;
int op;
int num_instrs = 0;
int num_flops = 0;
int num_syscalls = 0;
#ifdef VERBOSE
dr_printf("in dr_basic_block(tag="PFX")\n", tag);
# ifdef VERBOSE_VERBOSE
instrlist_disassemble(drcontext, tag, bb, STDOUT);
# endif
#endif
/* count up # flops, then do single increment at end */
for (instr = instrlist_first(bb); instr != NULL; instr = instr_get_next(instr)) {
num_instrs++;
op = instr_get_opcode(instr);
if (op >= OP_fadd && op <= OP_fcomip) {
/* FIXME: exclude loads and stores */
#ifdef VERBOSE
dr_print_instr(drcontext, STDOUT, instr, "Found flop: ");
#endif
num_flops++;
}
if (instr_is_syscall(instr)) {
num_syscalls++;
}
}
if (num_instrs > 0 || num_flops > 0 || num_syscalls > 0) {
uint eflags;
bool need_to_save = true;
/* insert increment at start, for maximum prob. of not needing
* to save flags
*/
for (instr = instrlist_first(bb); instr != NULL;
instr = instr_get_next(instr)) {
eflags = instr_get_eflags(instr);
/* could be more sophisticated and look beyond exit */
if (instr_is_exit_cti(instr) || (eflags & EFLAGS_READ_6) != 0)
break;
if ((eflags & EFLAGS_WRITE_6) == EFLAGS_WRITE_6) {
need_to_save = false;
break;
}
}
instr = instrlist_first(bb);
if (need_to_save)
dr_save_arith_flags(drcontext, bb, instr, SPILL_SLOT_1);
if (num_instrs > 0)
insert_inc(drcontext, bb, instr, &stats->num_instrs, num_instrs);
if (num_flops > 0)
insert_inc(drcontext, bb, instr, &stats->num_flops, num_flops);
if (num_syscalls > 0)
insert_inc(drcontext, bb, instr, &stats->num_syscalls, num_syscalls);
if (need_to_save)
dr_restore_arith_flags(drcontext, bb, instr, SPILL_SLOT_1);
}
return DR_EMIT_DEFAULT;
}
+131
View File
@@ -0,0 +1,131 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
/* C++ sample client:
* stl_test.cpp
*
* Some simple tests with C++ STL containers to make sure they
* work with a DR client.
*/
#include "dr_api.h"
#include <vector>
#include <list>
#include <map>
using namespace std;
DR_EXPORT void
dr_init(client_id_t client_id)
{
int i;
bool success = true;
//
// Put values in a vector and read them out
//
#ifdef SHOW_RESULTS
dr_printf("testing vector...");
#endif
vector<int>* v = new vector<int>();
for (i=0; i<5; i++) {
v->push_back(i);
}
for (i=0; i<5; i++) {
#ifdef SHOW_RESULTS
dr_printf("%d ", (*v)[i]);
#endif
if ((*v)[i] != i) {
success = false;
}
}
delete v;
//
// Put values in a list and read them out
//
#ifdef SHOW_RESULTS
dr_printf("\ntesting list...");
#endif
list<int> l;
for (i=0; i<5; i++) {
l.push_back(i);
}
i = 0;
for (list<int>::iterator l_iter = l.begin(); l_iter != l.end(); l_iter++) {
#ifdef SHOW_RESULTS
dr_printf("%d ", *l_iter);
#endif
if (*l_iter != i) {
success = false;
}
i++;
}
//
// Put values in a map and read them out
//
#ifdef SHOW_RESULTS
dr_printf("\ntesting map...");
#endif
map<int,int> m;
for (i=0; i<5; i++) {
m[i] = i;
}
for (i=0; i<5; i++) {
#ifdef SHOW_RESULTS
dr_printf("%d ", m[i]);
#endif
if (m[i] != i) {
success = false;
}
}
//
// Done; print summary
//
#ifdef SHOW_RESULTS
if (success) {
dr_printf("\nSUCCESS\n");
}
else {
dr_printf("\nFAILURE\n");
}
#endif
}
+315
View File
@@ -0,0 +1,315 @@
/* **********************************************************
* Copyright (c) 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.
*/
/* Code Manipulation API Sample:
* strace.c
*
* Monitors system calls. As an example, we modify SYS_write/NtWriteFile.
* On Windows we have to take extra steps to find system call numbers
* and handle emulation parameters for WOW64 (Windows-On-Windows: 32-bit
* applications on 64-bit Windows).
*/
#include "dr_api.h"
#include <string.h> /* memset */
#ifdef LINUX
# include <syscall.h>
#endif
#ifdef WINDOWS
# define DISPLAY_STRING(msg) dr_messagebox(msg)
# define ATOMIC_INC(var) _InterlockedIncrement(&var)
#else
# define DISPLAY_STRING(msg) dr_printf("%s\n", msg);
# define ATOMIC_INC(var) __asm__ __volatile__("lock incl %0" : "=m" (var) : : "memory")
#endif
/* Some syscalls have more args, but this is the max we need for SYS_write/NtWriteFile */
#ifdef WINDOWS
# define SYS_MAX_ARGS 9
#else
# define SYS_MAX_ARGS 3
#endif
/* Thread-local data structure for storing system call parameters */
typedef struct {
reg_t param[SYS_MAX_ARGS];
#ifdef WINDOWS
reg_t xcx; /* emulation parameter for WOW64 */
#endif
bool repeat;
} per_thread_t;
/* The system call number of SYS_write/NtWriteFile */
static int write_sysnum;
static int num_syscalls;
static int get_write_sysnum(void);
static void event_exit(void);
static void event_thread_init(void *drcontext);
static void event_thread_exit(void *drcontext);
static bool event_filter_syscall(void *drcontext, int sysnum);
static bool event_pre_syscall(void *drcontext, int sysnum);
static void event_post_syscall(void *drcontext, int sysnum);
DR_EXPORT void
dr_init(client_id_t id)
{
write_sysnum = get_write_sysnum();
dr_register_thread_init_event(event_thread_init);
dr_register_thread_exit_event(event_thread_exit);
dr_register_filter_syscall_event(event_filter_syscall);
dr_register_pre_syscall_event(event_pre_syscall);
dr_register_post_syscall_event(event_post_syscall);
dr_register_exit_event(event_exit);
#ifdef SHOW_RESULTS
if (dr_is_notify_on())
dr_fprintf(STDERR, "Client strace is running\n");
#endif
}
static void
show_results(void)
{
#ifdef SHOW_RESULTS
char msg[512];
int len;
/* Note that using %f with dr_printf or dr_fprintf on Windows will print
* garbage as they use ntdll._vsnprintf, so we must use snprintf.
*/
len = snprintf(msg, sizeof(msg)/sizeof(msg[0]),
"<Number of system calls seen: %d>", num_syscalls);
DR_ASSERT(len > 0);
msg[sizeof(msg)/sizeof(msg[0])-1] = '\0';
DISPLAY_STRING(msg);
#endif /* SHOW_RESULTS */
}
static void
event_exit(void)
{
show_results();
}
static void
event_thread_init(void *drcontext)
{
/* create an instance of our data structure for this thread */
per_thread_t *data = (per_thread_t *)
dr_thread_alloc(drcontext, sizeof(per_thread_t));
memset(data, 0, sizeof(*data));
/* store it in the slot provided in the drcontext */
dr_set_tls_field(drcontext, data);
}
static void
event_thread_exit(void *drcontext)
{
per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext);
/* clean up memory */
dr_thread_free(drcontext, data, sizeof(per_thread_t));
}
static bool
event_filter_syscall(void *drcontext, int sysnum)
{
return true; /* intercept everything */
}
static bool
event_pre_syscall(void *drcontext, int sysnum)
{
ATOMIC_INC(num_syscalls);
#ifdef LINUX
if (sysnum == SYS_execve) {
/* our stats will be re-set post-execve so display now */
show_results();
# ifdef SHOW_RESULTS
dr_fprintf(STDERR, "<---- execve ---->\n");
# endif
}
#endif
#ifdef SHOW_RESULTS
dr_fprintf(STDERR, "[%d] "PFX" "PFX" "PFX"\n",
sysnum,
dr_syscall_get_param(drcontext, 0),
dr_syscall_get_param(drcontext, 1),
dr_syscall_get_param(drcontext, 2));
#endif
if (sysnum == write_sysnum) {
/* store params for access post-syscall */
per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext);
int i;
#ifdef WINDOWS
/* stderr and stdout are identical in our cygwin rxvt shell so for
* our example we suppress output starting with 'H' instead
*/
byte *output = (byte *) dr_syscall_get_param(drcontext, 5);
size_t len = dr_syscall_get_param(drcontext, 6);
byte first;
size_t read;
bool ok = dr_safe_read(output, 1, &first, &read);
if (!ok || read != 1)
return true; /* data unreadable: execute normally */
if (dr_is_wow64()) {
/* store the xcx emulation parameter for wow64 */
dr_mcontext_t mc;
dr_get_mcontext(drcontext, &mc, NULL);
data->xcx = mc.xcx;
}
#endif
for (i = 0; i < SYS_MAX_ARGS; i++)
data->param[i] = dr_syscall_get_param(drcontext, i);
/* suppress stderr */
if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDERR
#ifdef WINDOWS
&& first == 'H'
#endif
) {
/* pretend it succeeded */
#ifdef LINUX
/* return the #bytes == 3rd param */
dr_syscall_set_result(drcontext, dr_syscall_get_param(drcontext, 2));
#else
/* we should also set the IO_STATUS_BLOCK.Information field */
dr_syscall_set_result(drcontext, 0);
#endif
#ifdef SHOW_RESULTS
dr_fprintf(STDERR, " [%d] => skipped\n", sysnum);
#endif
return false; /* skip syscall */
} else if (dr_syscall_get_param(drcontext, 0) == (reg_t) STDOUT) {
if (!data->repeat) {
/* redirect stdout to stderr (unless it's our repeat) */
dr_syscall_set_param(drcontext, 0, (reg_t) STDERR);
}
/* we're going to repeat this syscall once */
data->repeat = !data->repeat;
}
}
return true; /* execute normally */
}
static void
event_post_syscall(void *drcontext, int sysnum)
{
#ifdef SHOW_RESULTS
dr_fprintf(STDERR, " [%d] => "PFX" ("SZFMT")\n",
sysnum,
dr_syscall_get_result(drcontext),
(ptr_int_t)dr_syscall_get_result(drcontext));
#endif
if (sysnum == write_sysnum) {
per_thread_t *data = (per_thread_t *) dr_get_tls_field(drcontext);
/* we repeat a write originally to stdout that we redirected to
* stderr: on the repeat we use stdout
*/
if (data->repeat) {
/* repeat syscall with stdout */
int i;
dr_syscall_set_sysnum(drcontext, write_sysnum);
dr_syscall_set_param(drcontext, 0, (reg_t) STDOUT);
for (i = 1; i < SYS_MAX_ARGS; i++)
dr_syscall_set_param(drcontext, i, data->param[i]);
#ifdef WINDOWS
if (dr_is_wow64()) {
/* Set the xcx emulation parameter for wow64: since
* we're executing the same system call again we can
* use that same parameter. For new system calls we'd
* need to determine the parameter from the ntdll
* wrapper.
*/
dr_mcontext_t mc;
dr_get_mcontext(drcontext, &mc, NULL);
mc.xcx = data->xcx;
dr_set_mcontext(drcontext, &mc, NULL);
}
#endif
dr_syscall_invoke_another(drcontext);
}
}
}
static int
get_write_sysnum(void)
{
#ifdef LINUX
return SYS_write;
#else
byte *entry;
module_data_t *data = dr_lookup_module_by_name("ntdll.dll");
DR_ASSERT(data != NULL);
entry = (byte *) dr_get_proc_address(data->start, "NtWriteFile");
DR_ASSERT(entry != NULL);
dr_free_module_data(data);
return decode_syscall_num(entry);
#endif
}
#ifdef WINDOWS
/* takes in an Nt syscall wrapper entry point */
static int
decode_syscall_num(byte *entry)
{
void *drcontext = dr_get_current_drcontext();
int num = -1;
byte *pc = entry;
uint opc;
instr_t instr;
instr_init(drcontext, &instr);
do {
instr_reset(drcontext, &instr);
pc = decode(drcontext, pc, &instr);
DR_ASSERT(instr_valid(&instr));
opc = instr_get_opcode(&instr);
/* safety check: should only get 11 or 12 bytes in */
if (pc - entry > 20) {
DR_ASSERT(false);
instr_free(drcontext, &instr);
return -1;
}
/* Note that we'll failed if somebody has hooked the wrapper */
if (opc == OP_mov_imm && opnd_is_reg(instr_get_dst(&instr, 0)) &&
opnd_get_reg(instr_get_dst(&instr, 0)) == REG_EAX) {
DR_ASSERT(opnd_is_immed_int(instr_get_src(&instr, 0)));
num = opnd_get_immed_int(instr_get_src(&instr, 0));
break;
}
/* stop at call to vsyscall or at int itself */
} while (opc != OP_call_ind && opc != OP_int);
instr_free(drcontext, &instr);
DR_ASSERT(num > -1);
return num;
}
#endif /* WINDOWS */
+253
View File
@@ -0,0 +1,253 @@
/* **********************************************************
* Copyright (c) 2003-2008 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.
*/
/* Code Manipulation API Sample:
* tracedump.c
*
* Disassembles a trace dump in binary format produced by the
* -tracedump_binary option. Also illustrates the standalone API.
*/
#include "dr_api.h"
#include <stdlib.h> /* for realloc */
#include <assert.h>
#include <stddef.h> /* for offsetof */
#include <string.h> /* for memcpy */
#define OUTPUT 0
#define VERBOSE 0
#define VERBOSE_VERBOSE 0
/* binary trace dump format is in dr_tools.h */
#define BUF_SIZE 4096
static app_pc
dis(void *drcontext, app_pc pc, app_pc display_pc)
{
return disassemble_from_copy(drcontext, pc, display_pc, STDOUT,
true/*show display_pc*/, true/*bytes*/);
}
/* We use an array of SEPARATE_STUB_MAX_SIZE */
#define STUB_STRUCT_MAX_SIZE (sizeof(tracedump_stub_data_t) + SEPARATE_STUB_MAX_SIZE)
#define STUBIDX(stubs, i) \
((tracedump_stub_data_t *)(((byte *)stubs)+(i)*STUB_STRUCT_MAX_SIZE))
static void
read_data(file_t f, void *drcontext)
{
byte sbuf[BUF_SIZE];
byte *dbuf = NULL;
int read, dlen = 0, i;
byte *p = sbuf, *pc, *next_pc;
tracedump_trace_header_t hdrs;
tracedump_file_header_t fhdr;
tracedump_stub_data_t *stubs;
int next_stub_offs;
int cur_stub;
read = dr_read_file(f, &fhdr, sizeof(fhdr));
assert(read == sizeof(fhdr));
if (fhdr.version != _USES_DR_VERSION_) {
dr_fprintf(STDERR, "Error: file version %d does not match tool version %d\n",
fhdr.version, _USES_DR_VERSION_);
return;
}
if (IF_X64_ELSE(!fhdr.x64, fhdr.x64)) {
dr_fprintf(STDERR, "Error: file architecture %s does not match tool's %s\n",
fhdr.x64 ? "x64" : "x86", IF_X64_ELSE("x64", "x86"));
return;
}
if (fhdr.linkcount_size != 0 && fhdr.linkcount_size != 4 &&
fhdr.linkcount_size != 8) {
dr_fprintf(STDERR, "Error: file is not a trace dump\n");
return;
}
while (1) {
read = dr_read_file(f, &hdrs, sizeof(tracedump_trace_header_t));
if (read != sizeof(tracedump_trace_header_t))
break; /* assume end of file */
#ifdef X86_64
set_x86_mode(drcontext, !hdrs.x64);
#endif
dr_printf("\nTRACE # %d\n", hdrs.frag_id);
dr_printf("Tag = "PFX"\n", hdrs.tag);
if (hdrs.num_bbs > 0) {
int j;
app_pc tag;
dr_printf("\nORIGINAL CODE\n");
for (j=0; j<hdrs.num_bbs; j++) {
read = dr_read_file(f, sbuf, BB_ORIGIN_HEADER_SIZE);
assert(read == BB_ORIGIN_HEADER_SIZE);
p = sbuf;
tag = *((app_pc*)p);
p += sizeof(tag);
dr_printf("Basic block %d: tag "PFX"\n", j, tag);
i = *((int*)p);
p += sizeof(i);
dr_printf("Size: %d bytes\n", i);
if (i >= BUF_SIZE) {
if (i >= dlen)
dbuf = realloc(dbuf, i);
p = dbuf;
} else
p = sbuf;
read = dr_read_file(f, p, i);
assert(read == i);
pc = p;
while (pc - p < i) {
pc = dis(drcontext, pc, tag + (pc - p));
}
}
dr_printf("END ORIGINAL CODE\n\n");
}
stubs = dr_global_alloc(hdrs.num_exits * STUB_STRUCT_MAX_SIZE);
assert(stubs != NULL);
next_stub_offs = hdrs.code_size;
if (fhdr.linkcount_size > 0) {
dr_printf("Exit stubs:\n");
}
for (i = 0; i<hdrs.num_exits; i++) {
assert(STUB_DATA_FIXED_SIZE+fhdr.linkcount_size < BUF_SIZE);
read = dr_read_file(f, sbuf, STUB_DATA_FIXED_SIZE+fhdr.linkcount_size);
assert(read == STUB_DATA_FIXED_SIZE+fhdr.linkcount_size);
p = sbuf;
/* We read in whole struct. The union and code fields are of
* course variable-sized so we update them after.
*/
*STUBIDX(stubs,i) = *(tracedump_stub_data_t *)p;
p += STUB_DATA_FIXED_SIZE;
/* linkcounts are no longer available but we have backward compatibility */
if (fhdr.linkcount_size == 8) {
STUBIDX(stubs,i)->count.count64 = *((uint64*)p);
p += 8;
dr_printf("\t#%d: target = "PFX", %s, count = %" UINT64_FORMAT_CODE "\n",
i, STUBIDX(stubs,i)->target,
STUBIDX(stubs,i)->linked ? "not linked" : "linked",
STUBIDX(stubs,i)->count.count64);
} else if (fhdr.linkcount_size == 4) {
STUBIDX(stubs,i)->count.count32 = *((uint *)p);
p += 4;
dr_printf("\t#%d: target = "PFX", %s, count = %lu\n",
i, STUBIDX(stubs,i)->target,
STUBIDX(stubs,i)->linked ? "not linked" : "linked",
STUBIDX(stubs,i)->count.count32);
} else {
dr_printf("\t#%d: target = "PFX", %s\n",
i, STUBIDX(stubs,i)->target,
STUBIDX(stubs,i)->linked ? "not linked" : "linked");
}
assert(p - sbuf == STUB_DATA_FIXED_SIZE+fhdr.linkcount_size);
if (STUBIDX(stubs,i)->stub_pc < hdrs.cache_start_pc ||
STUBIDX(stubs,i)->stub_pc >= hdrs.cache_start_pc + hdrs.code_size) {
assert(STUBIDX(stubs,i)->stub_size < BUF_SIZE);
assert(STUBIDX(stubs,i)->stub_size <= SEPARATE_STUB_MAX_SIZE);
read = dr_read_file(f, sbuf, STUBIDX(stubs,i)->stub_size);
assert(read == STUBIDX(stubs,i)->stub_size);
p = sbuf;
memcpy(STUBIDX(stubs,i)->stub_code, p, STUBIDX(stubs,i)->stub_size);
p += STUBIDX(stubs,i)->stub_size;
} else if (STUBIDX(stubs,i)->stub_pc - hdrs.cache_start_pc < next_stub_offs) {
next_stub_offs = STUBIDX(stubs,i)->stub_pc - hdrs.cache_start_pc;
}
}
if (hdrs.code_size >= dlen)
dbuf = realloc(dbuf, hdrs.code_size);
p = dbuf;
read = dr_read_file(f, p, hdrs.code_size);
assert(read == hdrs.code_size);
pc = p;
dr_printf("Size = %d\n", hdrs.code_size);
dr_printf("Body:\n");
dr_printf(" -------- indirect branch target entry: --------\n");
while (pc - p < next_stub_offs) {
if (pc - p == hdrs.entry_offs)
dr_printf(" -------- normal entry: --------\n");
next_pc = decode_next_pc(drcontext, pc);
if ((next_pc - p) == hdrs.entry_offs && (next_pc - pc == 6))
dr_printf(" -------- prefix entry: --------\n");
pc = dis(drcontext, pc, hdrs.cache_start_pc + (pc - p));
}
/* stubs */
for (cur_stub = 0; cur_stub < hdrs.num_exits; cur_stub++) {
bool separate = STUBIDX(stubs,cur_stub)->stub_pc < hdrs.cache_start_pc ||
STUBIDX(stubs,cur_stub)->stub_pc >= hdrs.cache_start_pc + hdrs.code_size;
app_pc stub_pc = (app_pc) STUBIDX(stubs,cur_stub)->stub_code;
dr_printf(" -------- exit stub %d: -------- <target: "PFX">\n",
cur_stub, STUBIDX(stubs,cur_stub)->target);
next_stub_offs = hdrs.code_size;
for (i=cur_stub + 1; i<hdrs.num_exits; i++) {
if (STUBIDX(stubs,i)->stub_pc >= hdrs.cache_start_pc &&
STUBIDX(stubs,i)->stub_pc < hdrs.cache_start_pc + hdrs.code_size) {
next_stub_offs = STUBIDX(stubs,i)->stub_pc - hdrs.cache_start_pc;
break;
}
}
if (separate) {
app_pc spc = stub_pc;
while (spc - stub_pc < STUBIDX(stubs,cur_stub)->stub_size) {
spc = dis(drcontext, spc, STUBIDX(stubs,cur_stub)->stub_pc +
(spc - stub_pc));
}
} else {
while (pc - p < next_stub_offs) {
pc = dis(drcontext, pc, hdrs.cache_start_pc + (pc - p));
}
}
}
dr_printf("END TRACE %d\n", hdrs.frag_id);
}
if (dbuf != NULL)
free(dbuf);
}
int
main(int argc, char *argv[])
{
file_t f;
void *drcontext = dr_standalone_init();
if (argc != 2) {
dr_fprintf(STDERR, "Usage: %s <tracefile>\n", argv[0]);
return 1;
}
f = dr_open_file(argv[1], DR_FILE_READ | DR_FILE_ALLOW_LARGE);
if (f == INVALID_FILE) {
dr_fprintf(STDERR, "Error opening %s\n", argv[1]);
return 1;
}
read_data(f, drcontext);
dr_close_file(f);
return 0;
}
+72
View File
@@ -0,0 +1,72 @@
REM **********************************************************
REM Copyright (c) 2008 VMware, Inc. All rights reserved.
REM **********************************************************
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions are met:
REM
REM * Redistributions of source code must retain the above copyright notice,
REM this list of conditions and the following disclaimer.
REM
REM * Redistributions in binary form must reproduce the above copyright notice,
REM this list of conditions and the following disclaimer in the documentation
REM and/or other materials provided with the distribution.
REM
REM * Neither the name of VMware, Inc. nor the names of its contributors may be
REM used to endorse or promote products derived from this software without
REM specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
REM AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
REM IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
REM ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
REM FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
REM DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
REM SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
REM OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
REM DAMAGE.
@echo off
REM This script provides the functionality common to all
REM the batch scripts in this module: it sets up the cygwin
REM mount points and provides the proper path to the
REM cygwin utilities in our local toolchain module. All
REM .bat files launching a cygwin command should call this
REM script first and then invoke a bash shell with the
REM path set to BASH_PATH.
if {%TCROOT%}=={} goto error
if not {%DYNAMORIO_TOOLCHAIN%}=={} goto set_reg
REM If DYNAMORIO_TOOLCHAIN is not set, provide a default
REM value relative to the location of this script.
set CUR_DIR=%CD%
cd %~dp0\..
set DYNAMORIO_TOOLCHAIN=%CD%\toolchain
cd %CUR_DIR%
REM Cygwin utils won't work correctly without the mount points
REM specified in the registry. Unmount first and then force
REM /, /usr/bin, and /usr/lib to point to our toolchain module.
:set_reg
set CYGDIR=%DYNAMORIO_TOOLCHAIN%\win32\cygwin-1.5.25-7
set CYGBIN=%CYGDIR%\bin
set CYGX11=%CYGDIR%\usr\X11R6\bin
%CYGBIN%\umount -A
%CYGBIN%\mount -f %CYGDIR% /
%CYGBIN%\mount -f %CYGDIR%\bin /usr/bin
%CYGBIN%\mount -f %CYGDIR%\lib /usr/lib
REM Provide a variable the calling .bat script can use to set
REM the path when invoking its cygwin command.
set BASH_PATH='%CYGBIN%':'%CYGX11%':$PATH
goto :eof
:error
echo ERROR: you must set TCROOT
exit /b 1
+65
View File
@@ -0,0 +1,65 @@
REM **********************************************************
REM Copyright (c) 2008 VMware, Inc. All rights reserved.
REM **********************************************************
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions are met:
REM
REM * Redistributions of source code must retain the above copyright notice,
REM this list of conditions and the following disclaimer.
REM
REM * Redistributions in binary form must reproduce the above copyright notice,
REM this list of conditions and the following disclaimer in the documentation
REM and/or other materials provided with the distribution.
REM
REM * Neither the name of VMware, Inc. nor the names of its contributors may be
REM used to endorse or promote products derived from this software without
REM specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
REM AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
REM IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
REM ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
REM FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
REM DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
REM SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
REM OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
REM DAMAGE.
@echo off
set CUR_DIR=%CD%
set TARG=
if {%1}=={vmap} set TARG=VMAP
if {%1}=={viper} set TARG=VMSAFE
if {%TARG%}=={} goto usage
cd %~dp0\..
set DR_HOME=%CD%
call %DR_HOME%\batch\common.bat
if %errorlevel% neq 0 goto error
cd %DR_HOME%\core
%CYGBIN%\bash -c "PATH=%BASH_PATH% make clear"
%CYGBIN%\bash -c "PATH=%BASH_PATH% make %TARG%=1 DEBUG=0 INTERNAL=0 api_headers"
cd %DR_HOME%\api\docs
%CYGBIN%\bash -c "PATH=%BASH_PATH% make clean"
%CYGBIN%\bash -c "PATH=%BASH_PATH% make %TARG%=1 pdf"
REM clean up mounts
%CYGBIN%\umount -A
cd %CUR_DIR%
goto :eof
:usage
echo "usage: %0 <viper|vmap>"
:error
cd %CUR_DIR%
exit /b 1
+51
View File
@@ -0,0 +1,51 @@
REM **********************************************************
REM Copyright (c) 2008 VMware, Inc. All rights reserved.
REM **********************************************************
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions are met:
REM
REM * Redistributions of source code must retain the above copyright notice,
REM this list of conditions and the following disclaimer.
REM
REM * Redistributions in binary form must reproduce the above copyright notice,
REM this list of conditions and the following disclaimer in the documentation
REM and/or other materials provided with the distribution.
REM
REM * Neither the name of VMware, Inc. nor the names of its contributors may be
REM used to endorse or promote products derived from this software without
REM specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
REM AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
REM IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
REM ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
REM FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
REM DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
REM SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
REM OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
REM DAMAGE.
@echo off
set CUR_DIR=%CD%
cd %~dp0\..
set DR_HOME=%CD%
call %DR_HOME%\batch\common.bat
if %errorlevel% neq 0 goto error
cd %DR_HOME%\tools
%CYGBIN%\bash -c "PATH=%BASH_PATH% ./makezip.sh %1 '%2' %3 %4 %5 %6"
REM clean up mounts
%CYGBIN%\umount -A
cd %CUR_DIR%
goto :eof
:error
cd %CUR_DIR%
exit /b 1
+33
View File
@@ -0,0 +1,33 @@
REM **********************************************************
REM Copyright (c) 2008 VMware, Inc. All rights reserved.
REM **********************************************************
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions are met:
REM
REM * Redistributions of source code must retain the above copyright notice,
REM this list of conditions and the following disclaimer.
REM
REM * Redistributions in binary form must reproduce the above copyright notice,
REM this list of conditions and the following disclaimer in the documentation
REM and/or other materials provided with the distribution.
REM
REM * Neither the name of VMware, Inc. nor the names of its contributors may be
REM used to endorse or promote products derived from this software without
REM specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
REM AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
REM IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
REM ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
REM FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
REM DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
REM SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
REM OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
REM DAMAGE.
@echo off
rd /s /q %1
exit /b 1
+164
View File
@@ -0,0 +1,164 @@
# **********************************************************
# Copyright (c) 2005-2008 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.
.PHONY: all clean
ifeq ($(shell uname -s | cut -c1-5), Linux)
MACHINE = linux
else
MACHINE = win32
endif
ifndef DYNAMORIO_MAKE
DYNAMORIO_MAKE := ../../make
endif
include $(DYNAMORIO_MAKE)/compiler.mk
# windows vs. linux flags, etc.
ifeq ($(MACHINE), linux)
U =-u
I =-I
D =-D
L =-L
INCR =-c
OUT =-o
EXEOUT =-o
WARN =-Wall
OPT =-O3
NOPT =-O0
DBG =-g3
LD = /usr/bin/ld
OBJ_SFX =o
EXE_SFX =
LIB_NAME =libdrprivate.so
else # win32
# avoid problems w/ line endings on #! files that cygwin's sh has
SHELL =bash
U =/U
I =/I
D =/D
L =/link /LIBPATH:
INCR =/c
OUT =/Fo
EXEOUT =/Fe
DLLOUT =/dll /out:
LIBOUT =/implib:
WARN =/W3
OPT =/O2
NOPT =/Od
DBG =/Zi
LD = link /nologo
OBJ_SFX =obj
EXE_SFX =.exe
LIB_NAME =dynamorio.dll
endif
# use release build if it exists, unless DEBUG=yes
ifeq ($(MACHINE), linux)
DYNAMORIO_DIR_BASE = $(DYNAMORIO_HOME)/exports/x86_linux_
DYNAMORIO_BUILD_DIR_BASE = $(DYNAMORIO_HOME)/build/x86_linux_
else
DYNAMORIO_DIR_BASE = $(DYNAMORIO_HOME)/exports/x86_win32_
DYNAMORIO_BUILD_DIR_BASE = $(DYNAMORIO_HOME)/build/x86_win32_
endif
# allow yes or 1 for DEBUG
ifeq ($(DEBUG),yes)
RELEASE_EXISTS=""
else
ifeq ($(DEBUG),1)
RELEASE_EXISTS=""
else
RELEASE_EXISTS=$(wildcard $(DYNAMORIO_DIR_BASE)rel)
endif
endif
ifeq ($(RELEASE_EXISTS), $(DYNAMORIO_DIR_BASE)rel)
DYNAMORIO_DIR = $(DYNAMORIO_DIR_BASE)rel
DYNAMORIO_BUILD_DIR = $(DYNAMORIO_BUILD_DIR_BASE)rel
else
DYNAMORIO_DIR = $(DYNAMORIO_DIR_BASE)dbg
DYNAMORIO_BUILD_DIR = $(DYNAMORIO_BUILD_DIR_BASE)dbg
endif
ifeq ($(MACHINE), linux)
DYNAMORIO_INC = $(I)$(DYNAMORIO_DIR)
else
DYNAMORIO_INC = $(I)$(subst /,\\,$(shell cygpath -m ${DYNAMORIO_DIR})) $(MSINCLUDE)
DYNAMORIO_LIBDIR = $(subst /,\\,$(shell cygpath -m ${DYNAMORIO_DIR})) $(MSLIB)
endif
CC_BASE = $(CC) $(DBG) $I.
# some apps need LINUX defined even if not using API
ifeq ($(MACHINE), win32)
# don't need to define WIN32, assumed by ifndef LINUX
CC_BASE += /MT
else
CC_BASE += $(D)LINUX
endif
CC_BASE_DYNAMORIO = $(CC_BASE) $(DYNAMORIO_INC) $(D)DYNAMO $(D)X86
ifeq ($(MACHINE), linux)
LINK = -lm
LINK_DYNAMORIO = $(L)$(DYNAMORIO_DIR) -ldynamorio -lm -Xlinker -rpath -Xlinker $(DYNAMORIO_DIR)
else # win32
# /MTd must be included when compiling, not on link line!
# else get weird link errors
WINLIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib \
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \
odbc32.lib odbccp32.lib imagehlp.lib libcmt.lib
LINK = $(WINLIBS) /link /subsystem:console
LINK_DYNAMORIO = $(L)$(DYNAMORIO_LIBDIR) $(WINLIBS) dynamorio.lib /subsystem:console
endif
ifeq ($(MACHINE), linux)
# FIXME: re-enable signal tests when have time to fix core signal bugs
SRCS := tracedump.c
else
SRCS := tracedump.c module_rsrc.c winsysnums.c vista_hash.c
endif
PGMS := $(patsubst %.c,%$(EXE_SFX),$(SRCS))
all: $(PGMS)
ifeq ($(MACHINE), win32)
# using %$(EXE_SFX) doesn't seem to work well on win32, so we duplicate
$(PGMS): %.exe: %.c
$(CC_BASE_DYNAMORIO) $(D)USE_DYNAMO $(EXEOUT)$@ $< $(LINK_DYNAMORIO)
else # linux
$(PGMS): %: %.c
$(CC_BASE_DYNAMORIO) $(D)USE_DYNAMO $(EXEOUT)$@ $< $(LINK_DYNAMORIO)
endif # linux
clean:
-rm -f $(PGMS) *.$(OBJ_SFX) *.pdb *.ilk *.opt
+82
View File
@@ -0,0 +1,82 @@
/* **********************************************************
* Copyright (c) 2006 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.
*/
/* FIXME - should use dr_fprintf but can't get that to work, then again this is
* standalone so doesn't really matter what we use. */
#include "dynamorio.h"
#include "dynamorio_mod.h"
#include "windows.h"
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
version_info_t info;
HMODULE hmod;
void *drcontext = dr_standalone_init();
if (argc != 2) {
printf("Usage: %s <dll to read>\n", argv[0]);
return 1;
}
/* Don't use LOAD_LIBRARY_AS_DATAFILE, it doesn't layout the sections as we expect
* use DONT_RESOLVE_DLL_REFERENCES instead */
hmod = LoadLibraryEx(argv[1], NULL, DONT_RESOLVE_DLL_REFERENCES);
if (hmod == NULL) {
printf("Can't find module %s\n", argv[1]);
return 2;
}
/* Need to round off the loaded as data flag to get actual base */
if (!get_module_resource_version_info((app_pc)((uint)hmod & 0xfffffffe), &info)) {
printf("Failed to read rsrc directory\n");
return 3;
}
printf("File Version = %04d.%04d.%04d.%04d, Product Version = %04d.%04d.%04d.%04d\n",
info.file_version.version_parts.p1, info.file_version.version_parts.p2,
info.file_version.version_parts.p3, info.file_version.version_parts.p4,
info.product_version.version_parts.p1, info.product_version.version_parts.p2,
info.product_version.version_parts.p3, info.product_version.version_parts.p4);
if (info.original_filename != NULL)
printf("Original File Name = \"%S\"\n", info.original_filename);
if (info.company_name != NULL)
printf("Company Name = \"%S\"\n", info.company_name);
if (info.product_name != NULL)
printf("Product Name = \"%S\"\n", info.product_name);
return 0;
}
+547
View File
@@ -0,0 +1,547 @@
/* **********************************************************
* Copyright (c) 2008 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.
*/
#include "dr_api.h"
#include <stdlib.h> /* for realloc */
#include <assert.h>
#include <stddef.h> /* for offsetof */
#include <string.h> /* for memcpy */
#include <imagehlp.h>
/*
* NOTE - I haven't tried running this with the dynamorio.dll in this directory so it
* might not work. I've been using a tot VMAP=1 build of core.
*
* ls *.dll > LIST
* for i in $( cat LIST ) ; do ../vista_hash.exe $i; done > ../OUTPUT
*/
void
dummy()
{}
static bool v = false;
static bool vv = false;
#define VVERBOSE_PRINT if (vv) printf
#define VERBOSE_PRINT if (v) printf
#define ASSERT(x) ((x) ? 0 : dr_messagebox("Error %d %s\n", __LINE__, #x) , 0)
#define ALIGN_BACKWARD(x, alignment) (((ptr_uint_t)x) & (~((alignment)-1)))
#define ALIGN_FORWARD(x, alignment) \
((((ptr_uint_t)x) + ((alignment)-1)) & (~((alignment)-1)))
bool
compare_pages(void *drcontext, byte *start1, byte *start2, uint start_offset)
{
static byte copy_buf1_i[2*PAGE_SIZE+100];
static byte copy_buf2_i[2*PAGE_SIZE+100];
static byte buf1_i[2*PAGE_SIZE+100];
static byte buf2_i[2*PAGE_SIZE+100];
byte *copy1 = (byte *)ALIGN_FORWARD(copy_buf1_i, PAGE_SIZE);
byte *copy2 = (byte *)ALIGN_FORWARD(copy_buf2_i, PAGE_SIZE);
byte *buf1 = (byte *)ALIGN_FORWARD(buf1_i, PAGE_SIZE);
byte *buf2 = (byte *)ALIGN_FORWARD(buf2_i, PAGE_SIZE);
byte *p1 = copy1+start_offset, *p2 = copy2+start_offset;
byte *b1 = buf1, *c1 = buf1, *b2 = buf2, *c2 = buf2;
int skipped_bytes1 = 0, skipped_identical_bytes1 = 0;
int skipped_bytes2 = 0, skipped_identical_bytes2 = 0;
/* we make a copy (zero extend the page) for decode to avoid walking to next,
* potentially invalid page */
memcpy(copy1, start1, PAGE_SIZE);
memcpy(copy2, start2, PAGE_SIZE);
/* Note - we do the compare ~1 instruction at a time, would be more effiecient
* to do the whole page and compare, but this makes it easier to track down where
* the differences originate from. */
while (p1 < copy1 + PAGE_SIZE) {
/* The idea is to do a lightweight decoding of the page and eliminate likely
* relocations from the instruction stream. I expect that relocations within
* the stream to be 4-byte immeds or 4-byte displacements with pointer like
* values. For now just using decode_sizeof to get the size of the instuction
* and based on that determine how much to chop off the end (instruction format
* is [...][disp][imm]) to remove the potential relocation. With better
* information from decode_sizeof (it knows whether an immed/disp is present or
* not and what offset it would be etc.) we could keep more of the bytes but
* this works for testing. What we'll miss unless we get really lucky is
* relocs in read only data (const string arrays, for dr the const decode
* tables full of pointers for ex.). */
/* How the assumptions work out. The assumption that we quickly get to the
* appropriate instruction frame seems valid. Most cases we synchronize very
* quickly, usually just a couple of bytes and very rarely more then 20.
* I Haven't seen any relocations in instructions that weren't caught
* below. However, so far only matching ~60% of sibling pages because of
* read only data relocations interspersed in the text sections. Instruction
* frame alignment isn't an issue that often and the second pass is catching
* most of those. */
while (p1 - copy1 <= p2 - copy2) {
uint num_bytes, i, num_prefix = 0;
uint size = decode_sizeof(p1, &num_prefix);
size -= num_prefix;
num_bytes = num_prefix;
if (size == 0) {
size = 1; /* treat invalid as size == 1 */
num_bytes += 1;
} else if (size <= 4) {
num_bytes += size; /* no 4-byte disp or imm */
} else if (size <= 6 ) {
num_bytes += size - 4; /* could have 4-byte disp or immed */
} else if (size <= 7) {
num_bytes += size - 5; /* could have 4-byte disp and upto 1-byte immed
* or 4-byte immed */
} else if (size <= 9) {
num_bytes += size - 6; /* could have 4-byte disp and upto 2-byte immed
* or 4-byte immed */
} else {
num_bytes += size - 8; /* could have 4-byte disp and 4-byte immed */
}
for (i = 0; i < num_bytes; i++)
*b1++ = *p1++;
skipped_bytes1 += size - (num_bytes - num_prefix);
for (i = 0; i < size - (num_bytes - num_prefix); i++) {
if (*p1 == *(copy2+(p1-copy1)))
skipped_identical_bytes1++;
p1++;
}
}
while (p2 - copy2 < p1 - copy1) {
uint num_bytes, i, num_prefix = 0;
uint size = decode_sizeof(p2, &num_prefix);
size -= num_prefix;
num_bytes = num_prefix;
if (size == 0) {
size = 1; /* treat invalid as size == 1 */
num_bytes += 1;
} else if (size <= 4) {
num_bytes += size;
} else if (size <=6 ) {
num_bytes += size - 4;
} else if (size <= 7) {
num_bytes += size - 5;
} else if (size <= 9) {
num_bytes += size - 6;
} else {
num_bytes += size - 8;
}
for (i = 0; i < num_bytes; i++)
*b2++ = *p2++;
skipped_bytes2 += size - (num_bytes - num_prefix);
for (i = 0; i < size - (num_bytes - num_prefix); i++) {
if (*p2 == *(copy1+(p2-copy2)))
skipped_identical_bytes2++;
p2++;
}
}
/* Do check */
while (c1 < b1 && c2 < b2) {
if (*c1++ != *c2++) {
VVERBOSE_PRINT("Mismatch found near offset 0x%04x of page %08x\n",
p1 - copy1, start1);
return false;
}
}
}
ASSERT(skipped_bytes1 == skipped_bytes2);
ASSERT(skipped_identical_bytes1 == skipped_identical_bytes2);
VVERBOSE_PRINT("Match found! skipped=%d skipped_identical=%d\n",
skipped_bytes1, skipped_identical_bytes1);
return true;
}
/* Note that we should keep an eye for potential additional qualifier
* flags. Alternatively we may simply mask off ~0xff to allow for any
* future flags added here.
*/
#define PAGE_PROTECTION_QUALIFIERS (PAGE_GUARD | PAGE_NOCACHE | PAGE_WRITECOMBINE)
bool
prot_is_writable(uint prot)
{
prot &= ~PAGE_PROTECTION_QUALIFIERS;
return (prot == PAGE_READWRITE || prot == PAGE_WRITECOPY ||
prot == PAGE_EXECUTE_READWRITE || prot == PAGE_EXECUTE_WRITECOPY);
}
# define OPT_HDR(nt_hdr_p, field) ((nt_hdr_p)->OptionalHeader.field)
# define OPT_HDR_P(nt_hdr_p, field) (&((nt_hdr_p)->OptionalHeader.field))
bool
get_IAT_section_bounds(app_pc module_base, app_pc *iat_start, app_pc *iat_end)
{
IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *) module_base;
IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *) (((ptr_uint_t)dos) + dos->e_lfanew);
IMAGE_DATA_DIRECTORY *dir;
if (dos->e_magic != IMAGE_DOS_SIGNATURE ||
nt == NULL || nt->Signature != IMAGE_NT_SIGNATURE)
return false;
dir = &OPT_HDR(nt, DataDirectory)[IMAGE_DIRECTORY_ENTRY_IAT];
*iat_start = module_base + dir->VirtualAddress;
*iat_end = module_base + dir->VirtualAddress + dir->Size;
return true;
}
int
usage(char *name)
{
printf("Usage: %s [-v] [-vv] [-no_second_pass] [-second_pass_offset <val>] [-no_assume_IAT_written] [-spin_for_debugger] <dll>\n", name);
return -1;
}
int
main(int argc, char *argv[])
{
byte *dll_1, *dll_2, *p1, *p2, *iat_start1, *iat_end1, *iat_start2, *iat_end2;
bool has_iat = false;
MEMORY_BASIC_INFORMATION info;
void *drcontext = dr_standalone_init();
uint writable_pages = 0, reserved_pages = 0, IAT_pages = 0;
uint matched_pages = 0, second_matched_pages = 0, unmatched_pages = 0;
uint exact_match_pages = 0, exact_no_match_pages = 0;
char reloc_file[MAX_PATH] = {0}, orig_file[MAX_PATH], *input_file;
uint old_size = 0, new_size = 0;
uint old_base = 0, new_base = 0x69000000; /* unlikely to collide */
/* user specified option defaults */
uint arg_offs = 1;
bool use_second_pass = true;
bool assume_header_match = true;
uint second_pass_offset = 16; /* FIXME arbitrary, what's a good choice? */
bool assume_IAT_written = true;
bool spin_for_debugger = false;
if (argc < 2)
return usage(argv[0]);
while (argv[arg_offs][0] == '-') {
if (strcmp(argv[arg_offs], "-vv") == 0) {
vv = true;
} else if (strcmp(argv[arg_offs], "-v") == 0) {
v = true;
} else if (strcmp(argv[arg_offs], "-no_second_pass") == 0) {
use_second_pass = false;
} else if (strcmp(argv[arg_offs], "-second_pass_offset") == 0) {
if (argc <= arg_offs+1)
return usage(argv[0]);
second_pass_offset = atoi(argv[++arg_offs]);
} else if (strcmp(argv[arg_offs], "-no_assume_IAT_written") == 0) {
assume_IAT_written = false;
} else if (strcmp(argv[arg_offs], "-spin_for_debugger") == 0) {
spin_for_debugger = true;
} else {
return usage(argv[0]);
}
arg_offs++;
}
input_file = argv[arg_offs++];
if (arg_offs != argc)
return usage(argv[0]);
snprintf(reloc_file, sizeof(reloc_file), "%s.reloc.dll", input_file);
reloc_file[sizeof(reloc_file)-1] = '\0';
if (!CopyFile(input_file, reloc_file, FALSE)) {
LPSTR msg = NULL;
uint error = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
0, GetLastError(), 0, msg, 0, NULL);
VERBOSE_PRINT("Copy Error %d (0x%x) = %s\n", error, error, msg);
return 1;
}
snprintf(orig_file, sizeof(orig_file), "%s.orig.dll", input_file);
orig_file[sizeof(orig_file)-1] = '\0';
if (!CopyFile(input_file, orig_file, FALSE)) {
LPSTR msg = NULL;
uint error = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
0, GetLastError(), 0, msg, 0, NULL);
VERBOSE_PRINT("Copy Error %d (0x%x) = %s\n", error, error, msg);
return 1;
}
if (ReBaseImage(reloc_file, "", TRUE, FALSE, FALSE, 0, &old_size, &old_base,
&new_size, &new_base, 0)) {
VERBOSE_PRINT("Rebased imsage \"%s\" from 0x%08x to 0x%08x\n"
"Size changed from %d bytes to %d bytes\n",
input_file, old_base, new_base, old_size, new_size);
} else {
LPSTR msg = NULL;
uint error = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER,
0, GetLastError(), 0, msg, 0, NULL);
VERBOSE_PRINT("Rebase Error %d (0x%x) = %s\n", error, error, msg);
return 1;
}
dll_1 = (byte *)ALIGN_BACKWARD(LoadLibraryExA(orig_file, NULL,
DONT_RESOLVE_DLL_REFERENCES),
PAGE_SIZE);
p1 = dll_1;
dll_2 = (byte *)ALIGN_BACKWARD(LoadLibraryExA(reloc_file, NULL,
DONT_RESOLVE_DLL_REFERENCES),
PAGE_SIZE);
p2 = dll_2;
VVERBOSE_PRINT("Loaded dll @ 0x%08x and 0x%08x\n", dll_1, dll_2);
if (dll_1 == NULL || dll_2 == NULL) {
VERBOSE_PRINT( "Error loading %s\n", input_file);
return 1;
}
/* Handle the first page specially since I'm seeing problems with a handful of
* dlls that aren't really getting rebased. mcupdate_GenuineIntel.dll for ex.
* (which does have relocations etc.) not sure what's up, but it's only a couple of
* dlls so will ignore them. If we really rebased the header should differ. */
if (memcmp(dll_1, dll_2, PAGE_SIZE) == 0) {
printf("%s - ERROR during relocating\n", input_file);
return 1;
} else {
exact_no_match_pages++;
if (assume_header_match)
/* We could modify the hash function to catch header pages. */
matched_pages++;
else
unmatched_pages++;
}
p1 += PAGE_SIZE;
p2 += PAGE_SIZE;
if (assume_IAT_written && get_IAT_section_bounds(dll_1, &iat_start1, &iat_end1)) {
has_iat = true;
ASSERT(get_IAT_section_bounds(dll_2, &iat_start2, &iat_end2) &&
iat_start1 - dll_1 == iat_start2 - dll_2 &&
iat_end1 - dll_1 == iat_end2 - dll_2);
}
while (dr_virtual_query(p1, &info, sizeof(info)) == sizeof(info) &&
info.State != MEM_FREE && info.AllocationBase == dll_1) {
/* we only check read-only pages (assumption writable pages aren't shareable) */
ASSERT(p1 == info.BaseAddress);
if (info.State != MEM_COMMIT) {
reserved_pages += info.RegionSize / PAGE_SIZE;
VVERBOSE_PRINT("skipping %d reserved pages\n", info.RegionSize / PAGE_SIZE);
p1 += info.RegionSize;
p2 += info.RegionSize;
} else if (!prot_is_writable(info.Protect)) {
int i;
for (i = 0; i < info.RegionSize / PAGE_SIZE; i++) {
bool exact = false;
if (assume_IAT_written && has_iat &&
iat_end1 > p1 && iat_start1 < p1 + PAGE_SIZE) {
/* overlaps an IAT page */
IAT_pages++;
p1 += PAGE_SIZE;
p2 += PAGE_SIZE;
continue;
}
if (memcmp(p1, p2, PAGE_SIZE) == 0) {
VVERBOSE_PRINT("Page Exact Match\n");
exact_match_pages++;
exact = true;
} else {
VVERBOSE_PRINT("Page Exact Mismatch\n");
exact_no_match_pages++;
}
if (compare_pages(drcontext, p1, p2, 0)) {
VVERBOSE_PRINT("Matched page\n");
matched_pages++;
} else {
VVERBOSE_PRINT("Failed to match page\n");
if (use_second_pass &&
compare_pages(drcontext, p1, p2, second_pass_offset)) {
second_matched_pages++;
} else {
unmatched_pages++;
}
ASSERT(!exact);
}
p1 += PAGE_SIZE;
p2 += PAGE_SIZE;
}
} else {
writable_pages += info.RegionSize / PAGE_SIZE;
VVERBOSE_PRINT("skipping %d writable pages\n", info.RegionSize / PAGE_SIZE);
p1 += info.RegionSize;
p2 += info.RegionSize;
}
}
VERBOSE_PRINT("%d exact match, %d not exact match\n%d hash_match, %d second_hash_match, %d hash_mismatch\n",
exact_match_pages, exact_no_match_pages, matched_pages, second_matched_pages, unmatched_pages);
printf("%s : %d pages - %d w %d res %d IAT = %d same %d differ : %d hash differ %d first hash differ : %d%% found, %d%% found first hash\n",
input_file, writable_pages + reserved_pages + IAT_pages + exact_match_pages + exact_no_match_pages,
writable_pages, reserved_pages, IAT_pages,
exact_match_pages, exact_no_match_pages,
unmatched_pages, unmatched_pages + second_matched_pages,
(100 * (matched_pages + second_matched_pages - exact_match_pages))/exact_no_match_pages,
(100 * (matched_pages - exact_match_pages))/exact_no_match_pages);
while (spin_for_debugger)
Sleep(1000);
return 0;
}
#if 0
/* First tried something like this, but we hit too many issues in decode and encode */
bool
compare_pages(void *drcontext, byte *start1, byte *start2)
{
byte *p1 = start1, *p2 = start2;
int skipped_bytes = 0, identical_skipped_bytes = 0;
while (p1 < start1 + PAGE_SIZE) {
int instr_size = decode_sizeof(p1, NULL _IF_X64(NULL));
if (p1 + instr_size > start1 + PAGE_SIZE) {
/* We're overlapping the end of the page, skip these. */
int end_skip = start1 + PAGE_SIZE - p1;
VVERBOSE_PRINT("Passing PAGE_END %d bytes", end_skip);
skipped_bytes += end_skip;
if (memcmp(p1, p2, end_skip) == 0)
identical_skipped_bytes += end_skip;
break;
}
if (decode_sizeof(p2, NULL _IF_X64(NULL)) != instr_size) {
VVERBOSE_PRINT("Instruction alignment mismatch\n");
return false;
}
/* assumption - instructions <= 4 bytes in size won't have relocations */
if (instr_size < 5) {
if (memcmp(p1, p2, instr_size) != 0) {
VVERBOSE_PRINT("Difference found in small instr\n");
return false;
}
p1 += size;
p2 += size;
} else {
/* guess if there could be a relocation */
instr_t *instr1 = instr_create(drcontext);
instr_t *instr2 = instr_create(drcontext);
p1 = decode(drcontext, p1, instr1);
p2 = decode(drcontext, p2, instr2);
if (p1 - start1 != p2 - start2) {
VVERBOSE_PRINT("Instruction alignment mismatch on full decode\n");
/* Fixme - free instr, don't expect this to happen */
return false;
}
if (instr_get_num_srcs(instr1) != instr_get_num_srcs(instr2) ||
instr_get_num_dsts(instr1) != instr_get_num_dsts(instr2)) {
VVERBOSE_PRINT("Full decode operand mismatch");
return false;
}
for (i = instr_get_num_srcs(instr1); i > 0; i--) {
opnd_t opnd = instr_get_src(instr1, i);
if (opnd_is_immed_int(opnd) && opnd_get_immed_int(opnd) > 0x10000) {
instr_set_src(instr1, i, opnd_create_immed_int(opnd_get_immed_int(opnd), opnd_get_size(opnd)));
}
}
}
}
}
void
modify_instr_for_relocations(void *drcontext, instr_t *inst,
ptr_uint_t *immed, ptr_uint_t *disp)
{
int i;
ptr_uint_t limmed = 0, ldisp = 0;
for (i = instr_num_srcs(inst) - 1; i >= 0; i--) {
opnd_t opnd = instr_get_src(inst, i);
if (opnd_is_immed_int(opnd) && opnd_get_immed_int(opnd) > 0x10000) {
if (limmed != 0) {
ASSERT(false);
} else {
limmed = opnd_get_immed_int(opnd);
}
instr_set_src(inst, i, opnd_create_immed_int(0, opnd_get_size(opnd)));
}
if (opnd_is_base_disp(opnd) && opnd_get_disp(opnd) > 0x10000) {
if (ldisp != 0 && ldisp != opnd_get_disp(opnd)) {
ASSERT(false);
} else {
ldisp = opnd_get_disp(opnd);
}
instr_set_src(inst, i, opnd_create_base_disp(opnd_get_base(opnd), opnd_get_index(opnd), opnd_get_scale(opnd), 0, opnd_get_size(opnd)));
}
}
for (i = instr_num_dsts(inst) - 1; i >= 0; i--) {
opnd_t opnd = instr_get_dst(inst, i);
ASSERT(!opnd_is_immed(opnd));
if (opnd_is_base_disp(opnd) && opnd_get_disp(opnd) > 0x10000) {
if (ldisp != 0 && ldisp != opnd_get_disp(opnd)) {
ASSERT(false);
} else {
ldisp = opnd_get_disp(opnd);
}
instr_set_dst(inst, i, opnd_create_base_disp(opnd_get_base(opnd), opnd_get_index(opnd), opnd_get_scale(opnd), 0, opnd_get_size(opnd)));
}
}
if (limmed != 0)
*immed = limmed;
if (ldisp != 0)
*disp = ldisp;
}
#endif
+463
View File
@@ -0,0 +1,463 @@
/* **********************************************************
* Copyright (c) 2003-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* winsysnums.c: analyzes a dll's exported routines, looking for system call
* numbers or Ki* routines -- typically pointed at a new ntdll.dll
*/
/* Uses the DR CLIENT_INTERFACE API, using DR as a standalone library, rather than
* being a client library working with DR on a target program.
*
* To build:
* 1) Build DR w/ CLIENT_INTERFACE=1
* 2) cl winsysnums.c /I$DYNAMORIO_HOME/exports/x86_win32_dbg /link /libpath:$DYNAMORIO_HOME/exports/x86_win32_dbg dynamorio.lib imagehlp.lib
*
* To run, you need to put dynamorio.dll into either the current directory
* or system32.
*/
#include "dr_api.h"
#include <assert.h>
#include <imagehlp.h>
#include <stdio.h>
#ifdef LINUX
# define EXPORT
#else
# define EXPORT __declspec(dllexport)
#endif
/* global params */
static bool expect_int2e = false;
static bool expect_sysenter = false;
static bool expect_wow = false;
static bool expect_x64 = false;
static bool verbose = false;
static bool list_exports = false;
static bool list_forwards = false;
static bool list_Ki = false;
static bool list_syscalls = false;
static bool ignore_Zw = false;
static void
common_print(char *fmt, va_list ap)
{
vfprintf(stdout, fmt, ap);
fflush(stdout);
}
static void
verbose_print(char *fmt, ...)
{
if (verbose) {
va_list ap;
va_start(ap, fmt);
common_print(fmt, ap);
va_end(ap);
}
}
static void
print(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
common_print(fmt, ap);
va_end(ap);
}
#define MAX_INSTRS_BEFORE_SYSCALL 16
#define MAX_INSTRS_IN_FUNCTION 256
typedef struct {
int sysnum;
int num_args;
int fixup_index; /* WOW dlls only */
} syscall_info_t;
/* returns false on failure */
static bool
decode_function(void *dcontext, byte *entry)
{
byte *pc;
int num_instr = 0;
bool found_ret = false;
instr_t *instr;
if (entry == NULL)
return false;
instr = instr_create(dcontext);
pc = entry;
while (true) {
instr_reset(dcontext, instr);
pc = decode(dcontext, pc, instr);
dr_print_instr(dcontext, STDOUT, instr, "");
if (instr_is_return(instr)) {
found_ret = true;
break;
}
num_instr++;
if (num_instr > MAX_INSTRS_IN_FUNCTION) {
print("ERROR: hit max instr limit %d\n", MAX_INSTRS_IN_FUNCTION);
break;
}
}
instr_destroy(dcontext, instr);
return found_ret;
}
static void
check_Ki(const char *name)
{
/* FIXME: eventually we should automatically analyze these, but
* not worth the time at this point. Once we have automatic
* analysis code, should put it into DR debug build init too! For
* now we issue manual instructions about verifying our
* assumptions, and look for unknown Ki routines.
*/
if (strcmp(name, "KiUserApcDispatcher") == 0) {
print("verify that:\n"
"\t1) *esp == call* target (not relied on)\n"
"\t2) *(esp+16) == CONTEXT\n");
} else if (strcmp(name, "KiUserExceptionDispatcher") == 0) {
print("verify that:\n"
"\t1) *esp = EXCEPTION_RECORD*\n"
"\t2) *(esp+4) == CONTEXT*\n");
} else if (strcmp(name, "KiRaiseUserExceptionDispatcher") == 0) {
print("we've never seen this guy invoked\n");
} else if (strcmp(name, "KiUserCallbackDispatcher") == 0) {
print("verify that:\n"
"\t1) peb->KernelCallbackTable[*(esp+4)] == call* target (not relied on)\n");
} else if (strcmp(name, "KiFastSystemCall") == 0) {
print("should be simply \"mov esp,edx; sysenter; ret\"\n");
} else if (strcmp(name, "KiFastSystemCallRet") == 0) {
print("should be simply \"ret\"\n");
} else if (strcmp(name, "KiIntSystemCall") == 0) {
print("should be simply \"lea 0x8(esp),edx; int 2e; ret\"\n");
} else {
print("WARNING! UNKNOWN Ki ROUTINE!\n");
}
}
/* returns false on failure */
static bool
decode_syscall_num(void *dcontext, byte *entry, syscall_info_t *info)
{
/* FIXME: would like to fail gracefully rather than have a DR assertion
* on non-code! => use DEBUG=0 INTERNAL=1 DR build!
*/
bool found_syscall = false, found_eax = false, found_edx = false, found_ecx = false;
bool found_ret = false;
byte *pc;
int num_instr = 0;
instr_t *instr;
if (entry == NULL)
return false;
info->num_args = -1; /* if find sysnum but not args */
info->sysnum = -1;
instr = instr_create(dcontext);
pc = entry;
/* FIXME - we don't support decoding 64bit instructions in 32bit mode, but I want
* this to work on 32bit machines. Hack fix based on the wrapper pattern, we skip
* the first instruction (mov r10, rcx) here, the rest should decode ok.
* Xref PR 236203. */
if (expect_x64 && *pc == 0x4c && *pc+1 == 0x8b && *pc+2 == 0xd1)
pc += 3;
while (true) {
instr_reset(dcontext, instr);
pc = decode(dcontext, pc, instr);
if (verbose)
dr_print_instr(dcontext, STDOUT, instr, "");
if (pc == NULL || !instr_valid(instr))
break;
/* ASSUMPTION: a mov imm of 0x7ffe0300 into edx followed by an
* indirect call via edx is a system call on XP and later
* On XP SP1 it's call *edx, while on XP SP2 it's call *(edx)
* For wow it's a call through fs.
* FIXME - core exports various is_*_syscall routines (such as
* instr_is_wow64_syscall()) which we could use here instead of
* duplicating if they were more flexible about when they could
* be called (instr_is_wow64_syscall() for ex. asserts if not
* in a wow process).
*/
if (/* int 2e or x64 */
(instr_is_syscall(instr) && found_eax && (expect_int2e || expect_x64)) ||
/* sysenter case */
(expect_sysenter && found_edx && found_eax &&
instr_is_call_indirect(instr) &&
/* XP SP{0,1}, 2003 SP0: call *edx */
((opnd_is_reg(instr_get_target(instr)) &&
opnd_get_reg(instr_get_target(instr)) == REG_EDX) ||
/* XP SP2, 2003 SP1: call *(edx) */
(opnd_is_base_disp(instr_get_target(instr)) &&
opnd_get_base(instr_get_target(instr)) == REG_EDX &&
opnd_get_index(instr_get_target(instr)) == REG_NULL &&
opnd_get_disp(instr_get_target(instr)) == 0))) ||
/* wow case */
(expect_wow && found_ecx && found_eax &&
instr_is_call_indirect(instr) &&
opnd_is_far_base_disp(instr_get_target(instr)) &&
opnd_get_base(instr_get_target(instr)) == REG_NULL &&
opnd_get_index(instr_get_target(instr)) == REG_NULL &&
opnd_get_segment(instr_get_target(instr)) == SEG_FS)) {
found_syscall = true;
} else if (instr_is_return(instr)) {
if (opnd_is_immed_int(instr_get_src(instr, 0)))
info->num_args = opnd_get_immed_int(instr_get_src(instr, 0));
else
info->num_args = 0;
found_ret = true;
break;
} else if (instr_is_cti(instr)) {
/* assume not a syscall wrapper if we hit a cti */
break; /* give up gracefully */
} else if ((!found_eax || !found_edx || !found_ecx) &&
instr_get_opcode(instr) == OP_mov_imm &&
opnd_is_reg(instr_get_dst(instr, 0))) {
if (!found_eax && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EAX) {
info->sysnum = opnd_get_immed_int(instr_get_src(instr, 0));
found_eax = true;
} else if (!found_edx && opnd_get_reg(instr_get_dst(instr, 0)) == REG_EDX) {
int imm = opnd_get_immed_int(instr_get_src(instr, 0));
if (imm == 0x7ffe0300)
found_edx = true;
} else if (!found_ecx && opnd_get_reg(instr_get_dst(instr, 0)) == REG_ECX) {
found_ecx = true;
info->fixup_index = opnd_get_immed_int(instr_get_src(instr, 0));
}
} else if (instr_get_opcode(instr) == OP_xor &&
opnd_is_reg(instr_get_src(instr, 0)) &&
opnd_get_reg(instr_get_src(instr, 0)) == REG_ECX &&
opnd_is_reg(instr_get_dst(instr, 0)) &&
opnd_get_reg(instr_get_dst(instr, 0)) == REG_ECX) {
/* xor to 0 */
found_ecx = true;
info->fixup_index = 0;
}
num_instr++;
if (num_instr > MAX_INSTRS_BEFORE_SYSCALL) /* wrappers should be short! */
break; /* avoid weird cases like NPXEMULATORTABLE */
}
instr_destroy(dcontext, instr);
return found_syscall;
}
static void
process_exports(void *dcontext, char *dllname)
{
LOADED_IMAGE img;
IMAGE_EXPORT_DIRECTORY *dir;
IMAGE_SECTION_HEADER *sec;
DWORD *name, *code;
WORD *ordinal;
const char *string;
uint size;
BOOL res;
int i;
byte *addr, *start_exports, *end_exports;
syscall_info_t sysinfo;
res = MapAndLoad(dllname, NULL, &img, FALSE, TRUE);
if (!res) {
print("Error loading %s\n", dllname);
return;
}
dir = (IMAGE_EXPORT_DIRECTORY *)
ImageDirectoryEntryToData(img.MappedAddress, FALSE,
IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
verbose_print("mapped at 0x%08x, exports is at 0x%08x, size is 0x%x\n",
img.MappedAddress, dir, size);
start_exports = (byte *) dir;
end_exports = start_exports + size;
verbose_print("name=%s, ord base=0x%08x, names=%d 0x%08x\n",
(char *) ImageRvaToVa(img.FileHeader, img.MappedAddress,
dir->Name, NULL),
dir->Base, dir->NumberOfNames, dir->AddressOfNames);
/* don't limit functions to lie in .text --
* for ntdll, some exported routines have their code after .text, inside
* ECODE section!
*/
sec = img.Sections;
for (i = 0; i < img.NumberOfSections; i++) {
verbose_print("Section %d %s: 0x%x + 0x%x == 0x%08x through 0x%08x\n",
i, sec->Name, sec->VirtualAddress, sec->SizeOfRawData,
ImageRvaToVa(img.FileHeader, img.MappedAddress,
sec->VirtualAddress, NULL),
(uint) ImageRvaToVa(img.FileHeader, img.MappedAddress,
sec->VirtualAddress, NULL) +
sec->SizeOfRawData);
sec++;
}
name = (DWORD *) ImageRvaToVa(img.FileHeader, img.MappedAddress,
dir->AddressOfNames, NULL);
code = (DWORD *) ImageRvaToVa(img.FileHeader, img.MappedAddress,
dir->AddressOfFunctions, NULL);
ordinal = (WORD *) ImageRvaToVa(img.FileHeader, img.MappedAddress,
dir->AddressOfNameOrdinals, NULL);
verbose_print("names: from 0x%08x to 0x%08x\n",
ImageRvaToVa(img.FileHeader, img.MappedAddress, name[0], NULL),
ImageRvaToVa(img.FileHeader, img.MappedAddress,
name[dir->NumberOfNames-1], NULL));
for (i = 0; i < dir->NumberOfNames; i++) {
string = (char *) ImageRvaToVa(img.FileHeader, img.MappedAddress, name[i], NULL);
/* ordinal is biased (dir->Base), but don't add base when using as index */
assert(dir->NumberOfFunctions > ordinal[i]);
/* I don't understand why have to do RVA to VA here, when dumpbin /exports
* seems to give the same offsets but by simply adding them to base we
* get the appropriate code location -- but that doesn't work here...
*/
addr = ImageRvaToVa(img.FileHeader, img.MappedAddress,
code[ordinal[i]], NULL);
verbose_print("name=%s 0x%08x, ord=%d, code=0x%x -> 0x%08x\n",
string, string, ordinal[i], code[ordinal[i]], addr);
if (list_exports) {
print("ord %3d offs 0x%08x %s\n", ordinal[i],
addr - img.MappedAddress, string);
}
if (list_Ki && string[0] == 'K' && string[1] == 'i') {
print("\n==================================================\n");
print("%s\n\n", string);
check_Ki(string);
print("\ndisassembly:\n");
decode_function(dcontext, addr);
print( "==================================================\n");
}
/* forwarded export points inside exports section */
if (addr >= start_exports && addr < end_exports) {
if (list_forwards || verbose) {
/* I've had issues w/ forwards before, so avoid printing crap */
if (addr[0] > 0 && addr[0] < 127)
print("%s is forwarded to %.128s\n", string, addr);
else
print("ERROR identifying forwarded entry for %s\n", string);
}
} else if (list_syscalls) {
if (!ignore_Zw || string[0] != 'Z' || string[1] != 'w') {
if (decode_syscall_num(dcontext, addr, &sysinfo)) {
if (sysinfo.sysnum == -1) {
/* we expect this sometimes */
if (strcmp(string, "KiFastSystemCall") != 0 &&
strcmp(string, "KiIntSystemCall") != 0) {
print("ERROR: unknown syscall #: %s\n", string);
}
} else {
if (expect_wow) {
print("syscall # 0x%04x %2d args fixup 0x%02x = %s\n",
sysinfo.sysnum, sysinfo.num_args,
sysinfo.fixup_index, string);
} else if (expect_x64) {
print("syscall # 0x%04x = %s\n",
sysinfo.sysnum, string);
} else {
print("syscall # 0x%04x %2d args = %s\n",
sysinfo.sysnum, sysinfo.num_args, string);
}
}
}
}
}
}
}
static void
usage(char *pgm)
{
print("Usage: %s [-syscalls <-sysenter | -int2e | -wow | -x64> [-ignore_Zw]] | "
"-Ki | -exports | -forwards | -v] <dll>\n", pgm);
exit(-1);
}
int
main(int argc, char *argv[])
{
void *dcontext = dr_standalone_init();
OSVERSIONINFO version;
int res;
char *dll;
bool forced = false;
for (res=1; res < argc; res++) {
if (strcmp(argv[res], "-sysenter") == 0) {
expect_sysenter = true;
forced = true;
} else if (strcmp(argv[res], "-int2e") == 0) {
expect_int2e = false;
forced = true;
} else if (strcmp(argv[res], "-wow") == 0) {
expect_wow = true;
forced = true;
} else if (strcmp(argv[res], "-x64") == 0) {
expect_x64 = true;
/* FIXME - ideally we should switch to 64bit decoding mode here
* or compile for 64bit and switch the other options to 32bit
* xref case PR 236203. We hack a fix for -syscalls (see
* decode_syscall_num()) but -Ki won't work. */
forced = true;
} else if (strcmp(argv[res], "-v") == 0) {
verbose = true;
} else if (strcmp(argv[res], "-exports") == 0) {
list_exports = true;
list_forwards = true; /* implied */
} else if (strcmp(argv[res], "-forwards") == 0) {
list_forwards = true;
} else if (strcmp(argv[res], "-Ki") == 0) {
list_Ki = true;
} else if (strcmp(argv[res], "-syscalls") == 0) {
list_syscalls = true;
} else if (strcmp(argv[res], "-ignore_Zw") == 0) {
ignore_Zw = true;
} else if (argv[res][0] == '-') {
usage(argv[0]);
assert(false); /* not reached */
} else {
break;
}
}
if (res >= argc ||
(!list_syscalls && !list_Ki && !list_forwards && !verbose)) {
usage(argv[0]);
assert(false); /* not reached */
}
dll = argv[res];
if (!forced && list_syscalls) {
usage(argv[0]);
assert(false); /* not reached */
}
process_exports(dcontext, dll);
return 0;
}
+2161
View File
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
# **********************************************************
# Copyright (c) 2006-2008 VMware, Inc. All rights reserved.
# **********************************************************
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of VMware, Inc. nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
# Copyright (c) 2006-2007 Determina Corp.
##################################################
# pass build and version numbers
# custom builds: 9XYYZ
# X = developer, YY = tree, Z = diffnum
# YY defaults to 1st 2 letters of CUR_TREE, unless CASENUM is defined,
# in which case it is the last 2 letters of CASENUM (all % 10 of course)
DEVELOPERS=dbruenin vkirians tgarnett slarsen bchandra
ifeq ($(strip ${USER}),)
# USER is set on unix, USERNAME on windows -- in this makefile we use USER
USER=${USERNAME}
endif
ifndef BUILD_NUMBER
# schemes like 1st letter, uid, etc. can be concocted but not easy to avoid
# collisions so we just have a list
DEVELOPER_NUMS=1 2 3 4 5 6 7 8 9
DEVNUM=$(foreach num,${DEVELOPER_NUMS},\
$(if $(findstring ${USER},$(word ${num},${DEVELOPERS})), ${num}))
ifeq (${strip ${DEVNUM}},)
# unknown developer gets 0
DEVNUM=0
endif
CUR_FULL=$(shell cd ..$(CUR_FULL_ADD); $(ECHO) $$PWD)
CUR_TREE=$(notdir ${CUR_FULL})
ifeq ($(strip ${CASENUM}),)
# convert 1st two chars in tree name to numbers where a=0, b=1, etc.
# I had it as the more familiar a=1, b=2 but then numbers get 1 added to
# them and it gets confusing.
TREENUM=$(shell x=${CUR_TREE}; for ((i=0; i<2; i++)); do \
$(ECHO) $$((36\#$${x:$$i:1} % 10)); done)
else
# take last 2 chars of CASENUM, converted to digits as above
TREENUM=$(shell x=${CASENUM}; for ((i=2; i>0; i--)); do \
$(ECHO) $$((36\#$${x:$$((-$$i)):1} % 10)); done)
# FIXME: auto-create tree name for diffs by adding CASENUM to CUR_TREE?
endif
BUILD_NUMBER_SPACES=9${DEVNUM}${TREENUM}${DIFFNUM}
# seems to be no make function for removing spaces so we invoke shell for sed
BUILD_NUMBER=$(shell $(ECHO) ${BUILD_NUMBER_SPACES} | $(SED) 's/ //g')
RESOURCE_DEFINES = $(D)PRIVATE_BUILD $(D)PRERELEASE_BUILD $(D)PRIVATE_BUILD_DESC="\"$(USER) DIFFNUM=$(DIFFNUM) $(CUR_FULL)\""
endif # BUILD_NUMBER
ifdef SPECIAL_BUILD
RESOURCE_DEFINES += $(D)SPECIAL_BUILD $(D)SPECIAL_BUILD_DESC="\"$(SPECIAL_BUILD)\""
endif
##################################################
+45
View File
@@ -0,0 +1,45 @@
/* **********************************************************
* Copyright (c) 2003-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
#include "globals.h"
#include "defines.h"
#if defined(__DATE__) && defined(__TIME__)
const char dynamorio_buildmark[] = __DATE__ " " __TIME__;
#else
const char dynamorio_buildmark[] = "unknown";
#endif
const char dynamorio_version_string[] = PRODUCT_NAME" "VERSION_NUMBER_STRING", "\
BUILD_NUMBER_STRING", (c) "COMPANY_LONG_NAME;
+1931
View File
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
/* **********************************************************
* Copyright (c) 2000-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/* file "dispatch.h" */
#ifndef _DISPATCH_H_
#define _DISPATCH_H_ 1
/* returns true if pc is a point at which DynamoRIO should stop interpreting */
bool
is_stopping_point(dcontext_t *dcontext, app_pc pc);
/* central hub of control flow in DynamoRIO */
void
dispatch(dcontext_t *dcontext);
void
issue_last_system_call_from_app(dcontext_t *dcontext);
void
transfer_to_dispatch(dcontext_t *dcontext, int app_errno, dr_mcontext_t *mc);
/* hooks on entry/exit to/from DR */
#define NO_HOOK ((void (*)(void)) NULL)
#define HOOK_ENABLED_HELPER SELF_PROTECT_ON_CXT_SWITCH
#define HOOK_ENABLED (HOOK_ENABLED_HELPER || INTERNAL_OPTION(single_thread_in_DR))
#define ENTER_DR_HOOK (HOOK_ENABLED ? entering_dynamorio : NO_HOOK)
#define EXIT_DR_HOOK (HOOK_ENABLED ? exiting_dynamorio : NO_HOOK)
#define ENTERING_DR() do { \
if (HOOK_ENABLED) \
ENTER_DR_HOOK(); \
} while (0);
#define EXITING_DR() do { \
if (HOOK_ENABLED) \
EXIT_DR_HOOK(); \
} while (0);
/* magic value to set next_tag to, to indicate a return to native_exec */
#define BACK_TO_NATIVE_AFTER_SYSCALL ((app_pc)(ptr_uint_t) -1)
#endif /* _DISPATCH_H_ */
+2755
View File
File diff suppressed because it is too large Load Diff
+1026
View File
File diff suppressed because it is too large Load Diff
+89
View File
@@ -0,0 +1,89 @@
/* **********************************************************
* Copyright (c) 2000-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.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/*
* emit.h - fragment code generation interfaces
*/
#ifndef _EMIT_H_
#define _EMIT_H_ 1
/* Emits code for ilist into the fcache, returns the created
* fragment. Adds the fragment to the fragment hashtable and
* links it as a new fragment.
*/
fragment_t *
emit_fragment(dcontext_t *dcontext, app_pc tag,
instrlist_t *ilist, uint flags, void *vmlist,
bool link);
fragment_t *
emit_fragment_ex(dcontext_t *dcontext, app_pc tag,
instrlist_t *ilist, uint flags, void *vmlist,
bool link, bool visible);
/* Emits code for ilist into the fcache, returns the created fragment.
* Does not add the fragment to the ftable, leaving it as an "invisible"
* fragment. This means it is the caller's responsibility to ensure
* it is properly disposed of when done with.
* The fragment is also not linked, to give the caller more flexibility.
*/
fragment_t *
emit_invisible_fragment(dcontext_t *dcontext, app_pc tag,
instrlist_t *ilist, uint flags, void *vmlist);
fragment_t *
emit_fragment_as_replacement(dcontext_t *dcontext, app_pc tag, instrlist_t *ilist,
uint flags, void *vmlist, fragment_t *replace);
# ifdef INTERNAL
void stress_test_recreate(dcontext_t *dcontext, fragment_t *f,
instrlist_t *ilist);
# endif
bool
final_exit_shares_prev_stub(dcontext_t *dcontext, instrlist_t *ilist, uint frag_flags);
/* Walks ilist and f's linkstubs, setting each linkstub_t's fields appropriately
* for the corresponding exit cti in ilist.
* If emit is true, also encodes each instr in ilist to f's cache slot,
* increments stats for new fragments, and returns the final pc after all encodings.
*/
cache_pc
set_linkstub_fields(dcontext_t *dcontext, fragment_t *f, instrlist_t *ilist,
uint num_direct_stubs, uint num_indirect_stubs, bool emit);
#endif /* _EMIT_H_ */
+4588
View File
File diff suppressed because it is too large Load Diff
+164
View File
@@ -0,0 +1,164 @@
/* **********************************************************
* Copyright (c) 2000-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/*
* fcache.h - fcache exports
*/
#ifndef _FCACHE_H_
#define _FCACHE_H_ 1
/* who's in the "trace" cache?
* when we have private traces we put temp-private bbs there (to avoid
* perf hit in speccpu of having separate priv bb cache that's not
* normally used)
*/
#define IN_TRACE_CACHE(flags) \
(TEST(FRAG_IS_TRACE, (flags)) || \
(!DYNAMO_OPTION(shared_traces) && TEST(FRAG_TEMP_PRIVATE, (flags))))
/* Case 8647: we don't need to pad jmps for coarse-grain bbs */
#define PAD_FRAGMENT_JMPS(flags) \
(TEST(FRAG_COARSE_GRAIN, (flags)) ? false : DYNAMO_OPTION(pad_jmps))
#define PAD_JMPS_SHIFT_START(flags) \
(PAD_FRAGMENT_JMPS(flags) ? \
(TEST(FRAG_IS_TRACE, (flags)) ? INTERNAL_OPTION(pad_jmps_shift_trace) : \
INTERNAL_OPTION(pad_jmps_shift_bb)) : false)
/* control over what to reset */
enum {
/* everything, separate since more than sum of others */
RESET_ALL = 0x001,
/* NYI (case 6335): just bb caches + heap */
RESET_BASIC_BLOCKS = 0x002,
/* NYI (case 6335): just trace caches + heap */
RESET_TRACES = 0x004,
/* just pending deletion entries (-reset_every_nth_pending)
* TODO OPTIMIZATION (case 7147): we could avoid suspending
* everyone and only suspend those threads w/ low flushtimes.
*/
RESET_PENDING_DELETION = 0x008,
};
/* protects all reset triggers: reset_pending and reset_at_nth_thread_triggered
* resets are not queued up -- one wins and the rest are canceled
*/
extern mutex_t reset_pending_lock;
/* indicates a call to fcache_reset_all_caches_proactively() is pending from dispatch */
extern uint reset_pending;
void fcache_init(void);
void fcache_exit(void);
bool fcache_check_option_compatibility(void);
#if defined(WINDOWS_PC_SAMPLE) && !defined(DEBUG)
/* for fast exit path */
void fcache_profile_exit(void);
#endif
#ifdef DEBUG
void fcache_stats_exit(void);
#endif
bool in_fcache(void *pc);
void fcache_thread_init(dcontext_t *dcontext);
#ifdef DEBUG
void fcache_thread_exit_stats(dcontext_t *dcontext);
#endif
void fcache_thread_exit(dcontext_t *dcontext);
void fcache_add_fragment(dcontext_t *dcontext, fragment_t *f);
void fcache_shift_start_pc(dcontext_t *dcontext, fragment_t *f, uint space);
void fcache_return_extra_space(dcontext_t *dcontext, fragment_t *f, size_t space);
void fcache_remove_fragment(dcontext_t *dcontext, fragment_t *f);
bool fcache_is_flush_pending(dcontext_t *dcontext);
bool fcache_flush_pending_units(dcontext_t *dcontext, fragment_t *was_I_flushed);
void fcache_free_pending_units(dcontext_t *dcontext, uint flushtime);
void fcache_flush_all_caches(void);
void fcache_reset_all_caches_proactively(uint target);
bool schedule_reset(uint target);
void fcache_low_on_memory(void);
/* macros to put mask check outside of function, for efficiency */
/* when NULL is passed for f then the entire fcache will be affected */
#define SELF_PROTECT_CACHE(dc, f, w) do { \
if (TEST(SELFPROT_CACHE, dynamo_options.protect_mask) && \
((f) == NULL || (fcache_is_writable(f) != (w)))) \
fcache_change_fragment_protection(dc, f, w); \
} while (0);
bool fcache_is_writable(fragment_t *f);
void fcache_change_fragment_protection(dcontext_t *dcontext,
fragment_t *f, bool writable);
#ifdef SIDELINE
dcontext_t * get_dcontext_for_fragment(fragment_t *f);
#endif
/* for adaptive working set */
bool fragment_lookup_deleted(dcontext_t *dcontext, app_pc tag);
/* Returns the fragment_t whose body (not cache slot) contains lookup_pc */
fragment_t *
fcache_fragment_pclookup(dcontext_t *dcontext, cache_pc lookup_pc, fragment_t *wrapper);
void
fcache_coarse_cache_delete(dcontext_t *dcontext, coarse_info_t *info);
/* Returns the coarse info for the cache unit containing pc; if that unit
* is not coarse, returns NULL.
*/
coarse_info_t *
get_fcache_coarse_info(cache_pc pc);
/* Returns the total size needed for the cache if info is frozen. */
size_t
coarse_frozen_cache_size(dcontext_t *dcontext, coarse_info_t *info);
void
fcache_coarse_init_frozen(dcontext_t *dcontext, coarse_info_t *info,
cache_pc start_pc, size_t size);
void
fcache_coarse_set_info(dcontext_t *dcontext, coarse_info_t *info);
#endif /* _FCACHE_H_ */
+8618
View File
File diff suppressed because it is too large Load Diff
+1215
View File
File diff suppressed because it is too large Load Diff
+90
View File
@@ -0,0 +1,90 @@
#!/usr/local/bin/perl
# **********************************************************
# Copyright (c) 2004-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.
# Copyright (c) 2004-2007 Determina Corp.
### gen_event_strings.pl
### reads in a .mc file and creates a header file with fmt string constants
### matching those in the .mc file (in printf style format)
$usage = "Usage : gen_event_strings <mc file> <target file>";
#print stderr "$#ARGV\n";
#print stderr "$ARGV[0]\n";
#print stderr "$ARGV[1]\n";
if ($#ARGV != 1) {
print "$usage";
exit 0;
}
open(IN, "<$ARGV[0]") || die("Error : gen_event_strings : couldn't open .mc file ","$ARGV[0]","\n");
open(OUT, ">$ARGV[1]") || die("Error : gen_event_strings : couldn't open output file ","$ARGV[0]","\n");
while ($line = <IN>) {
$line =~ s/\r?\n$//; # chomp not sufficient for cross-plaform perl
if ($line =~ /^SymbolicName *= *(\S+)\s*$/) {
$name = $1 . "_STRING";
$val = "";
if ($line = <IN>) {
$line =~ s/\r?\n$//; # chomp not sufficient for cross-plaform perl
if ($line !~ /^Language *= *English\s*$/) {
# may need to remove once have multilingual support? FIXME
die("Error : gen_event_strings : pattern match for Language=English failed for ",$name,"\n");
}
$success = 0;
while ($line = <IN>) {
$line =~ s/\r?\n$//; # chomp not sufficient for cross-plaform perl
if ($line =~ /^\.\s*$/) {
$sucess = 1;
last;
}
$val .= $line;
$val .= "\\n";
}
# remove final newline
chop $val;
chop $val;
if ($sucess == 0) {
die("Error : file ended unexpectedly");
}
# FIXME we only need %s for now, but following should be general
# as long as the letter codes match (seems to be the case), what
# about 1, 2, 3 can the .mc fmt string reorder the arguments?
$val =~ s/%.!(.)!/%\1/g;
print OUT "#define ",$name," \"",$val,"\"\n";
} else {
die("Error : file ended unexpectedly");
}
}
}
+904
View File
@@ -0,0 +1,904 @@
/* **********************************************************
* Copyright (c) 2000-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.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/*
* globals.h - global defines and typedefs, included in all files
*/
#ifndef _GLOBALS_H_
#define _GLOBALS_H_ 1
#ifdef WINDOWS
/* Vista SDK compiler default is to set NTDDI_VERSION to NTDDI_LONGHORN, causing
* problems w/ new Vista-only flags like in PROCESS_ALL_ACCESS in win32/injector.c.
* The problematic flag there, PROCESS_QUERY_LIMITED_INFORMATION, is a subset of
* PROCESS_QUERY_INFORMATION, so we don't lose anything by not asking for it on Vista.
* But if they add new non-subset flags in the future we'd need dynamic dispatch,
* as earlier Windows versions give access denied on unknown flags!
*/
#define _WIN32_WINNT _WIN32_WINNT_NT4 /* ==0x0400; NTDDI_VERSION is set from this */
# define WIN32_LEAN_AND_MEAN
/* Exclude rarely-used stuff from Windows headers */
/* Case 1167 - bumping up warning level to 4 - work in progress FIXME: */
#pragma warning( disable : 4054) //from function pointer 'void (__cdecl *)(void )' to data pointer 'unsigned char *'
#pragma warning( disable : 4100) //'envp' : unreferenced formal parameter
#pragma warning( disable : 4127) //conditional expression is constant (majority of warnings - 2078)
#pragma warning( disable : 4189) //'start_pc' : local variable is initialized but not referenced
#pragma warning( disable : 4204) //nonstandard extension used : non-constant aggregate initializer
#pragma warning( disable : 4210) //nonstandard extension used : function given file scope
#pragma warning( disable : 4505) //unreferenced local function has been removed
#pragma warning( disable : 4702) //unreachable code (should be disabled DEBUG=0, e.g. for INTERNAL_OPTION test)
/**************************************************/
/* warnings on compiling with VC 8.0, all on VC or PlatformSDK header files */
/* shows up in buildtools/VC/8.0/dist/VC/include/vadefs.h
* supposed to include identifier in the pop pragma and they don't
*/
#pragma warning( disable : 4159) // #pragma pack has popped previously pushed identifier
/* FIXME case 191729: this is coming from our own code. We could
* switch to the _s versions when on Windows.
*/
#pragma warning( disable : 4996) //'sscanf' was declared deprecated
/**************************************************/
#endif
#include "globals_shared.h"
/* currently we always export statistics structure */
#define DYNAMORIO_STATS_EXPORTS 1
/* we only export IR interface if CLIENT_INTERFACE is defined */
#ifdef CLIENT_INTERFACE
/* in Makefile, we define these (so that genapi.pl, etc. get them):
* define DYNAMORIO_IR_EXPORTS 1
* define CUSTOM_EXIT_STUBS 1
* define CUSTOM_TRACES 1
* CUSTOM_TRACES_RET_REMOVAL is aggressive -- assumes calling convention kept
* Only useful if custom traces are doing inlining => do not define for external
* release, or even by default for internal since it's always on even if
* not building custom traces!
*/
#endif /* CLIENT_INTERFACE */
# ifdef WINDOWS
# define DYNAMORIO_EXPORT __declspec(dllexport)
# elif defined(USE_VISIBILITY_ATTRIBUTES)
/* PR 262804: we use "protected" instead of "default" to ensure our
* own uses won't be preempted. Note that for DR_APP_API in
* lib/dr_app.h we get a link error trying to use "protected": but we
* don't use dr_app_* internally anyway, so leaving as default.
*/
# define DYNAMORIO_EXPORT __attribute__ ((visibility ("protected")))
# else
/* visibility attribute not available in gcc < 3.3 (we use linker script) */
# define DYNAMORIO_EXPORT
# endif
#ifdef DYNAMORIO_IR_EXPORTS
# define DR_API DYNAMORIO_EXPORT
#else
# define DR_API
#endif
#ifdef UNSUPPORTED_API
# define DR_UNS_API DR_API
#else
# define DR_UNS_API /* nothing */
#endif
#define INLINE_ONCE inline
#include <stdlib.h>
#include <stdio.h>
/* N.B.: some of these typedefs and defines are duplicated in
* lib/globals_shared.h!
*/
#ifdef WINDOWS
#include <windows.h>
typedef unsigned long ulong;
typedef unsigned short ushort;
/* We can't put this in globals_shared.h b/c it needs windows.h and
* not all users of globals_shared.h want that included, so we
* duplicate it here (we do have Linux file_t stuff in globals_shared.h)
*/
/* since a FILE cannot be used outside of the DLL it was created in,
* we have to use HANDLE on Windows
* we hide the distinction behind the file_t type
*/
typedef HANDLE file_t;
#define INVALID_FILE INVALID_HANDLE_VALUE
#define STDOUT (file_t)get_stdout_handle()
#define STDERR (file_t)get_stderr_handle()
#define DIRSEP '\\'
#define ALT_DIRSEP '/'
#else /* LINUX */
/* uint, ushort, and ulong are in types.h */
#include <sys/types.h> /* for wait */
#define DIRSEP '/'
#define ALT_DIRSEP DIRSEP
#endif
/* FIXME: what is range of thread_id_t on linux and on win32?
* linux routines use -1 as sentinel, right?
* on win32, are ids only 16 bits?
* if so, change thread_id_t to be a signed int and use -1?
* For now, based on observation, no process on linux and no thread on windows
* has id 0 (on windows even a new thread in its init apc has a non-0 id)
*/
#define INVALID_THREAD_ID 0
typedef unsigned char uchar;
typedef byte * cache_pc; /* fragment cache pc */
typedef size_t app_rva_t; /* application offset from module base; PE32+ modules are
* limited to 2GB, but not elf x64 med/large code model. */
#define SUCCESS 0
#define FAILURE 1
/* macros to make conditional compilation look prettier */
#ifdef DGC_DIAGNOSTICS
# define _IF_DGCDIAG(x) , x
# define IF_DGCDIAG_ELSE(x, y) x
#else
# define _IF_DGCDIAG(x)
# define IF_DGCDIAG_ELSE(x, y) y
#endif
/* make sure defines are consistent */
#ifndef X86
#error Must define X86, no other platforms are supported
#endif
#if defined(PAPI) && defined(WINDOWS)
# error PAPI does not work on WINDOWS
#endif
#if defined(DCONTEXT_IN_EDI) && !defined(STEAL_REGISTER)
# error Must steal register to keep dcontext in edi
#endif
#if defined(SIDELINE_COUNT_STUDY)
# if !defined(PROFILE_LINKCOUNT) || !defined(SIDELINE)
# error SIDELINE_COUNT_STUDY requires PROFILE_LINKCOUNT and defined(SIDELINE)
# endif
#endif
#ifdef NATIVE_RETURN
# ifndef CUSTOM_EXIT_STUBS
# error NATIVE_RETURN requires CUSTOM_EXIT_STUBS
# endif
/* NOTE NATIVE_RETURN requires -unsafe_ignore_eflags */
#endif
#ifdef DGC_DIAGNOSTICS
# ifndef PROGRAM_SHEPHERDING
# error DGC_DIAGNOSTICS requires PROGRAM_SHEPHERDING
# endif
# ifndef DEBUG
# error DGC_DIAGNOSTICS requires DEBUG
# endif
#endif
#ifndef PROGRAM_SHEPHERDING
# ifdef SIMULATE_ATTACK
# error SIMULATE_ATTACK requires PROGRAM_SHEPHERDING
# endif
#endif
struct _opnd_t;
typedef struct _opnd_t opnd_t;
struct _instr_t;
typedef struct _instr_t instr_t;
struct _instr_list_t;
struct _fragment_t;
typedef struct _fragment_t fragment_t;
struct _future_fragment_t;
typedef struct _future_fragment_t future_fragment_t;
struct _trace_t;
typedef struct _trace_t trace_t;
struct _linkstub_t;
typedef struct _linkstub_t linkstub_t;
struct _dcontext_t;
typedef struct _dcontext_t dcontext_t;
struct vm_area_vector_t;
typedef struct vm_area_vector_t vm_area_vector_t;
struct _coarse_info_t;
typedef struct _coarse_info_t coarse_info_t;
struct _coarse_freeze_info_t;
typedef struct _coarse_freeze_info_t coarse_freeze_info_t;
struct _module_data_t;
/* DR_API EXPORT TOFILE dr_defines.h */
/* DR_API EXPORT BEGIN */
typedef struct _instr_list_t instrlist_t;
typedef struct _module_data_t module_data_t;
/* DR_API EXPORT END */
#if defined(RETURN_AFTER_CALL) || defined(RCT_IND_BRANCH)
struct _rct_module_table_t;
typedef struct _rct_module_table_t rct_module_table_t;
typedef enum {
RCT_RAC = 0,
RCT_RCT,
RCT_NUM_TYPES,
} rct_type_t;
#endif
#ifdef CLIENT_INTERFACE
typedef struct _client_to_do_list_t {
/* used to make a list of fragments to delete/replace */
/* deletes frag at tag if ilist is null else replaces it with ilist */
instrlist_t *ilist;
app_pc tag;
struct _client_to_do_list_t *next;
} client_todo_list_t;
/* Clients need a separate list to queue up flush requests from dr_flush() */
typedef struct _client_flush_req_t {
app_pc start;
size_t size;
uint flush_id; /* client supplied identifier for this flush */
void (*flush_callback)(int);
struct _client_flush_req_t *next;
} client_flush_req_t;
/* for -thin_client we don't allocate client_data currently, also client_data could be
* NULL during thread startup or teardown (i.e. mutex_wait_contended_lock() usage) */
#define IS_CLIENT_THREAD(dcontext) \
((dcontext) != NULL && (dcontext)->client_data != NULL && \
(dcontext)->client_data->is_client_thread)
/* Client interface-specific data for dcontexts */
typedef struct _client_data_t {
/* field for use by user via exported API */
void * user_field;
client_todo_list_t * to_do;
client_flush_req_t *flush_list;
# ifdef CLIENT_SIDELINE
mutex_t sideline_mutex;
mutex_t sideline_heap_lock;
# endif
/* fields for doing release and debug build checks against erroneous API usage */
module_data_t *no_delete_mod_data;
/* Client-owned threads, such as a client nudge thread, require special
* synchronization support. is_client_thread means that the thread is currently
* completely owned by the client. client_thread_safe_for_sync is use to mark
* client-owned threads that are safe for synch_with_all_threads synchronization but
* are in dynamo/native code (such as in dr_thread_yield(), dr_sleep(),
* dr_mutex_lock() and dr_messagebox()). Note it does not need to be set when
* the client is in client library code. For dr_mutex_lock() we set client_grab_mutex
* to the client mutex that is being locked so that we can set
* client_thread_safe_for_sync only around the actual wait.
* FIXME - PR 231301, we may need a way for clients that call ntdll directly to
* mark client_thread_safe_for_synch for client-owned threads when calling out to
* ntdll. Especially if they're calling system calls that wait or take a long time
* to finish etc. Applies to generated code and other libraries called by the client
* lib as well.
*/
bool is_client_thread; /* NOTE - use IS_CLIENT_THREAD() */
bool client_thread_safe_for_synch;
void *client_grab_mutex;
/* flags for asserts on linux and for getting param base right on windows */
bool in_pre_syscall;
bool in_post_syscall;
/* flag for dr_syscall_invoke_another() */
bool invoke_another_syscall;
} client_data_t;
#endif
typedef struct _thread_record_t {
thread_id_t id; /* linux: pid, win32: thread id */
#ifdef WINDOWS
HANDLE handle; /* win32 thread handle */
#endif
uint num; /* creation ordinal */
bool under_dynamo_control; /* used for deciding whether to intercept events */
dcontext_t *dcontext; /* allows other threads to see this thread's context */
struct _thread_record_t * next;
} thread_record_t;
/* we don't include dr_api.h, that's for external use, we only need _app
* (everything in dr_defines.h is duplicated in our own header files)
*/
#ifdef DR_APP_EXPORTS
/* we only export app interface if DR_APP_EXPORTS is defined */
# include "dr_app.h"
/* a few always-exported routines are part of the app interface */
# undef DYNAMORIO_EXPORT
# define DYNAMORIO_EXPORT DR_APP_API
#endif
#ifdef PROFILE_LINKCOUNT
#ifndef LINKCOUNT_64_BITS
typedef uint linkcount_type_t;
#else
typedef uint64 linkcount_type_t;
#endif
#endif
#include "heap.h"
#include "utils.h"
#include "options.h"
#include "os_exports.h"
#include "arch_exports.h"
#include "vmareas.h"
#include "instrlist.h"
#include "dispatch.h"
#include "dr_stats.h"
/* size of each Dynamo thread-private stack */
#define DYNAMORIO_STACK_SIZE dynamo_options.stack_size
/* global flags */
extern bool automatic_startup; /* ignore start/stop api, run entire program */
extern bool control_all_threads; /* ok for "weird" things to happen -- not all
threads are under our control */
extern bool dynamo_heap_initialized; /* has dynamo_heap been initialized? */
extern bool dynamo_initialized; /* has dynamo been initialized? */
extern bool dynamo_exited; /* has dynamo exited? */
extern bool dynamo_exited_and_cleaned; /* has dynamo component cleanup started? */
#ifdef DEBUG
extern bool dynamo_exited_log_and_stats; /* are stats and logfile shut down? */
#endif
extern bool dynamo_resetting; /* in middle of global reset? */
extern bool dynamo_all_threads_synched; /* are all other threads suspended safely? */
#if defined(CLIENT_INTERFACE) || defined(STANDALONE_UNIT_TEST)
extern bool standalone_library; /* used as standalone library */
#endif
#ifdef LINUX
extern bool post_execve; /* have we performed an execve? */
#endif
/* global instance of statistics struct */
extern dr_statistics_t *stats;
/* the process-wide logfile */
extern file_t main_logfile;
/* initial stack so we don't have to use app's */
extern byte * initstack;
extern mutex_t initstack_mutex;
extern byte * initstack_app_xsp;
#if defined(WINDOWS) && defined(STACK_GUARD_PAGE)
/* PR203701: separate stack for error reporting when the dstack is exhausted */
extern byte * exception_stack;
#endif
/* keeps track of how many threads are in cleanup_and_terminate so that we know
* if any threads could still be using shared resources even if they aren't on
* the all_threads list */
extern int exiting_thread_count;
bool is_on_initstack(byte *esp);
bool is_on_dstack(dcontext_t *dcontext, byte *esp);
bool is_currently_on_dstack(dcontext_t *dcontext);
#ifdef WINDOWS
extern bool dr_early_injected;
extern int dr_early_injected_location;
extern bool dr_injected_primary_thread;
extern bool dr_injected_secondary_thread;
extern bool dr_late_injected_primary_thread;
#endif
#ifdef RETURN_AFTER_CALL
extern bool dr_preinjected;
#endif
#ifdef DR_APP_EXPORTS
/* flags to indicate when DR is being initialized / exited using the API */
extern bool dr_api_entry;
extern bool dr_api_exit;
#endif
/* in dynamo.c */
/* 9-bit addressed hash table takes up 2K, has capacity of 512
* we never resize, assuming won't be seeing more than a few hundred threads
*/
#define ALL_THREADS_HASH_BITS 9
extern thread_record_t **all_threads;
extern mutex_t all_threads_lock;
DYNAMORIO_EXPORT int dynamorio_app_init(void);
int dynamorio_app_exit(void);
#if defined(CLIENT_INTERFACE) || defined(STANDALONE_UNIT_TEST)
dcontext_t * standalone_init(void);
void standalone_exit(void);
#endif
thread_record_t * thread_lookup(thread_id_t tid);
void add_thread(IF_WINDOWS_(HANDLE hthread)
thread_id_t tid, bool under_dynamo_control, dcontext_t *dcontext);
bool remove_thread(IF_WINDOWS_(HANDLE hthread) thread_id_t tid);
uint get_thread_num(thread_id_t tid);
int get_num_threads(void);
void get_list_of_threads(thread_record_t ***list, int *num);
bool is_thread_known(thread_id_t tid);
bool is_thread_initialized(void);
int dynamo_thread_init(void);
int dynamo_thread_exit(void);
void dynamo_thread_stack_free_and_exit(byte *stack);
int dynamo_other_thread_exit(thread_record_t *tr
_IF_WINDOWS(bool detach_stacked_callbacks));
void dynamo_thread_under_dynamo(dcontext_t *dcontext);
void dynamo_thread_not_under_dynamo(dcontext_t *dcontext);
/* used for synch to prevent thread creation/deletion in critical periods */
extern mutex_t thread_initexit_lock;
dcontext_t * create_new_dynamo_context(bool initial);
void initialize_dynamo_context(dcontext_t *dcontext);
dcontext_t * create_callback_dcontext(dcontext_t *old_dcontext);
int dynamo_nullcalls_exit(void);
int dynamo_process_exit(void);
#ifdef LINUX
void dynamorio_fork_init(dcontext_t *dcontext);
#endif
dr_statistics_t * get_dr_stats(void);
/* functions needed by detach */
int dynamo_shared_exit(IF_WINDOWS_ELSE_NP(bool detach_stacked_callbacks, void));
/* perform exit tasks that require full thread data structs */
void dynamo_process_exit_with_thread_info(void);
/* enter/exit DR hooks */
void entering_dynamorio(void);
void exiting_dynamorio(void);
void handle_system_call(dcontext_t *dcontext);
/* self-protection */
void protect_data_section(uint sec, bool writable);
#ifdef DEBUG
const char *get_data_section_name(app_pc pc);
bool check_should_be_protected(uint sec);
# ifdef WINDOWS
bool data_sections_enclose_region(app_pc start, app_pc end);
# endif
#endif /* DEBUG */
/* all the locks used to protect shared data structures during multi-operation
* sequences, exported so that micro-operations can assert that one is held
*/
extern mutex_t bb_building_lock;
extern recursive_lock_t change_linking_lock;
/* where the current app thread's control is */
typedef enum {
WHERE_APP=0,
WHERE_INTERP,
WHERE_DISPATCH,
WHERE_MONITOR,
WHERE_SYSCALL_HANDLER,
WHERE_SIGNAL_HANDLER,
WHERE_TRAMPOLINE,
WHERE_CONTEXT_SWITCH,
WHERE_IBL,
WHERE_FCACHE,
WHERE_UNKNOWN,
#ifdef HOT_PATCHING_INTERFACE
WHERE_HOTPATCH,
#endif
WHERE_LAST
} where_am_i_t;
/* make args easier to read for protection change calls
* since only two possibilities not using new type
*/
enum {
READONLY=false,
WRITABLE=true
};
/* To handle TRY/EXCEPT/FINALLY setjmp */
typedef struct try_except_context_t {
/* FIXME: we are using a local dr_jmp_buf which is relatively
* small so minimal risk of dstack pressure. Alternatively, we
* can disallow nesting and have a single buffer per dcontext.
*/
dr_jmp_buf_t context;
struct try_except_context_t *prev_context;
} try_except_context_t;
typedef struct {
/* WARNING: if you change the offsets of any of these fields,
* you must also change the offsets in <arch>/<arch.s>
*/
dr_mcontext_t mcontext; /* real machine context (in arch_exports.h) */
#ifdef LINUX
int errno; /* errno used for app and dynamo */
#endif
bool at_syscall; /* for shared deletion syscalls_synch_flush,
* as well as syscalls handled from dispatch,
* and for reset to identify when at syscalls
*/
#ifdef X64
/* For Windows, 4 bytes of padding to fill out the 4-byte at_syscall,
* since dr_mcontext_t is 8-byte aligned */
#endif
} unprotected_context_t;
/* dynamo-specific context associated with each active app thread
* N.B.: make sure to update these routines as necessary if
* you add or remove fields:
* create_new_dynamo_context
* create_callback_dcontext
* initialize_dynamo_context
* swap_dcontexts
* if you add any pointers to data structures, make sure callback_setup()
* clears them to prevent stale pointers on callback return
*/
struct _dcontext_t {
/* NOTE: For any field to survive across callback stack switches it must either
* be indirected through a modular field or explicitly copied in
* create_callback_dcontext() (like the modular fields are).
*/
/* WARNING: if you change the offsets of any of these fields, up through
* ignore_enterexit, you must also change the offsets in <arch>/<arch.s>
*/
/* if SELFPROT_DCONTEXT, must split dcontext into unprotected and
* protected fields depending on whether they must be read-only
* when in the code cache.
* we waste sizeof(unprotected_context_t) bytes to provide runtime flexibility:
*/
union {
/* we use separate_upcontext if
* (TEST(SELFPROT_DCONTEXT, dynamo_options.protect_mask))
* else we use the inlined upcontext
*/
unprotected_context_t *separate_upcontext;
unprotected_context_t upcontext;
} upcontext;
/* HACK for x86.asm lack of runtime param access: this is either
* a self-ptr (to inlined upcontext) or if we separate upcontext it points there.
*/
unprotected_context_t *upcontext_ptr;
/* The next application pc to execute.
* Also used to store the cache pc to execute when entering the code cache,
* and set to the sentinel value BACK_TO_NATIVE_AFTER_SYSCALL for native_exec.
* FIXME: change to a union?
*/
app_pc next_tag;
linkstub_t * last_exit; /* last exit from cache */
byte * dstack; /* thread-private dynamo stack */
/* These are expected to retain their values across an entire native execution.
* We assume that callbacks and native_exec executions are properly nested, and
* we don't share these across callbacks, using the original value on returning.
*/
app_pc native_exec_retval; /* native_exec return address */
app_pc native_exec_retloc; /* native_exec return address app stack location */
#ifdef RETURN_STACK
byte * rstack; /* bottom of return stack */
byte * top_of_rstack; /* top of return stack */
#endif
int app_errno; /* storage for app's errno while in dynamo */
bool is_exiting; /* flag for exiting thread */
#ifdef WINDOWS
/* storage for an extra app value around sysenter system calls for the
* case 5441 Sygate interoperability hack */
/* FIXME - this needs to be moved into the upcontext as is written to
* in cache by ignore/shared_syscall, ramifications? */
app_pc sysenter_storage;
/* used to avoid enter/exit hooks for certain system calls (see case 4942) */
bool ignore_enterexit;
#endif
/* Coarse-grain cache exits require extra state storage as they do not
* use per-exit separate data structures
*/
union {
/* Indirect branches store on exit the source tag (with the type of
* branch coming from fake linkstubs), while direct store the source unit
*/
app_pc src_tag;
coarse_info_t *dir_exit;
} coarse_exit;
/************* end of offset-crucial fields *********************/
/* FIXME: now that we initialize a new thread's dcontext right away, and
* a new callback's as well, we should be able to get rid of this
*/
bool initialized; /* has this context been used yet? */
thread_id_t owning_thread;
#ifdef LINUX
process_id_t owning_process; /* handle shared address space w/o shared pid */
#endif
thread_record_t *thread_record; /* so don't have to do a thread_lookup */
where_am_i_t whereami; /* where control is at the moment */
void * allocated_start; /* used for cache alignment */
fragment_t * last_fragment; /* cached value of linkstub_fragment(last_exit) */
int sys_num; /* used for post_system_call */
#ifdef WINDOWS
reg_t * sys_param_base; /* used for post_system_call */
#endif
#if defined(LINUX) || defined(X64)
reg_t sys_param0; /* used for post_system_call */
reg_t sys_param1; /* used for post_system_call */
reg_t sys_param2; /* used for post_system_call */
reg_t sys_param3; /* used for post_system_call */
#endif
#ifdef LINUX
bool sys_was_int; /* was the last system call via do_int_syscall? */
bool sys_xbp; /* PR 313715: store orig xbp */
#endif
#ifdef X64
/* Is this thread in 32-bit (x86) or 64-bit (x64) mode?
* Default is to decode as base platform, but we want runtime ability to
* decode/encode 32-bit from 64-bit dynamorio.dll (we don't support the
* other way around: PR 236203).
*/
bool x86_mode;
#endif
/* to make things more modular these are void*: */
void * link_field;
void * monitor_field;
void * fcache_field;
void * fragment_field;
void * heap_field;
void * vm_areas_field;
void * os_field;
void * synch_field;
#ifdef LINUX
void * signal_field;
void * pcprofile_field;
bool signals_pending;
#endif
void * private_code; /* various thread-private routines */
#ifdef TRACE_HEAD_CACHE_INCR
cache_pc trace_head_pc; /* HACK to jmp to trace head w/o a prefix */
#endif
#ifdef WINDOWS
/* these fields used for "stack" of contexts for callbacks */
# ifdef DCONTEXT_IN_EDI
dcontext_t *next_saved;
# endif
dcontext_t *prev_unused;
/* need to be able to tell which dcontexts in callback stack are valid */
bool valid;
/* special slot used to deal with callback returns, where we want to
* restore state of prior guy on callback stack, yet need current state
* to restore native state prior to callback return interrupt/syscall.
* Also used as temp next_tag slot for fcache_enter_indirect and cb ret.
*/
reg_t nonswapped_scratch;
#endif
/* next_tag holds the do_syscall entry point, so we need another
* slot to hold asynch targets for APCs to know next target and
* for NtContinue and sigreturn to set next target
*/
app_pc asynch_target;
/* must store post-intercepted-syscall target to allow using normal
* dispatch() for native_exec syscalls
*/
app_pc native_exec_postsyscall;
#ifdef PROGRAM_SHEPHERDING
bool alloc_no_reserve; /* to implement executable_if_alloc policy */
#endif
#ifdef CUSTOM_TRACES_RET_REMOVAL
int num_calls;
int num_rets;
int call_depth;
#endif
#ifdef NATIVE_RETURN
# ifdef NATIVE_RETURN_CALLDEPTH
uint call_depth;
# endif
cache_pc last_retaddr; /* used by fixup_last_cti */
int num_calls_in_trace;
#endif
#ifdef CHECK_RETURNS_SSE2
int call_depth;
void * call_stack;
#endif
#ifdef DEBUG
file_t logfile;
thread_local_statistics_t * thread_stats;
bool expect_last_syscall_to_fail;
/* HACK to avoid recursion on pclookup for target invoking disassembly
* during decode_fragment() for a coarse target
*/
bool in_opnd_disassemble;
#endif /* DEBUG */
#ifdef DEADLOCK_AVOIDANCE
thread_locks_t * thread_owned_locks;
#endif
#ifdef KSTATS
thread_kstats_t * thread_kstats;
#endif
#ifdef PROFILE_RDTSC
uint64 cache_enter_time;
uint64 start_time; /* records start time for profiling */
fragment_t * prev_fragment;
/* top ten times spent in cache */
uint64 cache_frag_count; /* num frag execs in single cache period */
uint64 cache_time[10]; /* top ten times spent in cache */
uint64 cache_count[10]; /* top ten cache_frag_counts */
#endif
#ifdef CLIENT_INTERFACE
/* client interface-specific data */
client_data_t *client_data;
#endif
/* FIXME trace_sysenter_exit is used to capture an exit from a trace that
* ends in a SYSENTER and to enable trace head marking. So it's really a
* monitor-centric variable. It's placed in the context for now so that
* it's not shared across contexts (as the monitor data is). Cross-context
* sharing of this field could cause inadvertent trace head marking,
* for example, during a callback. A longer-term fix may be to move it to
* a context-private non-shared monitor struct.
*/
bool trace_sysenter_exit;
/* DR sets this field to indicate that it's forging an exception that
* may appear to originate in DR but should be passed on to the app. */
app_pc forged_exception_addr;
#ifdef HOT_PATCHING_INTERFACE
/* Fix for case 5367. */
bool nudge_thread; /* True only if this is a nudge thread. */
dr_jmp_buf_t hotp_excpt_state; /* To handle hot patch exceptions. */
#endif
try_except_context_t *try_except_state; /* for TRY/EXCEPT/FINALLY */
bool unwinding_exception; /* NYI support for TRY/FINALLY -
* marks exception until an EXCEPT handles */
#ifdef WINDOWS
/* for ASLR_SHARED_CONTENT, note per callback, not per thread to
* track properties of a syscall or a syscall pair. Even we don't
* expect to get APCs or callbacks while processing normal DLLs
* this should be per dcontext.
*/
aslr_syscall_context_t aslr_context;
/* Initially memset to 0 in create dcontext. If this is a nudge (or
* internal detach) thread (as detected by start address in intercept_apc),
* nudge_target is set to the corresponding nudge routine (currently always
* generic_nudge_target). We can then check this
* value in those routines after we come out of the cache as a security
* measure (xref case 552). This gives us some protection against an
* attacker leveraging our own detach routines and the like. FIXME - if
* the attacker is able to specify the start address for a newly created
* thread then they can fake this. */
void *nudge_target;
/* If free_app_stack is set, we free the application stack during thread exit
* cleanup. Used for nudge threads. */
bool free_app_stack;
#endif /* WINDOWS */
/* we keep an absolute address pointer to our tls state so that we
* can access it from other threads
*/
local_state_t *local_state;
#ifdef WINDOWS
/* case 8721: saving the win32 start address so we can print it in the
* ldmp. An alternative solution is to call NtQueryInformationThread
* with ThreadQuerySetWin32StartAddress at dump time. According to
* Nebbet, however, a thread calling ZwReplyWaitReplyPort or
* ZwReplyWaitRecievePort will clobber the start address.
*/
app_pc win32_start_addr;
#endif
/* Used to abort bb building on decode faults. Not persistent across cache. */
void *bb_build_info;
};
/* sentinel value for dcontext_t* used to indicate
* "global rather than a particular thread"
*/
#define GLOBAL_DCONTEXT ((dcontext_t *)PTR_UINT_MINUS_1)
/* FIXME: why do we need to force the inline for this simple function? */
static INLINE_FORCED dr_mcontext_t *
get_mcontext(dcontext_t *dcontext)
{
if (TEST(SELFPROT_DCONTEXT, dynamo_options.protect_mask))
return &(dcontext->upcontext.separate_upcontext->mcontext);
else
return &(dcontext->upcontext.upcontext.mcontext);
}
/* A number of routines (dump_mbi*, dump_mcontext, dump_callstack,
* print_modules) have an argument on whether to dump in an xml friendly format
* (for xml diagnostics files). We use these defines for readability. */
enum {
DUMP_XML=true,
DUMP_NOT_XML=false
};
/* Code cleanliness rules */
#ifdef WINDOWS
# define snprintf _snprintf
# define snwprintf _snwprintf
# define vsnprintf _vsnprintf
# define strcasecmp _stricmp
# define strncasecmp _strnicmp
# define wcscasecmp _wcsicmp
#endif
#define printf printf_forbidden_function
#define sprintf sprintf_forbidden_function
#define swprintf swprintf_forbidden_function
#define vsprintf vsprintf_forbidden_function
#define __try __try_forbidden_construct /* see case 4461 */
/* libc independence */
#define mprotect mprotect_forbidden_function
#define mmap mmap_forbidden_function
#define munmap munmap_forbidden_function
#define getppid getppid_forbidden_function
#define sched_yield sched_yield_forbidden_function
#define dup dup_forbidden_function
#define sigaltstack sigaltstack_forbidden_function
#define setitimer setitimer_forbidden_function
#define _exit _exit_forbidden_function
#define gettimeofday gettimeofday_forbidden_function
#define time time_forbidden_function
#define modify_ldt modify_ldt_forbidden_function
#endif /* _GLOBALS_H_ */
+194
View File
@@ -0,0 +1,194 @@
/* **********************************************************
* Copyright (c) 2006-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.
*/
/* Copyright (c) 2006-2007 Determina Corp. */
#include "globals.h"
#include "hashtable.h"
/* Returns the proper number of hash bits to have a capacity with the
* given load for the given number of entries
*/
uint
hashtable_bits_given_entries(uint entries, uint load)
{
/* Add 1 for the sentinel */
return hashtable_num_bits(((entries + 1) * 100) / load);
}
#ifdef HASHTABLE_STATISTICS
/* caller is responsible for any needed synchronization */
void
print_hashtable_stats(dcontext_t *dcontext,
const char *is_final_str, const char *is_trace_str,
const char *lookup_routine_str,
const char *brtype_str,
hashtable_statistics_t *lookup_stats)
{
uint64 hits_stat = lookup_stats->hit_stat;
uint64 total_lookups;
if (lookup_stats->hit_stat < lookup_stats->collision_hit_stat) {
/* HACK OVERFLOW: we special case here the case of a single overflow */
/* assuming only one overflow, which is the only case on spec (GAP) */
hits_stat = (uint64)lookup_stats->hit_stat + UINT_MAX + 1;
}
total_lookups= hits_stat + lookup_stats->miss_stat + lookup_stats->collision_hit_stat;
DOLOG(1, LOG_FRAGMENT|LOG_STATS, {
uint miss_top=0; uint miss_bottom=0;
uint hit_top=0; uint hit_bottom=0;
uint col_top=0; uint col_bottom=0;
if (total_lookups > 0) {
divide_uint64_print(lookup_stats->miss_stat, total_lookups, false,
4, &miss_top, &miss_bottom);
}
if (hits_stat > 0) {
divide_uint64_print(lookup_stats->collision_hit_stat, hits_stat,
false, 4, &hit_top, &hit_bottom);
divide_uint64_print(hits_stat + lookup_stats->collision_stat,
hits_stat, false, 4, &col_top, &col_bottom);
}
LOG(THREAD, LOG_FRAGMENT|LOG_STATS, 1,
"%s %s table %s%s lookup hits%s: "UINT64_FORMAT_STRING", "
"misses: %u, total: "UINT64_FORMAT_STRING", miss%%=%u.%.4u\n",
is_final_str, is_trace_str, lookup_routine_str, brtype_str,
(lookup_stats->hit_stat < lookup_stats->collision_hit_stat) ?
"[OVFL]" : "",
hits_stat,
lookup_stats->miss_stat,
total_lookups,
miss_top, miss_bottom);
LOG(THREAD, LOG_FRAGMENT|LOG_STATS, 1,
"%s %s table %s%s "
"collisions: %u, collision hits: %u, "
">2_or_miss: %u, overwrap: %u\n",
is_final_str, is_trace_str, lookup_routine_str, brtype_str,
lookup_stats->collision_stat,
/* FIXME: collision hit stats are updated only when inlining IBL head */
lookup_stats->collision_hit_stat,
lookup_stats->collision_stat - lookup_stats->collision_hit_stat,
lookup_stats->overwrap_stat);
LOG(THREAD, LOG_FRAGMENT|LOG_STATS, 1,
"%s %s table %s%s lookup "
" coll%%=%u.%.4u, dyn.avgcoll=%u.%.4u\n",
is_final_str, is_trace_str, lookup_routine_str, brtype_str,
hit_top, hit_bottom,
col_top, col_bottom);
if (lookup_stats->race_condition_stat || lookup_stats->unlinked_count_stat) {
LOG(THREAD, LOG_FRAGMENT|LOG_STATS, 1,
"%s %s table %s%s inlined ibl unlinking races: %d, unlinked: %d\n",
is_final_str, is_trace_str, lookup_routine_str, brtype_str,
lookup_stats->race_condition_stat,
lookup_stats->unlinked_count_stat);
}
if (lookup_stats->ib_stay_on_trace_stat) {
uint ontrace_top=0; uint ontrace_bottom=0;
uint lastexit_top=0; uint lastexit_bottom=0;
uint speculate_lastexit_top=0; uint speculate_lastexit_bottom=0;
/* indirect branch lookups */
uint64 total_dynamic_ibs =
total_lookups + lookup_stats->ib_stay_on_trace_stat +
(DYNAMO_OPTION(speculate_last_exit) ? lookup_stats->ib_trace_last_ibl_speculate_success : 0);
/* FIXME: add ib_stay_on_trace_stat_ovfl here */
if (total_dynamic_ibs > 0) {
divide_uint64_print(lookup_stats->ib_stay_on_trace_stat,
total_dynamic_ibs, false,
4, &ontrace_top, &ontrace_bottom);
divide_uint64_print(lookup_stats->ib_trace_last_ibl_exit,
total_dynamic_ibs, false,
4, &lastexit_top, &lastexit_bottom);
divide_uint64_print(lookup_stats->ib_trace_last_ibl_speculate_success,
total_dynamic_ibs, false,
4, &speculate_lastexit_top, &speculate_lastexit_bottom);
}
/* all percentages here relative to IB lookups */
/* ontrace is how often we stay on trace with respect to all indirect branches */
/* ontrace_fail is assuming IBL's that are not the last exit are due to ontrace failures */
/* lastexit is how many are on last IBL when it is not speculated */
/* lastexit_speculate is how many are speculatively hit (as of all IBs) */
LOG(THREAD, LOG_FRAGMENT|LOG_STATS, 1,
"%s %s table %s%s stay on trace hit:%s %u, last_ibl: %u, ontrace%%=%u.%.4u, lastexit%%=%u.%.4u\n",
is_final_str, is_trace_str, lookup_routine_str, brtype_str,
lookup_stats->ib_stay_on_trace_stat_ovfl ? " OVFL" : "",
lookup_stats->ib_stay_on_trace_stat,
lookup_stats->ib_trace_last_ibl_exit,
ontrace_top, ontrace_bottom,
lastexit_top, lastexit_bottom
);
LOG(THREAD, LOG_FRAGMENT|LOG_STATS, 1,
"%s %s table %s%s last trace exit speculation hit: %u, lastexit_ontrace%%=%u.%.4u(%%IB)\n",
is_final_str, is_trace_str, lookup_routine_str, brtype_str,
lookup_stats->ib_trace_last_ibl_speculate_success,
speculate_lastexit_top, speculate_lastexit_bottom);
}
if (lookup_stats->ib_trace_last_ibl_exit > 0) {
/* ignoring indirect branches that stayed on trace */
/* FIXME: add ib_stay_on_trace_stat_ovfl here */
uint speculate_only_lastexit_top=0; uint speculate_only_lastexit_bottom=0;
uint lastexit_ibl_top=0; uint lastexit_ibl_bottom=0;
uint speculate_lastexit_ibl_top=0; uint speculate_lastexit_ibl_bottom=0;
uint64 total_dynamic_ibl_no_trace = total_lookups + lookup_stats->ib_trace_last_ibl_exit;
if (total_dynamic_ibl_no_trace > 0) {
divide_uint64_print(lookup_stats->ib_trace_last_ibl_exit,
total_dynamic_ibl_no_trace, false,
4, &lastexit_ibl_top, &lastexit_ibl_bottom);
divide_uint64_print(lookup_stats->ib_trace_last_ibl_speculate_success,
total_dynamic_ibl_no_trace, false,
4, &speculate_lastexit_ibl_top, &speculate_lastexit_ibl_bottom);
}
/* ib_trace_last_ibl_exit includes all ib_trace_last_ibl_speculate_success */
divide_uint64_print(lookup_stats->ib_trace_last_ibl_speculate_success,
lookup_stats->ib_trace_last_ibl_exit, false,
4, &speculate_only_lastexit_top, &speculate_only_lastexit_bottom);
LOG(THREAD, LOG_FRAGMENT|LOG_STATS, 1,
"%s %s table %s%s last trace exit speculation hit: %u, speculation miss: %u, lastexit%%=%u.%.4u(%%IBL), lastexit_succ%%=%u.%.4u(%%IBL), spec hit%%=%u.%.4u(%%last exit)\n",
is_final_str, is_trace_str, lookup_routine_str, brtype_str,
lookup_stats->ib_trace_last_ibl_speculate_success,
lookup_stats->ib_trace_last_ibl_exit - lookup_stats->ib_trace_last_ibl_speculate_success,
lastexit_ibl_top, lastexit_ibl_bottom,
speculate_lastexit_ibl_top, speculate_lastexit_ibl_bottom,
speculate_only_lastexit_top, speculate_only_lastexit_bottom
);
}
});
}
#endif /* HASHTABLE_STATISTICS */
+187
View File
@@ -0,0 +1,187 @@
/* **********************************************************
* Copyright (c) 2006-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.
*/
/* Copyright (c) 2006-2007 Determina Corp. */
/*
* hashtable.h
*
* Hashtable support common among all hashtables
*
*/
#ifndef _HASHTABLE_H_
#define _HASHTABLE_H_ 1
/* Flags stored in the table_flags bitfield that are common to
* all hashtables
*/
/* Is the table itself shared? */
#define HASHTABLE_SHARED 0x00000001
/* Are the entries in the table shared?
* FIXME: right now this is never used independently from LOCKLESS_ACCESS,
* perhaps get rid of it
*/
#define HASHTABLE_ENTRY_SHARED 0x00000002
/* Is the table accessed for reads concurrently without a lock? */
#define HASHTABLE_LOCKLESS_ACCESS 0x00000004
/* Is the table the primary, master list of its contents? */
#define HASHTABLE_NOT_PRIMARY_STORAGE 0x00000004
/* Is the table allocated in persistent memory? */
#define HASHTABLE_PERSISTENT 0x00000008
/* For debug builds: use per-entry statistics? */
#define HASHTABLE_USE_ENTRY_STATS 0x00000010
/* For non-performance-critical tables where we'd rather save memory */
#define HASHTABLE_RELAX_CLUSTER_CHECKS 0x00000020
/* Disallow adding or removing from the table, and acquire no locks on lookups
* Only used for persisted coarse units.
*/
#define HASHTABLE_READ_ONLY 0x00000040
/* Align the main table to the cache line */
#define HASHTABLE_ALIGN_TABLE 0x00000080
/* Specific tables can add their own flags starting with this value
* FIXME: any better way? how know when hit limit with <<?
*/
#define HASHTABLE_CUSTOM_FLAGS_START 0x00010000
/* Flags to NOT propagate to copies */
#define HASHTABLE_COPY_IGNORE_FLAGS (HASHTABLE_READ_ONLY)
/* single_thread_in_DR does not need rw locks since we do not access shared
* tables from ibl while holding locks (we do so in a lockless manner)
*/
#define TABLE_NEEDS_LOCK(ptable) \
(TEST(HASHTABLE_SHARED, (ptable)->table_flags) && \
!TEST(HASHTABLE_READ_ONLY, (ptable)->table_flags)) \
/* is_local is currently debug-only and only affects asserts */
#define ASSERT_TABLE_SYNCHRONIZED(ptable, RW) \
ASSERT_OWN_##RW##_LOCK(TABLE_NEEDS_LOCK(ptable) && \
!(ptable)->is_local && \
!INTERNAL_OPTION(single_thread_in_DR), &(ptable)->rwlock)
#define TABLE_RWLOCK(ptable,rw,lock) do { \
if (TABLE_NEEDS_LOCK(ptable)) \
rw##_##lock(&(ptable)->rwlock); \
} while (0)
#define TABLE_MEMOP(table_flags, op) \
(TEST((table_flags), HASHTABLE_PERSISTENT) ? \
heap_##op : nonpersistent_heap_##op)
#define TABLE_TYPE_MEMOP(table_flags, op, dc, type, which, protected) \
(TEST((table_flags), HASHTABLE_PERSISTENT) ? \
HEAP_TYPE_##op(dc, type, which, protected): \
NONPERSISTENT_HEAP_TYPE_##op(dc, type, which))
/* table capacity includes a sentinel so this is equivalent to
* hash_index % (ftable->capacity - 1)
*/
#define HASH_INDEX_WRAPAROUND(hash_index,ftable) \
((hash_index) & (uint)(ftable->hash_mask >> ftable->hash_mask_offset))
#ifdef HASHTABLE_STATISTICS
/* Just a typechecking memset() wrapper */
# define INIT_HASHTABLE_STATS(lookup_stats) do { \
memset(&lookup_stats, 0, sizeof(hashtable_statistics_t)); \
ASSERT(lookup_stats.hit_stat == 0); \
} while (0)
# define HTABLE_STAT_INC(ftable,event) ftable->drlookup_stats.event##_stat++
#else
# define HTABLE_STAT_INC(ftable,event) ((void)0)
#endif
#ifdef HASHTABLE_STATISTICS
typedef struct _hashtable_statistics_t {
uint hit_stat; /* hit count of hash table lookups */
uint collision_hit_stat; /* lookups which collided but were hits */
uint collision_stat; /* total collision lookups (including misses) */
uint miss_stat; /* lookups which still ended up with a context switch */
uint overwrap_stat; /* lookups whose collision chain crosses overwrap sentinel */
uint race_condition_stat; /* number of inilned ibl unlinking race condition cases */
uint unlinked_count_stat; /* number of times unlinked */
/* Stay on trace check combined with hashtable lookups gives the
* dynamic count of indirect branches
* FIXME: case 4817 where bb's could also cache one target
* or see the CGO03 paper for multiple cached locations with similar stats
*/
uint ib_stay_on_trace_stat; /* hash table lookup avoided - cached single target location */
/* This is likely to overflow in many cases, yet 64-bit in cache
* increment is too heavy weight, should instead save last value
* assuming that some rare, yet common enough event happens
* between every 4 billion increments
*/
uint ib_stay_on_trace_stat_last; /* last value */
uint ib_stay_on_trace_stat_ovfl; /* number of times last was bigger than current */
uint ib_trace_last_ibl_exit; /* hash table lookup for last exit - not cached */
/* FIXME: add last and ovfl flag here as well */
/* case 4817: add counter on extra check for converting IB into conditional
* and add its success rate
*/
uint ib_trace_last_ibl_speculate_success; /* stay-on-trace check success on last exit */
/* FIXME: add last and ovfl flag here as well */
} hashtable_statistics_t;
/* A table used by IBL parallel to the lookuptable to collect statistics */
typedef struct _fragment_stat_entry_t {
/* hits * static collision length should equal */
uint hits; /* hits in IBL */
/* we need a filler for in-cache lookups */
uint age; /* used to measure for how long an entry hasn't been used */
} fragment_stat_entry_t;
#endif /* HASHTABLE_STATISTICS */
/* Returns the proper number of hash bits to have a capacity with the
* given load for the given number of entries
*/
uint
hashtable_bits_given_entries(uint entries, uint load);
#ifdef HASHTABLE_STATISTICS
/* caller is responsible for any needed synchronization */
void
print_hashtable_stats(dcontext_t *dcontext,
const char *is_final_str, const char *is_trace_str,
const char *lookup_routine_str,
const char *brtype_str,
hashtable_statistics_t *lookup_stats);
#endif
#endif /* _HASHTABLE_H_ */
+2229
View File
File diff suppressed because it is too large Load Diff
+4580
View File
File diff suppressed because it is too large Load Diff
+319
View File
@@ -0,0 +1,319 @@
/* **********************************************************
* Copyright (c) 2001-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.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2001 Hewlett-Packard Company */
/*
* heap.c - heap manager
*/
#ifndef _HEAP_H_
#define _HEAP_H_ 1
#ifdef HEAP_ACCOUNTING
typedef enum {
ACCT_FRAGMENT=0,
ACCT_COARSE_LINK,
ACCT_FRAG_FUTURE,
ACCT_FRAG_TABLE,
ACCT_IBLTABLE,
ACCT_TRACE,
ACCT_FCACHE_EMPTY,
ACCT_VMAREA_MULTI,
ACCT_IR,
ACCT_AFTER_CALL,
ACCT_VMAREAS,
ACCT_SYMBOLS,
# ifdef SIDELINE
ACCT_SIDELINE,
# endif
ACCT_THCOUNTER,
ACCT_TOMBSTONE, /* N.B.: leaks in this category are not reported;
* not currently used */
ACCT_HOT_PATCHING,
ACCT_THREAD_MGT,
ACCT_MEM_MGT,
ACCT_STATS,
ACCT_SPECIAL,
/* NOTE: Also update the whichheap_name in heap.c when adding here */
ACCT_OTHER,
ACCT_LAST
} which_heap_t;
# define HEAPACCT(x) , x
# define IF_HEAPACCT_ELSE(x, y) x
#else
# define HEAPACCT(x)
# define IF_HEAPACCT_ELSE(x, y) y
#endif
typedef byte * heap_pc;
#define HEAP_ALIGNMENT sizeof(heap_pc*)
extern vm_area_vector_t *landing_pad_areas;
/* Request that the supplied region be 32bit offset reachable from the DR heap. Should
* be called before vmm_heap_init() so we can place the DR heap to meet these constraints.
* Can also be called post vmm_heap_init() but at that point acts as an assert that the
* supplied region is reachable since the heap is already reserved. */
void
request_region_be_heap_reachable(byte *start, size_t size);
/* virtual heap manager */
void vmm_heap_init(void);
void vmm_heap_exit(void);
void print_vmm_heap_data(file_t outf);
void get_vmm_heap_bounds(byte **heap_start/*OUT*/, byte **heap_end/*OUT*/);
bool heap_check_option_compatibility(void);
bool is_vmm_reserved_address(byte *pc, size_t size);
bool rel32_reachable_from_heap(byte *target);
/* heap management */
void heap_init(void);
void heap_exit(void);
void heap_reset_init(void);
void heap_reset_free(void);
void heap_thread_init(dcontext_t *dcontext);
void heap_thread_exit(dcontext_t *dcontext);
/* re-initializes non-persistent memory */
void heap_thread_reset_init(dcontext_t *dcontext);
/* frees all non-persistent memory */
void heap_thread_reset_free(dcontext_t *dcontext);
/* these functions use the global heap instead of a thread's heap: */
void *global_heap_alloc(size_t size HEAPACCT(which_heap_t which));
void global_heap_free(void *p, size_t size HEAPACCT(which_heap_t which));
void *global_heap_realloc(void *ptr, size_t old_num, size_t new_num,
size_t element_size HEAPACCT(which_heap_t which));
bool lockwise_safe_to_allocate_memory(void);
/* use heap_mmap to allocate large chunks of executable memory */
void *heap_mmap(size_t size);
void heap_munmap(void *p, size_t size);
void *heap_mmap_reserve(size_t reserve_size, size_t commit_size);
void *heap_mmap_ex(size_t reserve_size, size_t commit_size, uint prot, bool guarded);
void heap_munmap_ex(void *p, size_t size, bool guarded);
/* updates dynamo_areas and calls the os_ versions */
byte *
map_file(file_t f, size_t size, size_t offs, app_pc addr, uint prot,
bool copy_on_write);
bool
unmap_file(byte *map, size_t size);
/* Allocates executable memory in the same allocation region as this thread's
* stack, to save address space (case 9474).
*/
void *
heap_mmap_reserve_post_stack(dcontext_t *dcontext,
size_t reserve_size, size_t commit_size);
void
heap_munmap_post_stack(dcontext_t *dcontext, void *p, size_t reserve_size);
/* It is up to the caller to ensure commit_size is a page size multiple,
* and that it does not extend beyond the initial reservation.
*/
void
heap_mmap_extend_commitment(void *p, size_t commit_size);
void
heap_mmap_retract_commitment(void *retract_start, size_t decommit_size);
/* use stack_alloc to build a stack -- it returns TOS */
void *stack_alloc(size_t size);
void stack_free(void *p, size_t size);
#ifdef STACK_GUARD_PAGE
/* checks if pc is in guard page on stack */
bool is_stack_overflow(dcontext_t *dcontext, byte *sp);
#endif
/* these are for thread-local allocs
* passing dcontext == GLOBAL_DCONTEXT will end up calling global_heap_{alloc,free}
*/
void *heap_alloc(dcontext_t *dcontext, size_t size HEAPACCT(which_heap_t which));
void heap_free(dcontext_t *dcontext, void *p, size_t size HEAPACCT(which_heap_t which));
#ifdef HEAP_ACCOUNTING
void print_heap_statistics(void);
#endif
/* FIXME: persistence is yet another dimension here
* let's clean all these up and have a single alloc routine?
*/
void *nonpersistent_heap_alloc(dcontext_t *dcontext, size_t size
HEAPACCT(which_heap_t which));
void nonpersistent_heap_free(dcontext_t *dcontext, void *p, size_t size
HEAPACCT(which_heap_t which));
bool local_heap_protected(dcontext_t *dcontext);
void protect_local_heap(dcontext_t *dcontext, bool writable);
void protect_global_heap(bool writable);
void *global_unprotected_heap_alloc(size_t size HEAPACCT(which_heap_t which));
void global_unprotected_heap_free(void *p, size_t size HEAPACCT(which_heap_t which));
#define UNPROTECTED_LOCAL_ALLOC(dc, ...) global_unprotected_heap_alloc(__VA_ARGS__)
#define UNPROTECTED_LOCAL_FREE(dc, ...) global_unprotected_heap_free(__VA_ARGS__)
#define UNPROTECTED_GLOBAL_ALLOC global_unprotected_heap_alloc
#define UNPROTECTED_GLOBAL_FREE global_unprotected_heap_free
/* use global heap for shared fragments and their related data structures */
#define FRAGMENT_ALLOC_DC(dc, flags) (TEST(FRAG_SHARED, (flags)) ? GLOBAL_DCONTEXT : (dc))
#define FRAGMENT_TABLE_ALLOC_DC(dc, flags) (TEST(FRAG_TABLE_SHARED, (flags)) ? GLOBAL_DCONTEXT : (dc))
/* convenience for allocating a single type: does cast, sizeof, and HEAPACCT
* for you, and takes param for whether protected or not
*/
#define PROTECTED true
#define UNPROTECTED false
#define HEAP_ARRAY_ALLOC(dc, type, num, which, protected) \
((protected) ? \
(type *) heap_alloc(dc, sizeof(type)*(num) HEAPACCT(which)) : \
(type *) UNPROTECTED_LOCAL_ALLOC(dc, sizeof(type)*(num) HEAPACCT(which)))
#define HEAP_TYPE_ALLOC(dc, type, which, protected) \
HEAP_ARRAY_ALLOC(dc, type, 1, which, protected)
#define HEAP_ARRAY_ALLOC_MEMSET(dc, type, num, which, protected, val) \
memset(HEAP_ARRAY_ALLOC(dc, type, num, which, protected), (val), \
sizeof(type)*(num));
#define HEAP_ARRAY_FREE(dc, p, type, num, which, protected) \
((protected) ? \
heap_free(dc, (type*)p, sizeof(type)*(num) HEAPACCT(which)) : \
UNPROTECTED_LOCAL_FREE(dc, (type*)p, sizeof(type)*(num) HEAPACCT(which)))
#define HEAP_TYPE_FREE(dc, p, type, which, protected) \
HEAP_ARRAY_FREE(dc, p, type, 1, which, protected)
/* nonpersistent heap is assumed to be protected */
#define NONPERSISTENT_HEAP_ARRAY_ALLOC(dc, type, num, which) \
(type *) nonpersistent_heap_alloc(dc, sizeof(type)*(num) HEAPACCT(which))
#define NONPERSISTENT_HEAP_TYPE_ALLOC(dc, type, which) \
NONPERSISTENT_HEAP_ARRAY_ALLOC(dc, type, 1, which)
#define NONPERSISTENT_HEAP_ARRAY_FREE(dc, p, type, num, which) \
nonpersistent_heap_free(dc, (type*)p, sizeof(type)*(num) HEAPACCT(which))
#define NONPERSISTENT_HEAP_TYPE_FREE(dc, p, type, which) \
NONPERSISTENT_HEAP_ARRAY_FREE(dc, p, type, 1, which)
/* special heap of same-sized blocks that avoids global locks */
void *special_heap_init(uint block_size, bool use_lock, bool executable,
bool persistent);
void special_heap_exit(void *special);
void *special_heap_alloc(void *special);
void *special_heap_calloc(void *special, uint num);
void special_heap_free(void *special, void *p);
void special_heap_cfree(void *special, void *p, uint num);
#if defined(WINDOWS_PC_SAMPLE) && !defined(DEBUG)
void special_heap_profile_exit(void);
#endif
/* iterator over units in a special heap */
typedef struct _special_heap_iterator {
/* opaque types, exposed to support stack-alloc iterator */
void *heap;
void *next_unit;
} special_heap_iterator_t;
/* Special heap iterator. Initialized with special_heap_iterator_start(), and
* destroyed with special_heap_iterator_stop() to release the lock.
* If the special heap uses no lock for alloc, it is up to the caller
* to prevent race conditions causing problems.
* Accessor special_heap_iterator_next() should be called only when
* predicate special_heap_iterator_hasnext() is true.
* Any mutation of the heap while iterating will result in a deadlock
* for heaps that use locks for alloc.
*/
void
special_heap_iterator_start(void *heap, special_heap_iterator_t *shi);
bool
special_heap_iterator_hasnext(special_heap_iterator_t *shi);
void
special_heap_iterator_next(special_heap_iterator_t *shi /* IN/OUT */,
app_pc *heap_start /* OUT */, app_pc *heap_end /* OUT */);
void
special_heap_iterator_stop(special_heap_iterator_t *shi);
/* Special heap w/ a vector for lookups */
void *
special_heap_pclookup_init(uint block_size, bool use_lock, bool executable,
bool persistent, vm_area_vector_t *vector, void *vector_data,
byte *heap_region, size_t heap_size, bool unit_full);
void
special_heap_set_vector_data(void *special, void *vector_data);
/* Returns false if the special heap has more than one unit or has a
* non-externally-allocated unit.
* Sets the cur pc for the only unit to end_pc.
*/
bool
special_heap_set_unit_end(void *special, byte *end_pc);
void heap_vmareas_synch_units(void);
/* Utility routine to delete special heap locks; needed for case 9593. */
void special_heap_delete_lock(void *special);
#ifdef DEBUG_MEMORY
# define HEAP_TO_BYTE_EX(hex) 0x##hex
# define HEAP_TO_BYTE(hex) HEAP_TO_BYTE_EX(hex)
# define HEAP_TO_UINT_EX(hex) 0x##hex##hex##hex##hex
# define HEAP_TO_UINT(hex) HEAP_TO_UINT_EX(hex)
# ifdef X64
# define HEAP_TO_PTR_UINT_EX(hex) 0x##hex##hex##hex##hex##hex##hex##hex##hex
# else
# define HEAP_TO_PTR_UINT_EX(hex) 0x##hex##hex##hex##hex
# endif
# define HEAP_TO_PTR_UINT(hex) HEAP_TO_PTR_UINT_EX(hex)
# define HEAP_UNALLOCATED cd
# define HEAP_UNALLOCATED_BYTE HEAP_TO_BYTE(HEAP_UNALLOCATED)
# define HEAP_UNALLOCATED_UINT HEAP_TO_UINT(HEAP_UNALLOCATED)
# define HEAP_UNALLOCATED_PTR_UINT HEAP_TO_PTR_UINT(HEAP_UNALLOCATED)
# define HEAP_ALLOCATED ab
# define HEAP_ALLOCATED_BYTE HEAP_TO_BYTE(HEAP_ALLOCATED)
# define HEAP_ALLOCATED_UINT HEAP_TO_UINT(HEAP_ALLOCATED)
# define HEAP_ALLOCATED_PTR_UINT HEAP_TO_PTR_UINT(HEAP_ALLOCATED)
# define HEAP_PAD bc
# define HEAP_PAD_BYTE HEAP_TO_BYTE(HEAP_PAD)
# define HEAP_PAD_UINT HEAP_TO_UINT(HEAP_PAD)
# define HEAP_PAD_PTR_UINT HEAP_TO_PTR_UINT(HEAP_PAD)
#endif
#endif /* _HEAP_H_ */
+6375
View File
File diff suppressed because it is too large Load Diff
+150
View File
@@ -0,0 +1,150 @@
/* **********************************************************
* Copyright (c) 2005-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2005-2007 Determina Corp. */
/*
* hotpatch.h - Exported interfaces from the hot patching module
*/
#ifndef _HOTPATCH_H_
#define _HOTPATCH_H_ 1
#ifdef HOT_PATCHING_INTERFACE /* Around the whole file */
/*----------------------------------------------------------------------------*/
/* Exported data types */
/* This type identifies a patch point that was matched during offset lookup.
* It describes the module, set and vulnerability the matching patch point
* belongs to.
*/
typedef struct {
/* Array index of the matching vulnerability in hotp_vul_table. */
int vul_index;
/* Array index of the matching set in hotp_vul_table[vul_index]. */
int set_index;
int module_index; /* Matching module index in the matching set. */
int ppoint_index; /* Matching patch point index in the matching module. */
} hotp_offset_match_t;
/*----------------------------------------------------------------------------*/
/* Exported data */
typedef enum {
/* Definitions of context types that are to be dumped into forensics files.
* Used by hotp, hotp_only & gbop to dump the right app context; case 8099.
* This is to overcome the limitations in using our current interface
* to report violations; planned to be fixed for Marlin - case 8079.
*/
CXT_TYPE_HOT_PATCH,
CXT_TYPE_CORE_HOOK
} cxt_type_t;
/* Leak to handle case 9593. This should go if we find a cleaner solution. */
#ifdef HEAP_ACCOUNTING
DEBUG_DECLARE(extern int hotp_only_tramp_bytes_leaked;)
#endif
#ifdef DEBUG_MEMORY
DEBUG_DECLARE(bool hotp_only_contains_leaked_trampoline(byte *pc, size_t size);)
#endif
/*----------------------------------------------------------------------------*/
/* Exported function prototypes */
bool hotp_does_region_need_patch(const app_pc start, const app_pc end,
bool own_hot_patch_lock);
bool hotp_inject(dcontext_t *dcontext, instrlist_t *ilist);
/* hotp_process_image() can be called in two different ways, one to process
* the image and the other one to just check it (bool just_check). just_check
* is used only in hotp_only mode to find out if a dll being loaded needs
* patching.
* FIXME: have another wrapper for just_check case; keeps it clean.
*/
void hotp_process_image(const app_pc base, const bool loaded,
const bool own_hot_patch_lock, const bool just_check,
bool *needs_processing, const thread_record_t **all_threads,
const int num_threads);
bool
hotp_ppoint_on_list(app_rva_t ppoint,
app_rva_t *hotp_ppoint_vec, uint hotp_ppoint_vec_num);
/* Returns the number of patch points for the matched vuls in [start,end).
* For now this routine assumes that [start,end) is contained in a single module.
* The caller must own the hotp_vul_table_lock (as a read lock).
*/
int
hotp_num_matched_patch_points(const app_pc start, const app_pc end);
/* Stores in vec the offsets for all the matched patch points in [start,end).
* Returns -1 if vec_num is too small (still fills it up).
* For now this routine assumes that [start,end) is contained in a single module.
* The caller must own the hotp_vul_table_lock (as a read lock).
*/
int
hotp_get_matched_patch_points(const app_pc start, const app_pc end,
app_rva_t *vec, uint vec_num);
/* Checks whether any matched patch point in [start, end) is not listed on
* hotp_ppoint_vec. If hotp_ppoint_vec is NULL just checks whether any patch
* point is matched in the region. For now this routine assumes that
* [start,end) is contained in a single module.
*/
bool
hotp_point_not_on_list(const app_pc start, const app_pc end, bool own_hot_patch_lock,
app_rva_t *hotp_ppoint_vec, uint hotp_ppoint_vec_num);
void hotp_nudge_handler(uint nudge_action_mask);
void hotp_init(void);
void hotp_exit(void);
void hotp_reset_init(void);
void hotp_reset_free(void);
read_write_lock_t *hotp_get_lock(void);
void hotp_print_diagnostics(file_t diagnostics_file);
bool hotp_only_in_tramp(const app_pc eip);
void hotp_only_detach_helper(void);
void hotp_only_mem_prot_change(const app_pc start, const size_t size,
const bool remove, const bool inject);
void hotp_spill_before_notify(dcontext_t *dcontext,
fragment_t **frag_spill /* OUT */,
fragment_t *new_frag, const app_pc new_frag_tag,
app_pc *new_tag_spill /* OUT */,
const app_pc new_tag,
dr_mcontext_t *cxt_spill /* OUT */,
const void *new_cxt, cxt_type_t cxt_type);
void hotp_restore_after_notify(dcontext_t *dcontext,
const fragment_t *old_frag,
const app_pc old_next_tag,
const dr_mcontext_t *old_cxt);
#endif /* HOT_PATCHING_INTERFACE Around the whole file */
#endif /* _HOTPATCH_H_ 1 */
+387
View File
@@ -0,0 +1,387 @@
/* **********************************************************
* Copyright (c) 2000-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.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/* file "instr_list.c" */
#include "globals.h"
#include "instrlist.h"
#include "instr.h"
#include <string.h>
#ifdef DEBUG
/* case 10450: give messages to clients */
# undef ASSERT /* N.B.: if have issues w/ DYNAMO_OPTION, re-instate */
# undef ASSERT_TRUNCATE
# undef ASSERT_BITFIELD_TRUNCATE
# undef ASSERT_NOT_REACHED
# define ASSERT DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
# define ASSERT_TRUNCATE DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
# define ASSERT_BITFIELD_TRUNCATE DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
# define ASSERT_NOT_REACHED DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
#endif
/* returns an empty instrlist_t object */
instrlist_t*
instrlist_create(dcontext_t *dcontext)
{
instrlist_t *ilist = (instrlist_t*) heap_alloc(dcontext, sizeof(instrlist_t)
HEAPACCT(ACCT_IR));
CLIENT_ASSERT(ilist != NULL, "instrlist_create: allocation error");
instrlist_init(ilist);
return ilist;
}
/* initializes an instrlist_t object */
void
instrlist_init(instrlist_t *ilist)
{
CLIENT_ASSERT(ilist != NULL, "instrlist_create: NULL parameter");
ilist->first = ilist->last = NULL;
ilist->flags = 0; /* no flags set */
ilist->translation_target = NULL;
}
/* frees the instrlist_t object */
void
instrlist_destroy(dcontext_t *dcontext, instrlist_t *ilist)
{
CLIENT_ASSERT(ilist->first == NULL && ilist->last == NULL,
"instrlist_destroy: list not empty");
heap_free(dcontext, ilist, sizeof(instrlist_t) HEAPACCT(ACCT_IR));
}
/* frees the Instrs in the instrlist_t */
void
instrlist_clear(dcontext_t *dcontext, instrlist_t *ilist)
{
instr_t *instr;
while (NULL != (instr = instrlist_first(ilist))) {
instrlist_remove(ilist, instr);
instr_destroy(dcontext, instr);
}
}
/* frees the Instrs in the instrlist_t and the instrlist_t object itself */
void
instrlist_clear_and_destroy(dcontext_t *dcontext, instrlist_t *ilist)
{
instrlist_clear(dcontext,ilist);
instrlist_destroy(dcontext,ilist);
}
/* All future Instrs inserted into ilist that do not have raw bits
* will have instr_set_translation called with pc as the target
*/
void
instrlist_set_translation_target(instrlist_t *ilist, app_pc pc)
{
ilist->translation_target = pc;
}
app_pc
instrlist_get_translation_target(instrlist_t *ilist)
{
return ilist->translation_target;
}
void
instrlist_set_our_mangling(instrlist_t *ilist, bool ours)
{
if (ours)
ilist->flags |= INSTR_OUR_MANGLING;
else
ilist->flags &= ~INSTR_OUR_MANGLING;
}
bool
instrlist_get_our_mangling(instrlist_t *ilist)
{
return TEST(INSTR_OUR_MANGLING, ilist->flags);
}
/* returns the first inst in the list */
instr_t*
instrlist_first(instrlist_t *ilist)
{
return ilist->first;
}
/* returns the last inst in the list */
instr_t*
instrlist_last(instrlist_t *ilist)
{
return ilist->last;
}
static inline void
check_translation(instrlist_t *ilist, instr_t *inst)
{
if (ilist->translation_target != NULL && instr_get_translation(inst) == NULL) {
instr_set_translation(inst, ilist->translation_target);
}
if (instrlist_get_our_mangling(ilist))
instr_set_our_mangling(inst, true);
}
/* appends inst to the list ("inst" can be a chain of insts) */
void
instrlist_append(instrlist_t *ilist, instr_t *inst)
{
instr_t *top = inst;
instr_t *bot;
CLIENT_ASSERT(instr_get_prev(inst) == NULL,
"instrlist_append: cannot add middle of list");
check_translation(ilist, inst);
while (instr_get_next(inst)) {
inst = instr_get_next(inst);
check_translation(ilist, inst);
}
bot = inst;
if (ilist->last) {
instr_set_next(ilist->last, top);
instr_set_prev(top, ilist->last);
ilist->last = bot;
}
else {
ilist->first = top;
ilist->last = bot;
}
}
/* prepends inst to the list ("inst" can be a chain of insts) */
void
instrlist_prepend(instrlist_t *ilist, instr_t *inst)
{
instr_t *top = inst;
instr_t *bot;
CLIENT_ASSERT(instr_get_prev(inst) == NULL,
"instrlist_prepend: cannot add middle of list");
check_translation(ilist, inst);
while (instr_get_next(inst)) {
inst = instr_get_next(inst);
check_translation(ilist, inst);
}
bot = inst;
if (ilist->first) {
instr_set_next(bot, ilist->first);
instr_set_prev(ilist->first, bot);
ilist->first = top;
}
else {
ilist->first = top;
ilist->last = bot;
}
}
/* inserts "inst" before "where" ("inst" can be a chain of insts) */
void
instrlist_preinsert(instrlist_t *ilist, instr_t *where, instr_t *inst)
{
instr_t *whereprev;
instr_t *top = inst;
instr_t *bot;
if (where == NULL) {
/* if where is NULL there is no inst to send for a "before" */
instrlist_append(ilist, inst);
return;
}
CLIENT_ASSERT(where != NULL, "instrlist_preinsert: where cannot be NULL");
CLIENT_ASSERT(instr_get_prev(inst) == NULL,
"instrlist_preinsert: cannot add middle of list");
whereprev = instr_get_prev(where);
check_translation(ilist, inst);
while (instr_get_next(inst)) {
inst = instr_get_next(inst);
check_translation(ilist, inst);
}
bot = inst;
if (whereprev) {
instr_set_next(whereprev, top);
instr_set_prev(top, whereprev);
}
else {
ilist->first = top;
}
instr_set_next(bot, where);
instr_set_prev(where, bot);
}
/* inserts "inst" after "where" ("inst" can be a chain of insts) */
void
instrlist_postinsert(instrlist_t *ilist, instr_t *where, instr_t *inst)
{
instr_t *wherenext;
instr_t *top = inst;
instr_t *bot;
if (where == NULL) {
/* if where is NULL there is no inst to send for an "after" */
instrlist_prepend(ilist, inst);
return;
}
CLIENT_ASSERT(where != NULL, "instrlist_postinsert: where cannot be NULL");
CLIENT_ASSERT(instr_get_prev(inst) == NULL,
"instrlist_postinsert: cannot add middle of list");
wherenext = instr_get_next(where);
check_translation(ilist, inst);
while (instr_get_next(inst)) {
inst = instr_get_next(inst);
check_translation(ilist, inst);
}
bot = inst;
instr_set_next(where, top);
instr_set_prev(top, where);
if (wherenext) {
instr_set_next(bot, wherenext);
instr_set_prev(wherenext, bot);
}
else {
ilist->last = bot;
}
}
/* replace oldinst with newinst, remove oldinst from ilist, and return oldinst
(newinst can be a chain of insts) */
instr_t*
instrlist_replace(instrlist_t *ilist, instr_t *oldinst, instr_t *newinst)
{
instr_t *where;
CLIENT_ASSERT(oldinst != NULL, "instrlist_replace: oldinst cannot be NULL");
CLIENT_ASSERT(instr_get_prev(newinst) == NULL,
"instrlist_replace: cannot add middle of list");
where = instr_get_prev(oldinst);
instrlist_remove(ilist, oldinst);
if (where)
instrlist_postinsert(ilist, where, newinst);
else
instrlist_prepend(ilist, newinst);
return oldinst;
}
/* removes "inst" from the instrlist_t it currently belongs to */
void
instrlist_remove(instrlist_t *ilist, instr_t *inst)
{
if (instr_get_prev(inst))
instr_set_next(instr_get_prev(inst), instr_get_next(inst));
else
ilist->first = instr_get_next(inst);
if (instr_get_next(inst))
instr_set_prev(instr_get_next(inst), instr_get_prev(inst));
else
ilist->last = instr_get_prev(inst);
instr_set_prev(inst, NULL);
instr_set_next(inst, NULL);
}
instrlist_t*
instrlist_clone(dcontext_t *dcontext, instrlist_t *old)
{
instr_t *inst, *copy;
instrlist_t *newlist = instrlist_create(dcontext);
inst = instrlist_first(old);
while (inst != NULL) {
copy = instr_clone(dcontext, inst);
/* to copy instr targets we temporarily clobber note field */
instr_set_note(inst, (void *)copy);
instrlist_append(newlist, copy);
inst = instr_get_next(inst);
}
/* Fix up instr targets and restore note field */
for (inst = instrlist_first(old), copy = instrlist_first(newlist);
inst != NULL && copy != NULL;
inst = instr_get_next(inst), copy = instr_get_next(copy)) {
if (instr_is_cti(copy) && opnd_is_instr(instr_get_target(copy))) {
opnd_t op = instr_get_target(copy);
instr_t *tgt;
CLIENT_ASSERT(opnd_get_instr(op) != NULL,
"instrlist_clone: NULL instr target");
/* would be nice to assert the instr tgt is in this instrlist */
tgt = (instr_t *) instr_get_note(opnd_get_instr(op));
if (opnd_is_far_instr(op)) {
instr_set_target(copy, opnd_create_far_instr
(opnd_get_segment_selector(op), tgt));
} else
instr_set_target(copy, opnd_create_instr(tgt));
}
/* restore note field */
instr_set_note(inst, instr_get_note(copy));
}
return newlist;
}
/*
* puts a whole list (prependee) onto the front of ilist
* frees prependee when done because it will contain nothing useful
*/
void
instrlist_prepend_instrlist(dcontext_t *dcontext,instrlist_t *ilist,
instrlist_t *prependee)
{
instr_t *first=instrlist_first(prependee);
if (!first)
return;
instrlist_prepend(ilist,first);
instrlist_init(prependee);
instrlist_destroy(dcontext,prependee);
}
void instrlist_append_instrlist(dcontext_t *dcontext,instrlist_t *ilist,
instrlist_t *appendee)
{
instr_t *first=instrlist_first(appendee);
if (!first)
return;
instrlist_append(ilist,first);
instrlist_init(appendee);
instrlist_destroy(dcontext,appendee);
}
+188
View File
@@ -0,0 +1,188 @@
/* **********************************************************
* Copyright (c) 2000-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/* file "instrlist.h" */
#ifndef _INSTRLIST_H_
#define _INSTRLIST_H_ 1
struct _instr_list_t {
instr_t *first;
instr_t *last;
int flags;
app_pc translation_target;
}; /* instrlist_t */
/* DR_API EXPORT TOFILE dr_ir_instrlist.h */
/* DR_API EXPORT BEGIN */
/****************************************************************************
* INSTRLIST ROUTINES
*/
/**
* @file dr_ir_instrlist.h
* @brief Functions to create and manipulate lists of instructions.
*/
/* DR_API EXPORT END */
/* basic instrlist_t functions */
DR_API
/** Returns an initialized instrlist_t allocated on the thread-local heap. */
instrlist_t*
instrlist_create(dcontext_t *dcontext);
DR_API
/** Initializes \p ilist. */
void
instrlist_init(instrlist_t *ilist);
DR_API
/** Deallocates the thread-local heap storage for \p ilist. */
void
instrlist_destroy(dcontext_t *dcontext, instrlist_t *ilist);
DR_API
/** Frees the instructions in \p ilist. */
void
instrlist_clear(dcontext_t *dcontext, instrlist_t *ilist);
DR_API
/** Destroys the instructions in \p ilist and destroys the instrlist_t object itself. */
void
instrlist_clear_and_destroy(dcontext_t *dcontext, instrlist_t *ilist);
DR_API
/**
* All future instructions inserted into \p ilist that do not have raw bits
* will have instr_set_translation() called with \p pc as the target.
* This is a convenience routine to make it easy to have the same
* code generate non-translation and translation instructions, and it does
* not try to enforce that all instructions have translations (e.g.,
* some could be inserted via instr_set_next()).
*/
void
instrlist_set_translation_target(instrlist_t *ilist, app_pc pc);
DR_API
/** Returns the translation target, or NULL if none is set. */
app_pc
instrlist_get_translation_target(instrlist_t *ilist);
/* not exported: for PR 267260 */
void
instrlist_set_our_mangling(instrlist_t *ilist, bool ours);
bool
instrlist_get_our_mangling(instrlist_t *ilist);
DR_API
/** Returns the first instr_t in \p ilist. */
instr_t*
instrlist_first(instrlist_t *ilist);
DR_API
/** Returns the last instr_t in \p ilist. */
instr_t*
instrlist_last(instrlist_t *ilist);
DR_API
/** Adds \p instr to the end of \p ilist. */
void
instrlist_append(instrlist_t *ilist, instr_t *instr);
DR_API
/** Adds \p instr to the front of \p ilist. */
void
instrlist_prepend(instrlist_t *ilist, instr_t *instr);
DR_API
/**
* Allocates a new instrlist_t and for each instr_t in \p old allocates
* a new instr_t using instr_clone to produce a complete copy of \p old.
* Each operand that is opnd_is_instr() has its target updated
* to point to the corresponding instr_t in the new instrlist_t
* (this routine assumes that all such targets are contained within \p old,
* and may fault otherwise).
*/
instrlist_t*
instrlist_clone(dcontext_t *dcontext, instrlist_t *old);
/* Adds every instr_t in prependee to the front of ilist (maintaining
* the original order).
* Then calls instrlist_destroy on prependee.
* FIXME: get rid of this?
*/
void
instrlist_prepend_instrlist(dcontext_t *dcontext, instrlist_t *ilist,
instrlist_t *prependee);
/* Adds every instr_t in appendee to the end of ilist (maintaining
* the original order).
* Then calls instrlist_destroy on appendee.
* FIXME: get rid of this?
*/
void
instrlist_append_instrlist(dcontext_t *dcontext, instrlist_t *ilist,
instrlist_t *appendee);
/* instrlist_t functions focusing on a paricular instr_t
* For insert_before and insert_after, if the instr is NULL, either
* instrlist_append or instrlist_prepend will be called
*/
DR_API
/** Inserts \p instr into \p ilist prior to \p where. */
void
instrlist_preinsert(instrlist_t *ilist, instr_t *where, instr_t *instr);
DR_API
/** Inserts \p instr into \p ilist after \p where. */
void
instrlist_postinsert(instrlist_t *ilist, instr_t *where, instr_t *instr);
DR_API
/** Replaces \p oldinst with \p newinst in \p ilist (does not destroy \p oldinst). */
instr_t*
instrlist_replace(instrlist_t *ilist, instr_t *oldinst, instr_t *newinst);
DR_API
/** Removes (does not destroy) \p instr from \p ilist. */
void
instrlist_remove(instrlist_t *ilist, instr_t *instr);
#endif /* _INSTRLIST_H_ */
+618
View File
@@ -0,0 +1,618 @@
/* **********************************************************
* Copyright (c) 2002-2007 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2002-2003 Massachusetts Institute of Technology */
/*
* io.c - Linux specific routines for i/o that will not
* trigger problematic pthread calls.
* For PR 219380 we also export this routine to clients on Windows.
*/
/* FIXME: failure modes should be more gracefull then failing asserts in most places */
#include "globals.h"
#include <string.h>
#include <stdarg.h> /* for varargs */
#define VA_ARG_CHAR2INT
#define BUF_SIZE 64
const static char base_letters[] = {
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
};
const static char base_letters_cap[] = {
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
};
#ifdef LINUX
const static double pos_inf = 1.0/0.0;
const static double neg_inf = -1.0/0.0;
#else
/* Windows says "error C2099: initializer is not a constant", or
* "error C2124: divide or mod by zero", for the above.
*/
# pragma warning(disable : 4723) /* warning C4723: potential divide by 0 */
const static double zerof = 0.0;
# define pos_inf (1.0/zerof)
# define neg_inf (-1.0/zerof)
#endif
/* convert uint64 to a string */
static char *
uint64_to_str(uint64 num, int base, char * buf, int decimal, bool caps)
{
int cnt;
char *p = buf;
int end = (43 > decimal ? 43 : decimal);
ASSERT(decimal < BUF_SIZE - 1); /* so don't overflow buf */
buf[end] = '\0';
for (cnt = end - 1; cnt >= 0; cnt--) {
buf[cnt] = caps ? base_letters_cap[(num %base)] : base_letters[(num % base)];
num /= base;
}
while (*p && *p == '0' && end - decimal > 0) {
p++;
decimal++;
}
return p;
}
/* convert ulong to a string */
static char *
ulong_to_str(ulong num, int base, char *buf, int decimal, bool caps)
{
int cnt;
char *p = buf;
int end = (22 > decimal ? 22 : decimal); /* room for 64 bits octal */
ASSERT(decimal < BUF_SIZE - 1); /* so don't overflow buf */
buf[end] = '\0';
for (cnt = end - 1; cnt >= 0; cnt--) {
buf[cnt] = caps ? base_letters_cap[(num %base)] : base_letters[(num % base)];
num /= base;
}
while (*p && *p == '0' && end - decimal> 0) {
p++;
decimal++;
}
return p;
}
/* assumes that d > 0 */
static long
double2int(double d)
{
long i = (long)d;
if ((d - (double)i) >= 0.5)
return i+1;
else
return i;
}
static char *
double_to_str(double d, int decimal, char *buf, bool force_dot, bool suppress_zeros)
{
/* support really big numbers with %f? */
char tmpbuf[BUF_SIZE];
char *pre, *post, *c;
long predot, postdot, sub, i;
/* get pre and post dot sections as integers */
if (d < 0)
d = -d;
if (decimal > 0)
predot = (long)d;
else
predot = double2int(d);
sub = 1;
for (i=0; i<decimal; i++)
sub *= 10;
postdot = double2int((d - (long)d) * (double)sub);
if (postdot == sub) {
/* we had a .9* that rounded up! */
postdot = 0;
predot++;
}
pre = ulong_to_str((ulong)predot, 10, tmpbuf, 1, false);
for (i=0, c = pre; *c; c++)
buf[i++] = *c;
if (force_dot || !(decimal == 0 || (suppress_zeros && postdot == 0))) {
buf[i++] = '.';
post = ulong_to_str((ulong)postdot, 10, tmpbuf, decimal, false);
for (c = post; *c; c++)
buf[i++] = *c;
/* remove trailing zeros */
if (suppress_zeros) {
while (buf[i-1] == '0')
i--;
}
}
buf[i] = '\0';
ASSERT(i<BUF_SIZE); /* make sure don't overflow buffer */
return buf;
}
static char *
double_to_exp_str(double d, int exp, int decimal, char * buf, bool force_dot, bool suppress_zeros, bool caps)
{
char tmp_buf[BUF_SIZE];
char *tc;
int i = 0;
uint abval;
tc = double_to_str(d, decimal, tmp_buf, force_dot, suppress_zeros);
while (*tc) {
buf[i++] = *tc++;
}
if (caps)
buf[i++] = 'E';
else
buf[i++] = 'e';
if (exp < 0) {
buf[i++] = '-';
abval = -exp;
} else {
buf[i++] = '+';
abval = exp;
}
/* exp value always printed as at least 2 characters */
tc = ulong_to_str((ulong)abval, 10, tmp_buf, 2, false);
while (*tc) {
buf[i++] = *tc++;
}
buf[i] = '\0';
ASSERT(i < BUF_SIZE); /* make sure don't overflow buffer */
return buf;
}
int
our_vsnprintf(char *s, size_t max, const char *fmt, va_list ap)
{
const char *c;
char *str = NULL;
char *start = s;
char buf[BUF_SIZE];
if (fmt == NULL)
return 0;
c = fmt;
while (*c) {
if (*c == '%') {
int fill = 0;
char filler = ' ';
int decimal = -1; /* codes defaults (6 int, 1 float, all string) */
char charbuf[2] = {'\0','\0'};
char prefixbuf[3] = {'\0','\0','\0'};
char *prefix;
bool minus_flag = false;
bool plus_flag = false;
bool pound_flag = false;
bool space_flag = false;
bool h_type = false;
bool l_type = false;
bool ll_type = false;
prefix = prefixbuf;
c++;
ASSERT(*c);
/* Collect flags -, +, #, 0, */
while (*c == '0' || *c == '-' || *c == '#' || *c == '+' || *c == ' ') {
if (*c == '0')
filler = '0';
if (*c == '-')
minus_flag = true;
if (*c == '+')
plus_flag = true;
if (*c == '#')
pound_flag = true;
if (*c == ' ')
space_flag = true;
c++;
ASSERT(*c);
}
if (minus_flag)
filler = ' ';
if (plus_flag)
space_flag = false;
/* get field width */
if (*c == '*') {
fill = va_arg(ap, int);
if (fill < 0) {
minus_flag = true;
fill = -fill;
}
c++;
ASSERT(*c);
} else {
while (*c >= '0' && *c <= '9') {
fill *= 10;
fill += *c - '0';
c++;
ASSERT(*c);
}
}
/* get precision */
if (*c == '.') {
c++;
ASSERT(*c);
decimal = 0;
if (*c == '*') {
decimal = va_arg(ap, int);
c++;
ASSERT(*c);
} else {
while (*c >= '0' && *c <= '9') {
decimal *= 10;
decimal += *c - '0';
c++;
ASSERT(*c);
}
}
}
/* get size modifiers l, h, ll/L */
if (*c == 'l' || *c == 'L' || *c == 'h') {
if (*c == 'L')
ll_type = true;
if (*c == 'h')
h_type = true;
if (*c == 'l') {
c++;
ASSERT(*c);
if (*c == 'l') {
ll_type = true;
c++;
ASSERT(*c);
} else {
l_type = true;
}
} else {
c++;
ASSERT(*c);
}
}
/* dispatch */
switch (*c) {
case '%':
charbuf[0] = '%';
str = charbuf;
break;
case 'd':
case 'i':
{
long val;
ulong abval;
if (decimal == -1)
decimal = 1; /* defaults */
else
filler = ' ';
if (l_type)
val = va_arg(ap, long); /* get arg */
else if (h_type)
val = (long)va_arg(ap, int); /* short is promoted to int */
else
val = (long)va_arg(ap, int);
if (val >= 0 && space_flag)
prefixbuf[0] = ' '; /* set prefix */
if (val >= 0 && plus_flag)
prefixbuf[0] = '+';
if (val < 0) {
prefixbuf[0] = '-';
abval = -val;
} else {
abval = val;
}
str = ulong_to_str(abval, 10, buf, decimal, false); /* generate string */
break;
}
case 'I':
{ /* %I64, to match Win32 */
uint64 val;
/* must be %I64u */
ASSERT(*(c+1)=='6' && *(c+2)=='4' && *(c+3)=='u');
if (decimal == -1)
decimal = 1;
else
filler = ' ';
c += 3;
val = (uint64)va_arg(ap, uint64);
str = uint64_to_str(val, 10, buf, decimal, false);
break;
}
case 'u':
/* handle long long u type */
if (decimal == -1)
decimal = 1;
else
filler = ' ';
if (ll_type) {
str = uint64_to_str((uint64)va_arg(ap, uint64), 10, buf, decimal, false);
break;
}
/* note no break */
case 'x':
case 'X':
case 'o':
case 'p':
{
ptr_uint_t val;
bool caps = *c == 'X';
int base = 10;
if (decimal == -1)
decimal = 1; /* defaults */
else
filler = ' ';
if (*c == 'p')
decimal = 2 * sizeof(void *); /* pointer precision */
if ((pound_flag && *c != 'u') || (*c == 'p')) { /* generate prefix */
prefixbuf[0] = '0';
if (*c == 'x' || *c == 'p')
prefixbuf[1] = 'x';
if (*c == 'X')
prefixbuf[1] = 'X';
}
ASSERT(sizeof(void *) == sizeof(val));
if (*c == 'p')
val = (ptr_uint_t) va_arg(ap, void *); /* get val */
else if (l_type)
val = (ptr_uint_t) va_arg(ap, ulong);
else if (h_type)
val = (ptr_uint_t) va_arg(ap, uint); /* ushort promoted */
else
val = (ptr_uint_t) va_arg(ap, uint);
if (*c == 'o')
base = 8; /* determine base */
if (*c == 'x' || *c == 'X' || *c == 'p')
base = 16;
ASSERT(sizeof(val) == sizeof(ulong));
str = ulong_to_str((ulong)val, base, buf, decimal, caps); /* generate string */
break;
}
case 'c':
/* FIXME: using int instead of char seems to work for RH7.2 as
* well as 8.0, but using char crashes 8.0 but not 7.2
*/
#ifdef VA_ARG_CHAR2INT
charbuf[0] = (char) va_arg(ap, int); /* char -> int in va_list */
#else
charbuf[0] = va_arg(ap, char);
#endif
str = charbuf;
break;
case 's':
str = va_arg(ap, char*);
break;
case 'g':
case 'G':
if (decimal == 0 || decimal == -1)
decimal = 1; /* default */
/* no break */
case 'e':
case 'E':
case 'f':
{
bool caps = (*c == 'E') || (*c == 'G');
/* pretty sure will always be promoted to a double in arg list */
double val = va_arg(ap, double);
double d = val;
int exp = 0;
bool is_g = (*c == 'g' || *c == 'G');
/* check for NaN */
if (val != val) {
if (caps)
str = "NAN";
else
str = "nan";
if (space_flag)
prefixbuf[0] = ' ';
break;
}
if (decimal == -1)
decimal = 6; /* default */
if (val >= 0 && space_flag)
prefixbuf[0] = ' '; /* get prefix */
if (val >= 0 && plus_flag)
prefixbuf[0] = '+';
if (val < 0)
prefixbuf[0] = '-';
/* check for inf */
if (val == pos_inf || val == neg_inf) {
if (caps)
str = "INF";
else
str = "inf";
break;
}
if (*c == 'f') { /* ready to generate string now for f */
str = double_to_str(val, decimal, buf, pound_flag, false);
break;
}
/* get exponent value */
while (d >= 10.0 || d <= -10.0) {
exp++;
d = d / 10.0;
}
while (d < 1.0 && d > -1.0 && d != 0.0) {
exp--;
d = d * 10.0;
}
if (is_g)
decimal--; /* g/G precision is number of signifigant digits */
if (is_g && exp >= -4 && exp <= decimal) {
/* exp is small enought for f, print without exponent */
str = double_to_str(val, decimal, buf, pound_flag, !pound_flag);
break;
}
/* print with exponent */
str = double_to_exp_str(d, exp, decimal, buf, pound_flag, is_g && !pound_flag, caps);
break;
}
case 'n':
{
/* save num of chars printed so far in address specified */
uint num_char = (uint) (s - start);
/* yes, snprintf on all platforms returns int, not ssize_t */
IF_X64(ASSERT(CHECK_TRUNCATE_TYPE_int(s - start)));
if (l_type) {
long * val = va_arg(ap, long *);
*val = (long) num_char;
} else if (h_type) {
short * val = va_arg(ap, short *);
*val = (short) num_char;
} else {
int * val = va_arg(ap, int *);
*val = num_char;
}
buf[0] = '\0';
str = buf;
break;
}
/* FIXME : support the following? */
case 'a':
case 'A':
default:
ASSERT_NOT_REACHED();
}
/* if filler is 0 fill after prefix, else fill before prefix */
/* if - flag then fill after str and ignore filler type */
/* calculate number of fill characters */
if (fill > 0) {
IF_X64(ASSERT(CHECK_TRUNCATE_TYPE_uint(strlen(str) + strlen(prefix))));
fill -= (uint) (strlen(str) + strlen(prefix));
}
/* insert prefix if filler is 0, filler won't be 0 if - flag is set */
if (filler == '0') {
while (*prefix) {
if (max > 0 && (size_t)(s - start) >= max)
goto max_reached;
*s = *prefix;
s++;
prefix++;
}
}
/* fill now if not left justified */
if (fill > 0 && !minus_flag) {
int i;
for (i = 0; i < fill; i++) {
if (max > 0 && (size_t)(s - start) >= max)
goto max_reached;
*s = filler;
s++;
}
}
/* insert prefix if not 0 filling */
if (filler != '0') {
while (*prefix) {
if (max > 0 && (size_t)(s - start) >= max)
goto max_reached;
*s = *prefix;
s++;
prefix++;
}
}
/* insert the actual str representation */
while (*str) {
if (max > 0 && (size_t)(s - start) >= max)
goto max_reached;
if (*c == 's' && decimal == 0)
break; /* check string precision */
decimal--;
*s = *str;
s++;
str++;
}
/* if left justified do the fill now after the actual string */
if (fill > 0 && minus_flag) {
int i;
for (i = 0; i < fill; i++) {
if (max > 0 && (size_t)(s - start) >= max)
goto max_reached;
*s = filler;
s++;
}
}
c++;
}
else {
const char *cstart = c;
int nbytes = 0;
while (*c && *c != '%') {
nbytes++;
c++;
}
while (cstart < c) {
if (max > 0 && (size_t)(s - start) >= max)
goto max_reached;
*s = *cstart;
s++;
cstart++;
}
}
}
if (max == 0 || (size_t)(s - start) < max)
*s = '\0';
max_reached:
/* yes, snprintf on all platforms returns int, not ssize_t */
IF_X64(ASSERT(CHECK_TRUNCATE_TYPE_int(s - start)));
return (int) (s - start);
}
int
our_snprintf(char *s, size_t max, const char *fmt, ...)
{
int res;
va_list ap;
ASSERT(s);
va_start(ap, fmt);
res = our_vsnprintf(s, max, fmt, ap);
va_end(ap);
return res;
}
+101
View File
@@ -0,0 +1,101 @@
/* **********************************************************
* Copyright (c) 2002-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#ifndef _DR_API_H_
#define _DR_API_H_ 1
/**
* @file dr_api.h
* @brief Top-level include file for DynamoRIO API.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* Defines and type definitions */
#include "dr_defines.h"
/* Event registration routines */
#include "dr_events.h"
/* Application start/stop interface */
#include "dr_app.h"
/* High-level routines: memory allocation, mutex support, file
* support, printing, thread support, adaptive optimization,
* custom traces, processor-specific utilities, trace dumping,
* and module information.
*/
#include "dr_tools.h"
/* Utility routines for identifying features of the processor. */
#include "dr_proc.h"
/* opnd_t (operand) routines */
#include "dr_ir_opnd.h"
/* Instruction convenience & decode/disassemble routines */
#include "dr_ir_utils.h"
/* instrlist_t routines */
#include "dr_ir_instrlist.h"
/* instr_t routines */
#include "dr_ir_instr.h"
/* opcode OP_ constants and opcode-only routines */
#include "dr_ir_opcodes.h"
/* CREATE_INSTR_ macros */
#include "dr_ir_macros.h"
/**
* When registering a process, users must provide a list of paths to
* client libraries and their associated client-specific options. DR
* looks up "dr_init" in each client library and calls that function
* when the process starts. Clients can register to receive callbacks
* for the various events within dr_init. Note that client paths and
* options cannot include semicolons. \p client_id is the ID supplied
* at registration and is used to identify the client for
* dr_get_options(), dr_get_client_path(), and external nudges.
*/
DR_EXPORT void dr_init(client_id_t client_id);
/* Version checking */
DR_EXPORT LINK_ONCE int _USES_DR_VERSION_ = 103; /* 1.3.x */
#ifdef __cplusplus
}
#endif
#endif /* _DR_API_H_ */
+92
View File
@@ -0,0 +1,92 @@
/* **********************************************************
* Copyright (c) 2002-2008 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.
*/
/**
* @file dr_app.h
* @brief DR's application interface for running portions
* of a program under its control.
*/
#ifndef _DR_APP_H_
#define _DR_APP_H_ 1
#ifdef WINDOWS
# ifdef DR_APP_EXPORTS
# define DR_APP_API __declspec(dllexport)
# else
# define DR_APP_API __declspec(dllimport)
# endif
#else /* LINUX */
# if defined(DR_APP_EXPORTS) && defined(USE_VISIBILITY_ATTRIBUTES)
# define DR_APP_API __attribute__ ((visibility ("default")))
# else
# define DR_APP_API
# endif
#endif
/****************************************************************************
* DR Application Interface
*/
/**
* Application-wide initialization. Must be called before any other
* API function, and before the application creates any threads. Returns
* zero on success.
*/
DR_APP_API int dr_app_setup(void);
/**
* Application-wide cleanup. Prints statistics. Returns zero on success.
*/
DR_APP_API int dr_app_cleanup(void);
/**
* Causes application to run under DR control upon return
* from this call.
*/
DR_APP_API void dr_app_start(void);
/**
* Causes application to run directly on the machine upon return
* from this call; no effect if application is not currently
* running under DR control.
*/
DR_APP_API void dr_app_stop(void);
/**
* Causes application to run under DR control upon return from
* this call. DR never releases control. Useful for overriding
* dr_app_start/dr_app_stop calls in the rest of a program.
*/
DR_APP_API void dr_app_take_over(void);
#endif /* _DR_APP_H_ */
+668
View File
@@ -0,0 +1,668 @@
/* **********************************************************
* Copyright (c) 2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#ifndef _DR_CONFIG_H_
#define _DR_CONFIG_H_ 1
#ifdef WINDOWS
/* DR_API EXPORT TOFILE dr_config.h */
/* DR_API EXPORT BEGIN */
#ifdef WINDOWS
/****************************************************************************
* Deployment API
*/
/**
* @file dr_config.h
* @brief Deployment API for Windows. Use these functions to register
* processes to run under DynamoRIO, unregister processes, obtain existing
* registration information, and nudge running processes.
* \note The dr_config library is currently not multi-thread safe. Users of
* the library should ensure that no more then one thread accesses the library
* at a time. This limitation will be addressed in future releases.
*/
/** Maximum length of a registered process's options string */
#define DR_MAX_OPTIONS_LENGTH 512
/** Specifies DynamoRIO's operation mode. */
typedef enum {
/**
* No mode. Clients should not attempt to register a process in
* this mode.
*/
DR_MODE_NONE = 0,
/** Run DynamoRIO in Code Manipulation mode. */
#ifdef HOT_PATCHING_INTERFACE
/** Note that this mode also supports the Probe API. */
#endif
DR_MODE_CODE_MANIPULATION = 1,
#ifdef HOT_PATCHING_INTERFACE
/** Run DynamoRIO in Probe mode. This mode has no code cache. */
DR_MODE_PROBE = 2,
#endif
#ifdef PROGRAM_SHEPHERDING
/** Run DynamoRIO in Memory Firewall mode. */
DR_MODE_MEMORY_FIREWALL = 3,
#endif
} dr_operation_mode_t;
/** Return status codes for process registration, unregistration and nudging. */
typedef enum {
/** Operation succeeded. */
DR_SUCCESS,
/** Process registration failed due to an existing registration. */
DR_PROC_REG_EXISTS,
/** Operation failed because the supplied process is not registered. */
DR_PROC_REG_INVALID,
/** Client registration failed due to an invalid priority value. */
DR_PRIORITY_INVALID,
/** Client registration failed due to a conflicting ID. */
DR_ID_CONFLICTING,
/** Client operation failed due to an invalid client ID. */
DR_ID_INVALID,
/** Unknown failure. Check that caller has adequate permissions for this operation. */
DR_FAILURE,
/** Nudge operation failed because the specified process id is not under DR. */
DR_NUDGE_PID_NOT_INJECTED,
/** Nudge operation timed out waiting for target process to finish handling a nudge.*/
DR_NUDGE_TIMEOUT,
} dr_config_status_t;
/** Allow targeting both WOW64 and native 64-bit processes separately. */
typedef enum {
DR_PLATFORM_DEFAULT, /**< The platform this tool is compiled for. */
DR_PLATFORM_32BIT, /**< 32-bit settings (for 32-bit or WOW64 processes). */
DR_PLATFORM_64BIT, /**< 64-bit settings (for native 64-bit processes). */
} dr_platform_t;
/**
* Register a process to run under DynamoRIO. This requires administrative
* privileges. Note that this routine only sets the base options to run
* a process under DynamoRIO. To register one or more clients, call
* dr_register_client() subsequently.
*
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable (e.g., calc.exe).
*
* \param[in] dr_root_dir A NULL-terminated string specifying the full
* path to a valid DynamoRIO root directory.
* The string length cannot exceed MAX_PATH.
*
* \param[in] dr_mode Specifies the mode under which DynamoRIO should
* operate. See dr_operation_mode_t.
*
* \param[in] debug If true, a DynamoRIO debug build will be used;
* otherwise, a release build will be used.
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to set.
*
* \param[in] dr_options A NULL-terminated string controlling
* DynamoRIO's behavior. Most users should
* not need to specify options. The total
* string length cannot exceed #DR_MAX_OPTIONS_LENGTH.
*
* \return A dr_config_status_t code indicating the result of
* registration. Note that registration fails if the requested
* process is already registered. To modify a process's
* registration, first call dr_unregister_process() to remove an
* existing registration.
*
* \remarks
* After registration, a process will run under DynamoRIO the next time
* it launches. Note that some processes may require a system reboot to
* restart. Process registration persists across reboots until explicitly
* unregistered.
*
* \note On Windows NT, a reboot is required after the initial
* dr_register_process() in order for DynamoRIO to take control of any
* application.
*
* \note An application that does not link with user32.dll will not be
* run under control of DynamoRIO unless it's launched by the \c drinject.exe
* tool (in bin/bin32 or bin/bin64) or the parent process (typically
* explorer.exe, for manually launched applications) is already under
* DynamoRIO control (the parent can be in any mode, but 32-bit parent
* cannot inject into a 64-bit child). Only some small non-graphical
* applications do not link with user32.dll.
*/
dr_config_status_t
dr_register_process(const char *process_name,
const char *dr_root_dir,
dr_operation_mode_t dr_mode,
bool debug,
dr_platform_t dr_platform,
const char *dr_options);
/**
* Unregister a process from running under DynamoRIO. This requires administrative
* privileges.
*
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable (e.g., calc.exe).
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to unset.
*
* \return A dr_config_status_t code indicating the result of
* unregistration. Note that unregistration fails if the process
* is not currently registered to run under DynamoRIO.
*/
dr_config_status_t
dr_unregister_process(const char *process_name,
dr_platform_t dr_platform);
/**
* Check if a process is registered to run under DynamoRIO. To obtain client
* information, use dr_get_client_info().
*
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable (e.g., calc.exe).
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to check.
*
* \param[out] dr_root_dir If the process is registered, the root DynamoRIO
* directory provided at registration. Callers can
* pass NULL if this value is not needed. Otherwise,
* the parameter must be a caller-allocated array of
* length MAX_PATH.
*
* \param[out] dr_mode If the process is registered, the mode provided
* at registration. Callers can pass NULL if this
* value is not needed.
*
* \param[out] debug If the process is registered, the debug flag
* provided at registration. Callers can pass NULL
* if this value is not needed.
*
* \param[out] dr_options If the process is registered, the extra DynamoRIO
* parameters provided at registration. Callers can
* pass NULL if this value is not needed. Otherwise,
* the parameter must be a caller-allocated array of
* length #DR_MAX_OPTIONS_LENGTH.
*
* \return true if the process is registered for the given platform.
*/
bool
dr_process_is_registered(const char *process_name,
dr_platform_t dr_platform,
char *dr_root_dir /* OUT */,
dr_operation_mode_t *dr_mode /* OUT */,
bool *debug /* OUT */,
char *dr_options /* OUT */);
typedef struct _dr_registered_process_iterator_t dr_registered_process_iterator_t;
/**
* Creates and starts an iterator for iterating over all processes registered for
* the given platform.
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to check.
*
* \return iterator for use with dr_registered_process_iterator_hasnext()and
* dr_registered_process_iterator_next(). Must be freed
* with dr_registered_process_iterator_stop()
*/
dr_registered_process_iterator_t *
dr_registered_process_iterator_start(dr_platform_t dr_platform);
/**
* \param[in] iter A registered process iterator created with
* dr_registered_process_iterator_start()
*
* \return true if there are more registered processes to iterate over
*/
bool
dr_registered_process_iterator_hasnext(dr_registered_process_iterator_t *iter);
/**
* Return information about a registered process
*
* \param[in] iter A registered process iterator created with
* dr_registered_process_iterator_start().
*
* \param[out] process_name The name of the registered process. Callers can
* pass NULL if this value is not needed. Otherwise
* the parameter must be a caller-allocated array
* of length MAX_PATH.
*
* \param[out] dr_root_dir The root DynamoRIO directory provided at registration.
* Callers can pass NULL if this value is not needed.
* Otherwise, the parameter must be a caller-allocated
* array of length MAX_PATH.
*
* \param[out] dr_mode If the process is registered, the mode provided
* at registration. Callers can pass NULL if this
* value is not needed.
*
* \param[out] debug If the process is registered, the debug flag
* provided at registration. Callers can pass NULL
* if this value is not needed.
*
* \param[out] dr_options If the process is registered, the extra DynamoRIO
* parameters provided at registration. Callers can
* pass NULL if this value is not needed. Otherwise,
* the parameter must be a caller-allocated array of
* length #DR_MAX_OPTIONS_LENGTH.
*
* \return true if the process is registered for the given platform.
*/
void
dr_registered_process_iterator_next(dr_registered_process_iterator_t *iter,
char *process_name /* OUT */,
char *dr_root_dir /* OUT */,
dr_operation_mode_t *dr_mode /* OUT */,
bool *debug /* OUT */,
char *dr_options /* OUT */);
/**
* Stops and frees a registered process iterator.
*
* \param[in] iter A registered process iterator created with
* dr_registered_process_iterator_start()
*/
void
dr_registered_process_iterator_stop(dr_registered_process_iterator_t *iter);
/**
* Register a client for a particular process. Note that the process must
* first be registered via dr_register_process() before calling this routine.
*
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable (e.g., calc.exe).
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to unset.
*
* \param[in] client_id A client_id_t uniquely identifying the client.
* DynamoRIO provides the client ID as a parameter
* to dr_init(). Clients use this ID to retrieve
* client-specific path and option information.
* Outside entities also identify the target of
* a nudge via this ID.
*
* \param[in] client_pri The client number, or priority. Client registration
* includes a value indicating the priority of a client
* relative to other clients. In multi-client settings,
* a client's priority influences event callback
* ordering. That is, higher priority clients can
* register their callbacks first; DynamoRIO then calls
* these routines last. Client priorities range
* consecutively from 0 to N-1, where N is the number
* of registered clients. Specify priority
* 0 to register a client with highest priority.
*
* \param[in] client_path A NULL-terminated string specifying the full path
* to a valid client library. The string length
* cannot exceed MAX_PATH. The client path may not
* include any semicolons.
*
* \param[in] client_options A NULL-terminated string specifying options that
* are available to the client via dr_get_options().
* The string length cannot exceed #DR_MAX_OPTIONS_LENGTH.
* The client options may not include any semicolons.
*
* \return A dr_config_status_t code indicating the result of registration.
*/
dr_config_status_t
dr_register_client(const char *process_name,
dr_platform_t dr_platform,
client_id_t client_id,
size_t client_pri,
const char *client_path,
const char *client_options);
/**
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable (e.g., calc.exe).
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to unset.
*
* \param[in] client_id The unique client ID provided at client
* registration.
*
* \return A dr_config_status_t code indicating the result of unregistration.
*/
dr_config_status_t
dr_unregister_client(const char *process_name,
dr_platform_t dr_platform,
client_id_t client_id);
/**
* Retrieve the number of clients registered for a particular process.
*
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable (e.g., calc.exe).
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to unset.
*
* \return The number of clients registered for the given process and platform.
*/
size_t
dr_num_registered_clients(const char *process_name,
dr_platform_t dr_platform);
/**
* Retrieve client registration information for a particular process.
*
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable (e.g., calc.exe).
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to unset.
*
* \param[in] client_id The unique client ID provided at client
* registration.
*
* \param[out] client_pri The client's priority.
*
* \param[out] client_path The client's path provided at registration.
* Callers can pass NULL if this value is not needed.
* Otherwise, the parameter must be a caller-allocated
* array of length MAX_PATH.
*
* \param[out] client_options The client options provided at registration.
* Callers can pass NULL if this value is not needed.
* Otherwise, the parameter must be a caller-allocated
* array of length #DR_MAX_OPTIONS_LENGTH.
*
* \return A dr_config_status_t code indicating the result of the call.
*/
dr_config_status_t
dr_get_client_info(const char *process_name,
dr_platform_t dr_platform,
client_id_t client_id,
size_t *client_pri, /* OUT */
char *client_path, /* OUT */
char *client_options /* OUT */);
typedef struct _dr_client_iterator_t dr_client_iterator_t;
/**
* Creates and starts an iterator for iterating over all clients registered for
* the given process.
*
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable (e.g., calc.exe).
*
* \param[in] dr_platform Configurations are kept separate on 64-bit Windows
* for 32-bit (WOW64) processes and 64-bit processes.
* This parameter allows selecting which of those
* configurations to check.
*
* \return iterator for use with dr_client_iterator_hasnext() and
* dr_client_iterator_next(). Must be freed with
* dr_client_iterator_stop()
*/
dr_client_iterator_t *
dr_client_iterator_start(const char *process_name,
dr_platform_t dr_platform);
/**
* \param[in] iter A client iterator created with dr_client_iterator_start()
*
* \return true if there are more clients to iterate over
*/
bool
dr_client_iterator_hasnext(dr_client_iterator_t *iter);
/**
* Return information about a client.
*
* \param[in] iter A client iterator created with dr_client_iterator_start()
*
* \param[out] client_id The unique client ID provided at client registration.
*
* \param[out] client_pri The client's priority.
*
* \param[out] client_path The client's path provided at registration.
* Callers can pass NULL if this value is not needed.
* Otherwise, the parameter must be a caller-allocated
* array of length MAX_PATH.
*
* \param[out] client_options The client options provided at registration.
* Callers can pass NULL if this value is not needed.
* Otherwise, the parameter must be a caller-allocated
* array of length #DR_MAX_OPTIONS_LENGTH.
*/
void
dr_client_iterator_next(dr_client_iterator_t *iter,
client_id_t *client_id, /* OUT */
size_t *client_pri, /* OUT */
char *client_path, /* OUT */
char *client_options /* OUT */);
/**
* Stops and frees a client iterator.
*
* \param[in] iter A client iterator created with dr_client_iterator_start()
*/
void
dr_client_iterator_stop(dr_client_iterator_t *iter);
/**
* Provides a mechanism for an external entity on the guest OS to
* communicate with a client. Requires administrative privileges. A
* process 'nudge' causes a client event handler to be invoked (use
* dr_register_nudge_event() to register the handler function). A
* nudge is ignored if the process is not running under DynamoRIO,
* the specified client is not loaded, or if the client does not
* provide a handler.
*
* \param[in] process_name A NULL-terminated string specifying the name
* of the target process. The string should
* identify the base name of the process, not the
* full path of the executable.
*
* \param[in] client_id The unique client ID provided at client
* registration.
*
* \param[in] arg An argument passed to the client's nudge
* handler.
*
* \param[in] timeout_ms The number of milliseconds to wait for each
* nudge to complete before continuing. If INFINITE
* is supplied then the wait is unbounded. If 0
* is supplied the no wait is performed. If a
* wait times out DR_NUDGE_TIMEOUT will be returned.
*
* \param[out] nudge_count Returns the number of processes nudged.
* Client can supply NULL if this value is
* not needed.
*
* \return A dr_config_status_t code indicating the result of the nudge.
*
* \remarks
* If there are multiple processes executing with the same name, all
* of them are nudged.
*
* \remarks
* A process nudge is a one way asynchronous communication from an
* external entity to a client. It does not allow a client to
* return information back to the nudge originator. To communicate
* from a client to another process, use the channels specified
* in \ref sec_comm.
*
* \note Nudging 64-bit processes is not yet supported.
*/
dr_config_status_t
dr_nudge_process(const char *process_name,
client_id_t client_id,
uint64 arg,
uint timeout_ms,
int *nudge_count /*OUT */);
/**
* Provides a mechanism for an external entity on the guest OS to
* communicate with a client. Requires administrative privileges. A
* process 'nudge' causes a client event handler to be invoked (use
* dr_register_nudge_event() to register the handler function). A
* nudge is ignored if the process is not running under DynamoRIO,
* the specified client is not loaded, or if the client does not
* provide a handler.
*
* \param[in] process_id The system id of the process to nudge
* (see dr_get_process_id())
*
* \param[in] client_id The unique client ID provided at client
* registration.
*
* \param[in] arg An argument passed to the client's nudge
* handler.
*
* \param[in] timeout_ms The number of milliseconds to wait for the
* nudge to complete before returning. If INFINITE
* is supplied then the wait is unbounded. If 0
* is supplied the no wait is performed. If the
* wait times out DR_NUDGE_TIMEOUT will be returned.
*
* \return A dr_config_status_t code indicating the result of the nudge.
*
* \remarks
* A process nudge is a one way asynchronous communication from an
* external entity to a client. It does not allow a client to
* return information back to the nudge originator. To communicate
* from a client to another process, use the channels specified
* in \ref sec_comm.
*
* \note Nudging 64-bit processes is not yet supported.
*/
dr_config_status_t
dr_nudge_pid(process_id_t process_id,
client_id_t client_id,
uint64 arg,
uint timeout_ms);
/**
* Provides a mechanism for an external entity on the guest OS to
* communicate with a client. Requires administrative privileges. A
* process 'nudge' causes a client event handler to be invoked (use
* dr_register_nudge_event() to register the handler function). A
* nudge is ignored if the process is not running under DynamoRIO,
* the specified client is not loaded, or if the client does not
* provide a handler. Nudges are attempted to all processes running
* on the system.
*
* \param[in] client_id The unique client ID provided at client
* registration.
*
* \param[in] arg An argument passed to the client's nudge
* handler.
*
* \param[in] timeout_ms The number of milliseconds to wait for each
* nudge to complete before continuing. If INFINITE
* is supplied then the wait is unbounded. If 0
* is supplied the no wait is performed. If a
* wait times out DR_NUDGE_TIMEOUT will be returned.
*
* \param[out] nudge_count Returns the number of processes nudged.
* Client can supply NULL if this value is
* not needed.
*
* \return A dr_config_status_t code indicating the result of the nudge.
*
* \remarks
* A process nudge is a one way asynchronous communication from an
* external entity to a client. It does not allow a client to
* return information back to the nudge originator. To communicate
* from a client to another process, use the channels specified
* in \ref sec_comm.
*
* \note Nudging 64-bit processes is not yet supported.
*/
dr_config_status_t
dr_nudge_all(client_id_t client_id,
uint64 arg,
uint timeout_ms,
int *nudge_count /*OUT */);
#endif /* WINDOWS */
/* DR_API EXPORT END */
#endif /* WINDOWS */
#endif /* _DR_CONFIG_H_ */
+161
View File
@@ -0,0 +1,161 @@
;; **********************************************************
;; Copyright (c) 2008 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.
;; PR 219380: provide ntdll.dll link support to clients
LIBRARY dynamorio
EXPORTS
wcstoul = NTDLL.wcstoul
wcstombs = NTDLL.wcstombs
wcstol = NTDLL.wcstol
wcsstr = NTDLL.wcsstr
wcsspn = NTDLL.wcsspn
wcsrchr = NTDLL.wcsrchr
wcspbrk = NTDLL.wcspbrk
wcsncpy = NTDLL.wcsncpy
wcsncmp = NTDLL.wcsncmp
wcsncat = NTDLL.wcsncat
wcslen = NTDLL.wcslen
wcscspn = NTDLL.wcscspn
wcscpy = NTDLL.wcscpy
wcscmp = NTDLL.wcscmp
wcschr = NTDLL.wcschr
wcscat = NTDLL.wcscat
towupper = NTDLL.towupper
towlower = NTDLL.towlower
toupper = NTDLL.toupper
tolower = NTDLL.tolower
tan = NTDLL.tan
strtoul = NTDLL.strtoul
strtol = NTDLL.strtol
strstr = NTDLL.strstr
strspn = NTDLL.strspn
strrchr = NTDLL.strrchr
strpbrk = NTDLL.strpbrk
strncpy = NTDLL.strncpy
strncmp = NTDLL.strncmp
strncat = NTDLL.strncat
strlen = NTDLL.strlen
strcspn = NTDLL.strcspn
strcmp = NTDLL.strcmp
strchr = NTDLL.strchr
sscanf = NTDLL.sscanf
sqrt = NTDLL.sqrt
sprintf = NTDLL.sprintf
sin = NTDLL.sin
qsort = NTDLL.qsort
pow = NTDLL.pow
memset = NTDLL.memset
memmove = NTDLL.memmove
memcpy = NTDLL.memcpy
memcmp = NTDLL.memcmp
memchr = NTDLL.memchr
mbstowcs = NTDLL.mbstowcs
log = NTDLL.log
labs = NTDLL.labs
isxdigit = NTDLL.isxdigit
iswxdigit = NTDLL.iswxdigit
iswspace = NTDLL.iswspace
iswlower = NTDLL.iswlower
iswdigit = NTDLL.iswdigit
iswctype = NTDLL.iswctype
iswalpha = NTDLL.iswalpha
isupper = NTDLL.isupper
isspace = NTDLL.isspace
ispunct = NTDLL.ispunct
isprint = NTDLL.isprint
islower = NTDLL.islower
isgraph = NTDLL.isgraph
isdigit = NTDLL.isdigit
iscntrl = NTDLL.iscntrl
isalpha = NTDLL.isalpha
isalnum = NTDLL.isalnum
floor = NTDLL.floor
fabs = NTDLL.fabs
cos = NTDLL.cos
ceil = NTDLL.ceil
atol = NTDLL.atol
atoi = NTDLL.atoi
atan = NTDLL.atan
abs = NTDLL.abs
_wtol = NTDLL._wtol
_wtoi64 = NTDLL._wtoi64
_wtoi = NTDLL._wtoi
_wcsupr = NTDLL._wcsupr
_wcsnicmp = NTDLL._wcsnicmp
_wcslwr = NTDLL._wcslwr
_wcsicmp = NTDLL._wcsicmp
_vsnprintf = NTDLL._vsnprintf
_ultow = NTDLL._ultow
_ultoa = NTDLL._ultoa
_ui64toa = NTDLL._ui64toa
_toupper = NTDLL._toupper
_tolower = NTDLL._tolower
_strupr = NTDLL._strupr
_strnicmp = NTDLL._strnicmp
_strlwr = NTDLL._strlwr
_stricmp = NTDLL._stricmp
_strcmpi = NTDLL._strcmpi
_snwprintf = NTDLL._snwprintf
;; we get "instrument.obj : warning LNK4197: export '_snprintf' specified
;; multiple times; using first specification", so we have to explicitly
;; re-list our own export (order doesn't matter):
snprintf
_snprintf = NTDLL._snprintf
_memicmp = NTDLL._memicmp
_memccpy = NTDLL._memccpy
_ltow = NTDLL._ltow
_ltoa = NTDLL._ltoa
_itow = NTDLL._itow
_itoa = NTDLL._itoa
_i64tow = NTDLL._i64tow
_i64toa = NTDLL._i64toa
_ftol = NTDLL._ftol
_fltused = NTDLL._fltused
_chkstk = NTDLL._chkstk
_aullshr = NTDLL._aullshr
_aullrem = NTDLL._aullrem
_aulldiv = NTDLL._aulldiv
_atoi64 = NTDLL._atoi64
_allshr = NTDLL._allshr
_allshl = NTDLL._allshl
_allrem = NTDLL._allrem
_allmul = NTDLL._allmul
_alldiv = NTDLL._alldiv
__toascii = NTDLL.__toascii
__iscsymf = NTDLL.__iscsymf
__iscsym = NTDLL.__iscsym
__isascii = NTDLL.__isascii
;; these are needed for samples/stats.c
NtCreateSection = NTDLL.NtCreateSection
NtMapViewOfSection = NTDLL.NtMapViewOfSection
NtUnmapViewOfSection = NTDLL.NtUnmapViewOfSection
NtOpenDirectoryObject = NTDLL.NtOpenDirectoryObject
RtlInitUnicodeString = NTDLL.RtlInitUnicodeString
+151
View File
@@ -0,0 +1,151 @@
;; **********************************************************
;; Copyright (c) 2008 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.
;; PR 219380: provide ntdll.dll link support to clients
LIBRARY dynamorio
EXPORTS
wcstoul = NTDLL.wcstoul
wcstombs = NTDLL.wcstombs
wcstol = NTDLL.wcstol
wcsstr = NTDLL.wcsstr
wcsspn = NTDLL.wcsspn
wcsrchr = NTDLL.wcsrchr
wcspbrk = NTDLL.wcspbrk
wcsncpy = NTDLL.wcsncpy
wcsncmp = NTDLL.wcsncmp
wcsncat = NTDLL.wcsncat
wcslen = NTDLL.wcslen
wcscspn = NTDLL.wcscspn
wcscpy = NTDLL.wcscpy
wcscmp = NTDLL.wcscmp
wcschr = NTDLL.wcschr
wcscat = NTDLL.wcscat
towupper = NTDLL.towupper
towlower = NTDLL.towlower
toupper = NTDLL.toupper
tolower = NTDLL.tolower
tan = NTDLL.tan
strtoul = NTDLL.strtoul
strtol = NTDLL.strtol
strstr = NTDLL.strstr
strspn = NTDLL.strspn
strrchr = NTDLL.strrchr
strpbrk = NTDLL.strpbrk
strncpy = NTDLL.strncpy
strncmp = NTDLL.strncmp
strncat = NTDLL.strncat
strlen = NTDLL.strlen
strcspn = NTDLL.strcspn
strcmp = NTDLL.strcmp
strchr = NTDLL.strchr
sscanf = NTDLL.sscanf
sqrt = NTDLL.sqrt
sprintf = NTDLL.sprintf
sin = NTDLL.sin
qsort = NTDLL.qsort
pow = NTDLL.pow
memset = NTDLL.memset
memmove = NTDLL.memmove
memcpy = NTDLL.memcpy
memcmp = NTDLL.memcmp
memchr = NTDLL.memchr
mbstowcs = NTDLL.mbstowcs
log = NTDLL.log
labs = NTDLL.labs
isxdigit = NTDLL.isxdigit
iswxdigit = NTDLL.iswxdigit
iswspace = NTDLL.iswspace
iswlower = NTDLL.iswlower
iswdigit = NTDLL.iswdigit
iswctype = NTDLL.iswctype
iswalpha = NTDLL.iswalpha
isupper = NTDLL.isupper
isspace = NTDLL.isspace
ispunct = NTDLL.ispunct
isprint = NTDLL.isprint
islower = NTDLL.islower
isgraph = NTDLL.isgraph
isdigit = NTDLL.isdigit
iscntrl = NTDLL.iscntrl
isalpha = NTDLL.isalpha
isalnum = NTDLL.isalnum
floor = NTDLL.floor
fabs = NTDLL.fabs
cos = NTDLL.cos
ceil = NTDLL.ceil
atol = NTDLL.atol
atoi = NTDLL.atoi
atan = NTDLL.atan
abs = NTDLL.abs
_wtol = NTDLL._wtol
_wtoi64 = NTDLL._wtoi64
_wtoi = NTDLL._wtoi
_wcsupr = NTDLL._wcsupr
_wcsnicmp = NTDLL._wcsnicmp
_wcslwr = NTDLL._wcslwr
_wcsicmp = NTDLL._wcsicmp
_vsnprintf = NTDLL._vsnprintf
_ultow = NTDLL._ultow
_ultoa = NTDLL._ultoa
_ui64toa = NTDLL._ui64toa
_toupper = NTDLL._toupper
_tolower = NTDLL._tolower
_strupr = NTDLL._strupr
_strnicmp = NTDLL._strnicmp
_strlwr = NTDLL._strlwr
_stricmp = NTDLL._stricmp
_strcmpi = NTDLL._strcmpi
_snwprintf = NTDLL._snwprintf
;; we get "instrument.obj : warning LNK4197: export '_snprintf' specified
;; multiple times; using first specification", so we have to explicitly
;; re-list our own export (order doesn't matter):
snprintf
_snprintf = NTDLL._snprintf
_memicmp = NTDLL._memicmp
_memccpy = NTDLL._memccpy
_ltow = NTDLL._ltow
_ltoa = NTDLL._ltoa
_itow = NTDLL._itow
_itoa = NTDLL._itoa
_i64tow = NTDLL._i64tow
_i64toa = NTDLL._i64toa
_fltused = NTDLL._fltused
_atoi64 = NTDLL._atoi64
__toascii = NTDLL.__toascii
__iscsymf = NTDLL.__iscsymf
__iscsym = NTDLL.__iscsym
__isascii = NTDLL.__isascii
;; these are needed for samples/stats.c
NtCreateSection = NTDLL.NtCreateSection
NtMapViewOfSection = NTDLL.NtMapViewOfSection
NtUnmapViewOfSection = NTDLL.NtUnmapViewOfSection
NtOpenDirectoryObject = NTDLL.NtOpenDirectoryObject
RtlInitUnicodeString = NTDLL.RtlInitUnicodeString
+126
View File
@@ -0,0 +1,126 @@
/* **********************************************************
* Copyright (c) 2002-2008 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.
*/
/* dr_stats.h: DR's shared memory interface */
#ifndef _DR_STATS_H_
#define _DR_STATS_H_ 1
#include "globals_shared.h"
#ifdef WINDOWS
/* No registry for stats (b/c it requires advapi32.dll which can't be used
* when injected via user32.dll registry key)
* Instead, a piece of shared memory with the key base name below holds the
* total number of DR instances.
*/
# define DR_SHMEM_KEY "DynamoRIOStatistics"
#elif defined(LINUX)
# define DYNAMORIO_MAGIC_STRING "DYNAMORIO_MAGIC_STRING"
# define DYNAMORIO_MAGIC_STRING_LEN 16 /*include trailing \0*/
#endif
#define STAT_NAME_MAX_LEN 50
typedef struct _single_stat_t {
/* We inline the stat description to make it easy for external processes
* to view our stats: they don't have to chase pointers, and we could put
* this in shared memory easily.
*/
char name[STAT_NAME_MAX_LEN]; /* the description of the stat */
/* FIXME PR 216209: we'll want 64-bit stats for x64 address regions; we can
* either add per-stat types, or just widen them all.
*/
stats_int_t value;
} single_stat_t;
/* Parameters and statistics exported by DR via drmarker.
* These should be treated as read-only except for the log_ fields.
* Unless otherwise mentioned, these stats are all process-wide.
*/
#define NUM_EVENTS 27
typedef struct _dr_statistics_t {
#ifdef LINUX
char magicstring[DYNAMORIO_MAGIC_STRING_LEN];
#endif
process_id_t process_id; /* process id */
char process_name[MAXIMUM_PATH]; /* process name */
uint logmask; /* what to log */
uint loglevel; /* how much detail to log */
char logdir[MAXIMUM_PATH]; /* full path of logging directory */
uint64 perfctr_vals[NUM_EVENTS];
uint num_stats;
#ifdef NOT_DYNAMORIO_CORE
/* variable-length to avoid tying to specific DR version */
single_stat_t stats[1];
#else
# ifdef DEBUG
# define STATS_DEF(desc, name) single_stat_t name##_pair;
# else
# define RSTATS_DEF(desc, name) single_stat_t name##_pair;
# endif
# include "statsx.h"
# undef STATS_DEF
# undef RSTATS_DEF
#endif
} dr_statistics_t;
#ifndef NOT_DYNAMORIO_CORE
/* Thread local statistics */
typedef struct {
thread_id_t thread_id;
mutex_t thread_stats_lock; /* transactional stats, for multiple stats invariants to hold */
/* TODO: We may also want to print another threads's stats without necessarily halting it,
* TODO: add stat name##_delta, which should be applied as a batch to the safe to read values.
* The basic idea of transactional stats is that uncommitted changes are not visible to readers.
* Some invariants between statistics, i.e. A=B+C should hold at the dump/committed points.
*
* The plan is:
* 1) delta accessed w/o lock only by the owning thread,
* 2) on dump any other thread which only reads the committed values while holding the commit lock,
* 3) The owning thread is the single writer to the committed values to apply the deltas,
* while holding the commit lock.
*
* Used for other threads to be able to request thread local stats,
* and also for the not fully explained self-interruption on linux?
*/
#ifdef DEBUG
# define STATS_DEF(desc, name) stats_int_t name##_thread;
#else
# define RSTATS_DEF(desc, name) stats_int_t name##_thread;
#endif
# include "statsx.h"
} thread_local_statistics_t;
#undef STATS_DEF
#undef RSTATS_DEF
#endif /* !NOT_DYNAMORIO_CORE */
#endif /* _DR_STATS_H_ */
+66
View File
@@ -0,0 +1,66 @@
/* **********************************************************
* Copyright (c) 2001-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Fortran wrappers for dynamo
* Fortran has restrictions on function names so can't just call dynamo_*!
* Call dr*() instead, and link with this .o file.
* For example:
* CALL DRSETUP()
* CALL DRSTART()
*/
#include "dr_app.h"
#ifdef DR_APP_EXPORTS
void drsetup_()
{
dr_app_setup();
}
void drcleanup_()
{
dr_app_cleanup();
}
void drstart_()
{
dr_app_start();
}
void drstop_()
{
dr_app_stop();
}
#endif
+442
View File
@@ -0,0 +1,442 @@
#!/usr/local/bin/perl
# **********************************************************
# Copyright (c) 2002-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.
# Copyright (c) 2003-2007 Determina Corp.
# Copyright (c) 2002-2003 Massachusetts Institute of Technology
# Copyright (c) 2002 Hewlett Packard Company
### genapi.pl
###
### generates header files and filter files for our exported data and routines
### N.B.: this script assumes several things about the layout of declarations:
### 1) comments are not sprinkled in weird places
### 2) multiple declarations do not share the same line
###
$usage = "Usage: $0 -header <destinationdir> <defines> | -filter <defines> | -debug\n";
$header = 0;
$debug = 0;
$filter = 0;
if ($#ARGV < 0) {
print "$usage";
exit 0;
}
while ($#ARGV >= 0) {
if ($ARGV[0] eq '-header') {
$header = 1;
shift;
if ($#ARGV != 1) {
print "$usage";
exit 0;
}
$dir = $ARGV[0];
if (! -d $dir) {
print "$dir is not a directory\n";
print "$usage";
exit 0;
}
shift;
$define_str = $ARGV[0];
$define_str =~ s/^[-\/]D//;
$define_str =~ s/ [-\/]D/ /g;
@define_els = split(' ', $define_str);
foreach $i (@define_els) {
$defines{$i} = 1;
}
} elsif ($ARGV[0] eq '-filter') {
$filter = 1;
shift;
$define_str = $ARGV[0];
$define_str =~ s/^[-\/]D//;
$define_str =~ s/ [-\/]D/ /g;
@define_els = split(' ', $define_str);
foreach $i (@define_els) {
$defines{$i} = 1;
}
} elsif ($ARGV[0] eq '-debug') {
$debug = 1;
} else {
print "$usage";
exit 0;
}
shift;
}
# I used to just do
# open(FIND, "find . -name \\*.h |")
# but there are dependencies between header files, and certain orders
# look nicer than others, so we have an explicit list here:
# Also, we now send output to multiple files, and their names are indicated
# by comments in the header files.
@headers =
(
'./instrlist.h',
'./lib/globals_shared.h', # defs
'./globals.h',
'./x86/arch_exports.h', # encode routines
'./x86/proc.h',
'./module_shared.h',
'./x86/instrument.h',
'./x86/instr.h',
'./x86/instr_create.h',
'./x86/decode.h', # OPSZ_ consts, decode routines
'./x86/decode_fast.h', # decode routines
'./x86/disassemble.h', # disassemble routines
'./fragment.h', # binary tracedump format
'./win32/os_private.h', # rsrc section walking
'./hotpatch.c', # probe api
'./lib/dr_config.h',
);
# PR 214947: VMware retroactively holds the copyright.
$copyright = q+/* **********************************************************
* Copyright (c) 2002-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.
*/
+;
if ($header) {
$outfile_init = 0;
} else {
open(OUT, ">-"); # stdout
if ($filter) {
# linker version script w/ no versions, just global and local symbol lists
# except old ld requires version -- ok, we'll put in one
print OUT "DYNAMORIO_0.9.5 {\nglobal:\n";
}
}
foreach $file (@headers) {
open(IN, "< $file") || die "Error: Couldn't open $file for input\n";
if ($debug) {
print stderr "Working on $file\n";
print OUT "\n/* from $file ----------------------------- */\n";
}
$output_routine = 0;
$output_directly = 0;
$output_verbatim = 0;
$did_output_something = 0;
$prev_define = 0;
$in_define = 0;
while (<IN>) {
chop;
# handle DOS end-of-line:
if ($_ =~ /\r$/) { chop; };
$l = $_;
if ($l =~ /^DR_API/) {
$output_routine = 1;
$did_output_something = 1;
$type = "";
} elsif ($header && $l =~ /DR_API EXPORT TOFILE ([A-Za-z_0-9\.]+)/) {
$outfile_init = 1;
$outfile = $1;
if (!defined($files{$outfile})) {
$files{$outfile} = $outfile;
$wrapdef{$outfile} = $outfile;
$wrapdef{$outfile} =~ s/\./_/g;
$wrapdef{$outfile} = "_" . uc($wrapdef{$outfile}) . "_";
if (! -e "$dir/$outfile") {
open(OUT, "> $dir/$outfile") ||
die "Error: Couldn't open $dir/$outfile for output\n";
print OUT "$copyright";
print OUT "#ifndef $wrapdef{$outfile}\n#define $wrapdef{$outfile} 1\n\n";
} else {
open(OUT, ">> $dir/$outfile") ||
die "Error: Couldn't open $dir/$outfile for append\n";
}
} else {
# FIXME: should store original filehandle and re-use it
open(OUT, ">> $dir/$outfile") ||
die "Error: Couldn't open $dir/$outfile for append\n";
}
} elsif ($header && $l =~ /DR_API EXPORT BEGIN/) {
$output_directly = 1;
$did_output_something = 1;
} elsif ($header && $l =~ /DR_API EXPORT VERBATIM/) {
$output_verbatim = 1;
$did_output_something = 1;
}
# if outputting verbatim, just output and grab the next line
# we can skip the following logic that interprets the #ifdefs,
# #ifndefs, etc.
elsif ($output_verbatim) {
if ($l =~ /DR_API EXPORT END/) {
$output_verbatim = 0;
}
else {
print OUT "$l\n";
}
next;
}
# to handle defines (yes a hack...need a better solution):
# only a define on immediately prior line to DR_API or to
# EXPORT BEGIN will kill following output, until the very next
# endif
# assumption: only those defines passed to us count,
# and they're only used in simple "#ifdef" statements
# (can't use cpp b/c it also removes #if's around entire .h file,
# plus we want to keep #ifdef LINUX and #ifdef WINDOWS stuff)
if ($prev_define && ($output_routine || $output_directly)) {
$in_undefined = 1;
if ($debug) {
print stderr "\tSkipping!\n";
}
}
if ($in_undefined) {
if ($l =~ /^\#\s*endif/ || $l =~ /^\#\s*else/) {
$in_undefined = 0;
if ($l =~ /^\#\s*else/) {
$kill_endif = 1;
}
}
# assumption: nothing else on endif line
$skip = 1;
# have to check for closings here
if ($output_routine && $l =~ /;/) {
$output_routine = 0;
}
if ($output_directly && $l =~ /DR_API EXPORT END/) {
$output_directly = 0;
}
} else {
$skip = 0;
}
if ($kill_endif && $l =~ /^\#\s*endif/) {
$kill_endif = 0;
$skip = 1;
}
if ($in_define || $in_define_keep) {
if ($l =~ /^\#\s*endif/) {
# we only support keep-defines being innermost
if ($in_define_keep) {
$in_define_keep = 0;
} else {
$in_define = 0;
$skip = 1;
}
}
}
if ($l =~ /^\#\s*ifdef (\S+)/ || $l =~ /^\#\s*if defined\((\S+)\)/) {
# we want to keep all WINDOWS, LINUX, and X64 defines, so ignore those.
if ($1 eq "WINDOWS" || $1 eq "LINUX" || $1 eq "X64" || $1 eq "X86_64") {
$in_define_keep = 1;
} else {
if ($debug) {
print stderr "Found ifdef $1 => $defines{$1}\n";
}
if (!defined($defines{$1})) {
$prev_define = 1;
} elsif ($output_routine || $output_directly) {
$in_define = 1;
}
$skip = 1;
}
} elsif ($l =~ /^\#\s*ifndef (\S+)/) {
# we want to keep all WINDOWS, LINUX, and X64 defines, so ignore those.
if ($1 eq "WINDOWS" || $1 eq "LINUX" || $1 eq "X64" || $1 eq "X86_64") {
$in_define_keep = 1;
} else {
if ($debug) {
print stderr "Found ifndef $1 => $defines{$1}\n";
}
if (defined($defines{$1})) {
$prev_define = 1;
} elsif ($output_routine || $output_directly) {
$in_define = 1;
}
$skip = 1;
}
} else {
$prev_define = 0;
}
if ($skip) {
next;
}
if ($output_routine) {
if ($filter) {
# only export these guys for DYNAMORIO_IR_EXPORTS
if (defined($defines{DYNAMORIO_IR_EXPORTS})) {
# symbol export list (-filter option)
if ($l =~ /^([A-Za-z0-9_]+)\s*\(/ ||
# order is important: 2nd line might pick up _IF_X64
# inside param list
$l =~ /^[a-zA-Z_].*\s+([A-Za-z0-9_]+)\s*\(/) {
print OUT "$1;\n";
}
}
if ($l =~ /;\s*$/ &&
$l !~ /^\s*\*/ && $l !~ /^\s*\/\*/) { # ignore ; inside comment
$output_routine = 0;
}
} else {
if ($header && !$outfile_init) {
die "Error: no initial output file specified\n";
}
unless ($debug) {
$l =~ s/^DR_API\s*//;
}
if ($type eq "") {
if ($l =~ /^\s*[A-Za-z_]+/) {
$l =~ /^\s*([A-Za-z0-9_]+\s*\*?)/;
$type = $1;
$type =~ s/\s*$//;
}
}
$l =~ s/dcontext_t *\*dcontext/void *drcontext/;
if ($l =~ /\);\s*$/) {
$output_routine = 0;
if ($debug || $header) {
print OUT "$l\n";
} else {
$l =~ s/;//;
print OUT "$l\n";
if ($type =~ /\*/) {
$ret = "\treturn NULL;\n";
} elsif ($type eq "void") {
$ret = "";
} elsif ($type eq "bool") {
$ret = "\treturn false;\n";
} elsif ($type eq "float") {
$ret = "\treturn 0.f;\n";
} elsif ($type eq "int" || $type eq "uint") {
$ret = "\treturn 0;\n";
} else {
# static to avoid "uninitialized var" compiler warnings
$ret = "\tstatic $type bogus;\n\treturn bogus;\n";
}
print OUT "{\n$ret}\n";
}
} else {
print OUT "$l\n";
}
}
} elsif ($output_directly) {
# instr_create.h needs this in its raw output for x64, but keep var name
$l =~ s/dcontext_t *\*dcontext/void *dcontext/;
# let's keep blank lines if we didn't create them by stripping
# everything out
if ($l =~ /^\s*$/) {
print OUT "\n";
}
elsif ($l !~ /DR_API/) {
if ($l =~ /OP_/) {
# remove pointers into decode tables
$l =~ s/(OP_[a-zA-Z0-9_]*,) *\/\*[^\*]*\*\/(.*)/\1\2/;
}
# PR 227381: auto-insert doxygen comments for REG_ enum lines without any
if ($file =~ "/instr.h" &&
$l =~ /^ *[RS]EG_/ && $l !~ /\/\*\*</) {
$l =~ s|([RS]EG_)(\w+), *|\1\2, /**< The "\L\2" register. */\n |g;
}
# Strip out FIXME comments
$l =~ s/\/\* FIXME.*\*\///;
if ($l !~ /^\s*$/) {
print OUT "$l\n";
}
}
if ($l =~ /DR_API EXPORT END/) {
$output_directly = 0;
print OUT "\n";
}
}
}
if ($did_output_something && !$filter) {
print OUT "\n";
}
close(IN);
}
if ($header) {
foreach $fname (keys(%files)) {
# FIXME: should store original filehandle, and close it here
open(OUT, ">> $dir/$files{$fname}") ||
die "Error: Couldn't open $dir/$files{$fname} for append\n";
print OUT "\n#endif /* $wrapdef{$fname} */\n";
close(OUT);
}
} else {
if ($filter) {
if (defined($defines{DR_APP_EXPORTS})) {
# now add in the APP_API routines -- ok to list symbol not found,
# so we need no hacks to remove the LOGPC ones based on the defines:
$app = `grep 'DR_APP_API.*;' ./lib/dr_app.h`;
$app =~ s/DR_APP_API [a-z]+ ([A-Za-z_]+)\(void\);/\1;/g;
print OUT $app;
}
# dynamorio_app_init and dynamorio_app_take_over are used
# by the linux injector
print OUT "dynamorio_app_init;\n";
print OUT "dynamorio_app_take_over;\n";
# add in our_std*, which are hard to match w/ DR_API and I'm in a hurry
# (should switch to visibility attributes now that we upgraded gcc)
print OUT "our_stdout;\n";
print OUT "our_stderr;\n";
# linker version script w/ no versions, just global and local symbol lists
print OUT "\nlocal: *;\n};\n";
}
close(OUT);
}
File diff suppressed because it is too large Load Diff
+123
View File
@@ -0,0 +1,123 @@
/* **********************************************************
* Copyright (c) 2005-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2005-2007 Determina Corp. */
#ifndef _HOTPATCH_INTERFACE_H_
#define _HOTPATCH_INTERFACE_H_ 1
/* This file defines the interface between the core and the hot patches. Any
* changes to this file will most likely require changes to both.
*/
#include "globals_shared.h" /* for reg_t */
/* CAUTION: The hot patch interface (i.e., engine) version should be kept in
* synch with the hot patches (hotpatch module) any time a new engine version
* is defined.
*/
#define HOTP_INTERFACE_VERSION 42000
/* This enum specifies the possible status codes that a hot patch routine can
* return to convey how its execution proceeded. This has to be a bit flag
* because event logging requests by a protector can be combined with other
* status codes.
*
* CAUTION: Changes to this enum will break hot patch code; all hot patch code
* has to be recompiled and hot patching engine version probably has
* to be upgraded. Be sure to talk with Alex.
*/
typedef enum {
/* Detector status codes. */
HOTP_EXEC_EXPLOIT_DETECTED = 0x00000001,
HOTP_EXEC_EXPLOIT_NOT_DETECTED = 0x00000002,
HOTP_EXEC_DETECTOR_ERROR = 0x00000004,
/* All codes below can only be returned by a protector. */
HOTP_EXEC_EXPLOIT_PROTECTED = 0x00000008,
HOTP_EXEC_EXPLOIT_NOT_PROTECTED = 0x00000010,
HOTP_EXEC_PROTECTOR_ERROR = 0x00000020,
/* These codes return both a status & request for a particular action. */
HOTP_EXEC_EXPLOIT_KILL_THREAD = 0x00000040,
HOTP_EXEC_EXPLOIT_KILL_PROCESS = 0x00000080,
HOTP_EXEC_EXPLOIT_RAISE_EXCEPTION = 0x00000100,
HOTP_EXEC_CHANGE_CONTROL_FLOW = 0x00000200,
/* This flag is orthogonal to the ones above and can be specified with
* any of those. This can be used both by detectors and protectors.
*/
HOTP_EXEC_LOG_EVENT = 0x00000400,
/* This status shouldn't be returned by a hot patch code. It is used to
* identify unexpected aborts of hot patch code, mostly due to exceptions.
*/
HOTP_EXEC_ABORTED = 0x00000800
} hotp_exec_status_t;
typedef dr_mcontext_t hotp_context_t;
/* TODO: may have to define one for detector & one for protector because their
* interface types will be different once the protector logging is done.
*/
typedef hotp_exec_status_t (*hotp_func_t)(hotp_context_t *app_reg_ptr);
#define APP_XDI(x) (((hotp_context_t*)(x))->xdi)
#define APP_XSI(x) (((hotp_context_t*)(x))->xsi)
#define APP_XBP(x) (((hotp_context_t*)(x))->xbp)
#define APP_XSP(x) (((hotp_context_t*)(x))->xsp)
#define APP_XBX(x) (((hotp_context_t*)(x))->xbx)
#define APP_XDX(x) (((hotp_context_t*)(x))->xdx)
#define APP_XCX(x) (((hotp_context_t*)(x))->xcx)
#define APP_XAX(x) (((hotp_context_t*)(x))->xax)
#define APP_R8(x) (((hotp_context_t*)(x))->r8)
#define APP_R9(x) (((hotp_context_t*)(x))->r9)
#define APP_R10(x) (((hotp_context_t*)(x))->r10)
#define APP_R11(x) (((hotp_context_t*)(x))->r11)
#define APP_R12(x) (((hotp_context_t*)(x))->r12)
#define APP_R13(x) (((hotp_context_t*)(x))->r13)
#define APP_R14(x) (((hotp_context_t*)(x))->r14)
#define APP_R15(x) (((hotp_context_t*)(x))->r15)
#define APP_XFLAGS(x) (((hotp_context_t*)(x))->xflags)
#ifndef X64 /* legacy support */
#define APP_EDI APP_XDI
#define APP_ESI APP_XSI
#define APP_EBP APP_XBP
#define APP_ESP APP_XSP
#define APP_EBX APP_XBX
#define APP_EDX APP_XDX
#define APP_ECX APP_XCX
#define APP_EAX APP_XAX
#endif
#endif /* _HOTPATCH_INTERFACE_H_ */
+143
View File
@@ -0,0 +1,143 @@
/* **********************************************************
* Copyright (c) 2004-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2004-2007 Determina Corp. */
/*
* kstatsx.h
*
* Timing statistics definitions and descriptions
*
*/
/* This file is included multiple times
- in stats.h once for structure definition,
- in stats.c
*/
/* Client files that include this header should define the following macros
#define KSTAT_DEF(description, name)
#define KSTAT_SUM(description, name, var1, var2) name = var1 + var2
*/
/* Keep descriptions and names up to a reasonable length -
* respectively 50 and 15 characters */
KSTAT_DEF("total measured and propagated in thread", thread_measured)
KSTAT_DEF("in bb building", bb_building)
KSTAT_DEF("in bb decoding", bb_decoding) /* sub-node of bb_building */
KSTAT_DEF("in emitting BB", bb_emit) /* sub-node of bb_building */
KSTAT_DEF("in mangling", mangling)
KSTAT_DEF("in emit", emit)
KSTAT_DEF("in hotpatch lookup", hotp_lookup)
KSTAT_DEF("in trace building", trace_building)
KSTAT_DEF("making temp private bb for trace building", temp_private_bb)
KSTAT_DEF("in trace monitor ", monitor_enter)
KSTAT_DEF("in trace monitor, thci ", monitor_enter_thci)
KSTAT_DEF("cache flush unit walk ", cache_flush_unit_walk)
KSTAT_DEF("flush_region", flush_region)
KSTAT_DEF("synchall flush ", synchall_flush)
KSTAT_DEF("coarse pclookup", coarse_pclookup)
KSTAT_DEF("coarse freeze all", coarse_freeze_all)
KSTAT_DEF("persisted cache generation", persisted_generation)
KSTAT_DEF("persisted cache load", persisted_load)
KSTAT_DEF("in dispatch exit, default", dispatch_num_exits)
/* preserving STATS names for num_exits_* responsible for time in DR */
KSTAT_DEF("in dispatch exit, ind target not in cache", num_exits_ind_good_miss)
KSTAT_DEF("in dispatch exit, dir target not in cache", num_exits_dir_miss)
KSTAT_SUM("in dispatch exit, all target not in cache", num_exits_not_in_cache,
num_exits_ind_good_miss, num_exits_dir_miss)
KSTAT_DEF("in dispatch exit, BB2BB, ind target ...", num_exits_ind_bad_miss_bb2bb)
KSTAT_DEF("in dispatch exit, BB2trace, ind target ...", num_exits_ind_bad_miss_bb2trace)
KSTAT_SUM("in dispatch exit, from BB", num_exits_ind_bad_miss_bb,
num_exits_ind_bad_miss_bb2bb, num_exits_ind_bad_miss_bb2trace)
KSTAT_DEF("in dispatch exit, trace2trace, ind target ...", num_exits_ind_bad_miss_trace2trace)
KSTAT_DEF("in dispatch exit, trace2BB not trace head, ind target", num_exits_ind_bad_miss_trace2bb_nth)
KSTAT_DEF("in dispatch exit, trace2BB trace head, ind target", num_exits_ind_bad_miss_trace2bb_th)
KSTAT_SUM("in dispatch exit, trace2BB, ind target ", num_exits_ind_bad_miss_trace2bb,
num_exits_ind_bad_miss_trace2bb_nth, num_exits_ind_bad_miss_trace2bb_th)
KSTAT_SUM("in dispatch exit, from trace", num_exits_ind_bad_miss_trace,
num_exits_ind_bad_miss_trace2trace, num_exits_ind_bad_miss_trace2bb)
KSTAT_SUM("in dispatch exit, ind target in cache but not table", num_exits_ind_bad_miss,
num_exits_ind_bad_miss_trace, num_exits_ind_bad_miss_bb)
KSTAT_DEF("in dispatch exit, syscall handling", num_exits_dir_syscall)
KSTAT_DEF("in dispatch exit, callback return", num_exits_dir_cbret)
KSTAT_DEF("in LOG", logging)
KSTAT_DEF("empty block overhead", overhead_empty)
KSTAT_DEF("nested block overhead", overhead_nested)
KSTAT_DEF("in syscalls [not propagated]", syscall_fcache)
KSTAT_DEF("pre-syscall handling", pre_syscall)
KSTAT_DEF("post-syscall handling", post_syscall)
KSTAT_DEF("pre-syscall FreeVM handling", pre_syscall_free)
KSTAT_DEF("pre-syscall ProtectVM handling", pre_syscall_protect)
KSTAT_DEF("pre-syscall Unmap handling", pre_syscall_unmap)
KSTAT_DEF("post-syscall AllocVM handling", post_syscall_alloc)
KSTAT_DEF("post-syscall Map handling", post_syscall_map)
KSTAT_DEF("native_exec [not propagated]", native_exec_fcache)
KSTAT_DEF("in fcache, default", fcache_default)
KSTAT_DEF("in bb cache, [not propagated]", fcache_bb_bb)
KSTAT_DEF("in trace cache, [not propagated]", fcache_trace_trace)
/* hard to SUM it up against either bb or trace only */
KSTAT_DEF("in bb cache out from trace cache, [not propagated]", fcache_bb_trace)
/* assuming we'll deal with lock contention separately we don't propagate this time to callers */
KSTAT_DEF("wait event (+context switch) [not propagated]", wait_event)
/* FIXME: we should add all critical section bodies as suggested in
* the mutex_t definition - if only we can share LOCK_RANK definitions
* in lockx.h and it will just work
*/
KSTAT_DEF("in rct analysis no relocations", rct_no_reloc)
KSTAT_DEF("in rct analysis using relocations [outer loop]", rct_reloc)
KSTAT_DEF("in rct analysis using relocations [per page loop]", rct_reloc_per_page)
KSTAT_DEF("in aslr_generate_relocated_section for validation", aslr_validate_relocate)
KSTAT_DEF("in module_contents_compare or aslr_compare_in_place", aslr_compare)
#ifdef KSTAT_UNIT_TEST
KSTAT_DEF("empty block overhead", empty)
KSTAT_DEF("total measured", measured)
KSTAT_DEF("in outer loop", iloop)
KSTAT_DEF("in inner loop", jloop)
#endif /* KSTAT_UNIT_TEST */

Some files were not shown because too many files have changed in this diff Show More