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