예제 #1
0
lldb::ProcessSP PlatformRemoteGDBServer::Attach(
    ProcessAttachInfo &attach_info, Debugger &debugger,
    Target *target, // Can be NULL, if NULL create a new target, else use
                    // existing one
    Error &error) {
  lldb::ProcessSP process_sp;
  if (IsRemote()) {
    if (IsConnected()) {
      lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
      std::string connect_url;
      if (!LaunchGDBServer(debugserver_pid, connect_url)) {
        error.SetErrorStringWithFormat("unable to launch a GDB server on '%s'",
                                       GetHostname());
      } else {
        if (target == NULL) {
          TargetSP new_target_sp;

          error = debugger.GetTargetList().CreateTarget(
              debugger, NULL, NULL, false, NULL, new_target_sp);
          target = new_target_sp.get();
        } else
          error.Clear();

        if (target && error.Success()) {
          debugger.GetTargetList().SetSelectedTarget(target);

          // The darwin always currently uses the GDB remote debugger plug-in
          // so even when debugging locally we are debugging remotely!
          process_sp = target->CreateProcess(
              attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
          if (process_sp) {
            error = process_sp->ConnectRemote(nullptr, connect_url.c_str());
            if (error.Success()) {
              ListenerSP listener_sp = attach_info.GetHijackListener();
              if (listener_sp)
                process_sp->HijackProcessEvents(listener_sp);
              error = process_sp->Attach(attach_info);
            }

            if (error.Fail() && debugserver_pid != LLDB_INVALID_PROCESS_ID) {
              KillSpawnedProcess(debugserver_pid);
            }
          }
        }
      }
    } else {
      error.SetErrorString("not connected to remote gdb server");
    }
  }
  return process_sp;
}
예제 #2
0
lldb::ProcessSP
PlatformLinux::Attach(ProcessAttachInfo &attach_info,
                      Debugger &debugger,
                      Target *target,
                      Listener &listener,
                      Error &error)
{
    lldb::ProcessSP process_sp;
    if (IsHost())
    {
        if (target == NULL)
        {
            TargetSP new_target_sp;
            FileSpec emptyFileSpec;
            ArchSpec emptyArchSpec;

            error = debugger.GetTargetList().CreateTarget (debugger,
                                                           emptyFileSpec,
                                                           emptyArchSpec,
                                                           false,
                                                           m_remote_platform_sp,
                                                           new_target_sp);
            target = new_target_sp.get();
        }
        else
            error.Clear();

        if (target && error.Success())
        {
            debugger.GetTargetList().SetSelectedTarget(target);

            process_sp = target->CreateProcess (listener,
                                                attach_info.GetProcessPluginName(),
                                                NULL);

            if (process_sp)
                error = process_sp->Attach (attach_info);
        }
    }
    else
    {
        if (m_remote_platform_sp)
            process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error);
        else
            error.SetErrorString ("the platform is not currently connected");
    }
    return process_sp;
}
예제 #3
0
lldb::ProcessSP
PlatformWindows::Attach(ProcessAttachInfo &attach_info,
                        Debugger &debugger,
                        Target *target,
                        Listener &listener,
                        Error &error)
{
    lldb::ProcessSP process_sp;
    if (IsHost())
    {
        if (target == NULL)
        {
            TargetSP new_target_sp;
            FileSpec emptyFileSpec;
            ArchSpec emptyArchSpec;

            error = debugger.GetTargetList().CreateTarget (debugger,
                                                           NULL,
                                                           NULL,
                                                           false,
                                                           NULL,
                                                           new_target_sp);
            target = new_target_sp.get();
        }
        else
            error.Clear();

        if (target && error.Success())
        {
            debugger.GetTargetList().SetSelectedTarget(target);
            // The Windows platform always currently uses the GDB remote debugger plug-in
            // so even when debugging locally we are debugging remotely!
            // Just like the darwin plugin.
            process_sp = target->CreateProcess (listener, "gdb-remote", NULL);

            if (process_sp)
                error = process_sp->Attach (attach_info);
        }
    }
    else
    {
        if (m_remote_platform_sp)
            process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error);
        else
            error.SetErrorString ("the platform is not currently connected");
    }
    return process_sp;
}
예제 #4
0
lldb::ProcessSP
PlatformWindows::Attach(ProcessAttachInfo &attach_info,
                        Debugger &debugger,
                        Target *target,
                        Error &error)
{
    error.Clear();
    lldb::ProcessSP process_sp;
    if (!IsHost())
    {
        if (m_remote_platform_sp)
            process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
        else
            error.SetErrorString ("the platform is not currently connected");
        return process_sp;
    }

    if (target == nullptr)
    {
        TargetSP new_target_sp;
        FileSpec emptyFileSpec;
        ArchSpec emptyArchSpec;

        error = debugger.GetTargetList().CreateTarget(debugger,
                                                      nullptr,
                                                      nullptr,
                                                      false,
                                                      nullptr,
                                                      new_target_sp);
        target = new_target_sp.get();
    }

    if (!target || error.Fail())
        return process_sp;

    debugger.GetTargetList().SetSelectedTarget(target);

    const char *plugin_name = attach_info.GetProcessPluginName();
    process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), plugin_name, nullptr);

    process_sp->HijackProcessEvents(attach_info.GetHijackListener());
    if (process_sp)
        error = process_sp->Attach (attach_info);

    return process_sp;
}
lldb::ProcessSP
PlatformRemoteGDBServer::DebugProcess (ProcessLaunchInfo &launch_info,
                                       Debugger &debugger,
                                       Target *target,       // Can be NULL, if NULL create a new target, else use existing one
                                       Error &error)
{
    lldb::ProcessSP process_sp;
    if (IsRemote())
    {
        if (IsConnected())
        {
            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
            uint16_t port = LaunchGDBserverAndGetPort(debugserver_pid);

            if (port == 0)
            {
                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
            }
            else
            {
                if (target == NULL)
                {
                    TargetSP new_target_sp;
                    
                    error = debugger.GetTargetList().CreateTarget (debugger,
                                                                   NULL,
                                                                   NULL,
                                                                   false,
                                                                   NULL,
                                                                   new_target_sp);
                    target = new_target_sp.get();
                }
                else
                    error.Clear();
                
                if (target && error.Success())
                {
                    debugger.GetTargetList().SetSelectedTarget(target);
                    
                    // The darwin always currently uses the GDB remote debugger plug-in
                    // so even when debugging locally we are debugging remotely!
                    process_sp = target->CreateProcess (launch_info.GetListenerForProcess(debugger), "gdb-remote", NULL);
                    
                    if (process_sp)
                    {
                        std::string connect_url =
                            MakeGdbServerUrl(m_platform_scheme, m_platform_hostname, port);
                        error = process_sp->ConnectRemote (nullptr, connect_url.c_str());
                        // Retry the connect remote one time...
                        if (error.Fail())
                            error = process_sp->ConnectRemote (nullptr, connect_url.c_str());
                        if (error.Success())
                            error = process_sp->Launch(launch_info);
                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
                        {
                            printf ("error: connect remote failed (%s)\n", error.AsCString());
                            KillSpawnedProcess(debugserver_pid);
                        }
                    }
                }
            }
        }
        else
        {
            error.SetErrorString("not connected to remote gdb server");
        }
    }
    return process_sp;

}
예제 #6
0
lldb::ProcessSP
PlatformPOSIX::Attach (ProcessAttachInfo &attach_info,
                       Debugger &debugger,
                       Target *target,
                       Error &error)
{
    lldb::ProcessSP process_sp;
    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));

    if (IsHost())
    {
        if (target == NULL)
        {
            TargetSP new_target_sp;

            error = debugger.GetTargetList().CreateTarget (debugger,
                                                           NULL,
                                                           NULL,
                                                           false,
                                                           NULL,
                                                           new_target_sp);
            target = new_target_sp.get();
            if (log)
                log->Printf ("PlatformPOSIX::%s created new target", __FUNCTION__);
        }
        else
        {
            error.Clear();
            if (log)
                log->Printf ("PlatformPOSIX::%s target already existed, setting target", __FUNCTION__);
        }

        if (target && error.Success())
        {
            debugger.GetTargetList().SetSelectedTarget(target);
            if (log)
            {
                ModuleSP exe_module_sp = target->GetExecutableModule ();
                log->Printf("PlatformPOSIX::%s set selected target to %p %s", __FUNCTION__, (void *)target,
                            exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() : "<null>");
            }


            process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), attach_info.GetProcessPluginName(), NULL);

            if (process_sp)
            {
                // Set UnixSignals appropriately.
                process_sp->SetUnixSignals (Host::GetUnixSignals ());

                auto listener_sp = attach_info.GetHijackListener();
                if (listener_sp == nullptr)
                {
                    listener_sp.reset(new Listener("lldb.PlatformPOSIX.attach.hijack"));
                    attach_info.SetHijackListener(listener_sp);
                }
                process_sp->HijackProcessEvents(listener_sp.get());
                error = process_sp->Attach (attach_info);
            }
        }
    }
    else
    {
        if (m_remote_platform_sp)
            process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error);
        else
            error.SetErrorString ("the platform is not currently connected");
    }
    return process_sp;
}
예제 #7
0
lldb::ProcessSP
PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
                                 Debugger &debugger,
                                 Target *target,       // Can be NULL, if NULL create a new target, else use existing one
                                 Listener &listener, 
                                 Error &error)
{
    lldb::ProcessSP process_sp;
    if (IsRemote())
    {
        if (IsConnected())
        {
            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
            ArchSpec remote_arch = GetRemoteSystemArchitecture();
            llvm::Triple &remote_triple = remote_arch.GetTriple();
            uint16_t port = 0;
            if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS)
            {
                // When remote debugging to iOS, we use a USB mux that always talks
                // to localhost, so we will need the remote debugserver to accept connections
                // only from localhost, no matter what our current hostname is
                port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1");
            }
            else
            {
                // All other hosts should use their actual hostname
                port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL);
            }
            
            if (port == 0)
            {
                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
            }
            else
            {
                if (target == NULL)
                {
                    TargetSP new_target_sp;
                    
                    error = debugger.GetTargetList().CreateTarget (debugger,
                                                                   NULL,
                                                                   NULL, 
                                                                   false,
                                                                   NULL,
                                                                   new_target_sp);
                    target = new_target_sp.get();
                }
                else
                    error.Clear();
                
                if (target && error.Success())
                {
                    debugger.GetTargetList().SetSelectedTarget(target);
                    
                    // The darwin always currently uses the GDB remote debugger plug-in
                    // so even when debugging locally we are debugging remotely!
                    process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
                    
                    if (process_sp)
                    {
                        char connect_url[256];
                        const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
                        const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
                        int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
                        const int connect_url_len = ::snprintf (connect_url, 
                                                                sizeof(connect_url), 
                                                                "connect://%s:%u", 
                                                                override_hostname ? override_hostname : GetHostname (), 
                                                                port + port_offset);
                        assert (connect_url_len < (int)sizeof(connect_url));
                        error = process_sp->ConnectRemote (NULL, connect_url);
                        if (error.Success())
                            error = process_sp->Attach(attach_info);
                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
                        {
                            m_gdb_client.KillSpawnedProcess(debugserver_pid);
                        }
                    }
                }
            }
        }
        else
        {
            error.SetErrorString("not connected to remote gdb server");
        }
    }
    return process_sp;
}
// 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(lldb_private::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;

    // Ensure we're using llgs for local debugging.
    if (!UseLlgsForLocalDebugging ())
    {
        assert (false && "we're trying to debug a local process but platform.plugin.linux.use-llgs-for-local is false, should never get here");
        error.SetErrorString ("attempted to start gdb-remote-based debugging for local process but platform.plugin.linux.use-llgs-for-local is false");
        return 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__);
    }

    // Set the unix signals properly.
    process_sp->SetUnixSignals (Host::GetUnixSignals ());

    // 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());
            process_sp->RestoreProcessEvents();

            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;
}
예제 #9
0
// For local debugging, NetBSD 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
PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger,
                             Target *target, // Can be NULL, if NULL create a new
                                             // target, else use existing one
                             Status &error) {
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
  LLDB_LOG(log, "target {0}", 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) {
    LLDB_LOG(log, "creating new target");
    TargetSP new_target_sp;
    error = debugger.GetTargetList().CreateTarget(
        debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
    if (error.Fail()) {
      LLDB_LOG(log, "failed to create new target: {0}", error);
      return process_sp;
    }

    target = new_target_sp.get();
    if (!target) {
      error.SetErrorString("CreateTarget() returned nullptr");
      LLDB_LOG(log, "error: {0}", error);
      return process_sp;
    }
  }

  // Mark target as currently selected target.
  debugger.GetTargetList().SetSelectedTarget(target);

  // Now create the gdb-remote process.
  LLDB_LOG(log, "having target create process with gdb-remote plugin");
  process_sp =
      target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr);

  if (!process_sp) {
    error.SetErrorString("CreateProcess() failed for gdb-remote process");
    LLDB_LOG(log, "error: {0}", error);
    return process_sp;
  }

  LLDB_LOG(log, "successfully created process");
  // Adjust launch for a hijacker.
  ListenerSP listener_sp;
  if (!launch_info.GetHijackListener()) {
    LLDB_LOG(log, "setting up hijacker");
    listener_sp =
        Listener::MakeListener("lldb.PlatformNetBSD.DebugProcess.hijack");
    launch_info.SetHijackListener(listener_sp);
    process_sp->HijackProcessEvents(listener_sp);
  }

  // Log file actions.
  if (log) {
    LLDB_LOG(log, "launching process with the following file actions:");
    StreamString stream;
    size_t i = 0;
    const FileAction *file_action;
    while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) {
      file_action->Dump(stream);
      LLDB_LOG(log, "{0}", stream.GetData());
      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(
          llvm::None, NULL, false, listener_sp);

      LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), 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 != PseudoTerminal::invalid_fd) {
      process_sp->SetSTDIOFileDescriptor(pty_fd);
      LLDB_LOG(log, "hooked up STDIO pty to process");
    } else
      LLDB_LOG(log, "not using process STDIO pty");
  } else {
    LLDB_LOG(log, "process launch failed: {0}", error);
    // FIXME figure out appropriate cleanup here.  Do we delete the target? Do
    // we delete the process?  Does our caller do that?
  }

  return process_sp;
}