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