LLDB mainline
ProcessIOHandler.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "lldb/Core/Debugger.h"
12#include "lldb/Host/Terminal.h"
13#include "lldb/Target/Target.h"
15#include "lldb/Utility/Log.h"
17#include "lldb/Utility/State.h"
18#include "lldb/Utility/Status.h"
19
20using namespace lldb_private;
21
23 : IOHandler(process->GetTarget().GetDebugger(), IOHandler::Type::ProcessIO),
24 m_process(process),
25 m_read_file(GetInputFD(), File::eOpenOptionReadOnly, false),
26 m_write_file(write_fd, File::eOpenOptionWriteOnly, false) {
27 m_pipe.CreateNew();
28}
29
31 std::lock_guard<std::mutex> guard(m_mutex);
32 SetIsDone(!running);
33 m_is_running = running;
34}
35
36// Each IOHandler gets to run until it is done. It should read data from the
37// "in" and place output into "out" and "err and return when done.
39 if (!m_read_file.IsValid() || !m_write_file.IsValid() || !m_pipe.CanRead() ||
40 !m_pipe.CanWrite()) {
41 SetIsDone(true);
42 return;
43 }
44
45 SetIsDone(false);
46 const int read_fd = m_read_file.GetDescriptor();
47 Terminal terminal(read_fd);
48 TerminalState terminal_state(terminal, false);
49 // FIXME: error handling?
50 llvm::consumeError(terminal.SetCanonical(false));
51 llvm::consumeError(terminal.SetEcho(false));
52// FD_ZERO, FD_SET are not supported on windows
53#ifndef _WIN32
54 const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
55 SetIsRunning(true);
56 while (true) {
57 {
58 std::lock_guard<std::mutex> guard(m_mutex);
59 if (GetIsDone())
60 break;
61 }
62
63 SelectHelper select_helper;
64 select_helper.FDSetRead(read_fd);
65 select_helper.FDSetRead(pipe_read_fd);
66 Status error = select_helper.Select();
67
68 if (error.Fail())
69 break;
70
71 char ch = 0;
72 size_t n;
73 if (select_helper.FDIsSetRead(read_fd)) {
74 n = 1;
75 if (m_read_file.Read(&ch, n).Success() && n == 1) {
76 if (m_write_file.Write(&ch, n).Fail() || n != 1)
77 break;
78 } else
79 break;
80 }
81
82 if (select_helper.FDIsSetRead(pipe_read_fd)) {
83 // Consume the interrupt byte
84 if (llvm::Expected<size_t> bytes_read = m_pipe.Read(&ch, 1)) {
85 if (ch == 'q')
86 break;
87 if (ch == 'i')
88 if (StateIsRunningState(m_process->GetState()))
89 m_process->SendAsyncInterrupt();
90 } else {
91 LLDB_LOG_ERROR(GetLog(LLDBLog::Process), bytes_read.takeError(),
92 "Pipe read failed: {0}");
93 }
94 }
95 }
96 SetIsRunning(false);
97#endif
98}
99
101 std::lock_guard<std::mutex> guard(m_mutex);
102 SetIsDone(true);
103 // Only write to our pipe to cancel if we are in
104 // IOHandlerProcessSTDIO::Run(). We can end up with a python command that
105 // is being run from the command interpreter:
106 //
107 // (lldb) step_process_thousands_of_times
108 //
109 // In this case the command interpreter will be in the middle of handling
110 // the command and if the process pushes and pops the IOHandler thousands
111 // of times, we can end up writing to m_pipe without ever consuming the
112 // bytes from the pipe in IOHandlerProcessSTDIO::Run() and end up
113 // deadlocking when the pipe gets fed up and blocks until data is consumed.
114 if (m_is_running) {
115 char ch = 'q'; // Send 'q' for quit
116 if (llvm::Error err = m_pipe.Write(&ch, 1).takeError()) {
117 LLDB_LOG_ERROR(GetLog(LLDBLog::Process), std::move(err),
118 "Pipe write failed: {0}");
119 }
120 }
121}
122
124 // Do only things that are safe to do in an interrupt context (like in a
125 // SIGINT handler), like write 1 byte to a file descriptor. This will
126 // interrupt the IOHandlerProcessSTDIO::Run() and we can look at the byte
127 // that was written to the pipe and then call
128 // m_process->SendAsyncInterrupt() from a much safer location in code.
129 if (m_active) {
130 char ch = 'i'; // Send 'i' for interrupt
131 return !errorToBool(m_pipe.Write(&ch, 1).takeError());
132 } else {
133 // This IOHandler might be pushed on the stack, but not being run
134 // currently so do the right thing if we aren't actively watching for
135 // STDIN by sending the interrupt to the process. Otherwise the write to
136 // the pipe above would do nothing. This can happen when the command
137 // interpreter is running and gets a "expression ...". It will be on the
138 // IOHandler thread and sending the input is complete to the delegate
139 // which will cause the expression to run, which will push the process IO
140 // handler, but not run it.
141
142 if (StateIsRunningState(m_process->GetState())) {
143 m_process->SendAsyncInterrupt();
144 return true;
145 }
146 }
147 return false;
148}
149
150#ifdef _WIN32
151
153
154IOHandlerProcessSTDIOWindows::IOHandlerProcessSTDIOWindows(Process *process)
155 : IOHandler(process->GetTarget().GetDebugger(), IOHandler::Type::ProcessIO),
156 m_process(process),
157 m_read_file(GetInputFD(), File::eOpenOptionReadOnly, false),
158 m_interrupt_event(
159 CreateEvent(/*lpEventAttributes=*/nullptr, /*bManualReset=*/FALSE,
160 /*bInitialState=*/FALSE, /*lpName=*/nullptr)) {}
161
162IOHandlerProcessSTDIOWindows::~IOHandlerProcessSTDIOWindows() {
163 if (m_interrupt_event != INVALID_HANDLE_VALUE)
164 ::CloseHandle(m_interrupt_event);
165}
166
167void IOHandlerProcessSTDIOWindows::SetIsRunning(bool running) {
168 std::lock_guard<std::mutex> guard(m_mutex);
169 SetIsDone(!running);
170 m_is_running = running;
171}
172
173llvm::Expected<bool>
174IOHandlerProcessSTDIOWindows::ConsoleHasTextInput(const HANDLE hStdin) {
175 // Check if there are already characters buffered. Pressing enter counts as
176 // 2 characters '\r\n' and only one of them is a keyDown event.
177 DWORD bytesAvailable = 0;
178 if (PeekNamedPipe(hStdin, nullptr, 0, nullptr, &bytesAvailable, nullptr)) {
179 if (bytesAvailable > 0)
180 return true;
181 }
182
183 while (true) {
184 INPUT_RECORD inputRecord;
185 DWORD numRead = 0;
186 if (!PeekConsoleInput(hStdin, &inputRecord, 1, &numRead))
187 return llvm::createStringError("failed to peek standard input");
188
189 if (numRead == 0)
190 return false;
191
192 if (inputRecord.EventType == KEY_EVENT &&
193 inputRecord.Event.KeyEvent.bKeyDown &&
194 inputRecord.Event.KeyEvent.uChar.AsciiChar != 0)
195 return true;
196
197 if (!ReadConsoleInput(hStdin, &inputRecord, 1, &numRead))
198 return llvm::createStringError("failed to read standard input");
199 }
200}
201
202void IOHandlerProcessSTDIOWindows::Run() {
203 if (!m_read_file.IsValid()) {
204 SetIsDone(true);
205 return;
206 }
207
208 SetIsDone(false);
209 SetIsRunning(true);
210
211 HANDLE hStdin = m_read_file.GetWaitableHandle();
212 HANDLE waitHandles[2] = {hStdin, m_interrupt_event};
213
214 DWORD consoleMode;
215 bool isConsole = GetConsoleMode(hStdin, &consoleMode) != 0;
216 // With ENABLE_LINE_INPUT, ReadFile returns only when a carriage return is
217 // read. This will block lldb in ReadFile until the user hits enter. Save
218 // the previous console mode to restore it later and remove
219 // ENABLE_LINE_INPUT.
220 DWORD oldConsoleMode = consoleMode;
221 SetConsoleMode(hStdin, consoleMode & ~ENABLE_LINE_INPUT & ~ENABLE_ECHO_INPUT);
222
223 while (true) {
224 {
225 std::lock_guard<std::mutex> guard(m_mutex);
226 if (GetIsDone())
227 goto exit_loop;
228 }
229
230 DWORD result = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
231 switch (result) {
232 case WAIT_FAILED:
233 goto exit_loop;
234 case WAIT_OBJECT_0: {
235 if (isConsole) {
236 auto hasInputOrErr = ConsoleHasTextInput(hStdin);
237 if (!hasInputOrErr) {
239 LLDB_LOG_ERROR(log, hasInputOrErr.takeError(),
240 "failed to process debuggee's IO: {0}");
241 goto exit_loop;
242 }
243
244 // If no text input is ready, go back to waiting.
245 if (!*hasInputOrErr)
246 continue;
247 }
248
249 char ch = 0;
250 DWORD read = 0;
251 if (!ReadFile(hStdin, &ch, 1, &read, nullptr) || read != 1)
252 goto exit_loop;
253
254 Status err;
255 m_process->PutSTDIN(&ch, 1, err);
256 if (err.Fail())
257 goto exit_loop;
258 break;
259 }
260 case WAIT_OBJECT_0 + 1: {
261 ControlOp op = m_pending_op.exchange(eControlOpNone);
262 if (op == eControlOpQuit)
263 goto exit_loop;
264 if (op == eControlOpInterrupt &&
265 StateIsRunningState(m_process->GetState()))
266 m_process->SendAsyncInterrupt();
267 break;
268 }
269 default:
270 goto exit_loop;
271 }
272 }
273
274exit_loop:;
275 SetIsRunning(false);
276 SetIsDone(true);
277 SetConsoleMode(hStdin, oldConsoleMode);
278}
279
280void IOHandlerProcessSTDIOWindows::Cancel() {
281 std::lock_guard<std::mutex> guard(m_mutex);
282 SetIsDone(true);
283 if (m_is_running) {
284 m_pending_op.store(eControlOpQuit);
285 ::SetEvent(m_interrupt_event);
286 }
287}
288
289bool IOHandlerProcessSTDIOWindows::Interrupt() {
290 if (m_active) {
291 m_pending_op.store(eControlOpInterrupt);
292 ::SetEvent(m_interrupt_event);
293 return true;
294 }
295 if (StateIsRunningState(m_process->GetState())) {
296 m_process->SendAsyncInterrupt();
297 return true;
298 }
299 return false;
300}
301
302#endif // _WIN32
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:394
void * HANDLE
lldb_private::Status Select()
void FDSetRead(lldb::socket_t fd)
bool FDIsSetRead(lldb::socket_t fd) const
An abstract base class for files.
Definition FileBase.h:34
NativeFile m_write_file
Write to this file (usually the primary pty for getting io to debuggee)
NativeFile m_read_file
Read from this file (usually actual STDIN for LLDB)
IOHandlerProcessSTDIO(Process *process, int write_fd)
Debugger & GetDebugger()
Definition IOHandler.h:130
IOHandler(Debugger &debugger, IOHandler::Type type)
Definition IOHandler.cpp:55
void SetIsDone(bool b)
Definition IOHandler.h:81
A plug-in interface definition class for debugging a process.
Definition Process.h:357
An error handling class.
Definition Status.h:118
bool Fail() const
Test for error condition.
Definition Status.cpp:293
A RAII-friendly terminal state saving/restoring class.
Definition Terminal.h:99
llvm::Error SetEcho(bool enabled)
Definition Terminal.cpp:80
llvm::Error SetCanonical(bool enabled)
Definition Terminal.cpp:96
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:327
bool StateIsRunningState(lldb::StateType state)
Check if a state represents a state where the process or thread is running.
Definition State.cpp:68