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