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