diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 | 
| commit | 9e6d35490a6542f9c97607f93c2ef8ca8e03cbcc (patch) | |
| tree | dd2a1ddf0476664c2b823409c36cbccd52662ca7 /source/Plugins/Platform/Linux/PlatformLinux.cpp | |
| parent | 3bd2e91faeb9eeec1aae82c64a3253afff551cfd (diff) | |
Notes
Diffstat (limited to 'source/Plugins/Platform/Linux/PlatformLinux.cpp')
| -rw-r--r-- | source/Plugins/Platform/Linux/PlatformLinux.cpp | 868 | 
1 files changed, 868 insertions, 0 deletions
| diff --git a/source/Plugins/Platform/Linux/PlatformLinux.cpp b/source/Plugins/Platform/Linux/PlatformLinux.cpp new file mode 100644 index 000000000000..8dc9769844c7 --- /dev/null +++ b/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -0,0 +1,868 @@ +//===-- PlatformLinux.cpp ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PlatformLinux.h" +#include "lldb/Host/Config.h" + +// C Includes +#include <stdio.h> +#ifndef LLDB_DISABLE_POSIX +#include <sys/utsname.h> +#endif + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/State.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/Property.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" + +// Define these constants from Linux mman.h for use when targeting +// remote linux systems even when host has different values. +#define MAP_PRIVATE 2 +#define MAP_ANON 0x20 + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_linux; + +static uint32_t g_initialize_count = 0; + +//------------------------------------------------------------------ +/// Code to handle the PlatformLinux settings +//------------------------------------------------------------------ + +namespace +{ +    class PlatformLinuxProperties : public Properties +    { +    public: +        PlatformLinuxProperties(); + +        ~PlatformLinuxProperties() override = default; + +        static ConstString& +        GetSettingName (); + +    private: +        static const PropertyDefinition* +        GetStaticPropertyDefinitions(); +    }; + +    typedef std::shared_ptr<PlatformLinuxProperties> PlatformLinuxPropertiesSP; + +} // anonymous namespace + +PlatformLinuxProperties::PlatformLinuxProperties() : +    Properties () +{ +    m_collection_sp.reset (new OptionValueProperties(GetSettingName ())); +    m_collection_sp->Initialize (GetStaticPropertyDefinitions ()); +} + +ConstString& +PlatformLinuxProperties::GetSettingName () +{ +    static ConstString g_setting_name("linux"); +    return g_setting_name; +} + +const PropertyDefinition* +PlatformLinuxProperties::GetStaticPropertyDefinitions() +{ +    static PropertyDefinition +    g_properties[] = +    { +        {  NULL        , OptionValue::eTypeInvalid, false, 0  , NULL, NULL, NULL  } +    }; + +    return g_properties; +} + +static const PlatformLinuxPropertiesSP & +GetGlobalProperties() +{ +    static PlatformLinuxPropertiesSP g_settings_sp; +    if (!g_settings_sp) +        g_settings_sp.reset (new PlatformLinuxProperties ()); +    return g_settings_sp; +} + +void +PlatformLinux::DebuggerInitialize (Debugger &debugger) +{ +    if (!PluginManager::GetSettingForPlatformPlugin (debugger, PlatformLinuxProperties::GetSettingName())) +    { +        const bool is_global_setting = true; +        PluginManager::CreateSettingForPlatformPlugin (debugger, +                                                       GetGlobalProperties()->GetValueProperties(), +                                                       ConstString ("Properties for the PlatformLinux plug-in."), +                                                       is_global_setting); +    } +} + +//------------------------------------------------------------------ + +PlatformSP +PlatformLinux::CreateInstance (bool force, const ArchSpec *arch) +{ +    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); +    if (log) +    { +        const char *arch_name; +        if (arch && arch->GetArchitectureName ()) +            arch_name = arch->GetArchitectureName (); +        else +            arch_name = "<null>"; + +        const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>"; + +        log->Printf ("PlatformLinux::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr); +    } + +    bool create = force; +    if (create == false && arch && arch->IsValid()) +    { +        const llvm::Triple &triple = arch->GetTriple(); +        switch (triple.getOS()) +        { +            case llvm::Triple::Linux: +                create = true; +                break; + +#if defined(__linux__) +            // Only accept "unknown" for the OS if the host is linux and +            // it "unknown" wasn't specified (it was just returned because it +            // was NOT specified) +            case llvm::Triple::OSType::UnknownOS: +                create = !arch->TripleOSWasSpecified(); +                break; +#endif +            default: +                break; +        } +    } + +    if (create) +    { +        if (log) +            log->Printf ("PlatformLinux::%s() creating remote-linux platform", __FUNCTION__); +        return PlatformSP(new PlatformLinux(false)); +    } + +    if (log) +        log->Printf ("PlatformLinux::%s() aborting creation of remote-linux platform", __FUNCTION__); + +    return PlatformSP(); +} + +ConstString +PlatformLinux::GetPluginNameStatic (bool is_host) +{ +    if (is_host) +    { +        static ConstString g_host_name(Platform::GetHostPlatformName ()); +        return g_host_name; +    } +    else +    { +        static ConstString g_remote_name("remote-linux"); +        return g_remote_name; +    } +} + +const char * +PlatformLinux::GetPluginDescriptionStatic (bool is_host) +{ +    if (is_host) +        return "Local Linux user platform plug-in."; +    else +        return "Remote Linux user platform plug-in."; +} + +ConstString +PlatformLinux::GetPluginName() +{ +    return GetPluginNameStatic(IsHost()); +} + +void +PlatformLinux::Initialize () +{ +    PlatformPOSIX::Initialize (); + +    if (g_initialize_count++ == 0) +    { +#if defined(__linux__) && !defined(__ANDROID__) +        PlatformSP default_platform_sp (new PlatformLinux(true)); +        default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); +        Platform::SetHostPlatform (default_platform_sp); +#endif +        PluginManager::RegisterPlugin(PlatformLinux::GetPluginNameStatic(false), +                                      PlatformLinux::GetPluginDescriptionStatic(false), +                                      PlatformLinux::CreateInstance, +                                      PlatformLinux::DebuggerInitialize); +    } +} + +void +PlatformLinux::Terminate () +{ +    if (g_initialize_count > 0) +    { +        if (--g_initialize_count == 0) +        { +            PluginManager::UnregisterPlugin (PlatformLinux::CreateInstance); +        } +    } + +    PlatformPOSIX::Terminate (); +} + +Error +PlatformLinux::ResolveExecutable (const ModuleSpec &ms, +                                  lldb::ModuleSP &exe_module_sp, +                                  const FileSpecList *module_search_paths_ptr) +{ +    Error error; +    // Nothing special to do here, just use the actual file and architecture + +    char exe_path[PATH_MAX]; +    ModuleSpec resolved_module_spec (ms); + +    if (IsHost()) +    { +        // If we have "ls" as the exe_file, resolve the executable location based on +        // the current path variables +        if (!resolved_module_spec.GetFileSpec().Exists()) +        { +            resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); +            resolved_module_spec.GetFileSpec().SetFile(exe_path, true); +        } + +        if (!resolved_module_spec.GetFileSpec().Exists()) +            resolved_module_spec.GetFileSpec().ResolveExecutableLocation (); + +        if (resolved_module_spec.GetFileSpec().Exists()) +            error.Clear(); +        else +        { +            error.SetErrorStringWithFormat("unable to find executable for '%s'", resolved_module_spec.GetFileSpec().GetPath().c_str()); +        } +    } +    else +    { +        if (m_remote_platform_sp) +        { +            error = GetCachedExecutable (resolved_module_spec, exe_module_sp, module_search_paths_ptr, *m_remote_platform_sp); +        } +        else +        { +            // We may connect to a process and use the provided executable (Don't use local $PATH). + +            if (resolved_module_spec.GetFileSpec().Exists()) +                error.Clear(); +            else +                error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path); +        } +    } + +    if (error.Success()) +    { +        if (resolved_module_spec.GetArchitecture().IsValid()) +        { +            error = ModuleList::GetSharedModule (resolved_module_spec, +                                                 exe_module_sp, +                                                 NULL, +                                                 NULL, +                                                 NULL); +            if (error.Fail()) +            { +                // If we failed, it may be because the vendor and os aren't known. If that is the +                // case, try setting them to the host architecture and give it another try. +                llvm::Triple &module_triple = resolved_module_spec.GetArchitecture().GetTriple(); +                bool is_vendor_specified = (module_triple.getVendor() != llvm::Triple::UnknownVendor); +                bool is_os_specified = (module_triple.getOS() != llvm::Triple::UnknownOS); +                if (!is_vendor_specified || !is_os_specified) +                { +                    const llvm::Triple &host_triple = HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple(); + +                    if (!is_vendor_specified) +                        module_triple.setVendorName (host_triple.getVendorName()); +                    if (!is_os_specified) +                        module_triple.setOSName (host_triple.getOSName()); + +                    error = ModuleList::GetSharedModule (resolved_module_spec, +                                                         exe_module_sp, +                                                         NULL, +                                                         NULL, +                                                         NULL); +                } +            } + +            // TODO find out why exe_module_sp might be NULL +            if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) +            { +                exe_module_sp.reset(); +                error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s", +                                                resolved_module_spec.GetFileSpec().GetPath().c_str(), +                                                resolved_module_spec.GetArchitecture().GetArchitectureName()); +            } +        } +        else +        { +            // No valid architecture was specified, ask the platform for +            // the architectures that we should be using (in the correct order) +            // and see if we can find a match that way +            StreamString arch_names; +            for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx) +            { +                error = ModuleList::GetSharedModule (resolved_module_spec, +                                                     exe_module_sp, +                                                     NULL, +                                                     NULL, +                                                     NULL); +                // Did we find an executable using one of the +                if (error.Success()) +                { +                    if (exe_module_sp && exe_module_sp->GetObjectFile()) +                        break; +                    else +                        error.SetErrorToGenericError(); +                } + +                if (idx > 0) +                    arch_names.PutCString (", "); +                arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName()); +            } + +            if (error.Fail() || !exe_module_sp) +            { +                if (resolved_module_spec.GetFileSpec().Readable()) +                { +                    error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", +                                                    resolved_module_spec.GetFileSpec().GetPath().c_str(), +                                                    GetPluginName().GetCString(), +                                                    arch_names.GetString().c_str()); +                } +                else +                { +                    error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str()); +                } +            } +        } +    } + +    return error; +} + +Error +PlatformLinux::GetFileWithUUID (const FileSpec &platform_file, +                                const UUID *uuid_ptr, FileSpec &local_file) +{ +    if (IsRemote()) +    { +        if (m_remote_platform_sp) +            return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file); +    } + +    // Default to the local case +    local_file = platform_file; +    return Error(); +} + +//------------------------------------------------------------------ +/// Default Constructor +//------------------------------------------------------------------ +PlatformLinux::PlatformLinux (bool is_host) : +    PlatformPOSIX(is_host)  // This is the local host platform +{ +} + +//------------------------------------------------------------------ +/// Destructor. +/// +/// The destructor is virtual since this class is designed to be +/// inherited from by the plug-in instance. +//------------------------------------------------------------------ +PlatformLinux::~PlatformLinux() = default; + +bool +PlatformLinux::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) +{ +    bool success = false; +    if (IsHost()) +    { +        success = Platform::GetProcessInfo (pid, process_info); +    } +    else +    { +        if (m_remote_platform_sp) +            success = m_remote_platform_sp->GetProcessInfo (pid, process_info); +    } +    return success; +} + +uint32_t +PlatformLinux::FindProcesses (const ProcessInstanceInfoMatch &match_info, +                              ProcessInstanceInfoList &process_infos) +{ +    uint32_t match_count = 0; +    if (IsHost()) +    { +        // Let the base class figure out the host details +        match_count = Platform::FindProcesses (match_info, process_infos); +    } +    else +    { +        // If we are remote, we can only return results if we are connected +        if (m_remote_platform_sp) +            match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos); +    } +    return match_count; +} + +bool +PlatformLinux::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) +{ +    if (IsHost()) +    { +        ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); +        if (hostArch.GetTriple().isOSLinux()) +        { +            if (idx == 0) +            { +                arch = hostArch; +                return arch.IsValid(); +            } +            else if (idx == 1) +            { +                // If the default host architecture is 64-bit, look for a 32-bit variant +                if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit()) +                { +                    arch = HostInfo::GetArchitecture(HostInfo::eArchKind32); +                    return arch.IsValid(); +                } +            } +        } +    } +    else +    { +        if (m_remote_platform_sp) +            return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch); + +        llvm::Triple triple; +        // Set the OS to linux +        triple.setOS(llvm::Triple::Linux); +        // Set the architecture +        switch (idx) +        { +            case 0: triple.setArchName("x86_64"); break; +            case 1: triple.setArchName("i386"); break; +            case 2: triple.setArchName("arm"); break; +            case 3: triple.setArchName("aarch64"); break; +            case 4: triple.setArchName("mips64"); break; +            case 5: triple.setArchName("hexagon"); break; +            case 6: triple.setArchName("mips"); break; +            case 7: triple.setArchName("mips64el"); break; +            case 8: triple.setArchName("mipsel"); break; +            default: return false; +        } +        // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the vendor by +        // calling triple.SetVendorName("unknown") so that it is a "unspecified unknown". +        // This means when someone calls triple.GetVendorName() it will return an empty string +        // which indicates that the vendor can be set when two architectures are merged + +        // Now set the triple into "arch" and return true +        arch.SetTriple(triple); +        return true; +    } +    return false; +} + +void +PlatformLinux::GetStatus (Stream &strm) +{ +    Platform::GetStatus(strm); + +#ifndef LLDB_DISABLE_POSIX +    // Display local kernel information only when we are running in host mode. +    // Otherwise, we would end up printing non-Linux information (when running +    // on Mac OS for example). +    if (IsHost()) +    { +        struct utsname un; + +        if (uname(&un)) +            return; + +        strm.Printf ("    Kernel: %s\n", un.sysname); +        strm.Printf ("   Release: %s\n", un.release); +        strm.Printf ("   Version: %s\n", un.version); +    } +#endif +} + +size_t +PlatformLinux::GetSoftwareBreakpointTrapOpcode (Target &target, +                                                BreakpointSite *bp_site) +{ +    ArchSpec arch = target.GetArchitecture(); +    const uint8_t *trap_opcode = NULL; +    size_t trap_opcode_size = 0; + +    switch (arch.GetMachine()) +    { +    default: +        assert(false && "CPU type not supported!"); +        break; + +    case llvm::Triple::aarch64: +        { +            static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xd4 }; +            trap_opcode = g_aarch64_opcode; +            trap_opcode_size = sizeof(g_aarch64_opcode); +        } +        break; +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +        { +            static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC }; +            trap_opcode = g_i386_breakpoint_opcode; +            trap_opcode_size = sizeof(g_i386_breakpoint_opcode); +        } +        break; +    case llvm::Triple::hexagon: +        { +            static const uint8_t g_hex_opcode[] = { 0x0c, 0xdb, 0x00, 0x54 }; +            trap_opcode = g_hex_opcode; +            trap_opcode_size = sizeof(g_hex_opcode); +        } +        break; +    case llvm::Triple::arm: +        { +            // The ARM reference recommends the use of 0xe7fddefe and 0xdefe +            // but the linux kernel does otherwise. +            static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 }; +            static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; + +            lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0)); +            AddressClass addr_class = eAddressClassUnknown; + +            if (bp_loc_sp) +            { +                addr_class = bp_loc_sp->GetAddress ().GetAddressClass (); + +                if (addr_class == eAddressClassUnknown && +                    (bp_loc_sp->GetAddress ().GetFileAddress () & 1)) +                { +                    addr_class = eAddressClassCodeAlternateISA; +                } +            } + +            if (addr_class == eAddressClassCodeAlternateISA) +            { +                trap_opcode = g_thumb_breakpoint_opcode; +                trap_opcode_size = sizeof(g_thumb_breakpoint_opcode); +            } +            else +            { +                trap_opcode = g_arm_breakpoint_opcode; +                trap_opcode_size = sizeof(g_arm_breakpoint_opcode); +            } +        } +        break; +    case llvm::Triple::mips: +    case llvm::Triple::mips64: +        { +            static const uint8_t g_hex_opcode[] = { 0x00, 0x00, 0x00, 0x0d }; +            trap_opcode = g_hex_opcode; +            trap_opcode_size = sizeof(g_hex_opcode); +        } +        break; +    case llvm::Triple::mipsel: +    case llvm::Triple::mips64el: +        { +            static const uint8_t g_hex_opcode[] = { 0x0d, 0x00, 0x00, 0x00 }; +            trap_opcode = g_hex_opcode; +            trap_opcode_size = sizeof(g_hex_opcode); +        } +        break; +    } + +    if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) +        return trap_opcode_size; +    return 0; +} + +int32_t +PlatformLinux::GetResumeCountForLaunchInfo (ProcessLaunchInfo &launch_info) +{ +    int32_t resume_count = 0; + +    // Always resume past the initial stop when we use eLaunchFlagDebug +    if (launch_info.GetFlags ().Test (eLaunchFlagDebug)) +    { +        // Resume past the stop for the final exec into the true inferior. +        ++resume_count; +    } + +    // If we're not launching a shell, we're done. +    const FileSpec &shell = launch_info.GetShell(); +    if (!shell) +        return resume_count; + +    std::string shell_string = shell.GetPath(); +    // We're in a shell, so for sure we have to resume past the shell exec. +    ++resume_count; + +    // Figure out what shell we're planning on using. +    const char *shell_name = strrchr (shell_string.c_str(), '/'); +    if (shell_name == NULL) +        shell_name = shell_string.c_str(); +    else +        shell_name++; + +    if (strcmp (shell_name, "csh") == 0 +             || strcmp (shell_name, "tcsh") == 0 +             || strcmp (shell_name, "zsh") == 0 +             || strcmp (shell_name, "sh") == 0) +    { +        // These shells seem to re-exec themselves.  Add another resume. +        ++resume_count; +    } + +    return resume_count; +} + +bool +PlatformLinux::CanDebugProcess () +{ +    if (IsHost ()) +    { +        return true; +    } +    else +    { +        // If we're connected, we can debug. +        return IsConnected (); +    } +} + +// For local debugging, Linux will override the debug logic to use llgs-launch rather than +// lldb-launch, llgs-attach.  This differs from current lldb-launch, debugserver-attach +// approach on MacOSX. +lldb::ProcessSP +PlatformLinux::DebugProcess (ProcessLaunchInfo &launch_info, +                             Debugger &debugger, +                             Target *target,       // Can be NULL, if NULL create a new target, else use existing one +                             Error &error) +{ +    Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); +    if (log) +        log->Printf ("PlatformLinux::%s entered (target %p)", __FUNCTION__, static_cast<void*>(target)); + +    // If we're a remote host, use standard behavior from parent class. +    if (!IsHost ()) +        return PlatformPOSIX::DebugProcess (launch_info, debugger, target, error); + +    // +    // For local debugging, we'll insist on having ProcessGDBRemote create the process. +    // + +    ProcessSP process_sp; + +    // Make sure we stop at the entry point +    launch_info.GetFlags ().Set (eLaunchFlagDebug); + +    // We always launch the process we are going to debug in a separate process +    // group, since then we can handle ^C interrupts ourselves w/o having to worry +    // about the target getting them as well. +    launch_info.SetLaunchInSeparateProcessGroup(true); + +    // Ensure we have a target. +    if (target == nullptr) +    { +        if (log) +            log->Printf ("PlatformLinux::%s creating new target", __FUNCTION__); + +        TargetSP new_target_sp; +        error = debugger.GetTargetList().CreateTarget (debugger, +                                                       nullptr, +                                                       nullptr, +                                                       false, +                                                       nullptr, +                                                       new_target_sp); +        if (error.Fail ()) +        { +            if (log) +                log->Printf ("PlatformLinux::%s failed to create new target: %s", __FUNCTION__, error.AsCString ()); +            return process_sp; +        } + +        target = new_target_sp.get(); +        if (!target) +        { +            error.SetErrorString ("CreateTarget() returned nullptr"); +            if (log) +                log->Printf ("PlatformLinux::%s failed: %s", __FUNCTION__, error.AsCString ()); +            return process_sp; +        } +    } +    else +    { +        if (log) +            log->Printf ("PlatformLinux::%s using provided target", __FUNCTION__); +    } + +    // Mark target as currently selected target. +    debugger.GetTargetList().SetSelectedTarget(target); + +    // Now create the gdb-remote process. +    if (log) +        log->Printf ("PlatformLinux::%s having target create process with gdb-remote plugin", __FUNCTION__); +    process_sp = target->CreateProcess (launch_info.GetListenerForProcess(debugger), "gdb-remote", nullptr); + +    if (!process_sp) +    { +        error.SetErrorString ("CreateProcess() failed for gdb-remote process"); +        if (log) +            log->Printf ("PlatformLinux::%s failed: %s", __FUNCTION__, error.AsCString ()); +        return process_sp; +    } +    else +    { +        if (log) +            log->Printf ("PlatformLinux::%s successfully created process", __FUNCTION__); +    } + +    // Adjust launch for a hijacker. +    ListenerSP listener_sp; +    if (!launch_info.GetHijackListener ()) +    { +        if (log) +            log->Printf ("PlatformLinux::%s setting up hijacker", __FUNCTION__); + +        listener_sp.reset (new Listener("lldb.PlatformLinux.DebugProcess.hijack")); +        launch_info.SetHijackListener (listener_sp); +        process_sp->HijackProcessEvents (listener_sp.get ()); +    } + +    // Log file actions. +    if (log) +    { +        log->Printf ("PlatformLinux::%s launching process with the following file actions:", __FUNCTION__); + +        StreamString stream; +        size_t i = 0; +        const FileAction *file_action; +        while ((file_action = launch_info.GetFileActionAtIndex (i++)) != nullptr) +        { +            file_action->Dump (stream); +            log->PutCString (stream.GetString().c_str ()); +            stream.Clear(); +        } +    } + +    // Do the launch. +    error = process_sp->Launch(launch_info); +    if (error.Success ()) +    { +        // Handle the hijacking of process events. +        if (listener_sp) +        { +            const StateType state = process_sp->WaitForProcessToStop (NULL, NULL, false, listener_sp.get()); + +            if (state == eStateStopped) +            { +                if (log) +                    log->Printf ("PlatformLinux::%s pid %" PRIu64 " state %s\n", +                                 __FUNCTION__, process_sp->GetID (), StateAsCString (state)); +            } +            else +            { +                if (log) +                    log->Printf ("PlatformLinux::%s pid %" PRIu64 " state is not stopped - %s\n", +                                 __FUNCTION__, process_sp->GetID (), StateAsCString (state)); +            } +        } + +        // Hook up process PTY if we have one (which we should for local debugging with llgs). +        int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); +        if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd) +        { +            process_sp->SetSTDIOFileDescriptor(pty_fd); +            if (log) +                log->Printf ("PlatformLinux::%s pid %" PRIu64 " hooked up STDIO pty to process", __FUNCTION__, process_sp->GetID ()); +        } +        else +        { +            if (log) +                log->Printf ("PlatformLinux::%s pid %" PRIu64 " not using process STDIO pty", __FUNCTION__, process_sp->GetID ()); +        } +    } +    else +    { +        if (log) +            log->Printf ("PlatformLinux::%s process launch failed: %s", __FUNCTION__, error.AsCString ()); +        // FIXME figure out appropriate cleanup here.  Do we delete the target? Do we delete the process?  Does our caller do that? +    } + +    return process_sp; +} + +void +PlatformLinux::CalculateTrapHandlerSymbolNames () +{ +    m_trap_handlers.push_back (ConstString ("_sigtramp")); +} + +uint64_t +PlatformLinux::ConvertMmapFlagsToPlatform(const ArchSpec &arch, unsigned flags) +{ +    uint64_t flags_platform = 0; +    uint64_t map_anon = MAP_ANON; + +    // To get correct flags for MIPS Architecture +    if (arch.GetTriple ().getArch () == llvm::Triple::mips64 +       || arch.GetTriple ().getArch () == llvm::Triple::mips64el  +       || arch.GetTriple ().getArch () == llvm::Triple::mips  +       || arch.GetTriple ().getArch () == llvm::Triple::mipsel) +           map_anon = 0x800; + +    if (flags & eMmapFlagsPrivate) +        flags_platform |= MAP_PRIVATE; +    if (flags & eMmapFlagsAnon) +        flags_platform |= map_anon; +    return flags_platform; +} + +ConstString +PlatformLinux::GetFullNameForDylib (ConstString basename) +{ +    if (basename.IsEmpty()) +        return basename; +     +    StreamString stream; +    stream.Printf("lib%s.so", basename.GetCString()); +    return ConstString(stream.GetData()); +} | 
