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