1bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov/* Copyright (c) 2008-2010, Google Inc.
2bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * All rights reserved.
3bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *
4bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * Redistribution and use in source and binary forms, with or without
5bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * modification, are permitted provided that the following conditions are
6bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * met:
7bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *
8bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *     * Redistributions of source code must retain the above copyright
9bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * notice, this list of conditions and the following disclaimer.
10bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *     * Neither the name of Google Inc. nor the names of its
11bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * contributors may be used to endorse or promote products derived from
12bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * this software without specific prior written permission.
13bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *
14bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov */
26bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
27bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// This file is part of ThreadSanitizer, a dynamic data race detector.
28bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
29bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// Some parts of the code in this file are taken from the examples
30bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// in DynamoRIO distribution, which have the following copyright.
31bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov/* **********************************************************
32bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * Copyright (c) 2003-2008 VMware, Inc.  All rights reserved.
33bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * **********************************************************/
34bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
35bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov/*
36bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * Redistribution and use in source and binary forms, with or without
37bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * modification, are permitted provided that the following conditions are met:
38bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *
39bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * * Redistributions of source code must retain the above copyright notice,
40bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *   this list of conditions and the following disclaimer.
41bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *
42bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * * Redistributions in binary form must reproduce the above copyright notice,
43bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *   this list of conditions and the following disclaimer in the documentation
44bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *   and/or other materials provided with the distribution.
45bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *
46bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * * Neither the name of VMware, Inc. nor the names of its contributors may be
47bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *   used to endorse or promote products derived from this software without
48bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *   specific prior written permission.
49bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov *
50bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
51bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
54bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
56bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
57bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
60bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov * DAMAGE.
61bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov */
62bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
63bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// Author: Konstantin Serebryany.
64bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// Author: Timur Iskhodzhanov.
65bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov//
66bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// ******* WARNING ********
67bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// This code is experimental. Do not expect anything here to work.
68bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// ***** END WARNING ******
69bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
70bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#include "dr_api.h"
71bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
72bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#include "ts_util.h"
73bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
74bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#define EXTRA_REPLACE_PARAMS
75bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#define REPORT_READ_RANGE(a,b)
76bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#define REPORT_WRITE_RANGE(a,b)
77bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#include "ts_replace.h"
78bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
79bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#define Printf dr_printf
80bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
81bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void *g_lock;
82bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic int   g_n_created_threads;
83bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
84bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovtypedef unordered_map<intptr_t, string> SymbolsTable;
85bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic SymbolsTable *sym_tab;
86bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
87bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstring *g_main_module_path;
88bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
89bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov//--------------- StackFrame ----------------- {{{1
90bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstruct StackFrame {
91bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  uintptr_t pc;
92bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  uintptr_t sp;
93bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  StackFrame(uintptr_t p, uintptr_t s) : pc(p), sp(s) { }
94bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov};
95bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
96bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
97bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov//--------------- DrThread ----------------- {{{1
98bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstruct DrThread {
99bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  int tid;  // A unique 0-based thread id.
100bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  vector<StackFrame> shadow_stack;
101bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov};
102bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
103bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic DrThread &GetCurrentThread(void *drcontext) {
104bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  return *(DrThread*)dr_get_tls_field(drcontext);
105bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
106bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
107bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov//--------------- ShadowStack ----------------- {{{1
108bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#define DEB_PR (0 && t.tid == 1)
109bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
110bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void PrintShadowStack(DrThread &t) {
111bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  Printf("T%d Shadow stack (%d)\n", t.tid, (int)t.shadow_stack.size());
112bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  for (int i = t.shadow_stack.size() - 1; i >= 0; i--) {
113bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    uintptr_t pc = t.shadow_stack[i].pc;
114bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    Printf("%s[%p]\n", g_main_module_path->c_str(), pc);
115bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
116bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  for (int i = t.shadow_stack.size() - 1; i >= 0; i--) {
117bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    uintptr_t pc = t.shadow_stack[i].pc;
118bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    uintptr_t sp = t.shadow_stack[i].sp;
119bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    Printf("  sp=%p pc=%p\n", sp, pc);
120bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
121bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
122bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
123bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void UpdateShadowStack(DrThread &t, uintptr_t sp) {
124bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  while (t.shadow_stack.size() > 0 && sp >= t.shadow_stack.back().sp) {
125bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    t.shadow_stack.pop_back();
126bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    if (DEB_PR) {
127bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      dr_mutex_lock(g_lock);
128bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      Printf("T%d PopShadowStack\n", t.tid);
129bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      PrintShadowStack(t);
130bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      dr_mutex_unlock(g_lock);
131bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    }
132bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
133bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
134bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
135bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void PushShadowStack(DrThread &t, uintptr_t pc, uintptr_t target_pc, uintptr_t sp) {
136bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (t.shadow_stack.size() > 0) {
137bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    t.shadow_stack.back().pc = pc;
138bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
139bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  t.shadow_stack.push_back(StackFrame(target_pc, sp));
140bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (DEB_PR) {
141bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_mutex_lock(g_lock);
142bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    Printf("T%d PushShadowStack %p %p %d\n", t.tid, pc, target_pc, sp);
143bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    PrintShadowStack(t);
144bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_mutex_unlock(g_lock);
145bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
146bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
147bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
148bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov//--------------- callbacks ----------------- {{{1
149bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void OnEvent_ThreadInit(void *drcontext) {
150bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  DrThread *t_ptr = new DrThread;
151bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  DrThread &t = *t_ptr;
152bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
153bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_mutex_lock(g_lock);
154bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  t.tid = g_n_created_threads++;
155bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_mutex_unlock(g_lock);
156bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
157bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_set_tls_field(drcontext, t_ptr);
158bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
159bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("T%d %s\n", t.tid, (char*)__FUNCTION__+8);
160bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
161bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
162bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void OnEvent_ThreadExit(void *drcontext) {
163bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  DrThread &t = GetCurrentThread(drcontext);
164bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("T%d %s\n", t.tid, (char*)__FUNCTION__+8);
165bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
166bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
167bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovvoid OnEvent_ModuleLoaded(void *drcontext, const module_data_t *info,
168bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                          bool loaded) {
169bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // if this assertion fails, your DynamoRIO is too old. You need rev261 with some patches...
170bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  CHECK(info->full_path);
171bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
172bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("%s: %s (%s)\n", __FUNCTION__,
173bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov            dr_module_preferred_name(info), info->full_path);
174bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (g_main_module_path == NULL) {
175bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    g_main_module_path = new string(info->full_path);
176bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
177bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
178bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
179bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void OnEvent_Exit(void) {
180bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("ThreadSanitizerDynamoRio: done\n");
181bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_mutex_destroy(g_lock);
182bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
183bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
184bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void On_Mop(uintptr_t pc, size_t size, void *a, bool is_w) {
185bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  void *drcontext = dr_get_current_drcontext();
186bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  DrThread &t = GetCurrentThread(drcontext);
187bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (t.tid == 777) {
188bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_fprintf(STDERR, "T%d pc=%p a=%p size=%ld %s\n", t.tid, pc, a, size, is_w ? "WRITE" : "READ");
189bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
190bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
191bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
192bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void On_Read(uintptr_t pc, size_t size, void *a) {
193bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  On_Mop(pc, size, a, false);
194bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
195bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
196bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void On_Write(uintptr_t pc, size_t size, void *a) {
197bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  On_Mop(pc, size, a, true);
198bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
199bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
200bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void On_AnyCall(uintptr_t pc, uintptr_t target_pc, uintptr_t sp, bool is_direct) {
201bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  void *drcontext = dr_get_current_drcontext();
202bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  DrThread &t = GetCurrentThread(drcontext);
203bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // dr_fprintf(STDOUT, "T%d CALL %p => %p; sp=%p\n", t.tid, pc, target_pc, sp);
204bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  PushShadowStack(t, pc, target_pc, sp);
205bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
206bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
207bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void On_DirectCall(uintptr_t pc, uintptr_t target_pc, uintptr_t sp) {
208bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  On_AnyCall(pc, target_pc, sp, true);
209bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
210bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
211bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void On_IndirectCall(uintptr_t pc, uintptr_t target_pc, uintptr_t sp) {
212bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  On_AnyCall(pc, target_pc, sp, false);
213bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
214bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
215bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void On_TraceEnter(uintptr_t pc, uintptr_t sp) {
216bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  void *drcontext = dr_get_current_drcontext();
217bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  DrThread &t = GetCurrentThread(drcontext);
218bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // dr_fprintf(STDOUT, "T%d TRACE:\n%p\n%p\n", t.tid, pc, sp);
219bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  UpdateShadowStack(t, sp);
220bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
221bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
222bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov//--------------- instrumentation ----------------- {{{1
223bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovopnd_t opnd_create_base_disp_from_dst(opnd_t dst) {
224bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  return opnd_create_base_disp(opnd_get_base(dst),
225bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                               opnd_get_index(dst),
226bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                               opnd_get_scale(dst),
227bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                               opnd_get_disp(dst),
228bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                               OPSZ_lea);
229bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
230bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
231bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void InstrumentOneMop(void* drcontext, instrlist_t *bb,
232bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                             instr_t *instr, opnd_t opnd, bool is_w) {
233bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  //   opnd_disassemble(drcontext, opnd, 1);
234bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  //   dr_printf("  -- (%s opnd)\n", is_w ? "write" : "read");
235bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  void *callback = (void*)(is_w ? On_Write : On_Read);
236bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  int size = opnd_size_in_bytes(opnd_get_size(opnd));
237bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
238bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  instr_t *tmp_instr = NULL;
239bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  reg_id_t reg = REG_XAX;
240bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
241bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  /* save %xax */
242bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_save_reg(drcontext, bb, instr, reg, SPILL_SLOT_2);
243bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
244bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (opnd_is_base_disp(opnd)) {
245bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    /* lea opnd => %xax */
246bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    opnd_set_size(&opnd, OPSZ_lea);
247bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    tmp_instr = INSTR_CREATE_lea(drcontext,
248bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                 opnd_create_reg(reg),
249bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                 opnd);
250bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  } else if(
251bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#ifdef X86_64
252bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      opnd_is_rel_addr(opnd) ||
253bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov#endif
254bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      opnd_is_abs_addr(opnd)) {
255bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    tmp_instr = INSTR_CREATE_mov_imm(drcontext,
256bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                     opnd_create_reg(reg),
257bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                     OPND_CREATE_INTPTR(opnd_get_addr(opnd)));
258bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
259bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (tmp_instr) {
260bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    // CHECK(tmp_instr);
261bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    instrlist_meta_preinsert(bb, instr, tmp_instr);
262bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
263bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    /* clean call */
264bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_insert_clean_call(drcontext, bb, instr, callback, false,
265bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         3,
266bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         OPND_CREATE_INTPTR(instr_get_app_pc(instr)),
267bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         OPND_CREATE_INT32(size),
268bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         opnd_create_reg(reg));
269bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    /* restore %xax */
270bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_restore_reg(drcontext, bb, instr, REG_XAX, SPILL_SLOT_2);
271bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  } else {
272bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_printf("%s ????????????????????\n", __FUNCTION__);
273bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
274bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
275bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
276bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void InstrumentMopInstruction(void *drcontext,
277bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                     instrlist_t *bb, instr_t *instr) {
278bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // reads:
279bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  for (int a = 0; a < instr_num_srcs(instr); a++) {
280bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    opnd_t curop = instr_get_src(instr, a);
281bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    if (opnd_is_memory_reference(curop)) {
282bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      InstrumentOneMop(drcontext, bb, instr, curop, false);
283bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    }
284bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
285bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // writes:
286bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  for (int a = 0; a < instr_num_dsts(instr); a++) {
287bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    opnd_t curop = instr_get_dst(instr, a);
288bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    if (opnd_is_memory_reference(curop)) {
289bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      InstrumentOneMop(drcontext, bb, instr, curop, true);
290bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    }
291bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
292bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  //dr_printf("reads: %d writes: %d\n", n_reads, n_writes);
293bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
294bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
295bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic void InstrumentInstruction(void *drcontext, instrlist_t *bb,
296bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                  instr_t *instr) {
297bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // instr_disassemble(drcontext, instr, 1);
298bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // dr_printf("  -- \n");
299bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (instr_is_call_direct(instr)) {
300bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_insert_call_instrumentation(drcontext, bb, instr,
301bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                   (app_pc)On_DirectCall);
302bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  } else if (instr_is_call_indirect(instr)) {
303bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_insert_mbr_instrumentation(drcontext, bb, instr,
304bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                  (app_pc)On_IndirectCall, SPILL_SLOT_1);
305bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
306bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  } else if (instr_reads_memory(instr) || instr_writes_memory(instr)) {
307bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    InstrumentMopInstruction(drcontext, bb, instr);
308bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
309bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
310bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
311bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic dr_emit_flags_t OnEvent_Trace(void *drcontext, void *tag,
312bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                     instrlist_t *trace, bool translating) {
313bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  instr_t *first_instr = NULL;
314bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  for (instr_t *instr = instrlist_first(trace); instr != NULL;
315bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov       instr = instr_get_next(instr)) {
316bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    if (instr_get_app_pc(instr)) {
317bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      first_instr = instr;
318bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      break;
319bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    }
320bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
321bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (first_instr) {
322bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    // instr_disassemble(drcontext, first_instr, 1);
323bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    // dr_printf("  -- in_trace %p\n", instr_get_app_pc(first_instr));
324bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_insert_clean_call(drcontext, trace, first_instr,
325bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         (void*)On_TraceEnter, false,
326bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         2,
327bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         OPND_CREATE_INTPTR(instr_get_app_pc(first_instr)),
328bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         opnd_create_reg(REG_XSP)
329bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                         );
330bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
331bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  return DR_EMIT_DEFAULT;
332bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
333bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
334bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovint replace_foo(int i, int j, int k) {
335bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf(" dy 'foo_replace'(%i, %i, %i)\n", i, j, k);
336bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  return 1;
337bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
338bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
339bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovtypedef unordered_map<intptr_t, void*> FunctionsReplaceMap;
340bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic FunctionsReplaceMap *fun_replace_map;
341bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
342bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovnamespace wrap {
343bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
344bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovint (*orig_foo)(int,int,int) = NULL;
345bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovint in_wrapper = 0;  // TODO: Make it thread-local
346bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
347bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic int wrapped_foo(int i, int j, int k) {
348bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  in_wrapper = 1;
349bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
350bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf(" dy 'foo_wrap'(%i, %i, %i)\n", i, j, k);
351bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("orig_foo = %p\n", orig_foo);
352bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  int ret = 13;
353bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (orig_foo != NULL)
354bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    ret = orig_foo(i, j, k) + 4200;
355bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  else
356bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_printf("ERROR! orig_foo is not set!\n");/**/
357bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
358bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  in_wrapper = 0;
359bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  return ret;
360bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
361bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
362bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovint is_in_wrapper(int arg) {
363bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // TODO: this may not work well with recursive functions
364bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  return in_wrapper;
365bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
366bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
367bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
368bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovvoid print_bb(void* drcontext, instrlist_t *bb, const char * desc) {
369bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("==================\n");
370bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("%s:\n", desc);
371bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  for (instr_t *i = instrlist_first(bb); i != NULL; i = instr_get_next(i)) {
372bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    instr_disassemble(drcontext, i, 1);
373bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_printf("\n");
374bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
375bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("==================\n");
376bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
377bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
378bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovstatic dr_emit_flags_t OnEvent_BB(void* drcontext, void *tag, instrlist_t *bb,
379bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                  bool for_trace, bool translating) {
380bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  instr_t *first_instr = instrlist_first(bb);
381bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  app_pc pc = instr_get_app_pc(first_instr);
382bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  string symbol_name = "UNKNOWN";
383bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (sym_tab->find((intptr_t)pc) != sym_tab->end()) {
384bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    symbol_name = (*sym_tab)[(intptr_t)pc];
385bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    //dr_printf("Symbol = %s\n", symbol_name.c_str());
386bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
387bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
388bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (fun_replace_map->count((intptr_t)pc) > 0) {
389bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    // Replace client function with the function supplied by the tool.
390bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    // The logic is inspired by drmemory/replace.c
391bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    app_pc target_fun = (app_pc)(*fun_replace_map)[(intptr_t)pc];
392bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    const module_data_t *info = dr_lookup_module(pc);
393bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    dr_printf("REDIR: %s (from %s) redirected to %p\n",
394bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov              symbol_name.c_str(), info->full_path, target_fun);
395bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
396bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    instrlist_clear(drcontext, bb);
397bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    instrlist_append(bb, INSTR_XL8(INSTR_CREATE_jmp(drcontext, opnd_create_pc(target_fun)), pc));
398bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  } else {
399bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    if (StringMatch("*foo_to_wrap*", symbol_name)) {
400bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      const module_data_t *info = dr_lookup_module(pc);
401bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      dr_printf(" 'foo_to_wrap' entry point: bb %p, %s / %s\n", pc, dr_module_preferred_name(info), info->full_path);
402bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      wrap::orig_foo = (int (*)(int,int,int))(void*)pc;
403bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
404bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      //print_bb(drcontext, bb, "BEFORE");
405bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      // TODO: Use something more optimized than clean_call
406bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      dr_insert_clean_call(drcontext, bb, first_instr, (void*)wrap::is_in_wrapper,
407bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                           false, 1, OPND_CREATE_INTPTR(pc));
408bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      instr_t *opr_instr = INSTR_CREATE_test(drcontext, opnd_create_reg(REG_XAX),
409bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                                        opnd_create_reg(REG_XAX));
410bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      instr_t *jne_instr = INSTR_CREATE_jcc(drcontext, OP_jz,
411bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov                                            opnd_create_pc((app_pc)wrap::wrapped_foo));
412bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      instrlist_meta_preinsert(bb, first_instr, opr_instr);
413bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      instrlist_meta_preinsert(bb, first_instr, jne_instr);
414bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
415bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      //print_bb(drcontext, bb, "AFTER");
416bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    }
417bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
418bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    instr_t *instr, *next_instr;
419bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    for (instr = instrlist_first(bb); instr != NULL; instr = next_instr) {
420bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      next_instr = instr_get_next(instr);
421bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      if (instr_get_app_pc(instr))  // don't instrument non-app code
422bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov        InstrumentInstruction(drcontext, bb, instr);
423bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    }
424bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
425bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
426bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    OnEvent_Trace(drcontext, tag, bb, translating);
427bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
428bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
429bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  return DR_EMIT_DEFAULT;
430bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
431bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
432bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovvoid ReadSymbolsTableFromFile(const char *filename) {
433bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  file_t f = dr_open_file(filename, DR_FILE_READ);
434bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  CHECK(f != INVALID_FILE);
435bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
436bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  const int BUFF_SIZE = 1 << 16;  // should be enough for testing
437bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  char buff[BUFF_SIZE];
438bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_read_file(f, buff, BUFF_SIZE);
439bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  char *cur_line = buff;
440bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  while (*cur_line) {
441bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    char *next_line = strstr(cur_line, "\n");
442bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    if (next_line != NULL)
443bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      *next_line = 0;
444bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    char fun_name[1024];
445bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    char dummy;
446bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    void* pc;
447bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    sscanf(cur_line, "%p %c %s", &pc, &dummy, fun_name);
448bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    //dr_printf("%s => %p\n", fun_name, pc);
449bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    (*sym_tab)[(intptr_t)pc] = fun_name;
450bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
451bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    if (next_line == NULL) break;
452bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    cur_line = next_line + 1;
453bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
454bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
455bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
456bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
457bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanovvoid ReplaceFunc3(void *img, void *rtn, string filter, void *fun_ptr) {
458bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  for (SymbolsTable::iterator i = sym_tab->begin(); i != sym_tab->end(); i++) {
459bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    if (StringMatch(filter, i->second))
460bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov      (*fun_replace_map)[(intptr_t)i->first] = fun_ptr;
461bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
462bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
463bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
464bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov//--------------- dr_init ----------------- {{{1
465bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy StepanovDR_EXPORT void dr_init(client_id_t id) {
466bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  sym_tab = new SymbolsTable;
467bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
468bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // HACK doesn't work if multiple options are passed.
469bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  const char *opstr = dr_get_options(id);
470bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_printf("Options: %s\n", opstr);
471bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  const char *fname = strstr(opstr, "--symbols=");
472bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  if (fname) {
473bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov    ReadSymbolsTableFromFile(fname + 10);
474bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  }
475bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
476bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  // Register events.
477bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_register_exit_event(OnEvent_Exit);
478bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_register_bb_event(OnEvent_BB);
479bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_register_trace_event(OnEvent_Trace);
480bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_register_thread_init_event(OnEvent_ThreadInit);
481bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_register_thread_exit_event(OnEvent_ThreadExit);
482bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  dr_register_module_load_event(OnEvent_ModuleLoaded);
483bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  g_lock = dr_mutex_create();
484bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov
485bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  fun_replace_map = new FunctionsReplaceMap();
486bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  void *img = NULL, *rtn = NULL;
487bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  #define AFUNPTR void*
488bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "memchr", (AFUNPTR)Replace_memchr);
489bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "strchr", (AFUNPTR)Replace_strchr);
490bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "index", (AFUNPTR)Replace_strchr);
491b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  ReplaceFunc3(img, rtn, "strchrnul", (AFUNPTR)Replace_strchrnul);
492bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "strrchr", (AFUNPTR)Replace_strrchr);
493bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "rindex", (AFUNPTR)Replace_strrchr);
494bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "strlen", (AFUNPTR)Replace_strlen);
495bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "memcpy", (AFUNPTR)Replace_memcpy);
496b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  ReplaceFunc3(img, rtn, "memmove", (AFUNPTR)Replace_memmove);
497b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  ReplaceFunc3(img, rtn, "memcmp", (AFUNPTR)Replace_memcmp);
498bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "strcpy", (AFUNPTR)Replace_strcpy);
499b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  ReplaceFunc3(img, rtn, "stpcpy", (AFUNPTR)Replace_stpcpy);
500b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  ReplaceFunc3(img, rtn, "strncpy", (AFUNPTR)Replace_strncpy);
501b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  ReplaceFunc3(img, rtn, "strcmp", (AFUNPTR)Replace_strcmp);
502b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  ReplaceFunc3(img, rtn, "strncmp", (AFUNPTR)Replace_strncmp);
503b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  ReplaceFunc3(img, rtn, "strcat", (AFUNPTR)Replace_strcat);
504bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov  ReplaceFunc3(img, rtn, "*foo_to_replace*", (AFUNPTR)replace_foo);
505bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov}
506bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// end. {{{1
507bec2f0e0495e343f55908a6f0cc4bd8dd27b27d1Evgeniy Stepanov// vim:shiftwidth=2:softtabstop=2:expandtab
508