initial open source import from formerly proprietary VMware sources
SVN-Revision: 1
@@ -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.
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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"> </a>
|
||||
<table bgcolor="#6699cc" width=100% cellspacing=0 cellpadding=5 border=0>
|
||||
<tr><td> <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&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"> </a>
|
||||
<table bgcolor="#6699cc" width=100% cellspacing=0 cellpadding=5 border=0>
|
||||
<tr><td> <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> </td></tr></table>
|
||||
<!--------------------------------------------------------------------------->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -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
|
||||
@@ -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> <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)
|
||||
|
||||
@@ -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> |</td></tr>
|
||||
<tr><td bgcolor="ffcc99"><tt>8b 46 0c</tt></td></tr>
|
||||
<tr align="middle" bgcolor="ffffff"><td> |</td></tr>
|
||||
<tr><td bgcolor="ffcc99"><tt>2b 46 1c</tt></td></tr>
|
||||
<tr align="middle" bgcolor="ffffff"><td> |</td></tr>
|
||||
<tr><td bgcolor="ffcc99"><tt>0f b7 4e 08</tt></td></tr>
|
||||
<tr align="middle" bgcolor="ffffff"><td> |</td></tr>
|
||||
<tr><td bgcolor="ffcc99"><tt>c1 e1 07</tt></td></tr>
|
||||
<tr align="middle" bgcolor="ffffff"><td> |</td></tr>
|
||||
<tr><td bgcolor="ffcc99"><tt>3b c1</tt></td></tr>
|
||||
<tr align="middle" bgcolor="ffffff"><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </td><td> |</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> </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> </td><td> |</td></tr>
|
||||
<tr><td> </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> </td><td> |</td></tr>
|
||||
<tr><td> </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> </td><td> |</td></tr>
|
||||
<tr><td> </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> </td><td> |</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> </td><td> |</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> </td><td> |</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> |</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>
|
||||
|
||||
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
|
||||
|
||||
***************************************************************************
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
<hr size="1"><address style="text-align: center;"><small>
|
||||
<img border=0 src="favicon.png"> $projectname version 1.3.1 --- $datetime
|
||||
<img border=0 src="favicon.png">
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
@@ -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%; }
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 617 B |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 276 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 617 B |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 9.4 KiB |
@@ -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
|
||||
@@ -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.
|
||||
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
|
||||
*/
|
||||
@@ -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
|
||||
|
||||
***************************************************************************
|
||||
****************************************************************************
|
||||
****************************************************************************
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
foo.dll yyybar.dll ynnVIPA_Test.exe nyytest.dll nnn
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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(§ion_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(§ion_attributes, §ion_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(§ion, access,
|
||||
§ion_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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
##################################################
|
||||
@@ -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;
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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 */
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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 */
|
||||