/* ********************************************************** * Copyright (c) 2011-2018 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. */ /* Illustrates using the drwrap extension. * * Wraps malloc on Linux, HeapAlloc on Windows. Finds the maximum * malloc size requested, and randomly changes a malloc to return * failure to test an application's handling of out-of-memory * conditions. */ #include "memtrace.h" #include "dr_api.h" #include "drmgr.h" #include "drwrap.h" #include "drsyms.h" #include #include /* for offsetof */ #include #include "drreg.h" #include "drutil.h" #include "drx.h" #include #include #ifdef WINDOWS # define IF_WINDOWS_ELSE(x, y) x #else # define IF_WINDOWS_ELSE(x, y) y #endif #if 1 #define DISPLAY_STRING(...) /*do nothing*/ #else #define DISPLAY_STRING(...) dr_printf(__VA_ARGS__); #endif static void event_exit(void); static void wrap_pre(void *wrapcxt, OUT void **user_data); static void wrap_post(void *wrapcxt, void *user_data); enum { REF_TYPE_READ = 0, REF_TYPE_WRITE = 1, }; /* Max number of mem_ref a buffer can have. It should be big enough * to hold all entries between clean calls. */ #define MAX_NUM_MEM_REFS 4096 /* The maximum size of buffer for holding mem_refs. */ #define MEM_BUF_SIZE (sizeof(mem_ref_t) * MAX_NUM_MEM_REFS) static client_id_t client_id; void *g_mutex; /* for multithread support */ /* Allocated TLS slot offsets */ enum { MEMTRACE_TLS_OFFS_BUF_PTR, MEMTRACE_TLS_COUNT, /* total number of TLS slots allocated */ }; static reg_id_t tls_seg; static uint tls_offs; static int tls_idx; static int trace_start = 0; #define TLS_SLOT(tls_base, enum_val) (void **)((byte *)(tls_base) + tls_offs + (enum_val)) #define BUF_PTR(tls_base) *(mem_ref_t **)TLS_SLOT(tls_base, MEMTRACE_TLS_OFFS_BUF_PTR) #define MINSERT instrlist_meta_preinsert typedef struct { mem_ref_t *buf_base; } per_thread_t; static void module_load_event(void *drcontext, const module_data_t *mod, bool loaded) { return; } /* For each memory reference app instr, we insert inline code to fill the buffer * with an instruction entry and memory reference entries. */ static dr_emit_flags_t event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *where, bool for_trace, bool translating, void *user_data) { return DR_EMIT_DEFAULT; } /* We transform string loops into regular loops so we can more easily * monitor every memory reference they make. */ 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 */ } if (!drx_expand_scatter_gather(drcontext, bb, NULL)) { DR_ASSERT(false); } return DR_EMIT_DEFAULT; } static void event_thread_init(void *drcontext) { dr_printf("(%s|%d)\n",__FUNCTION__ ,__LINE__); per_thread_t *data = (per_thread_t *)dr_thread_alloc(drcontext, sizeof(per_thread_t)); DR_ASSERT(data != NULL); drmgr_set_tls_field(drcontext, tls_idx, data); dr_printf("(%s|%d)\n",__FUNCTION__ ,__LINE__); for (int i = 0; i < 100; i++) { uint64 ret = (uint64)(ptr_uint_t)1234561231231234987987946546; char *str = (char *) malloc(64); sprintf(str, "%.0f", ret); printf(str); } } static void event_thread_exit(void *drcontext) { per_thread_t *data; data = (per_thread_t *)drmgr_get_tls_field(drcontext, tls_idx); dr_raw_mem_free(data->buf_base, MEM_BUF_SIZE); dr_thread_free(drcontext, data, sizeof(per_thread_t)); dr_printf("(%s|%d)\n",__FUNCTION__ ,__LINE__); } void app_help(void) { } static bool app_init(int argc, const char **argv) { return true; } static void app_exit() { } static void event_exit(void) { dr_printf("(%s|%d)\n",__FUNCTION__ ,__LINE__); if (!dr_raw_tls_cfree(tls_offs, MEMTRACE_TLS_COUNT)) DR_ASSERT(false); if (!drmgr_unregister_tls_field(tls_idx) || !drmgr_unregister_thread_init_event(event_thread_init) || !drmgr_unregister_thread_exit_event(event_thread_exit) || !drmgr_unregister_bb_app2app_event(event_bb_app2app) || !dr_unregister_exit_event(event_exit) || !drmgr_unregister_module_load_event(module_load_event) || !drmgr_unregister_bb_insertion_event(event_app_instruction) || drreg_exit() != DRREG_SUCCESS) DR_ASSERT(false); drutil_exit(); drx_exit(); drsym_exit(); drwrap_exit(); drmgr_exit(); app_exit(); } DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[]) { dr_set_client_name("DynamoRIO Sample Client 'memtrace'", "http://dynamorio.org/issues"); /* make it easy to tell, by looking at log file, which client executed */ DISPLAY_STRING("Client 'wrap' initializing\n"); /* also give notification to stderr */ if(!app_init(argc, argv)){ return; } if (!drmgr_init()) { DR_ASSERT(false); } drreg_options_t ops = { sizeof(ops), 3, false }; if (drreg_init(&ops) != DRREG_SUCCESS) { DR_ASSERT(false); } if (!drutil_init() || !drx_init() || !drwrap_init()) { DR_ASSERT(false); } if (drsym_init(0) != DRSYM_SUCCESS){ DR_ASSERT(false); } if (!drmgr_register_thread_init_event(event_thread_init) || !drmgr_register_thread_exit_event(event_thread_exit) || !drmgr_register_bb_app2app_event(event_bb_app2app, NULL) || !drmgr_register_module_load_event(module_load_event) || !drmgr_register_bb_instrumentation_event(NULL /*analysis_func*/, event_app_instruction, NULL)) DR_ASSERT(false); dr_register_exit_event(event_exit); client_id = id; 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, MEMTRACE_TLS_COUNT, 0)) DR_ASSERT(false); } static void wrap_pre(void *wrapcxt, OUT void **user_data) { return; } static void wrap_post(void *wrapcxt, void *user_data) { return; }