Home | History | Annotate | Download | only in Linux
      1 //===-- PlatformLinux.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 "PlatformLinux.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/ModuleList.h"
     25 #include "lldb/Core/ModuleSpec.h"
     26 #include "lldb/Core/PluginManager.h"
     27 #include "lldb/Core/StreamString.h"
     28 #include "lldb/Host/FileSpec.h"
     29 #include "lldb/Host/Host.h"
     30 #include "lldb/Target/Target.h"
     31 #include "lldb/Target/Process.h"
     32 
     33 using namespace lldb;
     34 using namespace lldb_private;
     35 
     36 static uint32_t g_initialize_count = 0;
     37 
     38 Platform *
     39 PlatformLinux::CreateInstance (bool force, const ArchSpec *arch)
     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(__linux__)
     52             // Only accept "unknown" for the vendor if the host is linux 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::Linux:
     68                     break;
     69 
     70 #if defined(__linux__)
     71                 // Only accept "unknown" for the OS if the host is linux and
     72                 // it "unknown" wasn't specified (it was just returned becasue it
     73                 // was NOT specified)
     74                 case llvm::Triple::UnknownOS:
     75                     create = !arch->TripleOSWasSpecified();
     76                     break;
     77 #endif
     78                 default:
     79                     create = false;
     80                     break;
     81             }
     82         }
     83     }
     84     if (create)
     85         return new PlatformLinux(true);
     86     return NULL;
     87 }
     88 
     89 
     90 lldb_private::ConstString
     91 PlatformLinux::GetPluginNameStatic (bool is_host)
     92 {
     93     if (is_host)
     94     {
     95         static ConstString g_host_name(Platform::GetHostPlatformName ());
     96         return g_host_name;
     97     }
     98     else
     99     {
    100         static ConstString g_remote_name("remote-linux");
    101         return g_remote_name;
    102     }
    103 }
    104 
    105 const char *
    106 PlatformLinux::GetPluginDescriptionStatic (bool is_host)
    107 {
    108     if (is_host)
    109         return "Local Linux user platform plug-in.";
    110     else
    111         return "Remote Linux user platform plug-in.";
    112 }
    113 
    114 lldb_private::ConstString
    115 PlatformLinux::GetPluginName()
    116 {
    117     return GetPluginNameStatic(IsHost());
    118 }
    119 
    120 void
    121 PlatformLinux::Initialize ()
    122 {
    123     if (g_initialize_count++ == 0)
    124     {
    125 #if defined(__linux__)
    126         PlatformSP default_platform_sp (new PlatformLinux(true));
    127         default_platform_sp->SetSystemArchitecture (Host::GetArchitecture());
    128         Platform::SetDefaultPlatform (default_platform_sp);
    129 #endif
    130         PluginManager::RegisterPlugin(PlatformLinux::GetPluginNameStatic(false),
    131                                       PlatformLinux::GetPluginDescriptionStatic(false),
    132                                       PlatformLinux::CreateInstance);
    133     }
    134 }
    135 
    136 void
    137 PlatformLinux::Terminate ()
    138 {
    139     if (g_initialize_count > 0)
    140     {
    141         if (--g_initialize_count == 0)
    142         {
    143             PluginManager::UnregisterPlugin (PlatformLinux::CreateInstance);
    144         }
    145     }
    146 }
    147 
    148 Error
    149 PlatformLinux::ResolveExecutable (const FileSpec &exe_file,
    150                                   const ArchSpec &exe_arch,
    151                                   lldb::ModuleSP &exe_module_sp,
    152                                   const FileSpecList *module_search_paths_ptr)
    153 {
    154     Error error;
    155     // Nothing special to do here, just use the actual file and architecture
    156 
    157     char exe_path[PATH_MAX];
    158     FileSpec resolved_exe_file (exe_file);
    159 
    160     if (IsHost())
    161     {
    162         // If we have "ls" as the exe_file, resolve the executable location based on
    163         // the current path variables
    164         if (!resolved_exe_file.Exists())
    165         {
    166             exe_file.GetPath(exe_path, sizeof(exe_path));
    167             resolved_exe_file.SetFile(exe_path, true);
    168         }
    169 
    170         if (!resolved_exe_file.Exists())
    171             resolved_exe_file.ResolveExecutableLocation ();
    172 
    173         if (resolved_exe_file.Exists())
    174             error.Clear();
    175         else
    176         {
    177             exe_file.GetPath(exe_path, sizeof(exe_path));
    178             error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
    179         }
    180     }
    181     else
    182     {
    183         if (m_remote_platform_sp)
    184         {
    185             error = m_remote_platform_sp->ResolveExecutable (exe_file,
    186                                                              exe_arch,
    187                                                              exe_module_sp,
    188                                                              NULL);
    189         }
    190         else
    191         {
    192             // We may connect to a process and use the provided executable (Don't use local $PATH).
    193 
    194             if (resolved_exe_file.Exists())
    195                 error.Clear();
    196             else
    197                 error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path);
    198         }
    199     }
    200 
    201     if (error.Success())
    202     {
    203         ModuleSpec module_spec (resolved_exe_file, exe_arch);
    204         if (exe_arch.IsValid())
    205         {
    206             error = ModuleList::GetSharedModule (module_spec,
    207                                                  exe_module_sp,
    208                                                  NULL,
    209                                                  NULL,
    210                                                  NULL);
    211             if (error.Fail())
    212             {
    213                 // If we failed, it may be because the vendor and os aren't known. If that is the
    214                 // case, try setting them to the host architecture and give it another try.
    215                 llvm::Triple &module_triple = module_spec.GetArchitecture().GetTriple();
    216                 bool is_vendor_specified = (module_triple.getVendor() != llvm::Triple::UnknownVendor);
    217                 bool is_os_specified = (module_triple.getOS() != llvm::Triple::UnknownOS);
    218                 if (!is_vendor_specified || !is_os_specified)
    219                 {
    220                     const llvm::Triple &host_triple = Host::GetArchitecture (Host::eSystemDefaultArchitecture).GetTriple();
    221 
    222                     if (!is_vendor_specified)
    223                         module_triple.setVendorName (host_triple.getVendorName());
    224                     if (!is_os_specified)
    225                         module_triple.setOSName (host_triple.getOSName());
    226 
    227                     error = ModuleList::GetSharedModule (module_spec,
    228                                                          exe_module_sp,
    229                                                          NULL,
    230                                                          NULL,
    231                                                          NULL);
    232                 }
    233             }
    234 
    235             // TODO find out why exe_module_sp might be NULL
    236             if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
    237             {
    238                 exe_module_sp.reset();
    239                 error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
    240                                                 exe_file.GetPath().c_str(),
    241                                                 exe_arch.GetArchitectureName());
    242             }
    243         }
    244         else
    245         {
    246             // No valid architecture was specified, ask the platform for
    247             // the architectures that we should be using (in the correct order)
    248             // and see if we can find a match that way
    249             StreamString arch_names;
    250             for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx)
    251             {
    252                 error = ModuleList::GetSharedModule (module_spec,
    253                                                      exe_module_sp,
    254                                                      NULL,
    255                                                      NULL,
    256                                                      NULL);
    257                 // Did we find an executable using one of the
    258                 if (error.Success())
    259                 {
    260                     if (exe_module_sp && exe_module_sp->GetObjectFile())
    261                         break;
    262                     else
    263                         error.SetErrorToGenericError();
    264                 }
    265 
    266                 if (idx > 0)
    267                     arch_names.PutCString (", ");
    268                 arch_names.PutCString (module_spec.GetArchitecture().GetArchitectureName());
    269             }
    270 
    271             if (error.Fail() || !exe_module_sp)
    272             {
    273                 error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
    274                                                 exe_file.GetPath().c_str(),
    275                                                 GetPluginName().GetCString(),
    276                                                 arch_names.GetString().c_str());
    277             }
    278         }
    279     }
    280 
    281     return error;
    282 }
    283 
    284 Error
    285 PlatformLinux::GetFile (const FileSpec &platform_file,
    286                         const UUID *uuid_ptr, FileSpec &local_file)
    287 {
    288     if (IsRemote())
    289     {
    290         if (m_remote_platform_sp)
    291             return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file);
    292     }
    293 
    294     // Default to the local case
    295     local_file = platform_file;
    296     return Error();
    297 }
    298 
    299 
    300 //------------------------------------------------------------------
    301 /// Default Constructor
    302 //------------------------------------------------------------------
    303 PlatformLinux::PlatformLinux (bool is_host) :
    304     Platform(is_host),  // This is the local host platform
    305     m_remote_platform_sp ()
    306 {
    307 }
    308 
    309 //------------------------------------------------------------------
    310 /// Destructor.
    311 ///
    312 /// The destructor is virtual since this class is designed to be
    313 /// inherited from by the plug-in instance.
    314 //------------------------------------------------------------------
    315 PlatformLinux::~PlatformLinux()
    316 {
    317 }
    318 
    319 bool
    320 PlatformLinux::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
    321 {
    322     bool success = false;
    323     if (IsHost())
    324     {
    325         success = Platform::GetProcessInfo (pid, process_info);
    326     }
    327     else
    328     {
    329         if (m_remote_platform_sp)
    330             success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
    331     }
    332     return success;
    333 }
    334 
    335 bool
    336 PlatformLinux::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
    337 {
    338     if (idx == 0)
    339     {
    340         arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
    341         return arch.IsValid();
    342     }
    343     else if (idx == 1)
    344     {
    345         // If the default host architecture is 64-bit, look for a 32-bit variant
    346         ArchSpec hostArch
    347                       = Host::GetArchitecture(Host::eSystemDefaultArchitecture);
    348         if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit())
    349         {
    350             arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
    351             return arch.IsValid();
    352         }
    353     }
    354     return false;
    355 }
    356 
    357 void
    358 PlatformLinux::GetStatus (Stream &strm)
    359 {
    360     struct utsname un;
    361 
    362     Platform::GetStatus(strm);
    363 
    364     if (uname(&un))
    365         return;
    366 
    367     strm.Printf ("    Kernel: %s\n", un.sysname);
    368     strm.Printf ("   Release: %s\n", un.release);
    369     strm.Printf ("   Version: %s\n", un.version);
    370 }
    371 
    372 size_t
    373 PlatformLinux::GetSoftwareBreakpointTrapOpcode (Target &target,
    374                                                 BreakpointSite *bp_site)
    375 {
    376     ArchSpec arch = target.GetArchitecture();
    377     const uint8_t *trap_opcode = NULL;
    378     size_t trap_opcode_size = 0;
    379 
    380     switch (arch.GetCore())
    381     {
    382     default:
    383         assert(false && "CPU type not supported!");
    384         break;
    385 
    386     case ArchSpec::eCore_x86_32_i386:
    387     case ArchSpec::eCore_x86_64_x86_64:
    388         {
    389             static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC };
    390             trap_opcode = g_i386_breakpoint_opcode;
    391             trap_opcode_size = sizeof(g_i386_breakpoint_opcode);
    392         }
    393         break;
    394     }
    395 
    396     if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
    397         return trap_opcode_size;
    398     return 0;
    399 }
    400 
    401 Error
    402 PlatformLinux::LaunchProcess (ProcessLaunchInfo &launch_info)
    403 {
    404     Error error;
    405 
    406     if (IsHost())
    407     {
    408         if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell))
    409         {
    410             const bool is_localhost = true;
    411             const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug);
    412             const bool first_arg_is_full_shell_command = false;
    413             if (!launch_info.ConvertArgumentsForLaunchingInShell (error,
    414                                                                   is_localhost,
    415                                                                   will_debug,
    416                                                                   first_arg_is_full_shell_command))
    417                 return error;
    418         }
    419         error = Platform::LaunchProcess (launch_info);
    420     }
    421     else
    422     {
    423         error.SetErrorString ("the platform is not currently connected");
    424     }
    425     return error;
    426 }
    427 
    428 lldb::ProcessSP
    429 PlatformLinux::Attach(ProcessAttachInfo &attach_info,
    430                       Debugger &debugger,
    431                       Target *target,
    432                       Listener &listener,
    433                       Error &error)
    434 {
    435     lldb::ProcessSP process_sp;
    436     if (IsHost())
    437     {
    438         if (target == NULL)
    439         {
    440             TargetSP new_target_sp;
    441             ArchSpec emptyArchSpec;
    442 
    443             error = debugger.GetTargetList().CreateTarget (debugger,
    444                                                            NULL,
    445                                                            emptyArchSpec,
    446                                                            false,
    447                                                            m_remote_platform_sp,
    448                                                            new_target_sp);
    449             target = new_target_sp.get();
    450         }
    451         else
    452             error.Clear();
    453 
    454         if (target && error.Success())
    455         {
    456             debugger.GetTargetList().SetSelectedTarget(target);
    457 
    458             process_sp = target->CreateProcess (listener,
    459                                                 attach_info.GetProcessPluginName(),
    460                                                 NULL);
    461 
    462             if (process_sp)
    463                 error = process_sp->Attach (attach_info);
    464         }
    465     }
    466     else
    467     {
    468         if (m_remote_platform_sp)
    469             process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error);
    470         else
    471             error.SetErrorString ("the platform is not currently connected");
    472     }
    473     return process_sp;
    474 }
    475