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