debugger_win.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/debug/debugger.h" 6 7#include <windows.h> 8#include <dbghelp.h> 9 10#include "base/basictypes.h" 11#include "base/debug_util.h" 12#include "base/logging.h" 13 14namespace base { 15namespace debug { 16 17namespace { 18 19// Minimalist key reader. 20// Note: Does not use the CRT. 21bool RegReadString(HKEY root, const wchar_t* subkey, 22 const wchar_t* value_name, wchar_t* buffer, int* len) { 23 HKEY key = NULL; 24 DWORD res = RegOpenKeyEx(root, subkey, 0, KEY_READ, &key); 25 if (ERROR_SUCCESS != res || key == NULL) 26 return false; 27 28 DWORD type = 0; 29 DWORD buffer_size = *len * sizeof(wchar_t); 30 // We don't support REG_EXPAND_SZ. 31 res = RegQueryValueEx(key, value_name, NULL, &type, 32 reinterpret_cast<BYTE*>(buffer), &buffer_size); 33 if (ERROR_SUCCESS == res && buffer_size != 0 && type == REG_SZ) { 34 // Make sure the buffer is NULL terminated. 35 buffer[*len - 1] = 0; 36 *len = lstrlen(buffer); 37 RegCloseKey(key); 38 return true; 39 } 40 RegCloseKey(key); 41 return false; 42} 43 44// Replaces each "%ld" in input per a value. Not efficient but it works. 45// Note: Does not use the CRT. 46bool StringReplace(const wchar_t* input, int value, wchar_t* output, 47 int output_len) { 48 memset(output, 0, output_len*sizeof(wchar_t)); 49 int input_len = lstrlen(input); 50 51 for (int i = 0; i < input_len; ++i) { 52 int current_output_len = lstrlen(output); 53 54 if (input[i] == L'%' && input[i + 1] == L'l' && input[i + 2] == L'd') { 55 // Make sure we have enough place left. 56 if ((current_output_len + 12) >= output_len) 57 return false; 58 59 // Cheap _itow(). 60 wsprintf(output+current_output_len, L"%d", value); 61 i += 2; 62 } else { 63 if (current_output_len >= output_len) 64 return false; 65 output[current_output_len] = input[i]; 66 } 67 } 68 return true; 69} 70 71} // namespace 72 73// Note: Does not use the CRT. 74bool SpawnDebuggerOnProcess(unsigned process_id) { 75 wchar_t reg_value[1026]; 76 int len = arraysize(reg_value); 77 if (RegReadString(HKEY_LOCAL_MACHINE, 78 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", 79 L"Debugger", reg_value, &len)) { 80 wchar_t command_line[1026]; 81 if (StringReplace(reg_value, process_id, command_line, 82 arraysize(command_line))) { 83 // We don't mind if the debugger is present because it will simply fail 84 // to attach to this process. 85 STARTUPINFO startup_info = {0}; 86 startup_info.cb = sizeof(startup_info); 87 PROCESS_INFORMATION process_info = {0}; 88 89 if (CreateProcess(NULL, command_line, NULL, NULL, FALSE, 0, NULL, NULL, 90 &startup_info, &process_info)) { 91 CloseHandle(process_info.hThread); 92 WaitForInputIdle(process_info.hProcess, 10000); 93 CloseHandle(process_info.hProcess); 94 return true; 95 } 96 } 97 } 98 return false; 99} 100 101bool BeingDebugged() { 102 return ::IsDebuggerPresent() != 0; 103} 104 105void BreakDebugger() { 106 if (DebugUtil::AreDialogsSuppressed()) 107 _exit(1); 108 __debugbreak(); 109} 110 111} // namespace debug 112} // namespace base 113