Skip to content

Instantly share code, notes, and snippets.

@JackKuo-tw
Created February 17, 2021 06:56
Show Gist options
  • Save JackKuo-tw/74453ab2bf69de1570b06b221fa25d4f to your computer and use it in GitHub Desktop.
Save JackKuo-tw/74453ab2bf69de1570b06b221fa25d4f to your computer and use it in GitHub Desktop.
Add drutil_expand_rep_string to instrace_*.c samples #4138
# **********************************************************
# Copyright (c) 2010-2020 Google, Inc. All rights reserved.
# Copyright (c) 2009-2010 VMware, Inc. All rights reserved.
# **********************************************************
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of VMware, Inc. nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
cmake_minimum_required(VERSION 3.7)
if ("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
set(DEBUG ON)
endif ("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
# To match Makefiles and have just one build type per configured build
# dir, we collapse VS generator configs to a single choice.
# This must be done prior to the project() command and the var
# must be set in the cache.
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
if (DEBUG)
set(CMAKE_CONFIGURATION_TYPES "Debug" CACHE STRING "" FORCE)
else ()
# Go w/ debug info (i#1392)
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" CACHE STRING "" FORCE)
endif ()
# we want to use the <VAR>_<config> variants of config-dependent properties
string(TOUPPER "${CMAKE_CONFIGURATION_TYPES}" upper)
set(location_suffix "_${upper}")
else ("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
set(location_suffix "")
endif ("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
project(DynamoRIO_samples)
if ("${CMAKE_VERSION}" VERSION_EQUAL "3.9" OR
"${CMAKE_VERSION}" VERSION_GREATER "3.9")
# i#1375: We are ok w/ the new policy of SKIP_BUILD_RPATH not affecting install names.
cmake_policy(SET CMP0068 NEW)
endif ()
set(output_dir "${PROJECT_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${output_dir}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${output_dir}")
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
# we don't support the Debug and Release subdirs
foreach (config ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER "${config}" config_upper)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${config_upper}
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${config_upper}
"${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${config_upper}
"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
endforeach ()
endif ()
if (BUILD_TESTS)
# For automated sanity tests we can't have msgboxes or output
set(SHOW_RESULTS_DEFAULT OFF)
else (BUILD_TESTS)
set(SHOW_RESULTS_DEFAULT ON)
endif (BUILD_TESTS)
option(SHOW_RESULTS
"Display client results in pop-up (Windows) or console message (Linux)"
${SHOW_RESULTS_DEFAULT})
if (SHOW_RESULTS)
add_definitions(-DSHOW_RESULTS)
endif (SHOW_RESULTS)
option(SHOW_SYMBOLS "Use symbol lookup in clients that support it" ON)
if (SHOW_SYMBOLS)
add_definitions(-DSHOW_SYMBOLS)
endif (SHOW_SYMBOLS)
if (NOT DEFINED GENERATE_PDBS)
# support running tests over ssh where pdb building is problematic
set(GENERATE_PDBS ON)
endif (NOT DEFINED GENERATE_PDBS)
# i#379: We usually want to build the samples with optimizations to improve the
# chances of inlining, but it's nice to be able to turn that off easily. A
# release build should already have optimizations, so this should only really
# affect debug builds.
option(OPTIMIZE_SAMPLES
"Build samples with optimizations to increase the chances of clean call inlining (overrides debug flags)"
ON)
if (WIN32)
set(OPT_CFLAGS "/O2")
else (WIN32)
set(OPT_CFLAGS "-O2")
endif (WIN32)
if (DEBUG)
set(OPT_CFLAGS "${OPT_CFLAGS} -DDEBUG")
endif (DEBUG)
# For C clients that only rely on the DR API and not on any 3rd party
# library routines, we could shrink the size of the client binary
# by disabling libc via "set(DynamoRIO_USE_LIBC OFF)".
if (NOT DEFINED DynamoRIO_DIR)
set(DynamoRIO_DIR "${PROJECT_SOURCE_DIR}/../cmake" CACHE PATH
"DynamoRIO installation's cmake directory")
endif (NOT DEFINED DynamoRIO_DIR)
find_package(DynamoRIO 8.0)
if (NOT DynamoRIO_FOUND)
message(FATAL_ERROR "DynamoRIO package required to build")
endif(NOT DynamoRIO_FOUND)
if (WIN32)
# disable stack protection: "unresolved external symbol ___security_cookie"
# disable the warning "unreferenced formal parameter" #4100
# disable the warning "conditional expression is constant" #4127
# disable the warning "cast from function pointer to data pointer" #4054
set(CL_CFLAGS "/GS- /wd4100 /wd4127 /wd4054")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CL_CFLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CL_CFLAGS}")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif (WIN32)
if (OPTIMIZE_SAMPLES)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPT_CFLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPT_CFLAGS}")
endif ()
function (add_sample_client name source_file_list extension_list)
add_library(${name} SHARED ${source_file_list})
configure_DynamoRIO_client(${name})
foreach (ext ${extension_list})
use_DynamoRIO_extension(${name} ${ext})
endforeach (ext)
# Provide a hint for how to use the client
if (NOT DynamoRIO_INTERNAL OR NOT "${CMAKE_GENERATOR}" MATCHES "Ninja")
DynamoRIO_get_full_path(path ${name} "${location_suffix}")
add_custom_command(TARGET ${name}
POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E echo "Usage: pass to drconfig or drrun: -c ${path}"
VERBATIM)
endif ()
endfunction (add_sample_client)
function (add_sample_standalone name source_file_list)
add_executable(${name} ${source_file_list})
configure_DynamoRIO_standalone(${name})
# Provide a hint for running
if (NOT DynamoRIO_INTERNAL OR NOT "${CMAKE_GENERATOR}" MATCHES "Ninja")
if (UNIX)
set(FIND_MSG "(set LD_LIBRARY_PATH)")
else (UNIX)
set(FIND_MSG "(set PATH or copy to same directory)")
endif (UNIX)
add_custom_command(TARGET ${name}
POST_BUILD
COMMAND ${CMAKE_COMMAND}
ARGS -E echo "Make sure the loader finds the dynamorio library ${FIND_MSG}"
VERBATIM)
endif ()
endfunction (add_sample_standalone)
###########################################################################
# As we'll be calling configure_DynamoRIO_{client,standalone} from within
# a function scope, we must set the global vars ahead of time:
configure_DynamoRIO_global(OFF ON)
# Use ;-separated lists for source files and extensions.
add_sample_client(bbbuf "bbbuf.c" "drmgr;drreg;drx")
add_sample_client(bbcount "bbcount.c" "drmgr;drreg;drx")
add_sample_client(bbsize "bbsize.c" "drmgr;drx")
add_sample_client(div "div.c" "drmgr")
add_sample_client(empty "empty.c" "")
add_sample_client(memtrace_simple "memtrace_simple.c;utils.c" "drmgr;drreg;drutil;drx")
add_sample_client(memval_simple "memval_simple.c;utils.c" "drmgr;drreg;drutil;drx")
add_sample_client(instrace_simple "instrace_simple.c;utils.c" "drmgr;drreg;drx")
add_sample_client(instrace_simple_expand_rep "instrace_simple_expand_rep.c;utils.c" "drmgr;drreg;drx;drutil")
add_sample_client(opcode_count "opcode_count.cpp" "drmgr;drreg;drx;droption")
if (X86) # FIXME i#1551, i#1569: port to ARM and AArch64
add_sample_client(cbr "cbr.c" "drmgr")
add_sample_client(countcalls "countcalls.c" "drmgr;drreg")
add_sample_client(inc2add "inc2add.c" "drmgr;drreg")
add_sample_client(memtrace_x86_binary "memtrace_x86.c;utils.c"
"drcontainers;drmgr;drreg;drutil;drx")
add_sample_client(memtrace_x86_text "memtrace_x86.c;utils.c"
"drcontainers;drmgr;drreg;drutil;drx")
_DR_append_property_list(TARGET memtrace_x86_text COMPILE_DEFINITIONS "OUTPUT_TEXT")
add_sample_client(instrace_x86_binary "instrace_x86.c;utils.c"
"drcontainers;drmgr;drreg;drx")
add_sample_client(instrace_x86_text "instrace_x86.c;utils.c"
"drcontainers;drmgr;drreg;drx")
_DR_append_property_list(TARGET instrace_x86_text COMPILE_DEFINITIONS "OUTPUT_TEXT")
add_sample_client(prefetch "prefetch.c" "drmgr")
if (NOT WIN32)
add_sample_client(ssljack "ssljack.c" "drmgr;drwrap")
endif (NOT WIN32)
# dr_insert_mbr_instrumentation is NYI
add_sample_client(modxfer "modxfer.c;utils.c" "drmgr;drreg;drx")
add_sample_client(modxfer_app2lib "modxfer_app2lib.c" "drmgr")
add_sample_client(instrcalls "instrcalls.c;utils.c" "drmgr;drsyms;drx")
# dr_insert_cbr_instrument_ex is NYI
add_sample_client(cbrtrace "cbrtrace.c;utils.c" "drmgr;drx")
add_sample_client(hot_bbcount "hot_bbcount.c" "drmgr;drreg;drbbdup;drx")
endif (X86)
add_sample_client(wrap "wrap.c" "drmgr;drwrap")
add_sample_client(signal "signal.c" "drmgr")
add_sample_client(syscall "syscall.c" "drmgr")
add_sample_client(inline "inline.c" "drmgr;drcontainers")
add_sample_client(inscount "inscount.cpp" "drmgr;droption")
add_sample_client(opcodes "opcodes.c" "drmgr;drreg;drx")
add_sample_client(stl_test "stl_test.cpp" "")
# Customized code
add_sample_client(mywrap "mywrap.c" "drmgr;drwrap;drsyms")
add_sample_client(trace_target_func_usage "trace_target_func_usage.c;utils.c" "drmgr;drreg;drutil;drx;drwrap;drsyms")
if (WIN32)
# This client is Windows-only.
add_sample_client(stats "stats.c;utils.c" "drmgr;drreg;drx")
# XXX i#893: drwrap's asm isn't SEH compliant.
_DR_append_property_string(TARGET wrap LINK_FLAGS "/safeseh:no")
endif ()
add_sample_standalone(tracedump "tracedump.c")
/* ******************************************************************************
* Copyright (c) 2011-2018 Google, Inc. All rights reserved.
* Copyright (c) 2010 Massachusetts Institute of Technology 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:
* instrace_simple.c
*
* Collects a dynamic instruction trace and dumps it to a text file.
* This is a simpler (and slower) version of instrace_x86.c.
*
* (1) It fills a per-thread-buffer from inlined instrumentation.
* (2) It calls a clean call to dump the buffer into a file.
*
* The trace is a simple text file with each line containing the PC and
* the opcode of the instruction.
*
* This client is a simple implementation of an instruction tracing tool
* without instrumentation optimization. It also uses simple absolute PC
* values and does not separate them into library offsets.
* Additionally, dumping as text is much slower than dumping as
* binary. See instrace_x86.c for a higher-performance sample.
*/
#include <stdio.h>
#include <stddef.h> /* for offsetof */
#include "dr_api.h"
#include "drmgr.h"
#include "drreg.h"
#include "drutil.h"
#include "utils.h"
/* Each ins_ref_t describes an executed instruction. */
typedef struct _ins_ref_t {
app_pc pc;
int opcode;
} ins_ref_t;
/* Max number of ins_ref a buffer can have. It should be big enough
* to hold all entries between clean calls.
*/
#define MAX_NUM_INS_REFS 8192
/* The maximum size of buffer for holding ins_refs. */
#define MEM_BUF_SIZE (sizeof(ins_ref_t) * MAX_NUM_INS_REFS)
/* thread private log file and counter */
typedef struct {
byte *seg_base;
ins_ref_t *buf_base;
file_t log;
FILE *logf;
uint64 num_refs;
} per_thread_t;
static client_id_t client_id;
static void *mutex; /* for multithread support */
static uint64 num_refs; /* keep a global instruction reference count */
/* Allocated TLS slot offsets */
enum {
INSTRACE_TLS_OFFS_BUF_PTR,
INSTRACE_TLS_COUNT, /* total number of TLS slots allocated */
};
static reg_id_t tls_seg;
static uint tls_offs;
static int tls_idx;
#define TLS_SLOT(tls_base, enum_val) (void **)((byte *)(tls_base) + tls_offs + (enum_val))
#define BUF_PTR(tls_base) *(ins_ref_t **)TLS_SLOT(tls_base, INSTRACE_TLS_OFFS_BUF_PTR)
#define MINSERT instrlist_meta_preinsert
static void
instrace(void *drcontext)
{
per_thread_t *data;
ins_ref_t *ins_ref, *buf_ptr;
data = drmgr_get_tls_field(drcontext, tls_idx);
buf_ptr = BUF_PTR(data->seg_base);
/* Example of dumped file content:
* 0x7f59c2d002d3: call
* 0x7ffeacab0ec8: mov
*/
/* We use libc's fprintf as it is buffered and much faster than dr_fprintf
* for repeated printing that dominates performance, as the printing does here.
*/
for (ins_ref = (ins_ref_t *)data->buf_base; ins_ref < buf_ptr; ins_ref++) {
/* We use PIFX to avoid leading zeroes and shrink the resulting file. */
fprintf(data->logf, PIFX ",%s\n", (ptr_uint_t)ins_ref->pc,
decode_opcode_name(ins_ref->opcode));
data->num_refs++;
}
BUF_PTR(data->seg_base) = data->buf_base;
}
/* clean_call dumps the memory reference info to the log file */
static void
clean_call(void)
{
void *drcontext = dr_get_current_drcontext();
instrace(drcontext);
}
static void
insert_load_buf_ptr(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t reg_ptr)
{
dr_insert_read_raw_tls(drcontext, ilist, where, tls_seg,
tls_offs + INSTRACE_TLS_OFFS_BUF_PTR, reg_ptr);
}
static void
insert_update_buf_ptr(void *drcontext, instrlist_t *ilist, instr_t *where,
reg_id_t reg_ptr, int adjust)
{
MINSERT(
ilist, where,
XINST_CREATE_add(drcontext, opnd_create_reg(reg_ptr), OPND_CREATE_INT16(adjust)));
dr_insert_write_raw_tls(drcontext, ilist, where, tls_seg,
tls_offs + INSTRACE_TLS_OFFS_BUF_PTR, reg_ptr);
}
static void
insert_save_opcode(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t base,
reg_id_t scratch, int opcode)
{
scratch = reg_resize_to_opsz(scratch, OPSZ_2);
MINSERT(ilist, where,
XINST_CREATE_load_int(drcontext, opnd_create_reg(scratch),
OPND_CREATE_INT16(opcode)));
MINSERT(ilist, where,
XINST_CREATE_store_2bytes(
drcontext, OPND_CREATE_MEM16(base, offsetof(ins_ref_t, opcode)),
opnd_create_reg(scratch)));
}
static void
insert_save_pc(void *drcontext, instrlist_t *ilist, instr_t *where, reg_id_t base,
reg_id_t scratch, app_pc pc)
{
instrlist_insert_mov_immed_ptrsz(drcontext, (ptr_int_t)pc, opnd_create_reg(scratch),
ilist, where, NULL, NULL);
MINSERT(ilist, where,
XINST_CREATE_store(drcontext,
OPND_CREATE_MEMPTR(base, offsetof(ins_ref_t, pc)),
opnd_create_reg(scratch)));
}
/* insert inline code to add an instruction entry into the buffer */
static void
instrument_instr(void *drcontext, instrlist_t *ilist, instr_t *where)
{
/* We need two scratch registers */
reg_id_t reg_ptr, reg_tmp;
if (drreg_reserve_register(drcontext, ilist, where, NULL, &reg_ptr) !=
DRREG_SUCCESS ||
drreg_reserve_register(drcontext, ilist, where, NULL, &reg_tmp) !=
DRREG_SUCCESS) {
DR_ASSERT(false); /* cannot recover */
return;
}
insert_load_buf_ptr(drcontext, ilist, where, reg_ptr);
insert_save_pc(drcontext, ilist, where, reg_ptr, reg_tmp, instr_get_app_pc(where));
insert_save_opcode(drcontext, ilist, where, reg_ptr, reg_tmp,
instr_get_opcode(where));
insert_update_buf_ptr(drcontext, ilist, where, reg_ptr, sizeof(ins_ref_t));
/* Restore scratch registers */
if (drreg_unreserve_register(drcontext, ilist, where, reg_ptr) != DRREG_SUCCESS ||
drreg_unreserve_register(drcontext, ilist, where, reg_tmp) != DRREG_SUCCESS)
DR_ASSERT(false);
}
/* For each app instr, we insert inline code to fill the buffer. */
static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *instr,
bool for_trace, bool translating, void *user_data)
{
/* we don't want to auto-predicate any instrumentation */
drmgr_disable_auto_predication(drcontext, bb);
if (!instr_is_app(instr))
return DR_EMIT_DEFAULT;
/* insert code to add an entry to the buffer */
instrument_instr(drcontext, bb, instr);
/* insert code once per bb to call clean_call for processing the buffer */
if (drmgr_is_first_instr(drcontext, instr)
/* XXX i#1698: there are constraints for code between ldrex/strex pairs,
* so we minimize the instrumentation in between by skipping the clean call.
* We're relying a bit on the typical code sequence with either ldrex..strex
* in the same bb, in which case our call at the start of the bb is fine,
* or with a branch in between and the strex at the start of the next bb.
* However, there is still a chance that the instrumentation code may clear the
* exclusive monitor state.
* Using a fault to handle a full buffer should be more robust, and the
* forthcoming buffer filling API (i#513) will provide that.
*/
IF_AARCHXX(&&!instr_is_exclusive_store(instr)))
dr_insert_clean_call(drcontext, bb, instr, (void *)clean_call, false, 0);
return DR_EMIT_DEFAULT;
}
static void
event_thread_init(void *drcontext)
{
per_thread_t *data = dr_thread_alloc(drcontext, sizeof(per_thread_t));
DR_ASSERT(data != NULL);
drmgr_set_tls_field(drcontext, tls_idx, data);
/* Keep seg_base in a per-thread data structure so we can get the TLS
* slot and find where the pointer points to in the buffer.
*/
data->seg_base = dr_get_dr_segment_base(tls_seg);
data->buf_base =
dr_raw_mem_alloc(MEM_BUF_SIZE, DR_MEMPROT_READ | DR_MEMPROT_WRITE, NULL);
DR_ASSERT(data->seg_base != NULL && data->buf_base != NULL);
/* put buf_base to TLS as starting buf_ptr */
BUF_PTR(data->seg_base) = data->buf_base;
data->num_refs = 0;
/* 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 as a client argument.
*/
data->log =
log_file_open(client_id, drcontext, NULL /* using client lib path */, "instrace",
#ifndef WINDOWS
DR_FILE_CLOSE_ON_FORK |
#endif
DR_FILE_ALLOW_LARGE);
data->logf = log_stream_from_file(data->log);
fprintf(data->logf, "Format: <instr address>,<opcode>\n");
}
static void
event_thread_exit(void *drcontext)
{
per_thread_t *data;
instrace(drcontext); /* dump any remaining buffer entries */
data = drmgr_get_tls_field(drcontext, tls_idx);
dr_mutex_lock(mutex);
num_refs += data->num_refs;
dr_mutex_unlock(mutex);
log_stream_close(data->logf); /* closes fd too */
dr_raw_mem_free(data->buf_base, MEM_BUF_SIZE);
dr_thread_free(drcontext, data, sizeof(per_thread_t));
}
static dr_emit_flags_t
event_bb_app2app(void *drcontext, void *tag, instrlist_t *bb, bool for_trace,
bool translating)
{
if (!drutil_expand_rep_string(drcontext, bb)) {
DR_ASSERT(false);
/* in release build, carry on: we'll just miss per-iter refs */
}
return DR_EMIT_DEFAULT;
}
static void
event_exit(void)
{
dr_log(NULL, DR_LOG_ALL, 1, "Client 'instrace' num refs seen: " SZFMT "\n", num_refs);
if (!dr_raw_tls_cfree(tls_offs, INSTRACE_TLS_COUNT))
DR_ASSERT(false);
if (!drmgr_unregister_tls_field(tls_idx) ||
!drmgr_unregister_bb_app2app_event(event_bb_app2app) ||
!drmgr_unregister_thread_init_event(event_thread_init) ||
!drmgr_unregister_thread_exit_event(event_thread_exit) ||
!drmgr_unregister_bb_insertion_event(event_app_instruction) ||
drreg_exit() != DRREG_SUCCESS)
DR_ASSERT(false);
dr_mutex_destroy(mutex);
drmgr_exit();
drutil_exit();
}
DR_EXPORT void
dr_client_main(client_id_t id, int argc, const char *argv[])
{
/* We need 2 reg slots beyond drreg's eflags slots => 3 slots */
drreg_options_t ops = { sizeof(ops), 3, false };
dr_set_client_name("DynamoRIO Sample Client 'instrace'",
"http://dynamorio.org/issues");
if (!drmgr_init() || drreg_init(&ops) != DRREG_SUCCESS || !drutil_init())
DR_ASSERT(false);
/* register events */
dr_register_exit_event(event_exit);
if (!drmgr_register_thread_init_event(event_thread_init) ||
!drmgr_register_bb_app2app_event(event_bb_app2app, NULL) ||
!drmgr_register_thread_exit_event(event_thread_exit) ||
!drmgr_register_bb_instrumentation_event(NULL /*analysis_func*/,
event_app_instruction, NULL))
DR_ASSERT(false);
client_id = id;
mutex = dr_mutex_create();
tls_idx = drmgr_register_tls_field();
DR_ASSERT(tls_idx != -1);
/* The TLS field provided by DR cannot be directly accessed from the code cache.
* For better performance, we allocate raw TLS so that we can directly
* access and update it with a single instruction.
*/
if (!dr_raw_tls_calloc(&tls_seg, &tls_offs, INSTRACE_TLS_COUNT, 0))
DR_ASSERT(false);
dr_log(NULL, DR_LOG_ALL, 1, "Client 'instrace' initializing\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment