Created
February 17, 2021 06:56
-
-
Save JackKuo-tw/74453ab2bf69de1570b06b221fa25d4f to your computer and use it in GitHub Desktop.
Add drutil_expand_rep_string to instrace_*.c samples #4138
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ********************************************************** | |
# 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") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ****************************************************************************** | |
* 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, ®_ptr) != | |
DRREG_SUCCESS || | |
drreg_reserve_register(drcontext, ilist, where, NULL, ®_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