15f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// Copyright (c) 2009 The Chromium Authors. All rights reserved.
25f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// Use of this source code is governed by a BSD-style license that can be
35f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// found in the LICENSE file.
45f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// TODO
60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner//  - Make capturing system call arguments optional and the number configurable.
75f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//  - Lots of places depend on the ABI so that we can modify EAX or EDX, this
85f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//    is safe, but these could be moved to be saved and restored anyway.
95f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//  - Understand the loader better, and make some more meaningful hooks with
105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//    proper data collection and durations.  Right now it's just noise.
115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//  - Get the returned pointer from AllocateHeap.
125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include <windows.h>
145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
15bdc601b196c48d4cd56a5ceb45d41ae4e87371abKen Dyck#include <stdio.h>
16aa58081902ad31927df02e8537d972eabe29d6dfDmitri Gribenko
1749aa7ff1245abd03e6e998e01302df31e4c6f8f6Argyrios Kyrtzidis#include <map>
18980e508ca70d6de75d2abfd96b4681fc98bb2698Steve Naroff#include <string>
19aaba5e346dffdbad5d1c42765a89e4a7afb0da67Douglas Gregor
20b17166c8077cd900cca83a895c43b30ea6660598Argyrios Kyrtzidis#include "assembler.h"
21e91593ef084479340582b2ba177b44be50a717b7Daniel Dunbar#include "logging.h"
22ea1471e0e967548c596a71469702f8846dbaf3c0John McCall#include "rdtsc.h"
232cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#include "sym_resolver.h"
247b90340c9c7d07aef4e301e72b5e8a30d5f4f0c8Argyrios Kyrtzidis#include "syscall_map.h"
2519cc4abea06a9b49e0e16a50d335c064cd723572Anders Carlsson
2614110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne#include "sidestep/mini_disassembler.h"
271b63e4f732dbc73d90abf886b4d21f8e3a165f6dChris Lattner
28a9376d470ccb0eac74fe09a6b2a18a890f1d17c4Chris Lattnernamespace {
295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
30f5942a44880be26878592eb052b737579349411eBenjamin Kramerstd::string JSONString(const std::string& str) {
3185f9bceab1542aafff012d4d28e998f4ba16e362Anders Carlsson  static const char hextable[] = "0123456789abcdef";
326fe7c8aa8c7546743ecd0ac0138c2cf5d8155386Nate Begeman  std::string out;
33f5942a44880be26878592eb052b737579349411eBenjamin Kramer  out.push_back('"');
340c8cd1ac55720276ad41fa7b4f8785bead5afd32Ted Kremenek  for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
35071cc7deffad608165b1ddd5263e8bf181861520Charles Davis    unsigned char c = static_cast<unsigned char>(*it);
362636197098e02fd7c90f9496056b8ab886dcbff0Argyrios Kyrtzidis    switch (c) {
3729445a0542d128cd7ee587ee52229670b9b54a12Anders Carlsson      case '\\':
385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      case '"':
395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      case '\'':
401827403a7138946305c0058f262e02b595cf882fDouglas Gregor        out.push_back('\\'); out.push_back(c);
411827403a7138946305c0058f262e02b595cf882fDouglas Gregor        break;
42225843186e3972ce798d3de00f86da9008b15a0eDouglas Gregor      default:
43225843186e3972ce798d3de00f86da9008b15a0eDouglas Gregor        if (c < 20 || c >= 127) {
44ffe37fdda5b4b4f162a45155c30d9f60ce110c12Sean Hunt          out.push_back('\\'); out.push_back('x');
45ffe37fdda5b4b4f162a45155c30d9f60ce110c12Sean Hunt          out.push_back(hextable[c >> 4]); out.push_back(hextable[c & 0xf]);
46a376d10acfacf19d6dfa41069f7929739a18dd7aDouglas Gregor        } else {
47a376d10acfacf19d6dfa41069f7929739a18dd7aDouglas Gregor          // Unescaped.
48ffe37fdda5b4b4f162a45155c30d9f60ce110c12Sean Hunt          out.push_back(c);
49ffe37fdda5b4b4f162a45155c30d9f60ce110c12Sean Hunt        }
504923aa25eb39d64106a5817c02d560a3aecf8b2cDouglas Gregor        break;
514923aa25eb39d64106a5817c02d560a3aecf8b2cDouglas Gregor    }
524923aa25eb39d64106a5817c02d560a3aecf8b2cDouglas Gregor  }
535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  out.push_back('"');
54aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov  return out;
555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
57a5ef44ff5d93a3be6ca67782828157a71894cf0cDmitri Gribenko}  // namespace
58aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
59aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenkoclass Playground {
60aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko public:
61aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kPlaygroundSize = 64 * 1024 * 1024;
62aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
63aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  // Encapsulate the configuration options to the playground.
64aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  class Options {
65c3fee3539fd00a6ce21dc1f574baf76686640072Dmitri Gribenko   public:
66c3fee3539fd00a6ce21dc1f574baf76686640072Dmitri Gribenko    Options()
67c3fee3539fd00a6ce21dc1f574baf76686640072Dmitri Gribenko        : stack_unwind_depth_(0),
68c3fee3539fd00a6ce21dc1f574baf76686640072Dmitri Gribenko          log_heap_(false),
69c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko          log_lock_(false),
70dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko          vista_(false) { }
71dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko
72c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko
73c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    // The maximum amount of frames we should unwind from the call stack.
74c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    int stack_unwind_depth() { return stack_unwind_depth_; }
75c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    void set_stack_unwind_depth(int depth) { stack_unwind_depth_ = depth; }
76c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko
77dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    // Whether we should log heap operations (alloc / free).
78dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    bool log_heap() { return log_heap_; }
79dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    void set_log_heap(bool x) { log_heap_ = x; }
80dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko
81dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    // Whether we should log lock (critical section) operations.
82dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    bool log_lock() { return log_lock_; }
83dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    void set_log_lock(bool x) { log_lock_ = x; }
84dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko
85dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    // Whether we are running on Vista.
86dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    bool vista() { return vista_; }
87dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    void set_vista(bool x) { vista_ = x; }
88dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko
89dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko   private:
90dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    int stack_unwind_depth_;
91dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    bool log_heap_;
92dce750b15eb5eb797ac9bbea118333d7d1896831Dmitri Gribenko    bool log_lock_;
93aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    bool vista_;
94aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  };
95aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
96aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  Playground(HANDLE proc, const Options& options)
9796b098674908eaa59a9128f3305cda6fbbdad563Dmitri Gribenko      : proc_(proc),
9896b098674908eaa59a9128f3305cda6fbbdad563Dmitri Gribenko        remote_addr_(NULL),
9996b098674908eaa59a9128f3305cda6fbbdad563Dmitri Gribenko        resolver_("ntdll.dll"),
10096b098674908eaa59a9128f3305cda6fbbdad563Dmitri Gribenko        options_(options) {
10196b098674908eaa59a9128f3305cda6fbbdad563Dmitri Gribenko    // We copy the entire playground into the remote process, and we have
10296b098674908eaa59a9128f3305cda6fbbdad563Dmitri Gribenko    // fields that we expect to be zero.  TODO this could be a lot better.
10396b098674908eaa59a9128f3305cda6fbbdad563Dmitri Gribenko    memset(buf_, 0, sizeof(buf_));
104811c820257746b1799b790b6adc7804f44154011Dmitri Gribenko  }
105aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
106aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  void AllocateInRemote() {
107aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    // Try to get something out of the way and easy to debug.
108aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    static void* kPlaygroundAddr = reinterpret_cast<void*>(0x66660000);
109aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    // Allocate our playground memory in the target process.  This is a big
110abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko    // slab of read/write/execute memory that we use for our code
111abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko    // instrumentation, and the memory for writing out our logging events.
112abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko    remote_addr_ = reinterpret_cast<char*>(
113abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko        VirtualAllocEx(proc_,
114abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko                       kPlaygroundAddr,
115abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko                       kPlaygroundSize,
116abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko                       MEM_COMMIT | MEM_RESERVE,
117abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko                       PAGE_EXECUTE_READWRITE));
11896b098674908eaa59a9128f3305cda6fbbdad563Dmitri Gribenko    if (remote_addr_ == NULL || remote_addr_ != kPlaygroundAddr) {
119c27bc80a98b9558513b50956c930eedc9e461ae0Dmitri Gribenko      NOTREACHED("Falied to allocate playground: 0x%08x", remote_addr_);
120c27bc80a98b9558513b50956c930eedc9e461ae0Dmitri Gribenko    }
121abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko  }
122abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko
123abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko  void CopyToRemote() {
124abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko    WriteProcessMemory(proc_,
125aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                       remote_addr_,
126aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                       buf_,
127aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                       sizeof(buf_),
128aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                       NULL);
129aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  }
130aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
131a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko  void CopyFromRemote() {
132a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    SIZE_T size = 0;
133a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    ReadProcessMemory(proc_,
134a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko                      remote_addr_,
135a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko                      buf_,
136a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko                      sizeof(buf_),
137a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko                      &size);
138a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko  }
139a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko
140a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko  enum EventRecordType {
141a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_LDR              = 0,
142a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_THREADBEGIN      = 1,
143a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_THREADNAME       = 2,
144a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_EXCEPTION        = 3,
145a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_PROCESSEXIT      = 4,
146a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_CREATETHREAD     = 5,
147a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_THREADEXIT       = 6,
148a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_ALLOCHEAP        = 7,
149a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_FREEHEAP         = 8,
150a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_SYSCALL          = 9,
151a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_ENTER_CS         = 10,
152a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_TRYENTER_CS      = 11,
153a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_LEAVE_CS         = 12,
154a444f1856459130bd3a1bb8995331c9e367db04fDmitri Gribenko    EVENT_TYPE_APC              = 13
155aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  };
156aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
157aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kThreadNameBufSize = 64;
158aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kLdrBufSize = 512;  // Looks like internal buffer is 512.
159aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
160aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kCodeBlockSize               = 256;
161aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
162811c820257746b1799b790b6adc7804f44154011Dmitri Gribenko  static const int kOffLdrCode                  = 0 * kCodeBlockSize;
1639c00676f2393335dc60c61faf944d4f8f622fac6Dmitri Gribenko  static const int kOffCreateThreadCode         = 1 * kCodeBlockSize;
164aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffThreadCode               = 2 * kCodeBlockSize;
165811c820257746b1799b790b6adc7804f44154011Dmitri Gribenko  static const int kOffExpCode                  = 3 * kCodeBlockSize;
166aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffExitCode                 = 4 * kCodeBlockSize;
167aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffThreadExitCode           = 5 * kCodeBlockSize;
168aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffAllocHeapCode            = 6 * kCodeBlockSize;
169aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffFreeHeapCode             = 7 * kCodeBlockSize;
170aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffSyscallCode              = 8 * kCodeBlockSize;
171aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffEnterCritSecCode         = 9 * kCodeBlockSize;
172811c820257746b1799b790b6adc7804f44154011Dmitri Gribenko  static const int kOffTryEnterCritSecCode      = 10 * kCodeBlockSize;
173aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffLeaveCritSecCode         = 11 * kCodeBlockSize;
174aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffApcDispCode              = 12 * kCodeBlockSize;
175aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
176aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffLogAreaPtr               = 4096;
177aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kOffLogAreaData              = 4096 + 4;
178aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
179aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  static const int kRecordHeaderSize = 8 + 4 + 4 + 4;
180aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
181aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  // Given the address to the start of a function, patch the function to jump
182aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  // to a given offset into the playground.  This function will try to take
183811c820257746b1799b790b6adc7804f44154011Dmitri Gribenko  // advantage of hotpatch code, if the function is prefixed with 5 0x90 bytes.
184aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  // Returns a std::string of any assembly instructions that must be relocated,
185aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  // as they were overwritten during patching.
186aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko  std::string PatchPreamble(int func_addr, int playground_off) {
187aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    sidestep::MiniDisassembler disas;
188811c820257746b1799b790b6adc7804f44154011Dmitri Gribenko    int stub_addr = reinterpret_cast<int>(remote_addr_ + playground_off);
189aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
190aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    std::string instrs;
191aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
192aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    char buf[15];
193aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    if (ReadProcessMemory(proc_,
194aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                          reinterpret_cast<void*>(func_addr - 5),
195aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                          buf,
196aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                          sizeof(buf),
197aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                          NULL) == 0) {
198aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko      NOTREACHED("ReadProcessMemory(0x%08x) failed: %d",
199aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko                 func_addr - 5, GetLastError());
200aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    }
201aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko
202aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    // TODO(deanm): It seems in more recent updates the compiler is generating
203aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    // complicated sequences for padding / alignment.  For example:
204aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    // 00000000  8DA42400000000    lea esp,[esp+0x0]
205aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    // 00000007  8D4900            lea ecx,[ecx+0x0]
2068bdb58a7835a9a90dd9b9791fccf269cbc1dcef3Dmitri Gribenko    // is used for a 16 byte alignment.  We need a better way of handling this.
2078bdb58a7835a9a90dd9b9791fccf269cbc1dcef3Dmitri Gribenko    if (memcmp(buf, "\x90\x90\x90\x90\x90", 5) == 0 ||
208abd56c816e9164b17bb3e7154a511b0c9896ffdbDmitri Gribenko        memcmp(buf, "\x00\x8D\x64\x24\x00", 5) == 0 ||
209aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko        memcmp(buf, "\x00\x00\x8D\x49\x00", 5) == 0) {
210aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko      unsigned int instr_bytes = 0;
211811c820257746b1799b790b6adc7804f44154011Dmitri Gribenko
212aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko      // We might have a hotpatch no-op of mov edi, edi "\x8b\xff".  It is a
213aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko      // bit of a waste to relocate it, but it makes everything simpler.
214c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko
215c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko      while (instr_bytes < 2) {
216c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko        if (disas.Disassemble(
2172125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko            reinterpret_cast<unsigned char*>(buf + 5 + instr_bytes),
218c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko            &instr_bytes) != sidestep::IT_GENERIC) {
219cd81df2dcff4e13eea6edfbfd52a4458d978d174Douglas Gregor          NOTREACHED("Could not disassemble or relocate instruction.");
2202125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko        }
221cd81df2dcff4e13eea6edfbfd52a4458d978d174Douglas Gregor        // We only read 10 bytes worth of instructions.
2222125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko        CHECK(instr_bytes < 10);
2232125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      }
2242125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko
2252125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      instrs.assign(buf + 5, instr_bytes);
2262125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko
2272125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      // We have a hotpatch prefix of 5 nop bytes.  We can use this for our
2282125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      // long jump, and then overwrite the first 2 bytes to jump back to there.
2292125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      CodeBuffer patch(buf);
2302125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      int off = stub_addr - func_addr;
2312125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      patch.jmp_rel(off);
2322125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      patch.jmp_rel_short(-2 - 5);
2332125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    } else {
2342125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      // We need a full 5 bytes for the jump.
2352125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      unsigned int instr_bytes = 0;
2362125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      while (instr_bytes < 5) {
2372125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko        if (disas.Disassemble(
2382125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko            reinterpret_cast<unsigned char*>(buf + 5 + instr_bytes),
2392125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko            &instr_bytes) != sidestep::IT_GENERIC) {
2402125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko          NOTREACHED("Could not disassemble or relocate instruction.");
2412125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko        }
2422125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko        // We only read 10 bytes worth of instructions.
2432125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko        CHECK(instr_bytes < 10);
2442125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      }
2452125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko
2462125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      instrs.assign(buf + 5, instr_bytes);
2472125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko
2482125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      // Overwrite the first 5 bytes with a relative jump to our stub.
2492125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      CodeBuffer patch(buf + 5);
2502125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      int off = stub_addr - (func_addr + 5);
2512125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      patch.jmp_rel(off);
2522125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    }
2532125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko
2542125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    // Write back the bytes, we are really probably writing more back than we
2552125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    // need to, but it shouldn't really matter.
2562125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    if (WriteProcessMemory(proc_,
2572125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko                           reinterpret_cast<void*>(func_addr - 5),
2582125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko                           buf,
2592125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko                           sizeof(buf),
2602125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko                           NULL) == 0) {
2612125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko      NOTREACHED("WriteProcessMemory(0x%08x) failed: %d",
2622125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko                 func_addr - 5, GetLastError());
2632125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    }
2642125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko
2652125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    return instrs;
2662125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko  }
2672125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko
2682125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko  std::string PatchPreamble(const char* func_name, int playground_off) {
2692125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    return PatchPreamble(
2702125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko        reinterpret_cast<int>(resolver_.Resolve(func_name)), playground_off);
2712125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko  }
2722125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko
2732125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko  // Restore any instructions that needed to be moved to make space for our
2742125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko  // patch and jump back to the original code.
2752125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko  void ResumeOriginalFunction(const char* func_name,
2762125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko                              const std::string& moved_instructions,
2772125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko                              int stub_offset,
2782125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko                              CodeBuffer* cb) {
2792125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    cb->emit_bytes(moved_instructions);
2802125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko    int off = resolver_.Resolve(func_name) +
281cd81df2dcff4e13eea6edfbfd52a4458d978d174Douglas Gregor              moved_instructions.size() -
2822125c9010e259548a8c476fa998a561889555c95Dmitri Gribenko              (remote_addr_ + stub_offset + cb->size() + 5);
283c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    cb->jmp_rel(off);
284c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko  }
285c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko
286c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko  // Makes a call to NtQueryPerformanceCounter, writing the timestamp to the
2871599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko  // buffer pointed to by EDI.  EDI it not incremented.  EAX is not preserved.
2881599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko  void AssembleQueryPerformanceCounter(CodeBuffer* cb) {
2891599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko    // Make a call to NtQueryPerformanceCounter and write the result into
290c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    // the log area.  The buffer we write to should be aligned, but we should
291cd81df2dcff4e13eea6edfbfd52a4458d978d174Douglas Gregor    // garantee that anyway for the logging area for performance.
292f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->push_imm(0);       // PerformanceFrequency
293f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->push(EDI);         // PerformanceCounter
294f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->mov_imm(EAX, reinterpret_cast<int>(
295f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko        resolver_.Resolve("ntdll!NtQueryPerformanceCounter")));
296f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->call(EAX);
297f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko  }
2981599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko
2991599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko  // This is the common log setup routine.  It will allocate a new log entry,
3001599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko  // and write out the common log header to the event entry.  The header is:
301f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko  // is [ 64bit QPC ] [ 32bit cpu id ] [ 32bit thread id ] [ 32bit rec id ]
3021599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko  // EDI will be left pointing to the log entry, with |space| bytes left for
303f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko  // type specific data.  All other registers should not be clobbered.
304f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko  void AssembleHeaderCode(CodeBuffer* cb, EventRecordType rt, int space) {
305f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->push(EAX);
306f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->push(EDX);
307f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->push(ECX);
3081599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko    cb->push(ESI);
309f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko
310f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    int unwind_depth = options_.stack_unwind_depth();
311f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko
312f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    // Load EDI with the number of bytes we want for our log entry, this will
313f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    // be used in the atomic increment to allocate the log entry.
314f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->mov_imm(EDI, kRecordHeaderSize + (unwind_depth * 4) + space);
315f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    // Do the increment and have EDI point to our log entry buffer space.
316f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->mov_imm(EDX, reinterpret_cast<int>(remote_addr_ + kOffLogAreaPtr));
317f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->inc_atomic(EDX, EDI);
3181599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko    // EDI is the buffer offset, make it a pointer to the record entry.
319f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->add_imm(EDI, reinterpret_cast<int>(remote_addr_ + kOffLogAreaData));
320f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko
321f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    AssembleQueryPerformanceCounter(cb);
322f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->add_imm(EDI, 8);
3231599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko
324f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->which_cpu();
325f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->stosd();
326f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko
327f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->which_thread();
328f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    cb->stosd();
329f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko
3301599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko    // Stack unwinding, follow EBP to the maximum number of frames, and make
331f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    // sure that it stays on the stack (between ESP and TEB.StackBase).
332f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko    if (unwind_depth > 0) {
333f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->mov_imm(ECX, unwind_depth);
334f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->fs(); cb->mov(EDX, Operand(0x04));  // get TEB.StackBase
3358d3ba23f2d9e6c87794d059412a0808c9cbacb25Dmitri Gribenko
336aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko      // Start at EBP.
3378376f5934a18b950ac7323d8a38ed231623010faDmitri Gribenko      cb->mov(EAX, EBP);
3388376f5934a18b950ac7323d8a38ed231623010faDmitri Gribenko
339f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      Label unwind_loop, bail;
3401599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko      cb->bind(&unwind_loop);
3411599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko
3421599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko      // Bail if (EAX < ESP) (below the stack)
343f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->cmp(EAX, ESP);
344f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->jcc(below, &bail);
345f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      // Bail if (EAX >= EDX) (above the stack)
346f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->cmp(EAX, EDX);
3471599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko      cb->jcc(above_equal, &bail);
348f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko
349f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      // We have a valid stack pointer, it should point to something like:
350f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      //   [ saved frame pointer ] [ return address ] [ arguments ... ]
351f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->mov(ESI, EAX);
352f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->lodsd();  // Get the new stack pointer to follow in EAX
353f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->movsd();  // Copy the return address to the log area.
354f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko
355f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko      cb->loop(&unwind_loop);
356f50555eedef33fd5a67d369aa0ae8a6f1d201543Dmitri Gribenko
357aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko      cb->bind(&bail);
358aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko      // If we did managed to unwind to the max, fill the rest with 0 (really
359aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko      // we just want to inc EDI to the end, and this is an easy way).
3608d3ba23f2d9e6c87794d059412a0808c9cbacb25Dmitri Gribenko      cb->mov_imm(EAX, 0);  // TODO use an xor
361c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko      cb->rep(); cb->stosd();
362c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    }
363c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko
364c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    // Store the type for this record entry.
365c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    cb->mov_imm(EAX, rt);
366c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    cb->stosd();
367c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko
3681599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko    cb->pop(ESI);
3691599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko    cb->pop(ECX);
3708d3ba23f2d9e6c87794d059412a0808c9cbacb25Dmitri Gribenko    cb->pop(EDX);
3718d3ba23f2d9e6c87794d059412a0808c9cbacb25Dmitri Gribenko    cb->pop(EAX);
3728d3ba23f2d9e6c87794d059412a0808c9cbacb25Dmitri Gribenko  }
3734b41c65feb93eeb6f6d27b49a2045ea1b72de9d1Dmitri Gribenko
3744b41c65feb93eeb6f6d27b49a2045ea1b72de9d1Dmitri Gribenko  void PatchLoader() {
3754b41c65feb93eeb6f6d27b49a2045ea1b72de9d1Dmitri Gribenko    static const EventRecordType kRecordType =  EVENT_TYPE_LDR;
3764b41c65feb93eeb6f6d27b49a2045ea1b72de9d1Dmitri Gribenko    static const char* kFuncName = "ntdll!DebugPrint";
3771599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko    static const int kStubOffset = kOffLdrCode;
3781599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko
3791599eac40a3b28de0824013dc2fb90551dfa01b0Dmitri Gribenko    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
380c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko
381c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    // Set ShowSnaps to one to get the print routines to be called.
382c41ace950dcf2254c9aa48e73647b89c35109f80Dmitri Gribenko    char enabled = 1;
3838d3ba23f2d9e6c87794d059412a0808c9cbacb25Dmitri Gribenko    WriteProcessMemory(
3848d3ba23f2d9e6c87794d059412a0808c9cbacb25Dmitri Gribenko        proc_, resolver_.Resolve("ntdll!ShowSnaps"), &enabled, 1, NULL);
3853e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
3863e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    CodeBuffer cb(buf_ + kStubOffset);
3873e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
3883e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.pop(EDX);  // return address
3893e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.pop(EAX);  // First param in eax
39061c4d28e36cd3f1be392cb77f07436d1fa6b0f9fDouglas Gregor    cb.push(ESI);
3913e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.push(EDI);
3923e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.push(EDX);
3933e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
3943e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.mov(ESI, EAX);  // ESI points at the string structure.
3953e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
3963e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // We used to do variable length based on the length supplied in the str
3973e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // structure, but it's easier (and sloppier) to just copy a fixed amount.
3983e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    AssembleHeaderCode(&cb, kRecordType, kLdrBufSize);
3993e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4003e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.lodsd();        // Load the character count
4013e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.lodsd();        // Load the char*
4023e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.mov(ESI, EAX);
4033e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.mov_imm(ECX, kLdrBufSize / 4);  // load the char count as the rep count
4043e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.rep(); cb.movsb();  // Copy the string to the logging buffer
40561c4d28e36cd3f1be392cb77f07436d1fa6b0f9fDouglas Gregor
4069e9c454b12671a624f666fc6fbf132fdf183effcEli Friedman    // Return
4076952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    cb.pop(EDX);
4086952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    cb.pop(EDI);
4096952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    cb.pop(ESI);
4109e9c454b12671a624f666fc6fbf132fdf183effcEli Friedman    cb.pop(ECX);  // don't care
4119e9c454b12671a624f666fc6fbf132fdf183effcEli Friedman    cb.pop(ECX);  // don't care
4129e9c454b12671a624f666fc6fbf132fdf183effcEli Friedman    cb.jmp(EDX);
4139e9c454b12671a624f666fc6fbf132fdf183effcEli Friedman  }
4146952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4156952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor  void PatchCreateThread() {
4163e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    static const EventRecordType kRecordType =  EVENT_TYPE_CREATETHREAD;
4173e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    static const char* kFuncName =
4183e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor      options_.vista() ? "ntdll!NtCreateThreadEx" : "ntdll!NtCreateThread";
4193e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    static const int kStubOffset = kOffCreateThreadCode;
4203e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4213e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
4223e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4233e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    CodeBuffer cb(buf_ + kStubOffset);
4243e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4253e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.push(EDI);
4263e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.push(ESI);
4274ba2a17694148e16eaa8d3917f657ffcd3667be4Jay Foad
4283e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    AssembleHeaderCode(&cb, kRecordType, 8);
4293e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4303e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.mov(EAX, Operand(ESP, 0x18 + 8));
4313e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4323e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // Super ugly hack.  To coorrelate between creating a thread and the new
4333e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // thread running, we stash something to identify the creating event when
4343e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // we log the created event.  We just use a pointer to the event log data
4353e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // since this will be unique and can tie the two events together.  We pass
4363e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // it by writing into the context structure, so it will be passed in ESI.
4373e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.add_imm(EAX, 0xa0);
4383e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.push(EDI);
4395f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    cb.mov(EDI, EAX);
4403e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.pop(EAX);
4413e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.push(EAX);
4423e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.stosd();
4433e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4443e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // Get and save CONTEXT.Eip
4453e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.mov(ESI, EDI);
4463e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.add_imm(ESI, 20);
447344577e6b58f42d18dc8118c8903b49a85dc005eAbramo Bagnara    cb.pop(EDI);
448344577e6b58f42d18dc8118c8903b49a85dc005eAbramo Bagnara    cb.mov(EAX, EDI);
449344577e6b58f42d18dc8118c8903b49a85dc005eAbramo Bagnara    cb.stosd();  // Record the event identifier to tie together the events.
4503e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.movsd();  // write Eip to the log event
4513e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4523e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.pop(ESI);
4536952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    cb.pop(EDI);
4546952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4556952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
4566952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor  }
4576952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4585f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  void PatchThreadBegin() {
4595f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    static const EventRecordType kRecordType =  EVENT_TYPE_THREADBEGIN;
4606952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    static const char* kFuncName = "ntdll!CsrNewThread";
4616952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    static const int kStubOffset = kOffThreadCode;
4626952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4636952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
4646952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4656952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    CodeBuffer cb(buf_ + kStubOffset);
4666952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
467ff676cb48fe8bf7be2feaa251dc7c5fb15af4730Abramo Bagnara    cb.push(EDI);
468ff676cb48fe8bf7be2feaa251dc7c5fb15af4730Abramo Bagnara
4696952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    AssembleHeaderCode(&cb, kRecordType, 8);
4706952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4716952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    cb.mov(EAX, ESI);  // We stashed the creator's eventid in the context ESI.
4726952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    cb.stosd();
4736952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4746952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    // TODO(deanm): The pointer is going to point into the CRT or something,
4756952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    // should we dig deeper to get more information about the real entry?
4766952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    cb.mov(EAX, Operand(EBP, 0x8));
4776952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    cb.stosd();
478ff676cb48fe8bf7be2feaa251dc7c5fb15af4730Abramo Bagnara    cb.pop(EDI);
479ff676cb48fe8bf7be2feaa251dc7c5fb15af4730Abramo Bagnara
4806952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
4816952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor  }
4826952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4836952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor  void PatchThreadBeginVista() {
4846952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    static const EventRecordType kRecordType =  EVENT_TYPE_THREADBEGIN;
4856952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    static const char* kFuncName = "ntdll!_RtlUserThreadStart";
4866952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    static const int kStubOffset = kOffThreadCode;
4876952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor
4886952f1e4256c5b43aee5e98cea4e9b663bd1d413Douglas Gregor    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
4893e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4903e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    CodeBuffer cb(buf_ + kStubOffset);
4913e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4923e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.push(EDI);
4933e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
4943e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    AssembleHeaderCode(&cb, kRecordType, 8);
4953e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
49661c4d28e36cd3f1be392cb77f07436d1fa6b0f9fDouglas Gregor    cb.mov(EAX, ESI);  // We stashed the creator's eventid in the context ESI.
49761c4d28e36cd3f1be392cb77f07436d1fa6b0f9fDouglas Gregor    cb.stosd();
49861c4d28e36cd3f1be392cb77f07436d1fa6b0f9fDouglas Gregor
4993e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // TODO(deanm): The pointer is going to point into the CRT or something,
5003e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    // should we dig deeper to get more information about the real entry?
5013e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    //cb.mov(EAX, Operand(EBP, 0x8));
5023e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.mov_imm(EAX, 0);
5033e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.stosd();
5043e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    cb.pop(EDI);
5053e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
5063e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
5073e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor  }
5083e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor
5093e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor  // Intercept exception dispatching so we can catch when threads set a thread
5103e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor  // name (which is an exception with a special code).  TODO it could be
5113e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor  // useful to log all exceptions.
5123e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor  void PatchSetThreadName() {
5133e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    static const EventRecordType kRecordType =  EVENT_TYPE_THREADNAME;
5143e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    static const char* kFuncName = "ntdll!RtlDispatchException";
5153e1274f2b99cb99c03cc8e2c6517c37d330b597aDouglas Gregor    static const int kStubOffset = kOffExpCode;
516071cc7deffad608165b1ddd5263e8bf181861520Charles Davis
517ee79a4c30e5d1c5285551c9a25b8ec6d45d46aa7John McCall    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
518ee79a4c30e5d1c5285551c9a25b8ec6d45d46aa7John McCall
51920cf717034ba1f20fc47c025ecb72ed9b631ad13Charles Davis    CodeBuffer cb(buf_ + kStubOffset);
520ee79a4c30e5d1c5285551c9a25b8ec6d45d46aa7John McCall
521ee79a4c30e5d1c5285551c9a25b8ec6d45d46aa7John McCall    cb.pop(EDX);  // return address
522ee79a4c30e5d1c5285551c9a25b8ec6d45d46aa7John McCall    cb.pop(EAX);  // ExceptionRecord
523071cc7deffad608165b1ddd5263e8bf181861520Charles Davis    cb.push(EAX);
52420cf717034ba1f20fc47c025ecb72ed9b631ad13Charles Davis    cb.push(EDX);
52520cf717034ba1f20fc47c025ecb72ed9b631ad13Charles Davis
52620cf717034ba1f20fc47c025ecb72ed9b631ad13Charles Davis    cb.push(ESI);
5277530c034c0c71a64c5a9173206d9742ae847af8bDavid Blaikie
528071cc7deffad608165b1ddd5263e8bf181861520Charles Davis    cb.mov(ESI, EAX);
529071cc7deffad608165b1ddd5263e8bf181861520Charles Davis    cb.lodsd();
530bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
531207f4d8543529221932af82836016a2ef066c917Peter Collingbourne    Label bail;
532207f4d8543529221932af82836016a2ef066c917Peter Collingbourne    // exception code
533207f4d8543529221932af82836016a2ef066c917Peter Collingbourne    cb.cmp_imm(EAX, 0x406D1388);
534207f4d8543529221932af82836016a2ef066c917Peter Collingbourne    cb.jcc(not_equal, &bail);
535207f4d8543529221932af82836016a2ef066c917Peter Collingbourne
536207f4d8543529221932af82836016a2ef066c917Peter Collingbourne    cb.push(EDI);
537207f4d8543529221932af82836016a2ef066c917Peter Collingbourne
5384dc34ebf2a0716bf77ba110dab6777a3fc4397ddPeter Collingbourne    AssembleHeaderCode(&cb, kRecordType, kThreadNameBufSize);
5394dc34ebf2a0716bf77ba110dab6777a3fc4397ddPeter Collingbourne
5404dc34ebf2a0716bf77ba110dab6777a3fc4397ddPeter Collingbourne    // Fetch the second parameter.
5414dc34ebf2a0716bf77ba110dab6777a3fc4397ddPeter Collingbourne    for (int i = 0; i < 6; ++i) {
542207f4d8543529221932af82836016a2ef066c917Peter Collingbourne      cb.lodsd();
543bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    }
544207f4d8543529221932af82836016a2ef066c917Peter Collingbourne
545bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    // TODO This is sloppy and we could run into unmapped memory...
546207f4d8543529221932af82836016a2ef066c917Peter Collingbourne    cb.mov(ESI, EAX);
547207f4d8543529221932af82836016a2ef066c917Peter Collingbourne    cb.mov_imm(ECX, kThreadNameBufSize / 4);
548207f4d8543529221932af82836016a2ef066c917Peter Collingbourne    cb.rep(); cb.movsd();
5493e3cd93b2fd9644e970c389e715c13883faf68b6Douglas Gregor
550bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    cb.pop(EDI);
551e91593ef084479340582b2ba177b44be50a717b7Daniel Dunbar
5521b63e4f732dbc73d90abf886b4d21f8e3a165f6dChris Lattner    cb.bind(&bail);
553bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    cb.pop(ESI);
554bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
555bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
556bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  }
557bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
558bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
559bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  void PatchThreadExit() {
560bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    static const EventRecordType kRecordType =  EVENT_TYPE_THREADEXIT;
561c5613b26a24a33d7450e3d0bf315c6ccc920ce7bMeador Inge    static const char* kFuncName = "ntdll!LdrShutdownThread";
562a6ea10e22b600d92e084f6b11b9b9a92d0eb2412Douglas Gregor    static const int kStubOffset = kOffThreadExitCode;
563e97179c675b341927807c718be215c8d1aab8acbDouglas Gregor
564bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
565e2d4f4ed44a32f179c6d48cd1dba8346ab2129d9Rafael Espindola    CodeBuffer cb(buf_ + kStubOffset);
566e2d4f4ed44a32f179c6d48cd1dba8346ab2129d9Rafael Espindola
567e2d4f4ed44a32f179c6d48cd1dba8346ab2129d9Rafael Espindola    cb.push(EDI);
568e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor    AssembleHeaderCode(&cb, kRecordType, 0);
569e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor    cb.pop(EDI);
570bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
57130c42404202d2e2512e51efc6066bd614cfdb5a4Douglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
572bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  }
573bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
574bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  void PatchAllocateHeap() {
57530c42404202d2e2512e51efc6066bd614cfdb5a4Douglas Gregor    static const EventRecordType kRecordType =  EVENT_TYPE_ALLOCHEAP;
576aa0cd85838f2a024e589ea4e8c2094130065af21Dmitri Gribenko    static const char* kFuncName = "ntdll!RtlAllocateHeap";
577bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    static const int kStubOffset = kOffAllocHeapCode;
578bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
579bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
5801eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    CodeBuffer cb(buf_ + kStubOffset);
581e91593ef084479340582b2ba177b44be50a717b7Daniel Dunbar
582bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    cb.push(EDI);
583bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    cb.push(ESI);
584bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
585bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    AssembleHeaderCode(&cb, kRecordType, 12);
586bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
587e91593ef084479340582b2ba177b44be50a717b7Daniel Dunbar    cb.mov(ESI, ESP);
588e91593ef084479340582b2ba177b44be50a717b7Daniel Dunbar    cb.add_imm(ESI, 12);  // Skip over our saved and the return address
5895f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    cb.movsd(); cb.movsd(); cb.movsd();  // Copy the 3 parameters
5903478eb6872d836600caf45b0f81c2065d685d6e0Ted Kremenek
5913478eb6872d836600caf45b0f81c2065d685d6e0Ted Kremenek    cb.pop(ESI);
5923478eb6872d836600caf45b0f81c2065d685d6e0Ted Kremenek    cb.pop(EDI);
5937d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor
59463fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
59563fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor  }
59663fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor
5970054531488928a424666ac11fcdc6bcc5112de52Douglas Gregor  void PatchFreeHeap() {
598dcfcfbec478f7ed96cd8d92f30c29bd4e30d5b9cTed Kremenek    static const EventRecordType kRecordType =  EVENT_TYPE_FREEHEAP;
59963fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor    static const char* kFuncName = "ntdll!RtlFreeHeap";
60063fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor    static const int kStubOffset = kOffFreeHeapCode;
60163fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor
60263fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
60363fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor    CodeBuffer cb(buf_ + kStubOffset);
60463fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor
60563fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor    cb.push(EDI);
60663fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor    cb.push(ESI);
607dcfcfbec478f7ed96cd8d92f30c29bd4e30d5b9cTed Kremenek
608dcfcfbec478f7ed96cd8d92f30c29bd4e30d5b9cTed Kremenek    AssembleHeaderCode(&cb, kRecordType, 12);
609dcfcfbec478f7ed96cd8d92f30c29bd4e30d5b9cTed Kremenek
610dcfcfbec478f7ed96cd8d92f30c29bd4e30d5b9cTed Kremenek    cb.mov(ESI, ESP);
611dcfcfbec478f7ed96cd8d92f30c29bd4e30d5b9cTed Kremenek    cb.add_imm(ESI, 12);  // Skip over our saved and the return address
612dcfcfbec478f7ed96cd8d92f30c29bd4e30d5b9cTed Kremenek    cb.movsd(); cb.movsd(); cb.movsd();  // Copy the 3 parameters
6136320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor
6146320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.pop(ESI);
6156320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.pop(EDI);
6166320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor
6176320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
6186320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor  }
619ab452ba8323d1985e08bade2bced588cddf2cc28Douglas Gregor
6200054531488928a424666ac11fcdc6bcc5112de52Douglas Gregor  // Don't even bother going back to the original code, just implement our
6210054531488928a424666ac11fcdc6bcc5112de52Douglas Gregor  // own KiFastSystemCall.  The original looks like:
6220054531488928a424666ac11fcdc6bcc5112de52Douglas Gregor  //   .text:7C90EB8B                 mov     edx, esp
6230054531488928a424666ac11fcdc6bcc5112de52Douglas Gregor  //   .text:7C90EB8D                 sysenter
6241eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  //   .text:7C90EB8F                 nop
6256f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith  //   .text:7C90EB90                 nop
6262cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  //   .text:7C90EB91                 nop
6272cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  //   .text:7C90EB92                 nop
6282cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  //   .text:7C90EB93                 nop
6295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  void PatchSyscall() {
630cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth    static const EventRecordType kRecordType =  EVENT_TYPE_SYSCALL;
631cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth    static const char* kFuncName = "ntdll!KiFastSystemCall";
6327c80bd64032e610c0dbd74fc0ef6ea334447f2fdSebastian Redl    static const int kStubOffset = kOffSyscallCode;
633dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor
6341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
635dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor
636dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor    {
637dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor      CodeBuffer cb(buf_ + kStubOffset);
638dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor
639c2ee10d79f70036af652a395ac1f8273f3d04e12Douglas Gregor      Label skip;
6405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
6415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // Skip 0xa5 which is QueryPerformanceCounter, to make sure we don't log
642dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor      // our own logging's QPC.  Disabled for now, using ret addr check...
6435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // cb.cmp_imm(EAX, 0xa5);
6445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // cb.jcc(equal, &skip);
645dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor
646dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor      // Check if the return address is from 0x6666 (our code region).
647dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor      // 66817C24066666    cmp word [esp+0x6],0x6666
648dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor      cb.emit(0x66); cb.emit(0x81); cb.emit(0x7C);
649cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.emit(0x24); cb.emit(0x06); cb.emit(0x66); cb.emit(0x66);
650cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.jcc(equal, &skip);
651dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor
652dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor      // This is all a bit shit.  Originally I thought I could store some state
653dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor      // on the stack above ESP, however, it seems that when APCs, etc are
654dbe833da54e1b6192991b64fc453cd50b5ee7909Douglas Gregor      // queued, they will use the stack above ESP.  Well, not above ESP, above
6551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump      // what was passed in as EDX into the systemcall, not matter if ESP was
656cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      // different than this :(.  So we need to store our state in the event
657cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      // log record, and then we stick a pointer to that over a ret addr...
6584923aa25eb39d64106a5817c02d560a3aecf8b2cDouglas Gregor
659cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      // Our stack starts like:
660cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      //  [ ret addr ] [ ret addr 2 ] [ arguments ]
661cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      // We will update it to look like
662cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      //  [ ret stub addr ] [ event entry ptr ] [ arguments ]
663cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth
664cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.push(EDI);  // save EDI since we're using it
6654e4d08403ca5cfd4d558fa2936215d3a4e5a528dDavid Blaikie      AssembleHeaderCode(&cb, kRecordType, 16 + 16 + 8);
666cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.mov(EDX, EAX);  // Save EAX...
667cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.stosd();  // eax is the syscall number
668cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.pop(EAX);
669cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.stosd();  // store the saved EDI
670cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.pop(EAX);
671cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.stosd();  // store the real return address
6724e4d08403ca5cfd4d558fa2936215d3a4e5a528dDavid Blaikie      cb.pop(EAX);
673cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.stosd();  // store the real (secondary) return address;
674cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth
675cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.push(ESI);
676cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.mov(ESI, ESP);
677cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.lodsd();
678cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.movsd();  // argument 1
679cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.movsd();  // argument 2
6802cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor      cb.movsd();  // argument 3
681cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.pop(ESI);
6822cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
6832cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor      cb.push(EDI);  // store our event ptr over the secondary ret addr.
684cd92a65edc7cbbbb7e3aee8d31008594de90fa51Chandler Carruth      cb.push_imm(reinterpret_cast<int>(remote_addr_ + kOffSyscallCode + 200));
68563fe86bee66fc145942c56b2cc564ea0b9b9ea12Douglas Gregor      cb.mov(EAX, EDX);  // restore EAX
6865f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
6875f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.bind(&skip);
688772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      cb.mov(EDX, ESP);
689772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      cb.sysenter();
690772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor
691772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      if (cb.size() > 200) {
692772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor        NOTREACHED("code too big: %d", cb.size());
693772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      }
694772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor    }
695772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor
696772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor    {
697772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      CodeBuffer cb(buf_ + kStubOffset + 200);
698772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor
699772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      // TODO share the QPC code, this is a copy and paste...
700772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor
701772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      cb.pop(EDI);  // get the log area
702772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor
703772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      cb.stosd();   // Log the system call return value.
704772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor
705772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      // QPC will clobber EAX, and it's very important to save it since it
706772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      // is the return value from the system call.  TODO validate if there is
707772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      // anything else we need to save...
708772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      cb.push(EAX);
709772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      AssembleQueryPerformanceCounter(&cb);
710772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      cb.pop(EAX);
711772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor
712772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      // We need to:
713772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      //  - Restore the original "seconary" return address
714772eeaefef2c883aabe35caf4543e7e32d290183Douglas Gregor      //  - Restore the original value of the EDI register
7155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      //  - Jump control flow to the original return address
716e27ec8ad56dbf1efb2de004b90fbbb86f740e3f1John McCall      // All 3 of these values are stored in the log record...
7176b304a0254a13f42390b865ff5ba668a49cc58aeJohn McCall      // [ syscall num ] [ saved edi ] [ real rets ] [ args ] [ retval ] [ ts ]
718e27ec8ad56dbf1efb2de004b90fbbb86f740e3f1John McCall      //                   currently edi points here     ----^
7196b304a0254a13f42390b865ff5ba668a49cc58aeJohn McCall
7205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.push(Operand(EDI, -4 - 16));   // push the real 2nd ret
7215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.push(Operand(EDI, -8 - 16));   // push the real ret
722bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor      cb.push(Operand(EDI, -12 - 16));  // push the saved EDI
723bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
724bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor      cb.pop(EDI);  // restore EDI that was saved in the record
7255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.ret();     // jmp back to the real ret ...
7261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
727bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor      if (cb.size() > 56) {
728bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor        NOTREACHED("ug");
729bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor      }
730bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    }
731bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  }
7325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
7335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Patch lock (criticial section) holding.
7341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  void PatchEnterCriticalSection() {
7355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    static const EventRecordType kRecordType =  EVENT_TYPE_ENTER_CS;
7365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    static const char* kFuncName = "ntdll!RtlEnterCriticalSection";
7375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    static const int kStubOffset = kOffEnterCritSecCode;
73815b91764d08e886391c865c4a444d7b51141c284Eli Friedman
7395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
7405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
7415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // We just want to capture the return address and original argument, so
7425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // we know when EnterCriticalSection returned, we don't want to know when
7435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // it entered because it could sit waiting.  We want to know when the lock
7445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // actually started being held.  The compiler will sometimes generated code
7455f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // that overwrites arguments, so we'll keep a copy of the argument just in
7465f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // case code like this is ever generated in the future.  TODO is it enough
7475f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // to just assume a LPCRITICAL_SECTION uniquely identifies the lock, or
7481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    // can the same lock have multiple different copies, I would assume not.
7495f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    {
7505f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      CodeBuffer cb(buf_ + kStubOffset);
7515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
7525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // Set up an additional frame so that we capture the return.
7535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // TODO use memory instructions instead of using registers.
7545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.pop(EAX);  // return address
7551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump      cb.pop(EDX);  // first argument (critical section pointer)
7565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
7575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.push(EDX);
7585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.push(EAX);
7595f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.push(EDX);
76064c438a4be2a871fa43c78264663ba1e9788b94dArgyrios Kyrtzidis      cb.push_imm(
7612df9ced9fd1e8c7d7b38443db07e0e811de22571Chris Lattner          reinterpret_cast<int>(remote_addr_ + kStubOffset + 40));
7622df9ced9fd1e8c7d7b38443db07e0e811de22571Chris Lattner
7632df9ced9fd1e8c7d7b38443db07e0e811de22571Chris Lattner      ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
7642df9ced9fd1e8c7d7b38443db07e0e811de22571Chris Lattner      CHECK(cb.size() < 40);
7653f59c975aa5d047f7edd1b900b5e885c38af0ef7Chris Lattner    }
766d3d77cd138f8e830f6547b6f83fcd5721ccf5f5dEli Friedman
7673f59c975aa5d047f7edd1b900b5e885c38af0ef7Chris Lattner    {
7683f59c975aa5d047f7edd1b900b5e885c38af0ef7Chris Lattner      CodeBuffer cb(buf_ + kStubOffset + 40);
7693f59c975aa5d047f7edd1b900b5e885c38af0ef7Chris Lattner
7703f59c975aa5d047f7edd1b900b5e885c38af0ef7Chris Lattner      cb.push(ESI);
7713a2503227c3db04a3619735127483263c1075ef7Chris Lattner      cb.mov(ESI, ESP);
77264c438a4be2a871fa43c78264663ba1e9788b94dArgyrios Kyrtzidis      cb.push(EAX);
773392da48160bd92ceb486792780467cbfdb2d0e8cJames Molloy      cb.push(EDI);
774392da48160bd92ceb486792780467cbfdb2d0e8cJames Molloy
775f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      AssembleHeaderCode(&cb, kRecordType, 4);
776f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith
777f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      cb.lodsd();  // Skip over our saved ESI
778f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      cb.lodsd();  // Skip over the return address
779f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      cb.movsd();  // Write the CRITICAL_SECTION* to the event record.
780f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith
781f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      cb.pop(EDI);
782f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      cb.pop(EAX);
783f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      cb.pop(ESI);
784f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith
785898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor      cb.ret(0x04);
786898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor    }
787898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor  }
788898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor
789898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor  void PatchTryEnterCriticalSection() {
790898574e7496ba8fd76290079d3a9d06954992734Douglas Gregor    static const EventRecordType kRecordType =  EVENT_TYPE_TRYENTER_CS;
7918e9bebdea69c590dedfbf27374114cb76fe12fbdDouglas Gregor    static const char* kFuncName = "ntdll!RtlTryEnterCriticalSection";
7922a984cad5ac3fdceeff2bd99daa7b90979313475John McCall    static const int kStubOffset = kOffTryEnterCritSecCode;
7932a984cad5ac3fdceeff2bd99daa7b90979313475John McCall
7942a984cad5ac3fdceeff2bd99daa7b90979313475John McCall    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
795864c041e118155c2b1ce0ba36942a3da5a4a055eJohn McCall
796864c041e118155c2b1ce0ba36942a3da5a4a055eJohn McCall    {
797864c041e118155c2b1ce0ba36942a3da5a4a055eJohn McCall      CodeBuffer cb(buf_ + kStubOffset);
7983c3b7f90a863af43fa63043d396553ecf205351cJohn McCall
7993c3b7f90a863af43fa63043d396553ecf205351cJohn McCall      // Set up an additional frame so that we capture the return.
8003c3b7f90a863af43fa63043d396553ecf205351cJohn McCall      // TODO use memory instructions instead of using registers.
8011de4d4e8cb2e9c88809fea8092bc6e835a5473d2John McCall      cb.pop(EAX);  // return address
8021de4d4e8cb2e9c88809fea8092bc6e835a5473d2John McCall      cb.pop(EDX);  // first argument (critical section pointer)
8031de4d4e8cb2e9c88809fea8092bc6e835a5473d2John McCall
8040ddaeb9b031070ec64afe92d9892875ac44df427John McCall      cb.push(EDX);
8050ddaeb9b031070ec64afe92d9892875ac44df427John McCall      cb.push(EAX);
8060ddaeb9b031070ec64afe92d9892875ac44df427John McCall      cb.push(EDX);
8075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.push_imm(reinterpret_cast<int>(remote_addr_ + kStubOffset + 40));
8085f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
8095f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
8105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      CHECK(cb.size() < 40);
8118e9bebdea69c590dedfbf27374114cb76fe12fbdDouglas Gregor    }
81213dcd00615de5c4279d97bdf63cd5f0a14fd9dccFariborz Jahanian
813de2e22d33afec98324a66a358dfe0951b3c7259aSteve Naroff    {
814de2e22d33afec98324a66a358dfe0951b3c7259aSteve Naroff      CodeBuffer cb(buf_ + kStubOffset + 40);
81513dcd00615de5c4279d97bdf63cd5f0a14fd9dccFariborz Jahanian
816ebcb57a8d298862c65043e88b2429591ab3c58d3Ted Kremenek      cb.push(ESI);
817ebcb57a8d298862c65043e88b2429591ab3c58d3Ted Kremenek      cb.mov(ESI, ESP);
81893a49944e0e68e32bc22d45d44ee136b34beffb3Fariborz Jahanian      cb.push(EDI);
81993a49944e0e68e32bc22d45d44ee136b34beffb3Fariborz Jahanian
820ebcb57a8d298862c65043e88b2429591ab3c58d3Ted Kremenek      cb.push(EAX);
821a526c5c67e5a0473c340903ee542ce570119665fTed Kremenek
8221eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump      AssembleHeaderCode(&cb, kRecordType, 8);
82333e1d64ab5cd5d27f8530ccd056191fe2c9f3f2eFariborz Jahanian
82433e1d64ab5cd5d27f8530ccd056191fe2c9f3f2eFariborz Jahanian      cb.lodsd();  // Skip over our saved ESI
8256e8ed16ffef02b82995a90bdcf10ffff7d63839aSebastian Redl      cb.lodsd();  // Skip over the return address
8266e8ed16ffef02b82995a90bdcf10ffff7d63839aSebastian Redl      cb.movsd();  // Write the CRITICAL_SECTION* to the event record.
8276e8ed16ffef02b82995a90bdcf10ffff7d63839aSebastian Redl
828aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov      cb.pop(EAX);
829aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov      cb.stosd();  // Write the return value to the event record.
830aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov
831fb40e3f10ccef93c4f8fb6bd4fe5a108fa6cd369Meador Inge      cb.pop(EDI);
832fb40e3f10ccef93c4f8fb6bd4fe5a108fa6cd369Meador Inge      cb.pop(ESI);
833fb40e3f10ccef93c4f8fb6bd4fe5a108fa6cd369Meador Inge
8345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      cb.ret(0x04);
8355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    }
836d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie  }
83778a916ec5ff5b66adec3c499e1b9af7b87668309Argyrios Kyrtzidis
83878a916ec5ff5b66adec3c499e1b9af7b87668309Argyrios Kyrtzidis  void PatchLeaveCriticalSection() {
83978a916ec5ff5b66adec3c499e1b9af7b87668309Argyrios Kyrtzidis    static const EventRecordType kRecordType =  EVENT_TYPE_LEAVE_CS;
8406320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    static const char* kFuncName = "ntdll!RtlLeaveCriticalSection";
8416320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    static const int kStubOffset = kOffLeaveCritSecCode;
8426320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor
8436320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
8446320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    CodeBuffer cb(buf_ + kStubOffset);
8456320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor
8466320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    // TODO use memory instructions instead of using registers.
8476320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.pop(EDX);  // return address
8486320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.pop(EAX);  // first argument (critical section pointer)
8496320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.push(EAX);
8506320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.push(EDX);
8516320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor
8526320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.push(EDI);
8536320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    AssembleHeaderCode(&cb, kRecordType, 4);
8546320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.stosd();  // Write the CRITICAL_SECTION* to the event record.
8556320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    cb.pop(EDI);
8566320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor
8576320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
8586320064d0c60fa8683f5623881c9394fd4aa7689Douglas Gregor  }
859251b4ff2578e26959a4c036140ccd61c5e9292f2Douglas Gregor
860663b5a0be7261c29bc4c526a71cffcfa02d4153eDouglas Gregor  // Patch APC dispatching.  This is a bit hacky, since the return to kernel
8617caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor  // mode is done with NtContinue, we have to shim in a stub return address to
862663b5a0be7261c29bc4c526a71cffcfa02d4153eDouglas Gregor  // catch when the callback is finished.  It is probably a bit fragile.
8637caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor  void PatchApcDispatcher() {
8647caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor    static const EventRecordType kRecordType =  EVENT_TYPE_APC;
8657caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor    static const char* kFuncName = "ntdll!KiUserApcDispatcher";
8661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    static const int kStubOffset = kOffApcDispCode;
8677caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor
8687caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
8697caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor
8701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    {
871251b4ff2578e26959a4c036140ccd61c5e9292f2Douglas Gregor      CodeBuffer cb(buf_ + kStubOffset);
8729421adc43891e272156fab640e5d5ee5054b779cArgyrios Kyrtzidis
8739421adc43891e272156fab640e5d5ee5054b779cArgyrios Kyrtzidis      // We don't really need to preserve these since we're the first thing
8747caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor      // executing from the kernel dispatch, but yeah, it is good practice.
8757caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor      cb.push(EDI);
8767caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor      cb.push(EAX);
8777caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor
878251b4ff2578e26959a4c036140ccd61c5e9292f2Douglas Gregor      AssembleHeaderCode(&cb, kRecordType, 4 + 4 + 8);
8799421adc43891e272156fab640e5d5ee5054b779cArgyrios Kyrtzidis
8807caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor      cb.mov_imm(EAX, reinterpret_cast<int>(remote_addr_ + kStubOffset + 140));
8817caa6825f42a0f7e97d6fc06233133c42b218e46Douglas Gregor      cb.xchg(EAX, Operand(ESP, 8));  // Swap the callback address with ours.
882af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      cb.stosd();  // Store the original callback function address.
883af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet
884af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      // TODO for now we're lazy and depend that ESI will be preserved, and we
885af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      // use it to store the pointer into our log record.  EDI isn't preserved.
8860d95f0d7b81110f77e99e833f766d19be7b7e072Francois Pichet      cb.mov(ESI, EDI);
8870d95f0d7b81110f77e99e833f766d19be7b7e072Francois Pichet
888af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      cb.pop(EAX);
889af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      cb.pop(EDI);
890af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet
891af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
892af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet
893af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      CHECK(cb.size() < 140);
894af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet    }
895af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet    {
896af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      CodeBuffer cb(buf_ + kStubOffset + 140);
8970d95f0d7b81110f77e99e833f766d19be7b7e072Francois Pichet
898af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      // This is our shim, we need to call the original callback function, then
899af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet      // we can catch the return and log when it was completed.
9007ba107a1863ddfa1664555854f0d7bdb3c491c92John McCall      cb.pop(EAX);  // The real return address, safe to use EAX w/ the ABI?
901ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.push(EDI);
9027ba107a1863ddfa1664555854f0d7bdb3c491c92John McCall
903ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.mov(EDI, ESI);
904ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.stosd();  // Store the real return address, we'll need it.
9050d8df780aef1acda5962347a32591efc629b6748Anders Carlsson
9061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump      cb.add_imm(ESI, -4);
9070d8df780aef1acda5962347a32591efc629b6748Anders Carlsson      cb.lodsd();   // Load the real callback address.
9080d8df780aef1acda5962347a32591efc629b6748Anders Carlsson
9090d8df780aef1acda5962347a32591efc629b6748Anders Carlsson      cb.mov(ESI, EDI);
9100d8df780aef1acda5962347a32591efc629b6748Anders Carlsson      cb.pop(EDI);
911ed97649e9574b9d854fa4d6109c9333ae0993554John McCall
912ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.call(EAX);  // Call the original callback address.
913ed97649e9574b9d854fa4d6109c9333ae0993554John McCall
914ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.push(EAX);
915ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.push(EDI);
916ed97649e9574b9d854fa4d6109c9333ae0993554John McCall
917ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.mov(EDI, ESI);
918ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      AssembleQueryPerformanceCounter(&cb);
919ed97649e9574b9d854fa4d6109c9333ae0993554John McCall
920ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.pop(EDI);
921ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.pop(EAX);
922ed97649e9574b9d854fa4d6109c9333ae0993554John McCall
923ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.push(Operand(ESI, -4));  // Push the real return address.
924ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      cb.ret();  // Return back to the APC Dispatcher.
925ed97649e9574b9d854fa4d6109c9333ae0993554John McCall
926ed97649e9574b9d854fa4d6109c9333ae0993554John McCall      CHECK(cb.size() < 50);
927ed97649e9574b9d854fa4d6109c9333ae0993554John McCall    }
928ed97649e9574b9d854fa4d6109c9333ae0993554John McCall  }
929ed97649e9574b9d854fa4d6109c9333ae0993554John McCall
930ed97649e9574b9d854fa4d6109c9333ae0993554John McCall  // We need to hook into process shutdown for two reasons.  Most importantly,
931ed97649e9574b9d854fa4d6109c9333ae0993554John McCall  // we need to copy the playground back from the process before the address
932ed97649e9574b9d854fa4d6109c9333ae0993554John McCall  // space goes away.  We could avoid this with shared memory, however, there
933ed97649e9574b9d854fa4d6109c9333ae0993554John McCall  // is a reason two.  In order to capture symbols for all of the libraries
934ed97649e9574b9d854fa4d6109c9333ae0993554John McCall  // loaded into arbitrary applications, on shutdown we do an instrusive load
9350d8df780aef1acda5962347a32591efc629b6748Anders Carlsson  // of symbols into the traced process.
9360d8df780aef1acda5962347a32591efc629b6748Anders Carlsson  //
937d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson  // ntdll!LdrShutdownProcess
938d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson  //  - NtSetEvent(event, 0);
939d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson  //  - NtWaitForSingleObject(event, FALSE, NULL);
940d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson  //  - jmp back
941d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson  void PatchExit(HANDLE exiting, HANDLE exited) {
9421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    static const EventRecordType kRecordType =  EVENT_TYPE_PROCESSEXIT;
943d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson    static const char* kFuncName = "ntdll!LdrShutdownProcess";
944d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson    static const int kStubOffset = kOffExitCode;
945d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson
946d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson    HANDLE rexiting, rexited;
947d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson    if (!DuplicateHandle(::GetCurrentProcess(),
948d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson                         exiting,
949d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson                         proc_,
950d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson                         &rexiting,
951d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson                         0,
9521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                         FALSE,
953d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson                         DUPLICATE_SAME_ACCESS)) {
954d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson      NOTREACHED("");
955d8b285fee4471f393da8ee30f552ceacdc362afaAnders Carlsson    }
95614d56ef43ff4921c6749f7340212fbb743fdbb9bFariborz Jahanian    if (!DuplicateHandle(::GetCurrentProcess(),
95714d56ef43ff4921c6749f7340212fbb743fdbb9bFariborz Jahanian                         exited,
95814d56ef43ff4921c6749f7340212fbb743fdbb9bFariborz Jahanian                         proc_,
959a6b8b2c09610b8bc4330e948ece8b940c2386406Richard Smith                         &rexited,
96014d56ef43ff4921c6749f7340212fbb743fdbb9bFariborz Jahanian                         0,
96114d56ef43ff4921c6749f7340212fbb743fdbb9bFariborz Jahanian                         FALSE,
962340fa242130c2d8d74c83edca0952e771aebe0e6Fariborz Jahanian                         DUPLICATE_SAME_ACCESS)) {
963340fa242130c2d8d74c83edca0952e771aebe0e6Fariborz Jahanian      NOTREACHED("");
964340fa242130c2d8d74c83edca0952e771aebe0e6Fariborz Jahanian    }
965a6b8b2c09610b8bc4330e948ece8b940c2386406Richard Smith
966a6b8b2c09610b8bc4330e948ece8b940c2386406Richard Smith    std::string moved_instructions = PatchPreamble(kFuncName, kStubOffset);
967340fa242130c2d8d74c83edca0952e771aebe0e6Fariborz Jahanian    CodeBuffer cb(buf_ + kStubOffset);
968340fa242130c2d8d74c83edca0952e771aebe0e6Fariborz Jahanian
9699b3acaa32548d0ce78b9c39a3911397f6738a47cFariborz Jahanian    cb.push(EDI);
9709b3acaa32548d0ce78b9c39a3911397f6738a47cFariborz Jahanian    AssembleHeaderCode(&cb, kRecordType, 0);
9719b3acaa32548d0ce78b9c39a3911397f6738a47cFariborz Jahanian    cb.pop(EDI);
972a6b8b2c09610b8bc4330e948ece8b940c2386406Richard Smith
973a6b8b2c09610b8bc4330e948ece8b940c2386406Richard Smith    // NtSetEvent(exiting, 0);
9749b3acaa32548d0ce78b9c39a3911397f6738a47cFariborz Jahanian    cb.push_imm(0);
9759b3acaa32548d0ce78b9c39a3911397f6738a47cFariborz Jahanian    cb.push_imm(reinterpret_cast<int>(rexiting));
976dd7fddb5b6883326e52b278a9b7e9cefea29aae0Chad Rosier    cb.mov_imm(EAX, reinterpret_cast<int>(
97752bbe7a1133c3cb57e9246f1b96c12940ea3821aFariborz Jahanian        resolver_.Resolve("ntdll!NtSetEvent")));
97852bbe7a1133c3cb57e9246f1b96c12940ea3821aFariborz Jahanian    cb.call(EAX);
979a6b8b2c09610b8bc4330e948ece8b940c2386406Richard Smith
98052bbe7a1133c3cb57e9246f1b96c12940ea3821aFariborz Jahanian    // NtWaitForSingleObject(exited, FALSE, INFINITE);
98152bbe7a1133c3cb57e9246f1b96c12940ea3821aFariborz Jahanian    cb.push_imm(0);
982dd7fddb5b6883326e52b278a9b7e9cefea29aae0Chad Rosier    cb.push_imm(0);
98352bbe7a1133c3cb57e9246f1b96c12940ea3821aFariborz Jahanian    cb.push_imm(reinterpret_cast<int>(rexited));
98452bbe7a1133c3cb57e9246f1b96c12940ea3821aFariborz Jahanian    cb.mov_imm(EAX, reinterpret_cast<int>(
985a6b8b2c09610b8bc4330e948ece8b940c2386406Richard Smith        resolver_.Resolve("ntdll!NtWaitForSingleObject")));
98652bbe7a1133c3cb57e9246f1b96c12940ea3821aFariborz Jahanian    cb.call(EAX);
98752bbe7a1133c3cb57e9246f1b96c12940ea3821aFariborz Jahanian
9887d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    ResumeOriginalFunction(kFuncName, moved_instructions, kStubOffset, &cb);
9897d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor  }
9907d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor
9917d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor
9927d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor  void Patch() {
9937d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    if (options_.vista()) {
9947d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor      // TODO(deanm): Make PatchCreateThread work on Vista.
9957d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor      PatchThreadBeginVista();
9967d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    } else {
9977d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor      PatchCreateThread();
9987d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor      PatchThreadBegin();
9997d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    }
10007d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor
10017d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    PatchThreadExit();
10027d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    PatchSetThreadName();
10037d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    PatchSyscall();
10047d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor
10057d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    PatchApcDispatcher();
10067d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor
10077d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    // The loader logging needs to be improved a bit to really be useful.
1008c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis    //PatchLoader();
1009c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis
1010c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis    // These are interesting, but will collect a ton of data:
1011c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis    if (options_.log_heap()) {
1012c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis      PatchAllocateHeap();
1013c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis      PatchFreeHeap();
1014c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis    }
1015c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis    if (options_.log_lock()) {
1016c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis      PatchEnterCriticalSection();
1017c91e9f439ae85d5f79a6b65672f1d7d1b55ccda0Argyrios Kyrtzidis      PatchTryEnterCriticalSection();
10187d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor      PatchLeaveCriticalSection();
10197d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor    }
10207d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor  }
10217d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor
10227d10b7eb670b821741b4c96f6cf7afbc3bb39abeDouglas Gregor  // Dump the event records from the playground to stdout in a JSON format.
1023e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor  // TODO: Drop RDTSCNormalizer, it was from old code that tried to use the
1024e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor  // rdtsc counters from the CPU, and this required a bunch of normalization
1025e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor  // to account for non-syncronized timestamps across different cores, etc.
1026e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor  void DumpJSON(RDTSCNormalizer* rdn, SymResolver* res) {
1027e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor    int pos = kOffLogAreaPtr;
1028e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor    int i = IntAt(pos);
1029e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor    pos += 4;
1030e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor
1031e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor    std::map<int, const char*> syscalls = CreateSyscallMap();
1032e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor
1033e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor    printf("parseEvents([\n");
1034e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor    for (int end = pos + i; pos < end; ) {
1035e664977aca2a05a77abab5a06dc0fb69e870cfb9Douglas Gregor      printf("{\n");
1036464175bba1318bef7905122e9fda20cff926df78Chris Lattner      __int64 ts = Int64At(pos);
1037464175bba1318bef7905122e9fda20cff926df78Chris Lattner      pos += 8;
1038464175bba1318bef7905122e9fda20cff926df78Chris Lattner      void* cpuid = reinterpret_cast<void*>(IntAt(pos));
1039a7674d8a9a69f3f6fe16e70cf2a3b2b15fb7c43dChris Lattner      pos += 4;
1040b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner      printf("'ms': %f,\n", rdn->MsFromStart(cpuid, ts));
1041b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner
1042b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner      printf("'cpu': 0x%x,\n'thread': 0x%x,\n", cpuid, IntAt(pos));
1043183700f494ec9b6701b6efe82bcb25f4c79ba561John McCall      pos += 4;
1044b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner
1045b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner      if (options_.stack_unwind_depth() > 0) {
1046b219cfc4d75f0a03630b7c4509ef791b7e97b2c8David Blaikie        printf("'stacktrace': [\n");
1047aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov        for (int i = 0; i < options_.stack_unwind_depth(); ++i) {
1048bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor          int retaddr = IntAt(pos + (i * 4));
1049bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor          if (!retaddr)
1050bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor            break;
1051b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner          printf("  [ 0x%x, %s ],\n",
1052b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner                 retaddr,
1053b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner                 res ? JSONString(res->Unresolve(retaddr)).c_str() : "\"\"");
10548b752f10c394b140f9ef89e049cbad1a7676fc25Ken Dyck        }
1055af707ab8fbb9451e8febb8d766f6c043628125c4Chris Lattner        printf("],\n");
1056af707ab8fbb9451e8febb8d766f6c043628125c4Chris Lattner        pos += (options_.stack_unwind_depth() * 4);
10575d484e8cf710207010720589d89602233de61d01Sebastian Redl      }
10585d484e8cf710207010720589d89602233de61d01Sebastian Redl
10594ba2a17694148e16eaa8d3917f657ffcd3667be4Jay Foad
1060bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor      EventRecordType rt = static_cast<EventRecordType>(IntAt(pos));
1061dcdafb6a701aa9d81edcb088915f58933315dc05Eli Friedman      pos += 4;
10624081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall
10634081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall      switch (rt) {
10644081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall        case EVENT_TYPE_LDR:
10654081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall        {
10664081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall          printf("'eventtype': 'EVENT_TYPE_LDR',\n");
10674081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall          std::string str(&buf_[pos], kLdrBufSize);
10684081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall          str = str.substr(0, str.find('\0'));
10694081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall          printf("'ldrinfo': %s,\n", JSONString(str).c_str());
107082d0b0aab9088e977c2a44c4a5a90479c63149fePeter Collingbourne          pos += kLdrBufSize;
10714081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall          break;
10724081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall        }
10734081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall        case EVENT_TYPE_CREATETHREAD:
10744081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall        {
10754081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall          printf("'eventtype': 'EVENT_TYPE_CREATETHREAD',\n"
10764081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall                 "'eventid': 0x%x,\n"
10774081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall                 "'startaddr': 0x%x,\n",
10784081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall                 IntAt(pos), IntAt(pos+4));
107978a7d7d79964119a3f35b262eb154b5cbf1001edFariborz Jahanian          pos += 8;
108078a7d7d79964119a3f35b262eb154b5cbf1001edFariborz Jahanian          break;
108178a7d7d79964119a3f35b262eb154b5cbf1001edFariborz Jahanian        }
108278a7d7d79964119a3f35b262eb154b5cbf1001edFariborz Jahanian        case EVENT_TYPE_THREADBEGIN:
1083dcdafb6a701aa9d81edcb088915f58933315dc05Eli Friedman        {
1084ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          printf("'eventtype': 'EVENT_TYPE_THREADBEGIN',\n"
1085ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 "'parenteventid': 0x%x,\n"
10864081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall                 "'startaddr': 0x%x,\n",
1087ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 IntAt(pos), IntAt(pos+4));
1088ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          pos += 8;
10894081a5c5f1381c4ec77f8ab3866693917e4329c4John McCall          break;
1090af707ab8fbb9451e8febb8d766f6c043628125c4Chris Lattner        }
10916217b80b7a1379b74cced1c076338262c3c980b3Ted Kremenek        case EVENT_TYPE_THREADNAME:
10925d484e8cf710207010720589d89602233de61d01Sebastian Redl        {
10935d484e8cf710207010720589d89602233de61d01Sebastian Redl          std::string str(&buf_[pos], kThreadNameBufSize);
10945d484e8cf710207010720589d89602233de61d01Sebastian Redl          str = str.substr(0, str.find('\0'));
10955d484e8cf710207010720589d89602233de61d01Sebastian Redl          printf("'eventtype': 'EVENT_TYPE_THREADNAME',\n"
10965d484e8cf710207010720589d89602233de61d01Sebastian Redl                 "'threadname': %s,\n",
10975d484e8cf710207010720589d89602233de61d01Sebastian Redl                 JSONString(str).c_str());
10983b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall          pos += kThreadNameBufSize;
10993b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall          break;
1100bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor        }
11013b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall        case EVENT_TYPE_PROCESSEXIT:
11023b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall        {
11033b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall          printf("'eventtype': 'EVENT_TYPE_PROCESSEXIT',\n");
1104bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor          break;
11053b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall        }
11063b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall        case EVENT_TYPE_THREADEXIT:
1107bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor        {
11083b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall          printf("'eventtype': 'EVENT_TYPE_THREADEXIT',\n");
11093b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall          break;
11103b6575108a5b6d8b92ac3a9a7794bf6c3a210907John McCall        }
11116deecb0d46bcfd048e651d2db7c4fb0d6407da96Rafael Espindola        case EVENT_TYPE_ALLOCHEAP:
11129f1210c3280104417a4ad30f0a00825ac8fa718aChad Rosier        {
1113dcdafb6a701aa9d81edcb088915f58933315dc05Eli Friedman          printf("'eventtype': 'EVENT_TYPE_ALLOCHEAP',\n"
1114ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 "'heaphandle': 0x%x,\n"
1115ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 "'heapflags': 0x%x,\n"
1116ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 "'heapsize': %d,\n",
1117ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 IntAt(pos), IntAt(pos+4), IntAt(pos+8));
1118ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          pos += 12;
1119ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          break;
1120ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall        }
1121ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall        case EVENT_TYPE_FREEHEAP:
1122ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall        {
1123ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          printf("'eventtype': 'EVENT_TYPE_FREEHEAP',\n"
1124ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 "'heaphandle': 0x%x,\n"
1125dac54c124e302d6f028ea5723c425b7f66fc7c71Ken Dyck                 "'heapflags': 0x%x,\n"
1126ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 "'heapptr': %d,\n",
1127ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 IntAt(pos), IntAt(pos+4), IntAt(pos+8));
1128ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          pos += 12;
1129ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          break;
1130ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall        }
1131ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall        case EVENT_TYPE_SYSCALL:
1132ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall        {
1133ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          int syscall = IntAt(pos);
1134ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          printf("'eventtype': 'EVENT_TYPE_SYSCALL',\n"
1135ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall                 "'syscall': 0x%x,\n", syscall);
1136ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall          pos += 16;
1137ba4f5d5754c8291690d01ca9581926673d69b24cJohn McCall
113805f62474dd2b0f1cb69adbe0787f2868788aa949Charles Davis          printf("'syscallargs': [\n");
1139af707ab8fbb9451e8febb8d766f6c043628125c4Chris Lattner          for (int i = 0; i < 3; ++i) {
1140dcdafb6a701aa9d81edcb088915f58933315dc05Eli Friedman            printf("  0x%x,\n", IntAt(pos));
1141eb6f5dc86531f794ba7746a2da4d28e37cf5da7eKen Dyck            pos += 4;
1142af707ab8fbb9451e8febb8d766f6c043628125c4Chris Lattner          }
1143b7cfe88e88cb4f46308de89cf3f0c81bfe624128Chris Lattner          printf("],\n");
1144929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall
1145929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall          printf("'retval': 0x%x,\n"
1146929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall                 "'done': %f,\n",
1147929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall                 IntAt(pos), rdn->MsFromStart(0, Int64At(pos+4)));
1148929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall          pos += 12;
1149929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall
1150929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall          if (syscalls.count(syscall) == 1) {
1151929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall            std::string sname = syscalls[syscall];
1152929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall            printf("'syscallname': %s,\n",
1153929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall                   JSONString(sname).c_str());
1154929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall            // Mark system calls that we should consider "waiting" system
1155929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall            // calls, where we are not actually active.
1156929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall            if (sname.find("WaitFor") != std::string::npos ||
1157929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall                sname.find("RemoveIoCompletion") != std::string::npos) {
1158929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall              printf("'waiting': 1,\n");
1159929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall            }
1160929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall          }
1161929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall          break;
1162929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall        }
1163929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall        case EVENT_TYPE_ENTER_CS:
1164929bbfb0b69165b55da3c56abf22aa10e20dadc6John McCall        {
1165ea1471e0e967548c596a71469702f8846dbaf3c0John McCall          printf("'eventtype': 'EVENT_TYPE_ENTER_CS',\n"
1166bee5a79fc95e3003d755031e3d2bb4410a71e1c1Ken Dyck                 "'critical_section': 0x%x,\n", IntAt(pos));
1167ea1471e0e967548c596a71469702f8846dbaf3c0John McCall          pos += 4;
1168eb6f5dc86531f794ba7746a2da4d28e37cf5da7eKen Dyck          break;
1169eb6f5dc86531f794ba7746a2da4d28e37cf5da7eKen Dyck        }
1170ea1471e0e967548c596a71469702f8846dbaf3c0John McCall        case EVENT_TYPE_TRYENTER_CS:
1171ea1471e0e967548c596a71469702f8846dbaf3c0John McCall        {
1172ea1471e0e967548c596a71469702f8846dbaf3c0John McCall          printf("'eventtype': 'EVENT_TYPE_TRYENTER_CS',\n"
1173bee5a79fc95e3003d755031e3d2bb4410a71e1c1Ken Dyck                 "'critical_section': 0x%x,\n"
1174ea1471e0e967548c596a71469702f8846dbaf3c0John McCall                 "'retval': 0x%x,\n",
1175ea1471e0e967548c596a71469702f8846dbaf3c0John McCall                 IntAt(pos), IntAt(pos+4));
1176ea1471e0e967548c596a71469702f8846dbaf3c0John McCall          pos += 8;
1177bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar          break;
1178bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar        }
1179bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar        case EVENT_TYPE_LEAVE_CS:
1180bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar        {
1181bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar          printf("'eventtype': 'EVENT_TYPE_LEAVE_CS',\n"
1182bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar                 "'critical_section': 0x%x,\n", IntAt(pos));
1183bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar          pos += 4;
1184bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar          break;
1185bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar        }
1186bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar        case EVENT_TYPE_APC:
1187bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar        {
1188bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar          int func_addr = IntAt(pos);
11890953e767ff7817f97b3ab20896b229891eeff45bJohn McCall          printf("'eventtype': 'EVENT_TYPE_APC',\n"
11900953e767ff7817f97b3ab20896b229891eeff45bJohn McCall                 "'func_addr': 0x%x,\n"
11910953e767ff7817f97b3ab20896b229891eeff45bJohn McCall                 "'func_addr_name': %s,\n"
11920953e767ff7817f97b3ab20896b229891eeff45bJohn McCall                 "'ret_addr': 0x%x,\n"
1193d2d2a11a91d7ddf468bfb70f66362d24806ed601Chris Lattner                 "'done': %f,\n",
1194bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar                 func_addr,
11955e301007e31e14c8ff647288e1b8bd8dbf8a5fe4Mike Stump                 res ? JSONString(res->Unresolve(func_addr)).c_str() : "\"\"",
11965e301007e31e14c8ff647288e1b8bd8dbf8a5fe4Mike Stump                 IntAt(pos+4), rdn->MsFromStart(0, Int64At(pos+8)));
1197a7674d8a9a69f3f6fe16e70cf2a3b2b15fb7c43dChris Lattner          pos += 16;
119872564e73277e29f6db3305d1f27ba408abb7ed88Douglas Gregor          break;
119972564e73277e29f6db3305d1f27ba408abb7ed88Douglas Gregor        }
120018857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor        default:
120172564e73277e29f6db3305d1f27ba408abb7ed88Douglas Gregor          NOTREACHED("Unknown event type: %d", rt);
120272564e73277e29f6db3305d1f27ba408abb7ed88Douglas Gregor          break;
1203d3d49bb27c7ffd9accc0a6c00e887111c0348845John McCall      }
120472564e73277e29f6db3305d1f27ba408abb7ed88Douglas Gregor      printf("},\n");
12055d2a6303467184b1f159bb6556efc434e50e3c28Chris Lattner    }
12065d2a6303467184b1f159bb6556efc434e50e3c28Chris Lattner    printf("]);");
120718857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor  }
120818857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor
120918857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor  int IntAt(int pos) { return *reinterpret_cast<int*>(&buf_[pos]); }
121018857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor  __int64 Int64At(int pos) { return *reinterpret_cast<__int64*>(&buf_[pos]); }
121118857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor
121272564e73277e29f6db3305d1f27ba408abb7ed88Douglas Gregor
1213fb22d96692c5240fb8d611290dbf7eeed3759c73Steve Naroff private:
121418857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor  // Handle the process we install into or read back from.
121518857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor  HANDLE proc_;
121618857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor  // The address where we will keep our playground in the remote process.
121718857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor  char* remote_addr_;
1218fb22d96692c5240fb8d611290dbf7eeed3759c73Steve Naroff  // Lookup addresses from symbol names for ntdll.dll.
12191d75118af76cae2bfc06389cde410e14bd0a19fcDaniel Dunbar  SymResolver resolver_;
12201eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  Options options_;
122198be4943e8dc4f3905629a7102668960873cf863Chris Lattner  // A local copy of the playground data, we copy it into the remote process.
1222fea966a4103ed9c018d1494b95e9d09b161f5a70Abramo Bagnara  char buf_[kPlaygroundSize];
1223bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar};
1224bc5419a2edc4030d1a623576fe339fbd3eed17a6Daniel Dunbar
1225fea966a4103ed9c018d1494b95e9d09b161f5a70Abramo Bagnara
1226030d8846c7e520330007087e949f621989876e3aChris Lattnerint main(int argc, char** argv) {
1227cd88b4171753dcb2bc0a21d78f1597c796bb8a20Argyrios Kyrtzidis  std::string command_line;
1228030d8846c7e520330007087e949f621989876e3aChris Lattner  bool use_symbols = false;
12295c09a02a5db85e08a432b6eeced9aa656349710dChristopher Lamb  bool attaching = false;
1230213541a68a3e137d11d2cefb612c6cdb410d7e8eNate Begeman  bool launched = false;
1231030d8846c7e520330007087e949f621989876e3aChris Lattner  bool manual_quit = false;
12329fcfe926432f3c3f7e9a61219e55c352fd358e45Chris Lattner
12339fcfe926432f3c3f7e9a61219e55c352fd358e45Chris Lattner  Playground::Options options;
12349fcfe926432f3c3f7e9a61219e55c352fd358e45Chris Lattner
12354bd998bbc228915d2b9cae5b67879de48940d05eEli Friedman  PROCESS_INFORMATION info = {0};
12366fe7c8aa8c7546743ecd0ac0138c2cf5d8155386Nate Begeman
12376fe7c8aa8c7546743ecd0ac0138c2cf5d8155386Nate Begeman  argc--; argv++;
12388eefcd353c1d06a10104f69e5079ebab3183f9a3Dan Gohman
12399fcfe926432f3c3f7e9a61219e55c352fd358e45Chris Lattner  while (argc > 0) {
12409fcfe926432f3c3f7e9a61219e55c352fd358e45Chris Lattner    if (std::string("--symbols") == argv[0]) {
12419fcfe926432f3c3f7e9a61219e55c352fd358e45Chris Lattner      use_symbols = true;
1242f9e9af7df0cea6e997ac04131c7af6ca4384b0ccChad Rosier    } else if (std::string("--vista") == argv[0]) {
1243f9e9af7df0cea6e997ac04131c7af6ca4384b0ccChad Rosier      options.set_vista(true);
1244f9e9af7df0cea6e997ac04131c7af6ca4384b0ccChad Rosier    } else if (std::string("--log-heap") == argv[0]) {
1245f9e9af7df0cea6e997ac04131c7af6ca4384b0ccChad Rosier      options.set_log_heap(true);
1246030d8846c7e520330007087e949f621989876e3aChris Lattner    } else if (std::string("--log-lock") == argv[0]) {
1247030d8846c7e520330007087e949f621989876e3aChris Lattner      options.set_log_lock(true);
12485d2a6303467184b1f159bb6556efc434e50e3c28Chris Lattner    } else if (std::string("--manual-quit") == argv[0]) {
12499e9b6dc3fd413f5341fab54b681420eeb21cd169Chris Lattner      manual_quit = true;
1250a7674d8a9a69f3f6fe16e70cf2a3b2b15fb7c43dChris Lattner    } else if (argc >= 2 && std::string("--unwind") == argv[0]) {
1251b219cfc4d75f0a03630b7c4509ef791b7e97b2c8David Blaikie      options.set_stack_unwind_depth(atoi(argv[1]));
1252d2d2a11a91d7ddf468bfb70f66362d24806ed601Chris Lattner      argc--; argv++;
125318857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor    } else if (argc >= 2 && !launched && std::string("--attach") == argv[0]) {
125418857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor      attaching = true;
125518857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor      info.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, atoi(argv[1]));
125618857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor      launched = true;
125718857644059c45da6776f1a288eec7b4cf3a844aDouglas Gregor      argc--; argv++;
12586f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner    } else if (!launched) {
1259bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor      STARTUPINFOA start_info = {0};
1260bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor      start_info.cb = sizeof(start_info);
12616f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner
1262692233e90a99c3a81dd04879d36eb9688f137c44Chris Lattner      if (!CreateProcessA(NULL,
1263692233e90a99c3a81dd04879d36eb9688f137c44Chris Lattner                          argv[0],
1264692233e90a99c3a81dd04879d36eb9688f137c44Chris Lattner                          NULL,
12656f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner                          NULL,
1266bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor                          FALSE,
1267bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor                          CREATE_SUSPENDED,
12686f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner                          NULL,
12693f59c975aa5d047f7edd1b900b5e885c38af0ef7Chris Lattner                          NULL,
12703f59c975aa5d047f7edd1b900b5e885c38af0ef7Chris Lattner                          &start_info,
1271bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor                          &info)) {
1272bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor        NOTREACHED("Failed to launch \"%s\": %d\n", argv[0], GetLastError());
127364c438a4be2a871fa43c78264663ba1e9788b94dArgyrios Kyrtzidis        return 1;
1274f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      }
1275bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor      launched = true;
1276bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    } else {
1277f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith      NOTREACHED("error parsing command line.");
1278f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith    }
1279bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    argc--; argv++;
1280bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  }
1281f5c209d23b20ada4a9b6235db50317239cbf6ae1Alisdair Meredith
1282692233e90a99c3a81dd04879d36eb9688f137c44Chris Lattner  if (!launched) {
12836f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner    printf("usage: traceline.exe \"app.exe my arguments\"\n"
1284bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor           "  --attach 123: buggy support for attaching to a process\n"
1285bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor           "  --unwind 16: unwind the stack to the specified max depth\n"
12866f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner           "  --symbols: use symbols for stacktraces\n"
1287692233e90a99c3a81dd04879d36eb9688f137c44Chris Lattner           "  --log-heap: log heap operations (alloc / free).\n"
12886f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner           "  --log-lock: log lock (critical section) operations.\n");
1289bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    return 1;
1290bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  }
12916f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner
1292692233e90a99c3a81dd04879d36eb9688f137c44Chris Lattner
12936f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner  HANDLE exiting = CreateEvent(NULL, FALSE, FALSE, NULL);
1294bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  HANDLE exited = CreateEvent(NULL, FALSE, FALSE, NULL);
1295bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
12966f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner  // The playground object is big (32MB), dynamically alloc.
1297692233e90a99c3a81dd04879d36eb9688f137c44Chris Lattner  Playground* pg = new Playground(info.hProcess, options);
12986f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner
1299bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  pg->AllocateInRemote();
1300bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  pg->Patch();
13016f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner  pg->PatchExit(exiting, exited);
1302ec16cb9b5a481d62a73ad47fa59034ced4d62022Chris Lattner  pg->CopyToRemote();
1303ec16cb9b5a481d62a73ad47fa59034ced4d62022Chris Lattner
1304ec16cb9b5a481d62a73ad47fa59034ced4d62022Chris Lattner  RDTSCNormalizer rdn;
1305ec16cb9b5a481d62a73ad47fa59034ced4d62022Chris Lattner  rdn.Start();
1306ec16cb9b5a481d62a73ad47fa59034ced4d62022Chris Lattner
1307aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov  if (!attaching)
1308aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov    ResumeThread(info.hThread);
1309aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov
1310aa4a99b4a62615db243f7a5c433169f2fc704420Anton Korobeynikov  // Wait until we have been notified that it's exiting.
13116f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner  if (manual_quit) {
1312bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    fprintf(stderr, "Press enter when you want stop tracing and collect.\n");
1313bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    fflush(stderr);
13146f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner    getchar();
13156f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner  } else {
1316bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    HANDLE whs[] = {exiting, info.hProcess};
1317bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    if (WaitForMultipleObjects(2, whs, FALSE, INFINITE) != WAIT_OBJECT_0) {
13186f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner      NOTREACHED("Failed to correctly capture process shutdown.");
13196f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner    }
1320bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  }
1321bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
13226f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner  pg->CopyFromRemote();
13236e8ed16ffef02b82995a90bdcf10ffff7d63839aSebastian Redl
1324bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  if (use_symbols) {
1325bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor    // Break in and get the symbols...
13261590d9c0fec4c710c2962e4bb71f76979b5163d3Sebastian Redl    SymResolver res(NULL, info.hProcess);
1327e04f5fc25cf49e8a5b836459d836c20dc3229a95Fariborz Jahanian    pg->DumpJSON(&rdn, &res);
1328e04f5fc25cf49e8a5b836459d836c20dc3229a95Fariborz Jahanian  } else {
1329e04f5fc25cf49e8a5b836459d836c20dc3229a95Fariborz Jahanian    pg->DumpJSON(&rdn, NULL);
1330bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  }
1331bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
1332e04f5fc25cf49e8a5b836459d836c20dc3229a95Fariborz Jahanian  // Notify that it can exit now, we are done.
1333a7674d8a9a69f3f6fe16e70cf2a3b2b15fb7c43dChris Lattner  SetEvent(exited);
1334bfef6d7c67831a135d6ab79931f010f750a730adChris Lattner
1335d1b3c2dd5bc1f3103bee6137957aa7c5f8f2f0bcSteve Naroff  CloseHandle(info.hProcess);
1336bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor  CloseHandle(info.hThread);
1337bcfd1f55bfbb3e5944cd5e03d07b343e280838c4Douglas Gregor
13386f62c2abd8077bf70d2166d37e8caa426b34d8e4Chris Lattner  delete pg;
1339485eeff9ba73376c8e01179bf1a501b1723446cbSteve Naroff}
1340207f4d8543529221932af82836016a2ef066c917Peter Collingbourne