]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp
Import mandoc snapshot 2017-06-08
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / Platform / NetBSD / PlatformNetBSD.cpp
1 //===-- PlatformNetBSD.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "PlatformNetBSD.h"
11 #include "lldb/Host/Config.h"
12
13 // C Includes
14 #include <stdio.h>
15 #ifndef LLDB_DISABLE_POSIX
16 #include <sys/utsname.h>
17 #endif
18
19 // C++ Includes
20 // Other libraries and framework includes
21 // Project includes
22 #include "lldb/Breakpoint/BreakpointLocation.h"
23 #include "lldb/Breakpoint/BreakpointSite.h"
24 #include "lldb/Core/Debugger.h"
25 #include "lldb/Core/Error.h"
26 #include "lldb/Core/Module.h"
27 #include "lldb/Core/ModuleSpec.h"
28 #include "lldb/Core/PluginManager.h"
29 #include "lldb/Host/Host.h"
30 #include "lldb/Host/HostInfo.h"
31 #include "lldb/Target/Process.h"
32
33 using namespace lldb;
34 using namespace lldb_private;
35 using namespace lldb_private::platform_netbsd;
36
37 PlatformSP PlatformNetBSD::CreateInstance(bool force, const ArchSpec *arch) {
38   // The only time we create an instance is when we are creating a remote
39   // netbsd platform
40   const bool is_host = false;
41
42   bool create = force;
43   if (create == false && arch && arch->IsValid()) {
44     const llvm::Triple &triple = arch->GetTriple();
45     switch (triple.getOS()) {
46     case llvm::Triple::NetBSD:
47       create = true;
48       break;
49
50     default:
51       break;
52     }
53   }
54   if (create)
55     return PlatformSP(new PlatformNetBSD(is_host));
56   return PlatformSP();
57 }
58
59 ConstString PlatformNetBSD::GetPluginNameStatic(bool is_host) {
60   if (is_host) {
61     static ConstString g_host_name(Platform::GetHostPlatformName());
62     return g_host_name;
63   } else {
64     static ConstString g_remote_name("remote-netbsd");
65     return g_remote_name;
66   }
67 }
68
69 const char *PlatformNetBSD::GetDescriptionStatic(bool is_host) {
70   if (is_host)
71     return "Local NetBSD user platform plug-in.";
72   else
73     return "Remote NetBSD user platform plug-in.";
74 }
75
76 static uint32_t g_initialize_count = 0;
77
78 void PlatformNetBSD::Initialize() {
79   Platform::Initialize();
80
81   if (g_initialize_count++ == 0) {
82 #if defined(__NetBSD__)
83     // Force a host flag to true for the default platform object.
84     PlatformSP default_platform_sp(new PlatformNetBSD(true));
85     default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
86     Platform::SetHostPlatform(default_platform_sp);
87 #endif
88     PluginManager::RegisterPlugin(PlatformNetBSD::GetPluginNameStatic(false),
89                                   PlatformNetBSD::GetDescriptionStatic(false),
90                                   PlatformNetBSD::CreateInstance);
91   }
92 }
93
94 void PlatformNetBSD::Terminate() {
95   if (g_initialize_count > 0 && --g_initialize_count == 0)
96     PluginManager::UnregisterPlugin(PlatformNetBSD::CreateInstance);
97
98   Platform::Terminate();
99 }
100
101 bool PlatformNetBSD::GetModuleSpec(const FileSpec &module_file_spec,
102                                    const ArchSpec &arch,
103                                    ModuleSpec &module_spec) {
104   if (m_remote_platform_sp)
105     return m_remote_platform_sp->GetModuleSpec(module_file_spec, arch,
106                                                module_spec);
107
108   return Platform::GetModuleSpec(module_file_spec, arch, module_spec);
109 }
110
111 Error PlatformNetBSD::RunShellCommand(const char *command,
112                                       const FileSpec &working_dir,
113                                       int *status_ptr, int *signo_ptr,
114                                       std::string *command_output,
115                                       uint32_t timeout_sec) {
116   if (IsHost())
117     return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr,
118                                  command_output, timeout_sec);
119   else {
120     if (m_remote_platform_sp)
121       return m_remote_platform_sp->RunShellCommand(command, working_dir,
122                                                    status_ptr, signo_ptr,
123                                                    command_output, timeout_sec);
124     else
125       return Error("unable to run a remote command without a platform");
126   }
127 }
128
129 Error PlatformNetBSD::ResolveExecutable(
130     const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
131     const FileSpecList *module_search_paths_ptr) {
132   Error error;
133   // Nothing special to do here, just use the actual file and architecture
134
135   char exe_path[PATH_MAX];
136   ModuleSpec resolved_module_spec(module_spec);
137
138   if (IsHost()) {
139     // If we have "ls" as the module_spec's file, resolve the executable
140     // location based on
141     // the current path variables
142     if (!resolved_module_spec.GetFileSpec().Exists()) {
143       module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path));
144       resolved_module_spec.GetFileSpec().SetFile(exe_path, true);
145     }
146
147     if (!resolved_module_spec.GetFileSpec().Exists())
148       resolved_module_spec.GetFileSpec().ResolveExecutableLocation();
149
150     if (resolved_module_spec.GetFileSpec().Exists())
151       error.Clear();
152     else {
153       error.SetErrorStringWithFormat(
154           "unable to find executable for '%s'",
155           resolved_module_spec.GetFileSpec().GetPath().c_str());
156     }
157   } else {
158     if (m_remote_platform_sp) {
159       error =
160           GetCachedExecutable(resolved_module_spec, exe_module_sp,
161                               module_search_paths_ptr, *m_remote_platform_sp);
162     } else {
163       // We may connect to a process and use the provided executable (Don't use
164       // local $PATH).
165
166       // Resolve any executable within a bundle on MacOSX
167       Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
168
169       if (resolved_module_spec.GetFileSpec().Exists()) {
170         error.Clear();
171       } else {
172         error.SetErrorStringWithFormat(
173             "the platform is not currently connected, and '%s' doesn't exist "
174             "in the system root.",
175             resolved_module_spec.GetFileSpec().GetPath().c_str());
176       }
177     }
178   }
179
180   if (error.Success()) {
181     if (resolved_module_spec.GetArchitecture().IsValid()) {
182       error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
183                                           module_search_paths_ptr, NULL, NULL);
184
185       if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) {
186         exe_module_sp.reset();
187         error.SetErrorStringWithFormat(
188             "'%s' doesn't contain the architecture %s",
189             resolved_module_spec.GetFileSpec().GetPath().c_str(),
190             resolved_module_spec.GetArchitecture().GetArchitectureName());
191       }
192     } else {
193       // No valid architecture was specified, ask the platform for
194       // the architectures that we should be using (in the correct order)
195       // and see if we can find a match that way
196       StreamString arch_names;
197       for (uint32_t idx = 0; GetSupportedArchitectureAtIndex(
198                idx, resolved_module_spec.GetArchitecture());
199            ++idx) {
200         error =
201             ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
202                                         module_search_paths_ptr, NULL, NULL);
203         // Did we find an executable using one of the
204         if (error.Success()) {
205           if (exe_module_sp && exe_module_sp->GetObjectFile())
206             break;
207           else
208             error.SetErrorToGenericError();
209         }
210
211         if (idx > 0)
212           arch_names.PutCString(", ");
213         arch_names.PutCString(
214             resolved_module_spec.GetArchitecture().GetArchitectureName());
215       }
216
217       if (error.Fail() || !exe_module_sp) {
218         if (resolved_module_spec.GetFileSpec().Readable()) {
219           error.SetErrorStringWithFormat(
220               "'%s' doesn't contain any '%s' platform architectures: %s",
221               resolved_module_spec.GetFileSpec().GetPath().c_str(),
222               GetPluginName().GetCString(), arch_names.GetData());
223         } else {
224           error.SetErrorStringWithFormat(
225               "'%s' is not readable",
226               resolved_module_spec.GetFileSpec().GetPath().c_str());
227         }
228       }
229     }
230   }
231
232   return error;
233 }
234
235 // From PlatformMacOSX only
236 Error PlatformNetBSD::GetFileWithUUID(const FileSpec &platform_file,
237                                       const UUID *uuid_ptr,
238                                       FileSpec &local_file) {
239   if (IsRemote()) {
240     if (m_remote_platform_sp)
241       return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
242                                                    local_file);
243   }
244
245   // Default to the local case
246   local_file = platform_file;
247   return Error();
248 }
249
250 //------------------------------------------------------------------
251 /// Default Constructor
252 //------------------------------------------------------------------
253 PlatformNetBSD::PlatformNetBSD(bool is_host)
254     : Platform(is_host), m_remote_platform_sp() {}
255
256 bool PlatformNetBSD::GetRemoteOSVersion() {
257   if (m_remote_platform_sp)
258     return m_remote_platform_sp->GetOSVersion(
259         m_major_os_version, m_minor_os_version, m_update_os_version);
260   return false;
261 }
262
263 bool PlatformNetBSD::GetRemoteOSBuildString(std::string &s) {
264   if (m_remote_platform_sp)
265     return m_remote_platform_sp->GetRemoteOSBuildString(s);
266   s.clear();
267   return false;
268 }
269
270 bool PlatformNetBSD::GetRemoteOSKernelDescription(std::string &s) {
271   if (m_remote_platform_sp)
272     return m_remote_platform_sp->GetRemoteOSKernelDescription(s);
273   s.clear();
274   return false;
275 }
276
277 // Remote Platform subclasses need to override this function
278 ArchSpec PlatformNetBSD::GetRemoteSystemArchitecture() {
279   if (m_remote_platform_sp)
280     return m_remote_platform_sp->GetRemoteSystemArchitecture();
281   return ArchSpec();
282 }
283
284 const char *PlatformNetBSD::GetHostname() {
285   if (IsHost())
286     return Platform::GetHostname();
287
288   if (m_remote_platform_sp)
289     return m_remote_platform_sp->GetHostname();
290   return NULL;
291 }
292
293 bool PlatformNetBSD::IsConnected() const {
294   if (IsHost())
295     return true;
296   else if (m_remote_platform_sp)
297     return m_remote_platform_sp->IsConnected();
298   return false;
299 }
300
301 Error PlatformNetBSD::ConnectRemote(Args &args) {
302   Error error;
303   if (IsHost()) {
304     error.SetErrorStringWithFormat(
305         "can't connect to the host platform '%s', always connected",
306         GetPluginName().GetCString());
307   } else {
308     if (!m_remote_platform_sp)
309       m_remote_platform_sp =
310           Platform::Create(ConstString("remote-gdb-server"), error);
311
312     if (m_remote_platform_sp) {
313       if (error.Success()) {
314         if (m_remote_platform_sp) {
315           error = m_remote_platform_sp->ConnectRemote(args);
316         } else {
317           error.SetErrorString(
318               "\"platform connect\" takes a single argument: <connect-url>");
319         }
320       }
321     } else
322       error.SetErrorString("failed to create a 'remote-gdb-server' platform");
323
324     if (error.Fail())
325       m_remote_platform_sp.reset();
326   }
327
328   return error;
329 }
330
331 Error PlatformNetBSD::DisconnectRemote() {
332   Error error;
333
334   if (IsHost()) {
335     error.SetErrorStringWithFormat(
336         "can't disconnect from the host platform '%s', always connected",
337         GetPluginName().GetCString());
338   } else {
339     if (m_remote_platform_sp)
340       error = m_remote_platform_sp->DisconnectRemote();
341     else
342       error.SetErrorString("the platform is not currently connected");
343   }
344   return error;
345 }
346
347 bool PlatformNetBSD::GetProcessInfo(lldb::pid_t pid,
348                                     ProcessInstanceInfo &process_info) {
349   bool success = false;
350   if (IsHost()) {
351     success = Platform::GetProcessInfo(pid, process_info);
352   } else if (m_remote_platform_sp) {
353     success = m_remote_platform_sp->GetProcessInfo(pid, process_info);
354   }
355   return success;
356 }
357
358 uint32_t
359 PlatformNetBSD::FindProcesses(const ProcessInstanceInfoMatch &match_info,
360                               ProcessInstanceInfoList &process_infos) {
361   uint32_t match_count = 0;
362   if (IsHost()) {
363     // Let the base class figure out the host details
364     match_count = Platform::FindProcesses(match_info, process_infos);
365   } else {
366     // If we are remote, we can only return results if we are connected
367     if (m_remote_platform_sp)
368       match_count =
369           m_remote_platform_sp->FindProcesses(match_info, process_infos);
370   }
371   return match_count;
372 }
373
374 const char *PlatformNetBSD::GetUserName(uint32_t uid) {
375   // Check the cache in Platform in case we have already looked this uid up
376   const char *user_name = Platform::GetUserName(uid);
377   if (user_name)
378     return user_name;
379
380   if (IsRemote() && m_remote_platform_sp)
381     return m_remote_platform_sp->GetUserName(uid);
382   return NULL;
383 }
384
385 const char *PlatformNetBSD::GetGroupName(uint32_t gid) {
386   const char *group_name = Platform::GetGroupName(gid);
387   if (group_name)
388     return group_name;
389
390   if (IsRemote() && m_remote_platform_sp)
391     return m_remote_platform_sp->GetGroupName(gid);
392   return NULL;
393 }
394
395 Error PlatformNetBSD::GetSharedModule(
396     const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
397     const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr,
398     bool *did_create_ptr) {
399   Error error;
400   module_sp.reset();
401
402   if (IsRemote()) {
403     // If we have a remote platform always, let it try and locate
404     // the shared module first.
405     if (m_remote_platform_sp) {
406       error = m_remote_platform_sp->GetSharedModule(
407           module_spec, process, module_sp, module_search_paths_ptr,
408           old_module_sp_ptr, did_create_ptr);
409     }
410   }
411
412   if (!module_sp) {
413     // Fall back to the local platform and find the file locally
414     error = Platform::GetSharedModule(module_spec, process, module_sp,
415                                       module_search_paths_ptr,
416                                       old_module_sp_ptr, did_create_ptr);
417   }
418   if (module_sp)
419     module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
420   return error;
421 }
422
423 bool PlatformNetBSD::GetSupportedArchitectureAtIndex(uint32_t idx,
424                                                      ArchSpec &arch) {
425   if (IsHost()) {
426     ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
427     if (hostArch.GetTriple().isOSNetBSD()) {
428       if (idx == 0) {
429         arch = hostArch;
430         return arch.IsValid();
431       } else if (idx == 1) {
432         // If the default host architecture is 64-bit, look for a 32-bit variant
433         if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit()) {
434           arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
435           return arch.IsValid();
436         }
437       }
438     }
439   } else {
440     if (m_remote_platform_sp)
441       return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch);
442
443     llvm::Triple triple;
444     // Set the OS to NetBSD
445     triple.setOS(llvm::Triple::NetBSD);
446     // Set the architecture
447     switch (idx) {
448     case 0:
449       triple.setArchName("x86_64");
450       break;
451     case 1:
452       triple.setArchName("i386");
453       break;
454     default:
455       return false;
456     }
457     // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the
458     // vendor by
459     // calling triple.SetVendorName("unknown") so that it is a "unspecified
460     // unknown".
461     // This means when someone calls triple.GetVendorName() it will return an
462     // empty string
463     // which indicates that the vendor can be set when two architectures are
464     // merged
465
466     // Now set the triple into "arch" and return true
467     arch.SetTriple(triple);
468     return true;
469   }
470   return false;
471 }
472
473 void PlatformNetBSD::GetStatus(Stream &strm) {
474 #ifndef LLDB_DISABLE_POSIX
475   struct ::utsname un;
476
477   strm << "      Host: ";
478
479   ::memset(&un, 0, sizeof(utsname));
480   if (::uname(&un) == -1) {
481     strm << "NetBSD" << '\n';
482   } else {
483     strm << un.sysname << ' ' << un.release;
484     if (un.nodename[0] != '\0')
485       strm << " (" << un.nodename << ')';
486     strm << '\n';
487
488     // Dump a common information about the platform status.
489     strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version
490          << '\n';
491   }
492 #endif
493
494   Platform::GetStatus(strm);
495 }
496
497 void PlatformNetBSD::CalculateTrapHandlerSymbolNames() {
498   m_trap_handlers.push_back(ConstString("_sigtramp"));
499 }
500
501 Error PlatformNetBSD::LaunchProcess(ProcessLaunchInfo &launch_info) {
502   Error error;
503   if (IsHost()) {
504     error = Platform::LaunchProcess(launch_info);
505   } else {
506     if (m_remote_platform_sp)
507       error = m_remote_platform_sp->LaunchProcess(launch_info);
508     else
509       error.SetErrorString("the platform is not currently connected");
510   }
511   return error;
512 }
513
514 lldb::ProcessSP PlatformNetBSD::Attach(ProcessAttachInfo &attach_info,
515                                        Debugger &debugger, Target *target,
516                                        Error &error) {
517   lldb::ProcessSP process_sp;
518   if (IsHost()) {
519     if (target == NULL) {
520       TargetSP new_target_sp;
521       ArchSpec emptyArchSpec;
522
523       error = debugger.GetTargetList().CreateTarget(debugger, "", emptyArchSpec,
524                                                     false, m_remote_platform_sp,
525                                                     new_target_sp);
526       target = new_target_sp.get();
527     } else
528       error.Clear();
529
530     if (target && error.Success()) {
531       debugger.GetTargetList().SetSelectedTarget(target);
532       // The netbsd always currently uses the GDB remote debugger plug-in
533       // so even when debugging locally we are debugging remotely!
534       // Just like the darwin plugin.
535       process_sp = target->CreateProcess(
536           attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
537
538       if (process_sp)
539         error = process_sp->Attach(attach_info);
540     }
541   } else {
542     if (m_remote_platform_sp)
543       process_sp =
544           m_remote_platform_sp->Attach(attach_info, debugger, target, error);
545     else
546       error.SetErrorString("the platform is not currently connected");
547   }
548   return process_sp;
549 }