150
|
1 //===-- PlatformRemoteGDBServer.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 "PlatformRemoteGDBServer.h"
|
|
10 #include "lldb/Host/Config.h"
|
|
11
|
|
12 #include "lldb/Breakpoint/BreakpointLocation.h"
|
|
13 #include "lldb/Core/Debugger.h"
|
|
14 #include "lldb/Core/Module.h"
|
|
15 #include "lldb/Core/ModuleList.h"
|
|
16 #include "lldb/Core/ModuleSpec.h"
|
|
17 #include "lldb/Core/PluginManager.h"
|
|
18 #include "lldb/Host/ConnectionFileDescriptor.h"
|
|
19 #include "lldb/Host/Host.h"
|
|
20 #include "lldb/Host/HostInfo.h"
|
|
21 #include "lldb/Host/PosixApi.h"
|
|
22 #include "lldb/Target/Process.h"
|
|
23 #include "lldb/Target/Target.h"
|
|
24 #include "lldb/Utility/FileSpec.h"
|
236
|
25 #include "lldb/Utility/LLDBLog.h"
|
150
|
26 #include "lldb/Utility/Log.h"
|
|
27 #include "lldb/Utility/ProcessInfo.h"
|
|
28 #include "lldb/Utility/Status.h"
|
|
29 #include "lldb/Utility/StreamString.h"
|
|
30 #include "lldb/Utility/UriParser.h"
|
236
|
31 #include "llvm/Support/FormatAdapters.h"
|
150
|
32
|
|
33 #include "Plugins/Process/Utility/GDBRemoteSignals.h"
|
221
|
34 #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
|
252
|
35 #include <optional>
|
150
|
36
|
|
37 using namespace lldb;
|
|
38 using namespace lldb_private;
|
|
39 using namespace lldb_private::platform_gdb_server;
|
|
40
|
173
|
41 LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteGDBServer, PlatformGDB)
|
150
|
42
|
|
43 static bool g_initialized = false;
|
|
44
|
|
45 void PlatformRemoteGDBServer::Initialize() {
|
|
46 Platform::Initialize();
|
|
47
|
|
48 if (!g_initialized) {
|
|
49 g_initialized = true;
|
|
50 PluginManager::RegisterPlugin(
|
|
51 PlatformRemoteGDBServer::GetPluginNameStatic(),
|
|
52 PlatformRemoteGDBServer::GetDescriptionStatic(),
|
|
53 PlatformRemoteGDBServer::CreateInstance);
|
|
54 }
|
|
55 }
|
|
56
|
|
57 void PlatformRemoteGDBServer::Terminate() {
|
|
58 if (g_initialized) {
|
|
59 g_initialized = false;
|
|
60 PluginManager::UnregisterPlugin(PlatformRemoteGDBServer::CreateInstance);
|
|
61 }
|
|
62
|
|
63 Platform::Terminate();
|
|
64 }
|
|
65
|
|
66 PlatformSP PlatformRemoteGDBServer::CreateInstance(bool force,
|
|
67 const ArchSpec *arch) {
|
|
68 bool create = force;
|
|
69 if (!create) {
|
|
70 create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
|
|
71 }
|
|
72 if (create)
|
|
73 return PlatformSP(new PlatformRemoteGDBServer());
|
|
74 return PlatformSP();
|
|
75 }
|
|
76
|
236
|
77 llvm::StringRef PlatformRemoteGDBServer::GetDescriptionStatic() {
|
150
|
78 return "A platform that uses the GDB remote protocol as the communication "
|
|
79 "transport.";
|
|
80 }
|
|
81
|
236
|
82 llvm::StringRef PlatformRemoteGDBServer::GetDescription() {
|
150
|
83 if (m_platform_description.empty()) {
|
|
84 if (IsConnected()) {
|
|
85 // Send the get description packet
|
|
86 }
|
|
87 }
|
|
88
|
|
89 if (!m_platform_description.empty())
|
|
90 return m_platform_description.c_str();
|
|
91 return GetDescriptionStatic();
|
|
92 }
|
|
93
|
|
94 bool PlatformRemoteGDBServer::GetModuleSpec(const FileSpec &module_file_spec,
|
|
95 const ArchSpec &arch,
|
|
96 ModuleSpec &module_spec) {
|
236
|
97 Log *log = GetLog(LLDBLog::Platform);
|
150
|
98
|
|
99 const auto module_path = module_file_spec.GetPath(false);
|
|
100
|
236
|
101 if (!m_gdb_client_up ||
|
|
102 !m_gdb_client_up->GetModuleInfo(module_file_spec, arch, module_spec)) {
|
150
|
103 LLDB_LOGF(
|
|
104 log,
|
|
105 "PlatformRemoteGDBServer::%s - failed to get module info for %s:%s",
|
|
106 __FUNCTION__, module_path.c_str(),
|
|
107 arch.GetTriple().getTriple().c_str());
|
|
108 return false;
|
|
109 }
|
|
110
|
|
111 if (log) {
|
|
112 StreamString stream;
|
|
113 module_spec.Dump(stream);
|
|
114 LLDB_LOGF(log,
|
|
115 "PlatformRemoteGDBServer::%s - got module info for (%s:%s) : %s",
|
|
116 __FUNCTION__, module_path.c_str(),
|
|
117 arch.GetTriple().getTriple().c_str(), stream.GetData());
|
|
118 }
|
|
119
|
|
120 return true;
|
|
121 }
|
|
122
|
|
123 Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file,
|
|
124 const UUID *uuid_ptr,
|
|
125 FileSpec &local_file) {
|
|
126 // Default to the local case
|
|
127 local_file = platform_file;
|
|
128 return Status();
|
|
129 }
|
|
130
|
|
131 /// Default Constructor
|
|
132 PlatformRemoteGDBServer::PlatformRemoteGDBServer()
|
236
|
133 : Platform(/*is_host=*/false) {}
|
150
|
134
|
|
135 /// Destructor.
|
|
136 ///
|
|
137 /// The destructor is virtual since this class is designed to be
|
|
138 /// inherited from by the plug-in instance.
|
223
|
139 PlatformRemoteGDBServer::~PlatformRemoteGDBServer() = default;
|
150
|
140
|
|
141 size_t PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode(
|
|
142 Target &target, BreakpointSite *bp_site) {
|
|
143 // This isn't needed if the z/Z packets are supported in the GDB remote
|
|
144 // server. But we might need a packet to detect this.
|
|
145 return 0;
|
|
146 }
|
|
147
|
|
148 bool PlatformRemoteGDBServer::GetRemoteOSVersion() {
|
236
|
149 if (m_gdb_client_up)
|
|
150 m_os_version = m_gdb_client_up->GetOSVersion();
|
150
|
151 return !m_os_version.empty();
|
|
152 }
|
|
153
|
252
|
154 std::optional<std::string> PlatformRemoteGDBServer::GetRemoteOSBuildString() {
|
236
|
155 if (!m_gdb_client_up)
|
252
|
156 return std::nullopt;
|
236
|
157 return m_gdb_client_up->GetOSBuildString();
|
150
|
158 }
|
|
159
|
252
|
160 std::optional<std::string>
|
236
|
161 PlatformRemoteGDBServer::GetRemoteOSKernelDescription() {
|
|
162 if (!m_gdb_client_up)
|
252
|
163 return std::nullopt;
|
236
|
164 return m_gdb_client_up->GetOSKernelDescription();
|
150
|
165 }
|
|
166
|
|
167 // Remote Platform subclasses need to override this function
|
|
168 ArchSpec PlatformRemoteGDBServer::GetRemoteSystemArchitecture() {
|
236
|
169 if (!m_gdb_client_up)
|
|
170 return ArchSpec();
|
|
171 return m_gdb_client_up->GetSystemArchitecture();
|
150
|
172 }
|
|
173
|
|
174 FileSpec PlatformRemoteGDBServer::GetRemoteWorkingDirectory() {
|
|
175 if (IsConnected()) {
|
236
|
176 Log *log = GetLog(LLDBLog::Platform);
|
150
|
177 FileSpec working_dir;
|
236
|
178 if (m_gdb_client_up->GetWorkingDir(working_dir) && log)
|
150
|
179 LLDB_LOGF(log,
|
|
180 "PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'",
|
236
|
181 working_dir.GetPath().c_str());
|
150
|
182 return working_dir;
|
|
183 } else {
|
|
184 return Platform::GetRemoteWorkingDirectory();
|
|
185 }
|
|
186 }
|
|
187
|
|
188 bool PlatformRemoteGDBServer::SetRemoteWorkingDirectory(
|
|
189 const FileSpec &working_dir) {
|
|
190 if (IsConnected()) {
|
|
191 // Clear the working directory it case it doesn't get set correctly. This
|
|
192 // will for use to re-read it
|
236
|
193 Log *log = GetLog(LLDBLog::Platform);
|
150
|
194 LLDB_LOGF(log, "PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')",
|
236
|
195 working_dir.GetPath().c_str());
|
|
196 return m_gdb_client_up->SetWorkingDir(working_dir) == 0;
|
150
|
197 } else
|
|
198 return Platform::SetRemoteWorkingDirectory(working_dir);
|
|
199 }
|
|
200
|
|
201 bool PlatformRemoteGDBServer::IsConnected() const {
|
236
|
202 if (m_gdb_client_up) {
|
|
203 assert(m_gdb_client_up->IsConnected());
|
|
204 return true;
|
|
205 }
|
|
206 return false;
|
150
|
207 }
|
|
208
|
|
209 Status PlatformRemoteGDBServer::ConnectRemote(Args &args) {
|
|
210 Status error;
|
|
211 if (IsConnected()) {
|
|
212 error.SetErrorStringWithFormat("the platform is already connected to '%s', "
|
|
213 "execute 'platform disconnect' to close the "
|
|
214 "current connection",
|
|
215 GetHostname());
|
173
|
216 return error;
|
|
217 }
|
|
218
|
|
219 if (args.GetArgumentCount() != 1) {
|
|
220 error.SetErrorString(
|
|
221 "\"platform connect\" takes a single argument: <connect-url>");
|
|
222 return error;
|
|
223 }
|
|
224
|
|
225 const char *url = args.GetArgumentAtIndex(0);
|
|
226 if (!url)
|
|
227 return Status("URL is null.");
|
|
228
|
252
|
229 std::optional<URI> parsed_url = URI::Parse(url);
|
236
|
230 if (!parsed_url)
|
173
|
231 return Status("Invalid URL: %s", url);
|
|
232
|
|
233 // We're going to reuse the hostname when we connect to the debugserver.
|
236
|
234 m_platform_scheme = parsed_url->scheme.str();
|
|
235 m_platform_hostname = parsed_url->hostname.str();
|
150
|
236
|
236
|
237 auto client_up =
|
|
238 std::make_unique<process_gdb_remote::GDBRemoteCommunicationClient>();
|
|
239 client_up->SetPacketTimeout(
|
|
240 process_gdb_remote::ProcessGDBRemote::GetPacketTimeout());
|
|
241 client_up->SetConnection(std::make_unique<ConnectionFileDescriptor>());
|
|
242 client_up->Connect(url, &error);
|
173
|
243
|
|
244 if (error.Fail())
|
|
245 return error;
|
|
246
|
236
|
247 if (client_up->HandshakeWithServer(&error)) {
|
|
248 m_gdb_client_up = std::move(client_up);
|
|
249 m_gdb_client_up->GetHostInfo();
|
173
|
250 // If a working directory was set prior to connecting, send it down
|
|
251 // now.
|
|
252 if (m_working_dir)
|
236
|
253 m_gdb_client_up->SetWorkingDir(m_working_dir);
|
|
254
|
|
255 m_supported_architectures.clear();
|
|
256 ArchSpec remote_arch = m_gdb_client_up->GetSystemArchitecture();
|
|
257 if (remote_arch) {
|
|
258 m_supported_architectures.push_back(remote_arch);
|
|
259 if (remote_arch.GetTriple().isArch64Bit())
|
|
260 m_supported_architectures.push_back(
|
|
261 ArchSpec(remote_arch.GetTriple().get32BitArchVariant()));
|
|
262 }
|
173
|
263 } else {
|
236
|
264 client_up->Disconnect();
|
173
|
265 if (error.Success())
|
|
266 error.SetErrorString("handshake failed");
|
150
|
267 }
|
|
268 return error;
|
|
269 }
|
|
270
|
|
271 Status PlatformRemoteGDBServer::DisconnectRemote() {
|
|
272 Status error;
|
236
|
273 m_gdb_client_up.reset();
|
150
|
274 m_remote_signals_sp.reset();
|
|
275 return error;
|
|
276 }
|
|
277
|
|
278 const char *PlatformRemoteGDBServer::GetHostname() {
|
236
|
279 if (m_gdb_client_up)
|
|
280 m_gdb_client_up->GetHostname(m_hostname);
|
|
281 if (m_hostname.empty())
|
150
|
282 return nullptr;
|
236
|
283 return m_hostname.c_str();
|
150
|
284 }
|
|
285
|
252
|
286 std::optional<std::string>
|
150
|
287 PlatformRemoteGDBServer::DoGetUserName(UserIDResolver::id_t uid) {
|
|
288 std::string name;
|
236
|
289 if (m_gdb_client_up && m_gdb_client_up->GetUserName(uid, name))
|
150
|
290 return std::move(name);
|
252
|
291 return std::nullopt;
|
150
|
292 }
|
|
293
|
252
|
294 std::optional<std::string>
|
150
|
295 PlatformRemoteGDBServer::DoGetGroupName(UserIDResolver::id_t gid) {
|
|
296 std::string name;
|
236
|
297 if (m_gdb_client_up && m_gdb_client_up->GetGroupName(gid, name))
|
150
|
298 return std::move(name);
|
252
|
299 return std::nullopt;
|
150
|
300 }
|
|
301
|
|
302 uint32_t PlatformRemoteGDBServer::FindProcesses(
|
|
303 const ProcessInstanceInfoMatch &match_info,
|
|
304 ProcessInstanceInfoList &process_infos) {
|
236
|
305 if (m_gdb_client_up)
|
|
306 return m_gdb_client_up->FindProcesses(match_info, process_infos);
|
|
307 return 0;
|
150
|
308 }
|
|
309
|
|
310 bool PlatformRemoteGDBServer::GetProcessInfo(
|
|
311 lldb::pid_t pid, ProcessInstanceInfo &process_info) {
|
236
|
312 if (m_gdb_client_up)
|
|
313 return m_gdb_client_up->GetProcessInfo(pid, process_info);
|
|
314 return false;
|
150
|
315 }
|
|
316
|
|
317 Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
|
236
|
318 Log *log = GetLog(LLDBLog::Platform);
|
150
|
319 Status error;
|
|
320
|
|
321 LLDB_LOGF(log, "PlatformRemoteGDBServer::%s() called", __FUNCTION__);
|
|
322
|
236
|
323 if (!IsConnected())
|
|
324 return Status("Not connected.");
|
150
|
325 auto num_file_actions = launch_info.GetNumFileActions();
|
|
326 for (decltype(num_file_actions) i = 0; i < num_file_actions; ++i) {
|
|
327 const auto file_action = launch_info.GetFileActionAtIndex(i);
|
|
328 if (file_action->GetAction() != FileAction::eFileActionOpen)
|
|
329 continue;
|
|
330 switch (file_action->GetFD()) {
|
|
331 case STDIN_FILENO:
|
236
|
332 m_gdb_client_up->SetSTDIN(file_action->GetFileSpec());
|
150
|
333 break;
|
|
334 case STDOUT_FILENO:
|
236
|
335 m_gdb_client_up->SetSTDOUT(file_action->GetFileSpec());
|
150
|
336 break;
|
|
337 case STDERR_FILENO:
|
236
|
338 m_gdb_client_up->SetSTDERR(file_action->GetFileSpec());
|
150
|
339 break;
|
|
340 }
|
|
341 }
|
|
342
|
236
|
343 m_gdb_client_up->SetDisableASLR(
|
150
|
344 launch_info.GetFlags().Test(eLaunchFlagDisableASLR));
|
236
|
345 m_gdb_client_up->SetDetachOnError(
|
150
|
346 launch_info.GetFlags().Test(eLaunchFlagDetachOnError));
|
|
347
|
|
348 FileSpec working_dir = launch_info.GetWorkingDirectory();
|
|
349 if (working_dir) {
|
236
|
350 m_gdb_client_up->SetWorkingDir(working_dir);
|
150
|
351 }
|
|
352
|
|
353 // Send the environment and the program + arguments after we connect
|
236
|
354 m_gdb_client_up->SendEnvironment(launch_info.GetEnvironment());
|
150
|
355
|
|
356 ArchSpec arch_spec = launch_info.GetArchitecture();
|
|
357 const char *arch_triple = arch_spec.GetTriple().str().c_str();
|
|
358
|
236
|
359 m_gdb_client_up->SendLaunchArchPacket(arch_triple);
|
150
|
360 LLDB_LOGF(
|
|
361 log,
|
|
362 "PlatformRemoteGDBServer::%s() set launch architecture triple to '%s'",
|
|
363 __FUNCTION__, arch_triple ? arch_triple : "<NULL>");
|
|
364
|
|
365 {
|
|
366 // Scope for the scoped timeout object
|
|
367 process_gdb_remote::GDBRemoteCommunication::ScopedTimeout timeout(
|
236
|
368 *m_gdb_client_up, std::chrono::seconds(5));
|
|
369 // Since we can't send argv0 separate from the executable path, we need to
|
|
370 // make sure to use the actual executable path found in the launch_info...
|
|
371 Args args = launch_info.GetArguments();
|
|
372 if (FileSpec exe_file = launch_info.GetExecutableFile())
|
|
373 args.ReplaceArgumentAtIndex(0, exe_file.GetPath(false));
|
|
374 if (llvm::Error err = m_gdb_client_up->LaunchProcess(args)) {
|
|
375 error.SetErrorStringWithFormatv("Cannot launch '{0}': {1}",
|
|
376 args.GetArgumentAtIndex(0),
|
|
377 llvm::fmt_consume(std::move(err)));
|
|
378 return error;
|
|
379 }
|
150
|
380 }
|
|
381
|
236
|
382 const auto pid = m_gdb_client_up->GetCurrentProcessID(false);
|
|
383 if (pid != LLDB_INVALID_PROCESS_ID) {
|
|
384 launch_info.SetProcessID(pid);
|
|
385 LLDB_LOGF(log,
|
|
386 "PlatformRemoteGDBServer::%s() pid %" PRIu64
|
|
387 " launched successfully",
|
|
388 __FUNCTION__, pid);
|
150
|
389 } else {
|
236
|
390 LLDB_LOGF(log,
|
|
391 "PlatformRemoteGDBServer::%s() launch succeeded but we "
|
|
392 "didn't get a valid process id back!",
|
|
393 __FUNCTION__);
|
|
394 error.SetErrorString("failed to get PID");
|
150
|
395 }
|
|
396 return error;
|
|
397 }
|
|
398
|
|
399 Status PlatformRemoteGDBServer::KillProcess(const lldb::pid_t pid) {
|
|
400 if (!KillSpawnedProcess(pid))
|
|
401 return Status("failed to kill remote spawned process");
|
|
402 return Status();
|
|
403 }
|
|
404
|
236
|
405 lldb::ProcessSP
|
|
406 PlatformRemoteGDBServer::DebugProcess(ProcessLaunchInfo &launch_info,
|
|
407 Debugger &debugger, Target &target,
|
|
408 Status &error) {
|
150
|
409 lldb::ProcessSP process_sp;
|
|
410 if (IsRemote()) {
|
|
411 if (IsConnected()) {
|
|
412 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
|
|
413 std::string connect_url;
|
|
414 if (!LaunchGDBServer(debugserver_pid, connect_url)) {
|
|
415 error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
|
|
416 GetHostname());
|
|
417 } else {
|
236
|
418 // The darwin always currently uses the GDB remote debugger plug-in
|
|
419 // so even when debugging locally we are debugging remotely!
|
|
420 process_sp = target.CreateProcess(launch_info.GetListener(),
|
|
421 "gdb-remote", nullptr, true);
|
150
|
422
|
236
|
423 if (process_sp) {
|
|
424 process_sp->HijackProcessEvents(launch_info.GetHijackListener());
|
252
|
425 process_sp->SetShadowListener(launch_info.GetShadowListener());
|
150
|
426
|
236
|
427 error = process_sp->ConnectRemote(connect_url.c_str());
|
|
428 // Retry the connect remote one time...
|
|
429 if (error.Fail())
|
221
|
430 error = process_sp->ConnectRemote(connect_url.c_str());
|
236
|
431 if (error.Success())
|
|
432 error = process_sp->Launch(launch_info);
|
|
433 else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) {
|
|
434 printf("error: connect remote failed (%s)\n", error.AsCString());
|
|
435 KillSpawnedProcess(debugserver_pid);
|
150
|
436 }
|
|
437 }
|
|
438 }
|
|
439 } else {
|
|
440 error.SetErrorString("not connected to remote gdb server");
|
|
441 }
|
|
442 }
|
|
443 return process_sp;
|
|
444 }
|
|
445
|
|
446 bool PlatformRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid,
|
|
447 std::string &connect_url) {
|
236
|
448 assert(IsConnected());
|
|
449
|
150
|
450 ArchSpec remote_arch = GetRemoteSystemArchitecture();
|
|
451 llvm::Triple &remote_triple = remote_arch.GetTriple();
|
|
452
|
|
453 uint16_t port = 0;
|
|
454 std::string socket_name;
|
|
455 bool launch_result = false;
|
|
456 if (remote_triple.getVendor() == llvm::Triple::Apple &&
|
|
457 remote_triple.getOS() == llvm::Triple::IOS) {
|
|
458 // When remote debugging to iOS, we use a USB mux that always talks to
|
|
459 // localhost, so we will need the remote debugserver to accept connections
|
|
460 // only from localhost, no matter what our current hostname is
|
|
461 launch_result =
|
236
|
462 m_gdb_client_up->LaunchGDBServer("127.0.0.1", pid, port, socket_name);
|
150
|
463 } else {
|
|
464 // All other hosts should use their actual hostname
|
|
465 launch_result =
|
236
|
466 m_gdb_client_up->LaunchGDBServer(nullptr, pid, port, socket_name);
|
150
|
467 }
|
|
468
|
|
469 if (!launch_result)
|
|
470 return false;
|
|
471
|
|
472 connect_url =
|
|
473 MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port,
|
|
474 (socket_name.empty()) ? nullptr : socket_name.c_str());
|
|
475 return true;
|
|
476 }
|
|
477
|
|
478 bool PlatformRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) {
|
236
|
479 assert(IsConnected());
|
|
480 return m_gdb_client_up->KillSpawnedProcess(pid);
|
150
|
481 }
|
|
482
|
|
483 lldb::ProcessSP PlatformRemoteGDBServer::Attach(
|
|
484 ProcessAttachInfo &attach_info, Debugger &debugger,
|
|
485 Target *target, // Can be NULL, if NULL create a new target, else use
|
|
486 // existing one
|
|
487 Status &error) {
|
|
488 lldb::ProcessSP process_sp;
|
|
489 if (IsRemote()) {
|
|
490 if (IsConnected()) {
|
|
491 lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
|
|
492 std::string connect_url;
|
|
493 if (!LaunchGDBServer(debugserver_pid, connect_url)) {
|
|
494 error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
|
|
495 GetHostname());
|
|
496 } else {
|
|
497 if (target == nullptr) {
|
|
498 TargetSP new_target_sp;
|
|
499
|
|
500 error = debugger.GetTargetList().CreateTarget(
|
|
501 debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
|
|
502 target = new_target_sp.get();
|
|
503 } else
|
|
504 error.Clear();
|
|
505
|
|
506 if (target && error.Success()) {
|
|
507 // The darwin always currently uses the GDB remote debugger plug-in
|
|
508 // so even when debugging locally we are debugging remotely!
|
|
509 process_sp =
|
|
510 target->CreateProcess(attach_info.GetListenerForProcess(debugger),
|
221
|
511 "gdb-remote", nullptr, true);
|
150
|
512 if (process_sp) {
|
221
|
513 error = process_sp->ConnectRemote(connect_url.c_str());
|
150
|
514 if (error.Success()) {
|
|
515 ListenerSP listener_sp = attach_info.GetHijackListener();
|
|
516 if (listener_sp)
|
|
517 process_sp->HijackProcessEvents(listener_sp);
|
252
|
518 process_sp->SetShadowListener(attach_info.GetShadowListener());
|
150
|
519 error = process_sp->Attach(attach_info);
|
|
520 }
|
|
521
|
|
522 if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) {
|
|
523 KillSpawnedProcess(debugserver_pid);
|
|
524 }
|
|
525 }
|
|
526 }
|
|
527 }
|
|
528 } else {
|
|
529 error.SetErrorString("not connected to remote gdb server");
|
|
530 }
|
|
531 }
|
|
532 return process_sp;
|
|
533 }
|
|
534
|
|
535 Status PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec,
|
|
536 uint32_t mode) {
|
236
|
537 if (!IsConnected())
|
|
538 return Status("Not connected.");
|
|
539 Status error = m_gdb_client_up->MakeDirectory(file_spec, mode);
|
|
540 Log *log = GetLog(LLDBLog::Platform);
|
150
|
541 LLDB_LOGF(log,
|
|
542 "PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) "
|
|
543 "error = %u (%s)",
|
236
|
544 file_spec.GetPath().c_str(), mode, error.GetError(),
|
|
545 error.AsCString());
|
150
|
546 return error;
|
|
547 }
|
|
548
|
|
549 Status PlatformRemoteGDBServer::GetFilePermissions(const FileSpec &file_spec,
|
|
550 uint32_t &file_permissions) {
|
236
|
551 if (!IsConnected())
|
|
552 return Status("Not connected.");
|
|
553 Status error =
|
|
554 m_gdb_client_up->GetFilePermissions(file_spec, file_permissions);
|
|
555 Log *log = GetLog(LLDBLog::Platform);
|
150
|
556 LLDB_LOGF(log,
|
|
557 "PlatformRemoteGDBServer::GetFilePermissions(path='%s', "
|
|
558 "file_permissions=%o) error = %u (%s)",
|
236
|
559 file_spec.GetPath().c_str(), file_permissions, error.GetError(),
|
150
|
560 error.AsCString());
|
|
561 return error;
|
|
562 }
|
|
563
|
|
564 Status PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
|
|
565 uint32_t file_permissions) {
|
236
|
566 if (!IsConnected())
|
|
567 return Status("Not connected.");
|
|
568 Status error =
|
|
569 m_gdb_client_up->SetFilePermissions(file_spec, file_permissions);
|
|
570 Log *log = GetLog(LLDBLog::Platform);
|
150
|
571 LLDB_LOGF(log,
|
|
572 "PlatformRemoteGDBServer::SetFilePermissions(path='%s', "
|
|
573 "file_permissions=%o) error = %u (%s)",
|
236
|
574 file_spec.GetPath().c_str(), file_permissions, error.GetError(),
|
150
|
575 error.AsCString());
|
|
576 return error;
|
|
577 }
|
|
578
|
|
579 lldb::user_id_t PlatformRemoteGDBServer::OpenFile(const FileSpec &file_spec,
|
|
580 File::OpenOptions flags,
|
|
581 uint32_t mode,
|
|
582 Status &error) {
|
236
|
583 if (IsConnected())
|
|
584 return m_gdb_client_up->OpenFile(file_spec, flags, mode, error);
|
|
585 return LLDB_INVALID_UID;
|
150
|
586 }
|
|
587
|
|
588 bool PlatformRemoteGDBServer::CloseFile(lldb::user_id_t fd, Status &error) {
|
236
|
589 if (IsConnected())
|
|
590 return m_gdb_client_up->CloseFile(fd, error);
|
|
591 error = Status("Not connected.");
|
|
592 return false;
|
150
|
593 }
|
|
594
|
|
595 lldb::user_id_t
|
|
596 PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) {
|
236
|
597 if (IsConnected())
|
|
598 return m_gdb_client_up->GetFileSize(file_spec);
|
|
599 return LLDB_INVALID_UID;
|
150
|
600 }
|
|
601
|
221
|
602 void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory(
|
|
603 CompletionRequest &request, bool only_dir) {
|
236
|
604 if (IsConnected())
|
|
605 m_gdb_client_up->AutoCompleteDiskFileOrDirectory(request, only_dir);
|
221
|
606 }
|
|
607
|
150
|
608 uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset,
|
|
609 void *dst, uint64_t dst_len,
|
|
610 Status &error) {
|
236
|
611 if (IsConnected())
|
|
612 return m_gdb_client_up->ReadFile(fd, offset, dst, dst_len, error);
|
|
613 error = Status("Not connected.");
|
|
614 return 0;
|
150
|
615 }
|
|
616
|
|
617 uint64_t PlatformRemoteGDBServer::WriteFile(lldb::user_id_t fd, uint64_t offset,
|
|
618 const void *src, uint64_t src_len,
|
|
619 Status &error) {
|
236
|
620 if (IsConnected())
|
|
621 return m_gdb_client_up->WriteFile(fd, offset, src, src_len, error);
|
|
622 error = Status("Not connected.");
|
|
623 return 0;
|
150
|
624 }
|
|
625
|
|
626 Status PlatformRemoteGDBServer::PutFile(const FileSpec &source,
|
|
627 const FileSpec &destination,
|
|
628 uint32_t uid, uint32_t gid) {
|
|
629 return Platform::PutFile(source, destination, uid, gid);
|
|
630 }
|
|
631
|
|
632 Status PlatformRemoteGDBServer::CreateSymlink(
|
|
633 const FileSpec &src, // The name of the link is in src
|
|
634 const FileSpec &dst) // The symlink points to dst
|
|
635 {
|
236
|
636 if (!IsConnected())
|
|
637 return Status("Not connected.");
|
|
638 Status error = m_gdb_client_up->CreateSymlink(src, dst);
|
|
639 Log *log = GetLog(LLDBLog::Platform);
|
150
|
640 LLDB_LOGF(log,
|
|
641 "PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') "
|
|
642 "error = %u (%s)",
|
236
|
643 src.GetPath().c_str(), dst.GetPath().c_str(), error.GetError(),
|
150
|
644 error.AsCString());
|
|
645 return error;
|
|
646 }
|
|
647
|
|
648 Status PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) {
|
236
|
649 if (!IsConnected())
|
|
650 return Status("Not connected.");
|
|
651 Status error = m_gdb_client_up->Unlink(file_spec);
|
|
652 Log *log = GetLog(LLDBLog::Platform);
|
150
|
653 LLDB_LOGF(log, "PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)",
|
236
|
654 file_spec.GetPath().c_str(), error.GetError(), error.AsCString());
|
150
|
655 return error;
|
|
656 }
|
|
657
|
|
658 bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) {
|
236
|
659 if (IsConnected())
|
|
660 return m_gdb_client_up->GetFileExists(file_spec);
|
|
661 return false;
|
150
|
662 }
|
|
663
|
|
664 Status PlatformRemoteGDBServer::RunShellCommand(
|
221
|
665 llvm::StringRef shell, llvm::StringRef command,
|
150
|
666 const FileSpec &
|
|
667 working_dir, // Pass empty FileSpec to use the current working directory
|
|
668 int *status_ptr, // Pass NULL if you don't want the process exit status
|
|
669 int *signo_ptr, // Pass NULL if you don't want the signal that caused the
|
|
670 // process to exit
|
|
671 std::string
|
|
672 *command_output, // Pass NULL if you don't want the command output
|
|
673 const Timeout<std::micro> &timeout) {
|
236
|
674 if (!IsConnected())
|
|
675 return Status("Not connected.");
|
|
676 return m_gdb_client_up->RunShellCommand(command, working_dir, status_ptr,
|
|
677 signo_ptr, command_output, timeout);
|
150
|
678 }
|
|
679
|
|
680 void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() {
|
|
681 m_trap_handlers.push_back(ConstString("_sigtramp"));
|
|
682 }
|
|
683
|
|
684 const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() {
|
|
685 if (!IsConnected())
|
|
686 return Platform::GetRemoteUnixSignals();
|
|
687
|
|
688 if (m_remote_signals_sp)
|
|
689 return m_remote_signals_sp;
|
|
690
|
|
691 // If packet not implemented or JSON failed to parse, we'll guess the signal
|
|
692 // set based on the remote architecture.
|
|
693 m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture());
|
|
694
|
|
695 StringExtractorGDBRemote response;
|
223
|
696 auto result =
|
236
|
697 m_gdb_client_up->SendPacketAndWaitForResponse("jSignalsInfo", response);
|
150
|
698
|
|
699 if (result != decltype(result)::Success ||
|
|
700 response.GetResponseType() != response.eResponse)
|
|
701 return m_remote_signals_sp;
|
|
702
|
252
|
703 auto object_sp = StructuredData::ParseJSON(response.GetStringRef());
|
150
|
704 if (!object_sp || !object_sp->IsValid())
|
|
705 return m_remote_signals_sp;
|
|
706
|
|
707 auto array_sp = object_sp->GetAsArray();
|
|
708 if (!array_sp || !array_sp->IsValid())
|
|
709 return m_remote_signals_sp;
|
|
710
|
|
711 auto remote_signals_sp = std::make_shared<lldb_private::GDBRemoteSignals>();
|
|
712
|
|
713 bool done = array_sp->ForEach(
|
|
714 [&remote_signals_sp](StructuredData::Object *object) -> bool {
|
|
715 if (!object || !object->IsValid())
|
|
716 return false;
|
|
717
|
|
718 auto dict = object->GetAsDictionary();
|
|
719 if (!dict || !dict->IsValid())
|
|
720 return false;
|
|
721
|
|
722 // Signal number and signal name are required.
|
252
|
723 uint64_t signo;
|
150
|
724 if (!dict->GetValueForKeyAsInteger("signo", signo))
|
|
725 return false;
|
|
726
|
|
727 llvm::StringRef name;
|
|
728 if (!dict->GetValueForKeyAsString("name", name))
|
|
729 return false;
|
|
730
|
|
731 // We can live without short_name, description, etc.
|
|
732 bool suppress{false};
|
|
733 auto object_sp = dict->GetValueForKey("suppress");
|
|
734 if (object_sp && object_sp->IsValid())
|
|
735 suppress = object_sp->GetBooleanValue();
|
|
736
|
|
737 bool stop{false};
|
|
738 object_sp = dict->GetValueForKey("stop");
|
|
739 if (object_sp && object_sp->IsValid())
|
|
740 stop = object_sp->GetBooleanValue();
|
|
741
|
|
742 bool notify{false};
|
|
743 object_sp = dict->GetValueForKey("notify");
|
|
744 if (object_sp && object_sp->IsValid())
|
|
745 notify = object_sp->GetBooleanValue();
|
|
746
|
236
|
747 std::string description;
|
150
|
748 object_sp = dict->GetValueForKey("description");
|
|
749 if (object_sp && object_sp->IsValid())
|
|
750 description = std::string(object_sp->GetStringValue());
|
|
751
|
|
752 remote_signals_sp->AddSignal(signo, name.str().c_str(), suppress, stop,
|
|
753 notify, description.c_str());
|
|
754 return true;
|
|
755 });
|
|
756
|
|
757 if (done)
|
|
758 m_remote_signals_sp = std::move(remote_signals_sp);
|
|
759
|
|
760 return m_remote_signals_sp;
|
|
761 }
|
|
762
|
|
763 std::string PlatformRemoteGDBServer::MakeGdbServerUrl(
|
|
764 const std::string &platform_scheme, const std::string &platform_hostname,
|
|
765 uint16_t port, const char *socket_name) {
|
|
766 const char *override_scheme =
|
|
767 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_SCHEME");
|
|
768 const char *override_hostname =
|
|
769 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
|
|
770 const char *port_offset_c_str =
|
|
771 getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
|
|
772 int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
|
|
773
|
|
774 return MakeUrl(override_scheme ? override_scheme : platform_scheme.c_str(),
|
|
775 override_hostname ? override_hostname
|
|
776 : platform_hostname.c_str(),
|
|
777 port + port_offset, socket_name);
|
|
778 }
|
|
779
|
|
780 std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme,
|
|
781 const char *hostname,
|
|
782 uint16_t port, const char *path) {
|
|
783 StreamString result;
|
221
|
784 result.Printf("%s://[%s]", scheme, hostname);
|
150
|
785 if (port != 0)
|
|
786 result.Printf(":%u", port);
|
|
787 if (path)
|
|
788 result.Write(path, strlen(path));
|
|
789 return std::string(result.GetString());
|
|
790 }
|
|
791
|
|
792 size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger,
|
|
793 Status &error) {
|
|
794 std::vector<std::string> connection_urls;
|
|
795 GetPendingGdbServerList(connection_urls);
|
|
796
|
|
797 for (size_t i = 0; i < connection_urls.size(); ++i) {
|
221
|
798 ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error);
|
150
|
799 if (error.Fail())
|
236
|
800 return i; // We already connected to i process successfully
|
150
|
801 }
|
|
802 return connection_urls.size();
|
|
803 }
|
|
804
|
|
805 size_t PlatformRemoteGDBServer::GetPendingGdbServerList(
|
|
806 std::vector<std::string> &connection_urls) {
|
|
807 std::vector<std::pair<uint16_t, std::string>> remote_servers;
|
236
|
808 if (!IsConnected())
|
|
809 return 0;
|
|
810 m_gdb_client_up->QueryGDBServer(remote_servers);
|
150
|
811 for (const auto &gdbserver : remote_servers) {
|
|
812 const char *socket_name_cstr =
|
|
813 gdbserver.second.empty() ? nullptr : gdbserver.second.c_str();
|
|
814 connection_urls.emplace_back(
|
|
815 MakeGdbServerUrl(m_platform_scheme, m_platform_hostname,
|
|
816 gdbserver.first, socket_name_cstr));
|
|
817 }
|
|
818 return connection_urls.size();
|
|
819 }
|