Exemple #1
0
static bool
LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec)
{
    const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
    if (exec_fspec)
    {
        char path[PATH_MAX];
        if (exec_fspec->GetPath(path, sizeof(path)))
        {
            // Make sure the module isn't already just a dSYM file...
            if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL)
            {
                size_t obj_file_path_length = strlen(path);
                strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
                strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));

                dsym_fspec.SetFile(path, false);

                if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
                {
                    return true;
                }
                else
                {
                    path[obj_file_path_length] = '\0';

                    char *last_dot = strrchr(path, '.');
                    while (last_dot != NULL && last_dot[0])
                    {
                        char *next_slash = strchr(last_dot, '/');
                        if (next_slash != NULL)
                        {
                            *next_slash = '\0';
                            strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path));
                            strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path));
                            dsym_fspec.SetFile(path, false);
                            if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
                                return true;
                            else
                            {
                                *last_dot = '\0';
                                char *prev_slash = strrchr(path, '/');
                                if (prev_slash != NULL)
                                    *prev_slash = '\0';
                                else
                                    break;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
        }
    }
    dsym_fspec.Clear();
    return false;
}
bool
PathMappingList::FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const
{
    if (!m_pairs.empty())
    {
        char orig_path[PATH_MAX];
        char new_path[PATH_MAX];
        const size_t orig_path_len = orig_spec.GetPath (orig_path, sizeof(orig_path));
        if (orig_path_len > 0)
        {
            const_iterator pos, end = m_pairs.end();
            for (pos = m_pairs.begin(); pos != end; ++pos)
            {
                const size_t prefix_len = pos->first.GetLength();
                
                if (orig_path_len >= prefix_len)
                {
                    if (::strncmp (pos->first.GetCString(), orig_path, prefix_len) == 0)
                    {
                        const size_t new_path_len = snprintf(new_path, sizeof(new_path), "%s/%s", pos->second.GetCString(), orig_path + prefix_len);
                        if (new_path_len < sizeof(new_path))
                        {
                            new_spec.SetFile (new_path, true);
                            if (new_spec.Exists())
                                return true;
                        }
                    }
                }
            }
        }
    }
    new_spec.Clear();
    return false;
}
Exemple #3
0
Error
ModuleCache::Get (const FileSpec &root_dir_spec,
                  const char *hostname,
                  const UUID &uuid,
                  const FileSpec &platform_module_spec,
                  FileSpec &cached_module_spec)
{
    cached_module_spec.Clear ();

    const auto module_spec_dir = GetModuleDirectory (root_dir_spec, uuid);
    const auto module_file_path = JoinPath (module_spec_dir, platform_module_spec.GetFilename ().AsCString ());

    Error error;
    if (!module_file_path.Exists ())
    {
        error.SetErrorStringWithFormat ("module %s not found", module_file_path.GetPath ().c_str ());
        return error;
    }
    cached_module_spec = module_file_path;

    // We may have already cached module but downloaded from an another host - in this case let's create a symlink to it.
    const auto sysroot_module_path_spec = GetHostSysRootModulePath (root_dir_spec, hostname, platform_module_spec);
    if (!sysroot_module_path_spec.Exists ())
        CreateHostSysRootModuleSymLink (sysroot_module_path_spec, cached_module_spec);

    return error;
}
Exemple #4
0
void
Function::GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
{
    line_no = 0;
    source_file.Clear();
    
    if (m_comp_unit == NULL)
        return;
        
    if (m_type != NULL && m_type->GetDeclaration().GetLine() != 0)
    {
        source_file = m_type->GetDeclaration().GetFile();
        line_no = m_type->GetDeclaration().GetLine();
    }
    else 
    {
        LineTable *line_table = m_comp_unit->GetLineTable();
        if (line_table == NULL)
            return;
            
        LineEntry line_entry;
        if (line_table->FindLineEntryByAddress (GetAddressRange().GetBaseAddress(), line_entry, NULL))
        {
            line_no = line_entry.line;
            source_file = line_entry.file;
        }
    }
}
Exemple #5
0
bool
HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec)
{
    file_spec.Clear();

    FileSpec temp_file_spec;
    if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
        return false;

    temp_file_spec.AppendPathComponent("lldb");
    if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success())
        return false;

    file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
    return true;
}
Exemple #6
0
Error
File::GetFileSpec (FileSpec &file_spec) const
{
    Error error;
#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
    if (IsValid ())
    {
        char path[PATH_MAX];
        if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
            error.SetErrorToErrno();
        else
            file_spec.SetFile (path, false);
    }
    else 
    {
        error.SetErrorString("invalid file handle");
    }
#elif defined(__linux__)
    char proc[64];
    char path[PATH_MAX];
    if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
        error.SetErrorString ("cannot resolve file descriptor");
    else
    {
        ssize_t len;
        if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
            error.SetErrorToErrno();
        else
        {
            path[len] = '\0';
            file_spec.SetFile (path, false);
        }
    }
#else
    error.SetErrorString ("File::GetFileSpec is not supported on this platform");
#endif

    if (error.Fail())
        file_spec.Clear();
    return error;
}
Exemple #7
0
void
Function::GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
{
    line_no = 0;
    source_file.Clear();
    
    // The -1 is kind of cheesy, but I want to get the last line entry for the given function, not the 
    // first entry of the next.
    Address scratch_addr(GetAddressRange().GetBaseAddress());
    scratch_addr.SetOffset (scratch_addr.GetOffset() + GetAddressRange().GetByteSize() - 1);
    
    LineTable *line_table = m_comp_unit->GetLineTable();
    if (line_table == NULL)
        return;
        
    LineEntry line_entry;
    if (line_table->FindLineEntryByAddress (scratch_addr, line_entry, NULL))
    {
        line_no = line_entry.line;
        source_file = line_entry.file;
    }
}
Exemple #8
0
bool
Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle)
{
    bundle.Clear();
    return false;
}
Exemple #9
0
static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
                                              FileSpec &dsym_fspec) {
  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
  const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
  if (exec_fspec) {
    char path[PATH_MAX];
    if (exec_fspec->GetPath(path, sizeof(path))) {
      // Make sure the module isn't already just a dSYM file...
      if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) {
        if (log) {
          if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) {
            log->Printf(
                "Searching for dSYM bundle next to executable %s, UUID %s",
                path, module_spec.GetUUIDPtr()->GetAsString().c_str());
          } else {
            log->Printf("Searching for dSYM bundle next to executable %s",
                        path);
          }
        }
        size_t obj_file_path_length = strlen(path);
        ::strncat(path, ".dSYM/Contents/Resources/DWARF/",
                  sizeof(path) - strlen(path) - 1);
        ::strncat(path, exec_fspec->GetFilename().AsCString(),
                  sizeof(path) - strlen(path) - 1);

        dsym_fspec.SetFile(path, false);

        ModuleSpecList module_specs;
        ModuleSpec matched_module_spec;
        if (dsym_fspec.Exists() &&
            FileAtPathContainsArchAndUUID(dsym_fspec,
                                          module_spec.GetArchitecturePtr(),
                                          module_spec.GetUUIDPtr())) {
          if (log) {
            log->Printf("dSYM with matching UUID & arch found at %s", path);
          }
          return true;
        } else {
          path[obj_file_path_length] = '\0';

          char *last_dot = strrchr(path, '.');
          while (last_dot != NULL && last_dot[0]) {
            char *next_slash = strchr(last_dot, '/');
            if (next_slash != NULL) {
              *next_slash = '\0';
              ::strncat(path, ".dSYM/Contents/Resources/DWARF/",
                        sizeof(path) - strlen(path) - 1);
              ::strncat(path, exec_fspec->GetFilename().AsCString(),
                        sizeof(path) - strlen(path) - 1);
              dsym_fspec.SetFile(path, false);
              if (dsym_fspec.Exists() &&
                  FileAtPathContainsArchAndUUID(
                      dsym_fspec, module_spec.GetArchitecturePtr(),
                      module_spec.GetUUIDPtr())) {
                if (log) {
                  log->Printf("dSYM with matching UUID & arch found at %s",
                              path);
                }
                return true;
              } else {
                *last_dot = '\0';
                char *prev_slash = strrchr(path, '/');
                if (prev_slash != NULL)
                  *prev_slash = '\0';
                else
                  break;
              }
            } else {
              break;
            }
          }
        }
      }
    }
  }
  dsym_fspec.Clear();
  return false;
}
Exemple #10
0
static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
                                              FileSpec &dsym_fspec) {
  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
  const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
  if (exec_fspec) {
    char path[PATH_MAX];
    if (exec_fspec->GetPath(path, sizeof(path))) {
      // Make sure the module isn't already just a dSYM file...
      if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) {
        if (log) {
          if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) {
            log->Printf(
                "Searching for dSYM bundle next to executable %s, UUID %s",
                path, module_spec.GetUUIDPtr()->GetAsString().c_str());
          } else {
            log->Printf("Searching for dSYM bundle next to executable %s",
                        path);
          }
        }
        ::strncat(path, ".dSYM/Contents/Resources/DWARF/",
                  sizeof(path) - strlen(path) - 1);
        ::strncat(path, exec_fspec->GetFilename().AsCString(),
                  sizeof(path) - strlen(path) - 1);

        dsym_fspec.SetFile(path, false);

        ModuleSpecList module_specs;
        ModuleSpec matched_module_spec;
        if (dsym_fspec.Exists() &&
            FileAtPathContainsArchAndUUID(dsym_fspec,
                                          module_spec.GetArchitecturePtr(),
                                          module_spec.GetUUIDPtr())) {
          if (log) {
            log->Printf("dSYM with matching UUID & arch found at %s", path);
          }
          return true;
        } else {
          FileSpec parent_dirs = exec_fspec;

          // Remove the binary name from the FileSpec
          parent_dirs.RemoveLastPathComponent();

          // Add a ".dSYM" name to each directory component of the path,
          // stripping off components.  e.g. we may have a binary like
          // /S/L/F/Foundation.framework/Versions/A/Foundation
          // and
          // /S/L/F/Foundation.framework.dSYM
          //
          // so we'll need to start with /S/L/F/Foundation.framework/Versions/A,
          // add the .dSYM part to the "A", and if that doesn't exist, strip off
          // the "A" and try it again with "Versions", etc., until we find a
          // dSYM bundle or we've stripped off enough path components that
          // there's no need to continue.

          for (int i = 0; i < 4; i++) {
            // Does this part of the path have a "." character - could it be a
            // bundle's top level directory?
            const char *fn = parent_dirs.GetFilename().AsCString();
            if (fn == nullptr)
              break;
            if (::strchr(fn, '.') != nullptr) {
              dsym_fspec = parent_dirs;
              dsym_fspec.RemoveLastPathComponent();

              // If the current directory name is "Foundation.framework", see if
              // "Foundation.framework.dSYM/Contents/Resources/DWARF/Foundation"
              // exists & has the right uuid.
              std::string dsym_fn = fn;
              dsym_fn += ".dSYM";
              dsym_fspec.AppendPathComponent(dsym_fn.c_str());
              dsym_fspec.AppendPathComponent("Contents");
              dsym_fspec.AppendPathComponent("Resources");
              dsym_fspec.AppendPathComponent("DWARF");
              dsym_fspec.AppendPathComponent(
                  exec_fspec->GetFilename().AsCString());
              if (dsym_fspec.Exists() &&
                  FileAtPathContainsArchAndUUID(
                      dsym_fspec, module_spec.GetArchitecturePtr(),
                      module_spec.GetUUIDPtr())) {
                if (log) {
                  log->Printf("dSYM with matching UUID & arch found at %s",
                              dsym_fspec.GetPath().c_str());
                }
                return true;
              }
            }
            parent_dirs.RemoveLastPathComponent();
          }
        }
      }
    }
  }
  dsym_fspec.Clear();
  return false;
}
Error
GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
                                                 uint16_t in_port,
                                                 lldb_private::ProcessLaunchInfo &launch_info,
                                                 uint16_t &out_port)
{
    out_port = in_port;
    Error error;
    // If we locate debugserver, keep that located version around
    static FileSpec g_debugserver_file_spec;
    
    char debugserver_path[PATH_MAX];
    FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
    
    // Always check to see if we have an environment override for the path
    // to the debugserver to use and use it if we do.
    const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
    if (env_debugserver_path)
        debugserver_file_spec.SetFile (env_debugserver_path, false);
    else
        debugserver_file_spec = g_debugserver_file_spec;
    bool debugserver_exists = debugserver_file_spec.Exists();
    if (!debugserver_exists)
    {
        // The debugserver binary is in the LLDB.framework/Resources
        // directory. 
        if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec))
        {
            debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME);
            debugserver_exists = debugserver_file_spec.Exists();
            if (debugserver_exists)
            {
                g_debugserver_file_spec = debugserver_file_spec;
            }
            else
            {
                g_debugserver_file_spec.Clear();
                debugserver_file_spec.Clear();
            }
        }
    }
    
    if (debugserver_exists)
    {
        debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));

        Args &debugserver_args = launch_info.GetArguments();
        debugserver_args.Clear();
        char arg_cstr[PATH_MAX];
        
        // Start args with "debugserver /file/path -r --"
        debugserver_args.AppendArgument(debugserver_path);

        // If a host and port is supplied then use it
        char host_and_port[128];
        if (hostname)
        {
            snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port);
            debugserver_args.AppendArgument(host_and_port);
        }
        else
        {
            host_and_port[0] = '\0';
        }

        // use native registers, not the GDB registers
        debugserver_args.AppendArgument("--native-regs");   
        // make debugserver run in its own session so signals generated by 
        // special terminal key sequences (^C) don't affect debugserver
        debugserver_args.AppendArgument("--setsid");

        char named_pipe_path[PATH_MAX];
        named_pipe_path[0] = '\0';

        bool listen = false;
        if (host_and_port[0])
        {
            // Create a temporary file to get the stdout/stderr and redirect the
            // output of the command into this file. We will later read this file
            // if all goes well and fill the data into "command_output_ptr"

            if (in_port == 0)
            {
                // Binding to port zero, we need to figure out what port it ends up
                // using using a named pipe...
                FileSpec tmpdir_file_spec;
                if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
                {
                    tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
                    strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
                }
                else
                {
                    strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path));
                }

                if (::mktemp (named_pipe_path))
                {
                    if (::mkfifo(named_pipe_path, 0600) == 0)
                    {
                        debugserver_args.AppendArgument("--named-pipe");
                        debugserver_args.AppendArgument(named_pipe_path);
                    }
                }
            }
            else
            {
                listen = true;
            }
        }
        else
        {
            // No host and port given, so lets listen on our end and make the debugserver
            // connect to us..
            error = StartListenThread ("localhost", 0);
            if (error.Fail())
                return error;

            ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
            out_port = connection->GetBoundPort(3);
            assert (out_port != 0);
            char port_cstr[32];
            snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port);
            // Send the host and port down that debugserver and specify an option
            // so that it connects back to the port we are listening to in this process
            debugserver_args.AppendArgument("--reverse-connect");
            debugserver_args.AppendArgument(port_cstr);
        }

        
        const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
        if (env_debugserver_log_file)
        {
            ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
            debugserver_args.AppendArgument(arg_cstr);
        }
        
        const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
        if (env_debugserver_log_flags)
        {
            ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
            debugserver_args.AppendArgument(arg_cstr);
        }
        
        // Close STDIN, STDOUT and STDERR. We might need to redirect them
        // to "/dev/null" if we run into any problems.
        launch_info.AppendCloseFileAction (STDIN_FILENO);
        launch_info.AppendCloseFileAction (STDOUT_FILENO);
        launch_info.AppendCloseFileAction (STDERR_FILENO);
        
        error = Host::LaunchProcess(launch_info);
        
        if (named_pipe_path[0])
        {
            File name_pipe_file;
            error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead);
            if (error.Success())
            {
                char port_cstr[256];
                port_cstr[0] = '\0';
                size_t num_bytes = sizeof(port_cstr);
                error = name_pipe_file.Read(port_cstr, num_bytes);
                assert (error.Success());
                assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
                out_port = Args::StringToUInt32(port_cstr, 0);
                name_pipe_file.Close();
            }
            Host::Unlink(named_pipe_path);
        }
        else if (listen)
        {
            
        }
        else
        {
            // Make sure we actually connect with the debugserver...
            JoinListenThread();
        }
    }
    else
    {
        error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME );
    }
    return error;
}
Error
GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,
                                                 const char *unix_socket_name,  // For handshaking
                                                 lldb_private::ProcessLaunchInfo &launch_info)
{
    Error error;
    // If we locate debugserver, keep that located version around
    static FileSpec g_debugserver_file_spec;
    
    // This function will fill in the launch information for the debugserver
    // instance that gets launched.
    launch_info.Clear();
    
    char debugserver_path[PATH_MAX];
    FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
    
    // Always check to see if we have an environment override for the path
    // to the debugserver to use and use it if we do.
    const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
    if (env_debugserver_path)
        debugserver_file_spec.SetFile (env_debugserver_path, false);
    else
        debugserver_file_spec = g_debugserver_file_spec;
    bool debugserver_exists = debugserver_file_spec.Exists();
    if (!debugserver_exists)
    {
        // The debugserver binary is in the LLDB.framework/Resources
        // directory. 
        if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec))
        {
            debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME);
            debugserver_exists = debugserver_file_spec.Exists();
            if (debugserver_exists)
            {
                g_debugserver_file_spec = debugserver_file_spec;
            }
            else
            {
                g_debugserver_file_spec.Clear();
                debugserver_file_spec.Clear();
            }
        }
    }
    
    if (debugserver_exists)
    {
        debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));

        Args &debugserver_args = launch_info.GetArguments();
        debugserver_args.Clear();
        char arg_cstr[PATH_MAX];
        
        // Start args with "debugserver /file/path -r --"
        debugserver_args.AppendArgument(debugserver_path);
        debugserver_args.AppendArgument(debugserver_url);
        // use native registers, not the GDB registers
        debugserver_args.AppendArgument("--native-regs");   
        // make debugserver run in its own session so signals generated by 
        // special terminal key sequences (^C) don't affect debugserver
        debugserver_args.AppendArgument("--setsid");
        
        if (unix_socket_name && unix_socket_name[0])
        {
            debugserver_args.AppendArgument("--unix-socket");
            debugserver_args.AppendArgument(unix_socket_name);
        }

        const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
        if (env_debugserver_log_file)
        {
            ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
            debugserver_args.AppendArgument(arg_cstr);
        }
        
        const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
        if (env_debugserver_log_flags)
        {
            ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
            debugserver_args.AppendArgument(arg_cstr);
        }
        //            debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
        //            debugserver_args.AppendArgument("--log-flags=0x802e0e");
        
        // We currently send down all arguments, attach pids, or attach 
        // process names in dedicated GDB server packets, so we don't need
        // to pass them as arguments. This is currently because of all the
        // things we need to setup prior to launching: the environment,
        // current working dir, file actions, etc.
