/* **********************************************************
* Copyright (c) 2013-2021 Google, 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 Google, 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 GOOGLE, 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_drx DynamoRIO eXtension utilities
The \p drx DynamoRIO Extension provides various utilities for
instrumentation and sports a BSD license, as opposed to the \p drutil Extension
which also contains instrumentation utilities but uses an LGPL 2.1 license.
- \ref sec_drx_setup
- \ref sec_drx_soft_kills
\section sec_drx_setup Setup
To use \p drx with your client simply include this line in your client's
\p CMakeLists.txt file:
\code use_DynamoRIO_extension(clientname drx) \endcode
That will automatically set up the include path and library dependence.
The \p drx_init() function may be called multiple times; subsequent calls
will be nops and will return \p true for success. This allows a
library to use \p drx without coordinating with the client over who invokes
\p drx_init().
\section sec_drx_soft_kills Soft Kills
A common scenario with multi-process applications is for a parent process
to directly kill child processes. This is problematic for most dynamic
tools as this leaves no chance for each child process to output the results
of its instrumentation. On Windows, \p drx provides a feature called "soft
kills" to address this situation. When enabled, this feature monitors
system calls that terminate child processes, whether directly or through
job objects. When detected, it notifies the client, who is expected to
then notify the target process via a nudge. Typically this nudge will
perform instrumentation output and then terminate its process, allowing the
parent to simply skip its own termination request. The nudge handler
should normally handle multiple requests, as it is not uncommon for the
parent to kill each child process through multiple mechanisms.
\section sec_drx_buf Buffer Filling API
The \p drx library also demonstrates a minimalistic buffer API. Its API is
currently in flux. These buffers may contain traces of data gathered during
instrumentation, such as memory traces, instruction traces, etc. Note that
per-thread buffers are used for all implementations. There currently exist
three types of buffers.
- \ref sec_drx_buf_trace
- \ref sec_drx_buf_circular
- \ref sec_drx_buf_circular_fast
- \ref sec_drx_buf_api
- \ref sec_drx_buf_no_api
\section sec_drx_buf_trace Trace Buffer
The trace buffer notifies the user when the buffer fills up and allows the
client to write the contents to disk or to a pipe, etc. Note that writing
multiple fields of a struct to the buffer runs the risk of the client being
notified that the buffer is filled before the entire struct has been written.
In order to circumvent this limitation, either write the element at the
highest offset in the struct first, so that the user never sees an
incompletely-written struct, or if this is not possible, allocate a buffer
whose size is a multiple of the size of the struct.
\section sec_drx_buf_circular Circular Buffer
This circular buffer will wrap around when it becomes full, and is used
when a client might only need to remember the most recent portion of a
sequence of events instead of recording an entire trace of events. This
circular buffer can be any size, but is specially optimized for a buffer
size of 65336.
\section sec_drx_buf_circular_fast Fast Circular Buffer
The only special case mentioned in \ref sec_drx_buf_circular is a buffer
of size 65336. Because the buffer is this size exactly, we can align it
to a 65336 byte boundary, and increment only the bottom two bytes of the
base pointer. By this method we are able to wrap around on overflow.
Note that this buffer is very good for homogeneous writes, such as in the
sample client \p bbuf (see \ref API_samples), where we only write \p app_pc
sized values. Since the buffer cannot be a different size, when using a
structure it is a good idea to increment \p buf_ptr to a size that evenly
divides the size of the buffer.
\section sec_drx_buf_api Using the Buffer API
There is a single API for modifying the buffer which is compatible with each
of these buffer types. The user must generally load the buffer pointer into
a register, perform some store operations relative to the register, and then
finally update the buffer pointer to accommodate these stores. Using offsets
for subsequent fields in a structure is the most efficient method, but please
note the warning in \ref sec_drx_buf_trace, where one should either allocate
an integer multiple of the size of the struct, or always write the last field
of a struct first.
\code
/* load the buffer pointer into reg_ptr */
drx_buf_insert_load_buf_ptr(drcontext, buf, bb, inst, reg_ptr);
/* Store whatever is in the scratch reg to the buffer at offset 0, and then
* to offset 8.
*/
drx_buf_insert_buf_store(drcontext, buf, bb, inst, reg_ptr,
DR_REG_NULL, opnd_create_reg(scratch1), OPSZ_PTR, 0);
drx_buf_insert_buf_store(drcontext, buf, bb, inst, reg_ptr,
DR_REG_NULL, opnd_create_reg(scratch2), OPSZ_PTR, 8);
/* We wrote 16 bytes (8 bytes of scratch1 and 8 bytes of scratch2), so we
* increment the buffer pointer by that amount, using reg_tmp as a temporary
* scratch register.
*/
drx_buf_insert_update_buf_ptr(drcontext, buf, bb, inst, reg_ptr,
reg_tmp, sizeof(reg_t)*2);
\endcode
\section sec_drx_buf_no_api Manually Modifying the Buffer
It is possible to manually modify the buffer without calling
drx_buf_insert_buf_store(). The provided store routines are for convenience
only, to ensure that an app translation is set for each instruction. If a user
writes to the buffer without using the provided operations, please make sure an
app translation is set.
*/