/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- GDBRemoteCommunicationServerPlatform.cpp --------------------------===// |
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 | | |
9 | | #include "GDBRemoteCommunicationServerPlatform.h" |
10 | | |
11 | | #include <cerrno> |
12 | | |
13 | | #include <chrono> |
14 | | #include <csignal> |
15 | | #include <cstring> |
16 | | #include <mutex> |
17 | | #include <optional> |
18 | | #include <sstream> |
19 | | #include <thread> |
20 | | |
21 | | #include "llvm/Support/FileSystem.h" |
22 | | #include "llvm/Support/JSON.h" |
23 | | #include "llvm/Support/Threading.h" |
24 | | |
25 | | #include "lldb/Host/Config.h" |
26 | | #include "lldb/Host/ConnectionFileDescriptor.h" |
27 | | #include "lldb/Host/FileAction.h" |
28 | | #include "lldb/Host/Host.h" |
29 | | #include "lldb/Host/HostInfo.h" |
30 | | #include "lldb/Interpreter/CommandCompletions.h" |
31 | | #include "lldb/Target/Platform.h" |
32 | | #include "lldb/Target/UnixSignals.h" |
33 | | #include "lldb/Utility/GDBRemote.h" |
34 | | #include "lldb/Utility/LLDBLog.h" |
35 | | #include "lldb/Utility/Log.h" |
36 | | #include "lldb/Utility/StreamString.h" |
37 | | #include "lldb/Utility/StructuredData.h" |
38 | | #include "lldb/Utility/TildeExpressionResolver.h" |
39 | | #include "lldb/Utility/UriParser.h" |
40 | | |
41 | | #include "lldb/Utility/StringExtractorGDBRemote.h" |
42 | | |
43 | | using namespace lldb; |
44 | | using namespace lldb_private::process_gdb_remote; |
45 | | using namespace lldb_private; |
46 | | |
47 | | GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port, |
48 | 2 | uint16_t max_port) { |
49 | 8 | for (; min_port < max_port; ++min_port6 ) |
50 | 6 | m_port_map[min_port] = LLDB_INVALID_PROCESS_ID; |
51 | 2 | } |
52 | | |
53 | 6 | void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) { |
54 | | // Do not modify existing mappings |
55 | 6 | m_port_map.insert({port, LLDB_INVALID_PROCESS_ID}); |
56 | 6 | } |
57 | | |
58 | | llvm::Expected<uint16_t> |
59 | 12 | GDBRemoteCommunicationServerPlatform::PortMap::GetNextAvailablePort() { |
60 | 12 | if (m_port_map.empty()) |
61 | 1 | return 0; // Bind to port zero and get a port, we didn't have any |
62 | | // limitations |
63 | | |
64 | 22 | for (auto &pair : m_port_map)11 { |
65 | 22 | if (pair.second == LLDB_INVALID_PROCESS_ID) { |
66 | 7 | pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; |
67 | 7 | return pair.first; |
68 | 7 | } |
69 | 22 | } |
70 | 4 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
71 | 4 | "No free port found in port map"); |
72 | 11 | } |
73 | | |
74 | | bool GDBRemoteCommunicationServerPlatform::PortMap::AssociatePortWithProcess( |
75 | 10 | uint16_t port, lldb::pid_t pid) { |
76 | 10 | auto pos = m_port_map.find(port); |
77 | 10 | if (pos != m_port_map.end()) { |
78 | 10 | pos->second = pid; |
79 | 10 | return true; |
80 | 10 | } |
81 | 0 | return false; |
82 | 10 | } |
83 | | |
84 | 3 | bool GDBRemoteCommunicationServerPlatform::PortMap::FreePort(uint16_t port) { |
85 | 3 | std::map<uint16_t, lldb::pid_t>::iterator pos = m_port_map.find(port); |
86 | 3 | if (pos != m_port_map.end()) { |
87 | 1 | pos->second = LLDB_INVALID_PROCESS_ID; |
88 | 1 | return true; |
89 | 1 | } |
90 | 2 | return false; |
91 | 3 | } |
92 | | |
93 | | bool GDBRemoteCommunicationServerPlatform::PortMap::FreePortForProcess( |
94 | 4 | lldb::pid_t pid) { |
95 | 4 | if (!m_port_map.empty()) { |
96 | 7 | for (auto &pair : m_port_map) { |
97 | 7 | if (pair.second == pid) { |
98 | 2 | pair.second = LLDB_INVALID_PROCESS_ID; |
99 | 2 | return true; |
100 | 2 | } |
101 | 7 | } |
102 | 4 | } |
103 | 2 | return false; |
104 | 4 | } |
105 | | |
106 | 3 | bool GDBRemoteCommunicationServerPlatform::PortMap::empty() const { |
107 | 3 | return m_port_map.empty(); |
108 | 3 | } |
109 | | |
110 | | // GDBRemoteCommunicationServerPlatform constructor |
111 | | GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( |
112 | | const Socket::SocketProtocol socket_protocol, const char *socket_scheme) |
113 | 0 | : GDBRemoteCommunicationServerCommon(), |
114 | 0 | m_socket_protocol(socket_protocol), m_socket_scheme(socket_scheme), |
115 | 0 | m_spawned_pids_mutex(), m_port_map(), m_port_offset(0) { |
116 | 0 | m_pending_gdb_server.pid = LLDB_INVALID_PROCESS_ID; |
117 | 0 | m_pending_gdb_server.port = 0; |
118 | |
|
119 | 0 | RegisterMemberFunctionHandler( |
120 | 0 | StringExtractorGDBRemote::eServerPacketType_qC, |
121 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_qC); |
122 | 0 | RegisterMemberFunctionHandler( |
123 | 0 | StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, |
124 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); |
125 | 0 | RegisterMemberFunctionHandler( |
126 | 0 | StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, |
127 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); |
128 | 0 | RegisterMemberFunctionHandler( |
129 | 0 | StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer, |
130 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer); |
131 | 0 | RegisterMemberFunctionHandler( |
132 | 0 | StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, |
133 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess); |
134 | 0 | RegisterMemberFunctionHandler( |
135 | 0 | StringExtractorGDBRemote::eServerPacketType_qProcessInfo, |
136 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); |
137 | 0 | RegisterMemberFunctionHandler( |
138 | 0 | StringExtractorGDBRemote::eServerPacketType_qPathComplete, |
139 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete); |
140 | 0 | RegisterMemberFunctionHandler( |
141 | 0 | StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, |
142 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); |
143 | 0 | RegisterMemberFunctionHandler( |
144 | 0 | StringExtractorGDBRemote::eServerPacketType_jSignalsInfo, |
145 | 0 | &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo); |
146 | |
|
147 | 0 | RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, |
148 | 0 | [](StringExtractorGDBRemote packet, Status &error, |
149 | 0 | bool &interrupt, bool &quit) { |
150 | 0 | error.SetErrorString("interrupt received"); |
151 | 0 | interrupt = true; |
152 | 0 | return PacketResult::Success; |
153 | 0 | }); |
154 | 0 | } |
155 | | |
156 | | // Destructor |
157 | 0 | GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() = |
158 | | default; |
159 | | |
160 | | Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( |
161 | | const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid, |
162 | 0 | std::optional<uint16_t> &port, std::string &socket_name) { |
163 | 0 | if (!port) { |
164 | 0 | llvm::Expected<uint16_t> available_port = m_port_map.GetNextAvailablePort(); |
165 | 0 | if (available_port) |
166 | 0 | port = *available_port; |
167 | 0 | else |
168 | 0 | return Status(available_port.takeError()); |
169 | 0 | } |
170 | | |
171 | | // Spawn a new thread to accept the port that gets bound after binding to |
172 | | // port 0 (zero). |
173 | | |
174 | | // ignore the hostname send from the remote end, just use the ip address that |
175 | | // we're currently communicating with as the hostname |
176 | | |
177 | | // Spawn a debugserver and try to get the port it listens to. |
178 | 0 | ProcessLaunchInfo debugserver_launch_info; |
179 | 0 | if (hostname.empty()) |
180 | 0 | hostname = "127.0.0.1"; |
181 | |
|
182 | 0 | Log *log = GetLog(LLDBLog::Platform); |
183 | 0 | LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(), |
184 | 0 | *port); |
185 | | |
186 | | // Do not run in a new session so that it can not linger after the platform |
187 | | // closes. |
188 | 0 | debugserver_launch_info.SetLaunchInSeparateProcessGroup(false); |
189 | 0 | debugserver_launch_info.SetMonitorProcessCallback( |
190 | 0 | std::bind(&GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, |
191 | 0 | this, std::placeholders::_1)); |
192 | |
|
193 | 0 | std::ostringstream url; |
194 | | // debugserver does not accept the URL scheme prefix. |
195 | | #if !defined(__APPLE__) |
196 | | url << m_socket_scheme << "://"; |
197 | | #endif |
198 | 0 | uint16_t *port_ptr = &*port; |
199 | 0 | if (m_socket_protocol == Socket::ProtocolTcp) { |
200 | 0 | std::string platform_uri = GetConnection()->GetURI(); |
201 | 0 | std::optional<URI> parsed_uri = URI::Parse(platform_uri); |
202 | 0 | url << '[' << parsed_uri->hostname.str() << "]:" << *port; |
203 | 0 | } else { |
204 | 0 | socket_name = GetDomainSocketPath("gdbserver").GetPath(); |
205 | 0 | url << socket_name; |
206 | 0 | port_ptr = nullptr; |
207 | 0 | } |
208 | |
|
209 | 0 | Status error = StartDebugserverProcess( |
210 | 0 | url.str().c_str(), nullptr, debugserver_launch_info, port_ptr, &args, -1); |
211 | |
|
212 | 0 | pid = debugserver_launch_info.GetProcessID(); |
213 | 0 | if (pid != LLDB_INVALID_PROCESS_ID) { |
214 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
215 | 0 | m_spawned_pids.insert(pid); |
216 | 0 | if (*port > 0) |
217 | 0 | m_port_map.AssociatePortWithProcess(*port, pid); |
218 | 0 | } else { |
219 | 0 | if (*port > 0) |
220 | 0 | m_port_map.FreePort(*port); |
221 | 0 | } |
222 | 0 | return error; |
223 | 0 | } |
224 | | |
225 | | GDBRemoteCommunication::PacketResult |
226 | | GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( |
227 | 0 | StringExtractorGDBRemote &packet) { |
228 | | // Spawn a local debugserver as a platform so we can then attach or launch a |
229 | | // process... |
230 | |
|
231 | 0 | Log *log = GetLog(LLDBLog::Platform); |
232 | 0 | LLDB_LOGF(log, "GDBRemoteCommunicationServerPlatform::%s() called", |
233 | 0 | __FUNCTION__); |
234 | |
|
235 | 0 | ConnectionFileDescriptor file_conn; |
236 | 0 | std::string hostname; |
237 | 0 | packet.SetFilePos(::strlen("qLaunchGDBServer;")); |
238 | 0 | llvm::StringRef name; |
239 | 0 | llvm::StringRef value; |
240 | 0 | std::optional<uint16_t> port; |
241 | 0 | while (packet.GetNameColonValue(name, value)) { |
242 | 0 | if (name.equals("host")) |
243 | 0 | hostname = std::string(value); |
244 | 0 | else if (name.equals("port")) { |
245 | | // Make the Optional valid so we can use its value |
246 | 0 | port = 0; |
247 | 0 | value.getAsInteger(0, *port); |
248 | 0 | } |
249 | 0 | } |
250 | |
|
251 | 0 | lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; |
252 | 0 | std::string socket_name; |
253 | 0 | Status error = |
254 | 0 | LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); |
255 | 0 | if (error.Fail()) { |
256 | 0 | LLDB_LOGF(log, |
257 | 0 | "GDBRemoteCommunicationServerPlatform::%s() debugserver " |
258 | 0 | "launch failed: %s", |
259 | 0 | __FUNCTION__, error.AsCString()); |
260 | 0 | return SendErrorResponse(9); |
261 | 0 | } |
262 | | |
263 | 0 | LLDB_LOGF(log, |
264 | 0 | "GDBRemoteCommunicationServerPlatform::%s() debugserver " |
265 | 0 | "launched successfully as pid %" PRIu64, |
266 | 0 | __FUNCTION__, debugserver_pid); |
267 | |
|
268 | 0 | StreamGDBRemote response; |
269 | 0 | assert(port); |
270 | 0 | response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, |
271 | 0 | *port + m_port_offset); |
272 | 0 | if (!socket_name.empty()) { |
273 | 0 | response.PutCString("socket_name:"); |
274 | 0 | response.PutStringAsRawHex8(socket_name); |
275 | 0 | response.PutChar(';'); |
276 | 0 | } |
277 | |
|
278 | 0 | PacketResult packet_result = SendPacketNoLock(response.GetString()); |
279 | 0 | if (packet_result != PacketResult::Success) { |
280 | 0 | if (debugserver_pid != LLDB_INVALID_PROCESS_ID) |
281 | 0 | Host::Kill(debugserver_pid, SIGINT); |
282 | 0 | } |
283 | 0 | return packet_result; |
284 | 0 | } |
285 | | |
286 | | GDBRemoteCommunication::PacketResult |
287 | | GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer( |
288 | 0 | StringExtractorGDBRemote &packet) { |
289 | 0 | namespace json = llvm::json; |
290 | |
|
291 | 0 | if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID) |
292 | 0 | return SendErrorResponse(4); |
293 | | |
294 | 0 | json::Object server{{"port", m_pending_gdb_server.port}}; |
295 | |
|
296 | 0 | if (!m_pending_gdb_server.socket_name.empty()) |
297 | 0 | server.try_emplace("socket_name", m_pending_gdb_server.socket_name); |
298 | |
|
299 | 0 | json::Array server_list; |
300 | 0 | server_list.push_back(std::move(server)); |
301 | |
|
302 | 0 | StreamGDBRemote response; |
303 | 0 | response.AsRawOstream() << std::move(server_list); |
304 | |
|
305 | 0 | StreamGDBRemote escaped_response; |
306 | 0 | escaped_response.PutEscapedBytes(response.GetString().data(), |
307 | 0 | response.GetSize()); |
308 | 0 | return SendPacketNoLock(escaped_response.GetString()); |
309 | 0 | } |
310 | | |
311 | | GDBRemoteCommunication::PacketResult |
312 | | GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess( |
313 | 0 | StringExtractorGDBRemote &packet) { |
314 | 0 | packet.SetFilePos(::strlen("qKillSpawnedProcess:")); |
315 | |
|
316 | 0 | lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); |
317 | | |
318 | | // verify that we know anything about this pid. Scope for locker |
319 | 0 | { |
320 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
321 | 0 | if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { |
322 | | // not a pid we know about |
323 | 0 | return SendErrorResponse(10); |
324 | 0 | } |
325 | 0 | } |
326 | | |
327 | | // go ahead and attempt to kill the spawned process |
328 | 0 | if (KillSpawnedProcess(pid)) |
329 | 0 | return SendOKResponse(); |
330 | 0 | else |
331 | 0 | return SendErrorResponse(11); |
332 | 0 | } |
333 | | |
334 | 0 | bool GDBRemoteCommunicationServerPlatform::KillSpawnedProcess(lldb::pid_t pid) { |
335 | | // make sure we know about this process |
336 | 0 | { |
337 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
338 | 0 | if (m_spawned_pids.find(pid) == m_spawned_pids.end()) |
339 | 0 | return false; |
340 | 0 | } |
341 | | |
342 | | // first try a SIGTERM (standard kill) |
343 | 0 | Host::Kill(pid, SIGTERM); |
344 | | |
345 | | // check if that worked |
346 | 0 | for (size_t i = 0; i < 10; ++i) { |
347 | 0 | { |
348 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
349 | 0 | if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { |
350 | | // it is now killed |
351 | 0 | return true; |
352 | 0 | } |
353 | 0 | } |
354 | 0 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
355 | 0 | } |
356 | | |
357 | 0 | { |
358 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
359 | 0 | if (m_spawned_pids.find(pid) == m_spawned_pids.end()) |
360 | 0 | return true; |
361 | 0 | } |
362 | | |
363 | | // the launched process still lives. Now try killing it again, this time |
364 | | // with an unblockable signal. |
365 | 0 | Host::Kill(pid, SIGKILL); |
366 | |
|
367 | 0 | for (size_t i = 0; i < 10; ++i) { |
368 | 0 | { |
369 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
370 | 0 | if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { |
371 | | // it is now killed |
372 | 0 | return true; |
373 | 0 | } |
374 | 0 | } |
375 | 0 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
376 | 0 | } |
377 | | |
378 | | // check one more time after the final sleep |
379 | 0 | { |
380 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
381 | 0 | if (m_spawned_pids.find(pid) == m_spawned_pids.end()) |
382 | 0 | return true; |
383 | 0 | } |
384 | | |
385 | | // no luck - the process still lives |
386 | 0 | return false; |
387 | 0 | } |
388 | | |
389 | | GDBRemoteCommunication::PacketResult |
390 | | GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo( |
391 | 0 | StringExtractorGDBRemote &packet) { |
392 | 0 | lldb::pid_t pid = m_process_launch_info.GetProcessID(); |
393 | 0 | m_process_launch_info.Clear(); |
394 | |
|
395 | 0 | if (pid == LLDB_INVALID_PROCESS_ID) |
396 | 0 | return SendErrorResponse(1); |
397 | | |
398 | 0 | ProcessInstanceInfo proc_info; |
399 | 0 | if (!Host::GetProcessInfo(pid, proc_info)) |
400 | 0 | return SendErrorResponse(1); |
401 | | |
402 | 0 | StreamString response; |
403 | 0 | CreateProcessInfoResponse_DebugServerStyle(proc_info, response); |
404 | 0 | return SendPacketNoLock(response.GetString()); |
405 | 0 | } |
406 | | |
407 | | GDBRemoteCommunication::PacketResult |
408 | | GDBRemoteCommunicationServerPlatform::Handle_qPathComplete( |
409 | 0 | StringExtractorGDBRemote &packet) { |
410 | 0 | packet.SetFilePos(::strlen("qPathComplete:")); |
411 | 0 | const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1); |
412 | 0 | if (packet.GetChar() != ',') |
413 | 0 | return SendErrorResponse(85); |
414 | 0 | std::string path; |
415 | 0 | packet.GetHexByteString(path); |
416 | |
|
417 | 0 | StringList matches; |
418 | 0 | StandardTildeExpressionResolver resolver; |
419 | 0 | if (only_dir) |
420 | 0 | CommandCompletions::DiskDirectories(path, matches, resolver); |
421 | 0 | else |
422 | 0 | CommandCompletions::DiskFiles(path, matches, resolver); |
423 | |
|
424 | 0 | StreamString response; |
425 | 0 | response.PutChar('M'); |
426 | 0 | llvm::StringRef separator; |
427 | 0 | std::sort(matches.begin(), matches.end()); |
428 | 0 | for (const auto &match : matches) { |
429 | 0 | response << separator; |
430 | 0 | separator = ","; |
431 | | // encode result strings into hex bytes to avoid unexpected error caused by |
432 | | // special characters like '$'. |
433 | 0 | response.PutStringAsRawHex8(match.c_str()); |
434 | 0 | } |
435 | |
|
436 | 0 | return SendPacketNoLock(response.GetString()); |
437 | 0 | } |
438 | | |
439 | | GDBRemoteCommunication::PacketResult |
440 | | GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir( |
441 | 0 | StringExtractorGDBRemote &packet) { |
442 | |
|
443 | 0 | llvm::SmallString<64> cwd; |
444 | 0 | if (std::error_code ec = llvm::sys::fs::current_path(cwd)) |
445 | 0 | return SendErrorResponse(ec.value()); |
446 | | |
447 | 0 | StreamString response; |
448 | 0 | response.PutBytesAsRawHex8(cwd.data(), cwd.size()); |
449 | 0 | return SendPacketNoLock(response.GetString()); |
450 | 0 | } |
451 | | |
452 | | GDBRemoteCommunication::PacketResult |
453 | | GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir( |
454 | 0 | StringExtractorGDBRemote &packet) { |
455 | 0 | packet.SetFilePos(::strlen("QSetWorkingDir:")); |
456 | 0 | std::string path; |
457 | 0 | packet.GetHexByteString(path); |
458 | |
|
459 | 0 | if (std::error_code ec = llvm::sys::fs::set_current_path(path)) |
460 | 0 | return SendErrorResponse(ec.value()); |
461 | 0 | return SendOKResponse(); |
462 | 0 | } |
463 | | |
464 | | GDBRemoteCommunication::PacketResult |
465 | | GDBRemoteCommunicationServerPlatform::Handle_qC( |
466 | 0 | StringExtractorGDBRemote &packet) { |
467 | | // NOTE: lldb should now be using qProcessInfo for process IDs. This path |
468 | | // here |
469 | | // should not be used. It is reporting process id instead of thread id. The |
470 | | // correct answer doesn't seem to make much sense for lldb-platform. |
471 | | // CONSIDER: flip to "unsupported". |
472 | 0 | lldb::pid_t pid = m_process_launch_info.GetProcessID(); |
473 | |
|
474 | 0 | StreamString response; |
475 | 0 | response.Printf("QC%" PRIx64, pid); |
476 | | |
477 | | // If we launch a process and this GDB server is acting as a platform, then |
478 | | // we need to clear the process launch state so we can start launching |
479 | | // another process. In order to launch a process a bunch or packets need to |
480 | | // be sent: environment packets, working directory, disable ASLR, and many |
481 | | // more settings. When we launch a process we then need to know when to clear |
482 | | // this information. Currently we are selecting the 'qC' packet as that |
483 | | // packet which seems to make the most sense. |
484 | 0 | if (pid != LLDB_INVALID_PROCESS_ID) { |
485 | 0 | m_process_launch_info.Clear(); |
486 | 0 | } |
487 | |
|
488 | 0 | return SendPacketNoLock(response.GetString()); |
489 | 0 | } |
490 | | |
491 | | GDBRemoteCommunication::PacketResult |
492 | | GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo( |
493 | 0 | StringExtractorGDBRemote &packet) { |
494 | 0 | StructuredData::Array signal_array; |
495 | |
|
496 | 0 | lldb::UnixSignalsSP signals = UnixSignals::CreateForHost(); |
497 | 0 | for (auto signo = signals->GetFirstSignalNumber(); |
498 | 0 | signo != LLDB_INVALID_SIGNAL_NUMBER; |
499 | 0 | signo = signals->GetNextSignalNumber(signo)) { |
500 | 0 | auto dictionary = std::make_shared<StructuredData::Dictionary>(); |
501 | |
|
502 | 0 | dictionary->AddIntegerItem("signo", signo); |
503 | 0 | dictionary->AddStringItem("name", signals->GetSignalAsStringRef(signo)); |
504 | |
|
505 | 0 | bool suppress, stop, notify; |
506 | 0 | signals->GetSignalInfo(signo, suppress, stop, notify); |
507 | 0 | dictionary->AddBooleanItem("suppress", suppress); |
508 | 0 | dictionary->AddBooleanItem("stop", stop); |
509 | 0 | dictionary->AddBooleanItem("notify", notify); |
510 | |
|
511 | 0 | signal_array.Push(dictionary); |
512 | 0 | } |
513 | |
|
514 | 0 | StreamString response; |
515 | 0 | signal_array.Dump(response); |
516 | 0 | return SendPacketNoLock(response.GetString()); |
517 | 0 | } |
518 | | |
519 | | void GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped( |
520 | 0 | lldb::pid_t pid) { |
521 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
522 | 0 | m_port_map.FreePortForProcess(pid); |
523 | 0 | m_spawned_pids.erase(pid); |
524 | 0 | } |
525 | | |
526 | 0 | Status GDBRemoteCommunicationServerPlatform::LaunchProcess() { |
527 | 0 | if (!m_process_launch_info.GetArguments().GetArgumentCount()) |
528 | 0 | return Status("%s: no process command line specified to launch", |
529 | 0 | __FUNCTION__); |
530 | | |
531 | | // specify the process monitor if not already set. This should generally be |
532 | | // what happens since we need to reap started processes. |
533 | 0 | if (!m_process_launch_info.GetMonitorProcessCallback()) |
534 | 0 | m_process_launch_info.SetMonitorProcessCallback(std::bind( |
535 | 0 | &GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped, this, |
536 | 0 | std::placeholders::_1)); |
537 | |
|
538 | 0 | Status error = Host::LaunchProcess(m_process_launch_info); |
539 | 0 | if (!error.Success()) { |
540 | 0 | fprintf(stderr, "%s: failed to launch executable %s", __FUNCTION__, |
541 | 0 | m_process_launch_info.GetArguments().GetArgumentAtIndex(0)); |
542 | 0 | return error; |
543 | 0 | } |
544 | | |
545 | 0 | printf("Launched '%s' as process %" PRIu64 "...\n", |
546 | 0 | m_process_launch_info.GetArguments().GetArgumentAtIndex(0), |
547 | 0 | m_process_launch_info.GetProcessID()); |
548 | | |
549 | | // add to list of spawned processes. On an lldb-gdbserver, we would expect |
550 | | // there to be only one. |
551 | 0 | const auto pid = m_process_launch_info.GetProcessID(); |
552 | 0 | if (pid != LLDB_INVALID_PROCESS_ID) { |
553 | | // add to spawned pids |
554 | 0 | std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex); |
555 | 0 | m_spawned_pids.insert(pid); |
556 | 0 | } |
557 | |
|
558 | 0 | return error; |
559 | 0 | } |
560 | | |
561 | 0 | void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) { |
562 | 0 | m_port_map = std::move(port_map); |
563 | 0 | } |
564 | | |
565 | 0 | const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { |
566 | 0 | static FileSpec g_domainsocket_dir; |
567 | 0 | static llvm::once_flag g_once_flag; |
568 | |
|
569 | 0 | llvm::call_once(g_once_flag, []() { |
570 | 0 | const char *domainsocket_dir_env = |
571 | 0 | ::getenv("LLDB_DEBUGSERVER_DOMAINSOCKET_DIR"); |
572 | 0 | if (domainsocket_dir_env != nullptr) |
573 | 0 | g_domainsocket_dir = FileSpec(domainsocket_dir_env); |
574 | 0 | else |
575 | 0 | g_domainsocket_dir = HostInfo::GetProcessTempDir(); |
576 | 0 | }); |
577 | |
|
578 | 0 | return g_domainsocket_dir; |
579 | 0 | } |
580 | | |
581 | | FileSpec |
582 | 0 | GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char *prefix) { |
583 | 0 | llvm::SmallString<128> socket_path; |
584 | 0 | llvm::SmallString<128> socket_name( |
585 | 0 | (llvm::StringRef(prefix) + ".%%%%%%").str()); |
586 | |
|
587 | 0 | FileSpec socket_path_spec(GetDomainSocketDir()); |
588 | 0 | socket_path_spec.AppendPathComponent(socket_name.c_str()); |
589 | |
|
590 | 0 | llvm::sys::fs::createUniqueFile(socket_path_spec.GetPath().c_str(), |
591 | 0 | socket_path); |
592 | 0 | return FileSpec(socket_path.c_str()); |
593 | 0 | } |
594 | | |
595 | 0 | void GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) { |
596 | 0 | m_port_offset = port_offset; |
597 | 0 | } |
598 | | |
599 | | void GDBRemoteCommunicationServerPlatform::SetPendingGdbServer( |
600 | 0 | lldb::pid_t pid, uint16_t port, const std::string &socket_name) { |
601 | 0 | m_pending_gdb_server.pid = pid; |
602 | 0 | m_pending_gdb_server.port = port; |
603 | 0 | m_pending_gdb_server.socket_name = socket_name; |
604 | 0 | } |