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