Home | History | Annotate | Download | only in FreeBSD
      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 *
     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
     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 *
    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
    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
    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 //------------------------------------------------------------------
    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 //------------------------------------------------------------------
    152 PlatformFreeBSD::~PlatformFreeBSD()
    153 {
    154 }
    155 
    156 
    157 Error
    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
    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
    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
    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
    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
    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 *
    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
    362 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
    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
    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
    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
    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
    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
    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 *
    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 *
    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
    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
    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
    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
    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