#if 0
        // Now append the program arguments
        if (inferior_argv)
        {
            // Terminate the debugserver args so we can now append the inferior args
            debugserver_args.AppendArgument("--");
            
            for (int i = 0; inferior_argv[i] != NULL; ++i)
                debugserver_args.AppendArgument (inferior_argv[i]);
        }
        else if (attach_pid != LLDB_INVALID_PROCESS_ID)
        {
            ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
            debugserver_args.AppendArgument (arg_cstr);
        }
        else if (attach_name && attach_name[0])
        {
            if (wait_for_launch)
                debugserver_args.AppendArgument ("--waitfor");
            else
                debugserver_args.AppendArgument ("--attach");
            debugserver_args.AppendArgument (attach_name);
        }
#endif
        
        // Close STDIN, STDOUT and STDERR. We might need to redirect them
        // to "/dev/null" if we run into any problems.
//        launch_info.AppendCloseFileAction (STDIN_FILENO);
//        launch_info.AppendCloseFileAction (STDOUT_FILENO);
//        launch_info.AppendCloseFileAction (STDERR_FILENO);
        
        error = Host::LaunchProcess(launch_info);
    }
    else
    {
        error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME );
    }
    return error;
}
Error
GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
                                                 uint16_t in_port,
                                                 ProcessLaunchInfo &launch_info,
                                                 uint16_t &out_port)
{
    Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
    if (log)
        log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port);

    out_port = in_port;
    Error error;
    // If we locate debugserver, keep that located version around
    static FileSpec g_debugserver_file_spec;
    
    char debugserver_path[PATH_MAX];
    FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
    
    // Always check to see if we have an environment override for the path
    // to the debugserver to use and use it if we do.
    const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
    if (env_debugserver_path)
    {
        debugserver_file_spec.SetFile (env_debugserver_path, false);
        if (log)
            log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path);
    }
    else
        debugserver_file_spec = g_debugserver_file_spec;
    bool debugserver_exists = debugserver_file_spec.Exists();
    if (!debugserver_exists)
    {
        // The debugserver binary is in the LLDB.framework/Resources
        // directory.
        if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec))
        {
            debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME);
            debugserver_exists = debugserver_file_spec.Exists();
            if (debugserver_exists)
            {
                if (log)
                    log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ());

                g_debugserver_file_spec = debugserver_file_spec;
            }
            else
            {
                if (log)
                    log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ());

                g_debugserver_file_spec.Clear();
                debugserver_file_spec.Clear();
            }
        }
    }
    
    if (debugserver_exists)
    {
        debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));

        Args &debugserver_args = launch_info.GetArguments();
        debugserver_args.Clear();
        char arg_cstr[PATH_MAX];

        // Start args with "debugserver /file/path -r --"
        debugserver_args.AppendArgument(debugserver_path);

#if !defined(__APPLE__)
        // First argument to lldb-server must be mode in which to run.
        debugserver_args.AppendArgument("gdbserver");
#endif

        // If a host and port is supplied then use it
        char host_and_port[128];
        if (hostname)
        {
            snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port);
            debugserver_args.AppendArgument(host_and_port);
        }
        else
        {
            host_and_port[0] = '\0';
        }

        // use native registers, not the GDB registers
        debugserver_args.AppendArgument("--native-regs");

        if (launch_info.GetLaunchInSeparateProcessGroup())
        {
            debugserver_args.AppendArgument("--setsid");
        }

        llvm::SmallString<PATH_MAX> named_pipe_path;
        Pipe port_pipe;

        bool listen = false;
        if (host_and_port[0])
        {
            // Create a temporary file to get the stdout/stderr and redirect the
            // output of the command into this file. We will later read this file
            // if all goes well and fill the data into "command_output_ptr"

            if (in_port == 0)
            {
                // Binding to port zero, we need to figure out what port it ends up
                // using using a named pipe...
                error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path);
                if (error.Success())
                {
                    debugserver_args.AppendArgument("--named-pipe");
                    debugserver_args.AppendArgument(named_pipe_path.c_str());
                }
                else
                {
                    if (log)
                        log->Printf("GDBRemoteCommunication::%s() "
                                "named pipe creation failed: %s",
                                __FUNCTION__, error.AsCString());
                    // let's try an unnamed pipe
                    error = port_pipe.CreateNew(true);
                    if (error.Fail())
                    {
                        if (log)
                            log->Printf("GDBRemoteCommunication::%s() "
                                    "unnamed pipe creation failed: %s",
                                    __FUNCTION__, error.AsCString());
                        return error;
                    }
                    int write_fd = port_pipe.GetWriteFileDescriptor();
                    debugserver_args.AppendArgument("--pipe");
                    debugserver_args.AppendArgument(std::to_string(write_fd).c_str());
                    launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor());
                }
            }
            else
            {
                listen = true;
            }
        }
        else
        {
            // No host and port given, so lets listen on our end and make the debugserver
            // connect to us..
            error = StartListenThread ("127.0.0.1", 0);
            if (error.Fail())
                return error;

            ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
            // Wait for 10 seconds to resolve the bound port
            out_port = connection->GetListeningPort(10);
            if (out_port > 0)
            {
                char port_cstr[32];
                snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port);
                // Send the host and port down that debugserver and specify an option
                // so that it connects back to the port we are listening to in this process
                debugserver_args.AppendArgument("--reverse-connect");
                debugserver_args.AppendArgument(port_cstr);
            }
            else
            {
                error.SetErrorString ("failed to bind to port 0 on 127.0.0.1");
                return error;
            }
        }
        
        const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
        if (env_debugserver_log_file)
        {
            ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
            debugserver_args.AppendArgument(arg_cstr);
        }
        
        const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
        if (env_debugserver_log_flags)
        {
            ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
            debugserver_args.AppendArgument(arg_cstr);
        }

        // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back.
        uint32_t env_var_index = 1;
        bool has_env_var;
        do
        {
            char env_var_name[64];
            snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++);
            const char *extra_arg = getenv(env_var_name);
            has_env_var = extra_arg != nullptr;

            if (has_env_var)
            {
                debugserver_args.AppendArgument (extra_arg);
                if (log)
                    log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg);
            }
        } while (has_env_var);

        // Close STDIN, STDOUT and STDERR.
        launch_info.AppendCloseFileAction (STDIN_FILENO);
        launch_info.AppendCloseFileAction (STDOUT_FILENO);
        launch_info.AppendCloseFileAction (STDERR_FILENO);

        // Redirect STDIN, STDOUT and STDERR to "/dev/null".
        launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
        launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true);
        launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true);
        
        error = Host::LaunchProcess(launch_info);
        
        if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
        {
            if (named_pipe_path.size() > 0)
            {
                error = port_pipe.OpenAsReader(named_pipe_path, false);
                if (error.Fail())
                    if (log)
                        log->Printf("GDBRemoteCommunication::%s() "
                                "failed to open named pipe %s for reading: %s",
                                __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
            }

            if (port_pipe.CanWrite())
                port_pipe.CloseWriteFileDescriptor();
            if (port_pipe.CanRead())
            {
                char port_cstr[256];
                port_cstr[0] = '\0';
                size_t num_bytes = sizeof(port_cstr);
                // Read port from pipe with 10 second timeout.
                error = port_pipe.ReadWithTimeout(port_cstr, num_bytes,
                        std::chrono::seconds{10}, num_bytes);
                if (error.Success())
                {
                    assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
                    out_port = StringConvert::ToUInt32(port_cstr, 0);
                    if (log)
                        log->Printf("GDBRemoteCommunication::%s() "
                                "debugserver listens %u port",
                                __FUNCTION__, out_port);
                }
                else
                {
                    if (log)
                        log->Printf("GDBRemoteCommunication::%s() "
                                "failed to read a port value from pipe %s: %s",
                                __FUNCTION__, named_pipe_path.c_str(), error.AsCString());

                }
                port_pipe.Close();
            }

            if (named_pipe_path.size() > 0)
            {
                const auto err = port_pipe.Delete(named_pipe_path);
                if (err.Fail())
                {
                    if (log)
                        log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s",
                                __FUNCTION__, named_pipe_path.c_str(), err.AsCString());
                }
            }

            // Make sure we actually connect with the debugserver...
            JoinListenThread();
        }
    }
    else
    {
        error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME );
    }
    return error;
}
Exemple #14
0
bool
HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec)
{
    file_spec.Clear();

#if defined(LLDB_DISABLE_PYTHON)
    if (type == lldb::ePathTypePythonDir)
        return false;
#endif

    FileSpec *result = nullptr;
    switch (type)
    {
        case lldb::ePathTypeLLDBShlibDir:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputeSharedLibraryDirectory (g_fields->m_lldb_so_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_so_dir;
            }
            break;
        case lldb::ePathTypeSupportExecutableDir:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputeSupportExeDirectory (g_fields->m_lldb_support_exe_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
                                    g_fields->m_lldb_support_exe_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_support_exe_dir;
            }
            break;
        case lldb::ePathTypeHeaderDir:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputeHeaderDirectory (g_fields->m_lldb_headers_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_headers_dir;
            }
            break;
        case lldb::ePathTypePythonDir:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputePythonDirectory (g_fields->m_lldb_python_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_python_dir;
            }
            break;
        case lldb::ePathTypeClangDir:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputeClangDirectory (g_fields->m_lldb_clang_resource_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_clang_resource_dir;
            }
            break;
        case lldb::ePathTypeLLDBSystemPlugins:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputeSystemPluginsDirectory (g_fields->m_lldb_system_plugin_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
                                    g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_system_plugin_dir;
            }
            break;
        case lldb::ePathTypeLLDBUserPlugins:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputeUserPluginsDirectory (g_fields->m_lldb_user_plugin_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
                                    g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_user_plugin_dir;
            }
            break;
        case lldb::ePathTypeLLDBTempSystemDir:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputeProcessTempFileDirectory (g_fields->m_lldb_process_tmp_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_process_tmp_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_process_tmp_dir;
            }
            break;
        case lldb::ePathTypeGlobalLLDBTempSystemDir:
            {
                static std::once_flag g_once_flag;
                static bool success = false;
                std::call_once(g_once_flag,  []() {
                    success = HostInfo::ComputeGlobalTempFileDirectory (g_fields->m_lldb_global_tmp_dir);
                    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
                    if (log)
                        log->Printf("HostInfoBase::GetLLDBPath(ePathTypeGlobalLLDBTempSystemDir) => '%s'", g_fields->m_lldb_global_tmp_dir.GetPath().c_str());
                });
                if (success)
                    result = &g_fields->m_lldb_global_tmp_dir;
            }
            break;
    }

    if (!result)
        return false;
    file_spec = *result;
    return true;
}