Exemplo n.º 1
0
bool
ThreadMacOSX::RestoreSuspendCount()
{
    Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
    if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
        log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
    Error err;
    lldb::tid_t tid = GetID ();
    if (ThreadIDIsValid(tid) == false)
        return false;
    else if (m_suspend_count > m_basic_info.suspend_count)
    {
        while (m_suspend_count > m_basic_info.suspend_count)
        {
            err = ::thread_resume (tid);
            if (err.Success())
                --m_suspend_count;
            if (log || err.Fail())
                err.PutToLog(log, "::thread_resume (%4.4x)", tid);
        }
    }
    else if (m_suspend_count < m_basic_info.suspend_count)
    {
        while (m_suspend_count < m_basic_info.suspend_count)
        {
            err = ::thread_suspend (tid);
            if (err.Success())
                --m_suspend_count;
            if (log || err.Fail())
                err.PutToLog(log, "::thread_suspend (%4.4x)", tid);
        }
    }
    return  m_suspend_count == m_basic_info.suspend_count;
}
Exemplo n.º 2
0
bool
Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Error &error)
{
    if (info == NULL)
        return false;

    posix_spawn_file_actions_t *file_actions = reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);

    switch (info->GetAction())
    {
        case FileAction::eFileActionNone:
            error.Clear();
            break;

        case FileAction::eFileActionClose:
            if (info->GetFD() == -1)
                error.SetErrorString("invalid fd for posix_spawn_file_actions_addclose(...)");
            else
            {
                error.SetError(::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), eErrorTypePOSIX);
                if (log && (error.Fail() || log))
                    error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)",
                                   static_cast<void *>(file_actions), info->GetFD());
            }
            break;

        case FileAction::eFileActionDuplicate:
            if (info->GetFD() == -1)
                error.SetErrorString("invalid fd for posix_spawn_file_actions_adddup2(...)");
            else if (info->GetActionArgument() == -1)
                error.SetErrorString("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
            else
            {
                error.SetError(
                    ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), info->GetActionArgument()),
                    eErrorTypePOSIX);
                if (log && (error.Fail() || log))
                    error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)",
                                   static_cast<void *>(file_actions), info->GetFD(), info->GetActionArgument());
            }
            break;

        case FileAction::eFileActionOpen:
            if (info->GetFD() == -1)
                error.SetErrorString("invalid fd in posix_spawn_file_actions_addopen(...)");
            else
            {
                int oflag = info->GetActionArgument();

                mode_t mode = 0;

                if (oflag & O_CREAT)
                    mode = 0640;

                error.SetError(
                    ::posix_spawn_file_actions_addopen(file_actions, info->GetFD(), info->GetPath(), oflag, mode),
                    eErrorTypePOSIX);
                if (error.Fail() || log)
                    error.PutToLog(log,
                                   "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)",
                                   static_cast<void *>(file_actions), info->GetFD(), info->GetPath(), oflag, mode);
            }
            break;
    }
    return error.Success();
}
Exemplo n.º 3
0
Error
Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
{
    Error error;
    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));

    posix_spawnattr_t attr;
    error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);

    if (error.Fail() || log)
        error.PutToLog(log, "::posix_spawnattr_init ( &attr )");
    if (error.Fail())
        return error;

    // Make a quick class that will cleanup the posix spawn attributes in case
    // we return in the middle of this function.
    lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy);

    sigset_t no_signals;
    sigset_t all_signals;
    sigemptyset (&no_signals);
    sigfillset (&all_signals);
    ::posix_spawnattr_setsigmask(&attr, &no_signals);
#if defined (__linux__)  || defined (__FreeBSD__)
    ::posix_spawnattr_setsigdefault(&attr, &no_signals);
#else
    ::posix_spawnattr_setsigdefault(&attr, &all_signals);
#endif

    short flags = GetPosixspawnFlags(launch_info);

    error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX);
    if (error.Fail() || log)
        error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags);
    if (error.Fail())
        return error;

    // posix_spawnattr_setbinpref_np appears to be an Apple extension per:
    // http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
#if defined (__APPLE__) && !defined (__arm__)
    
    // Don't set the binpref if a shell was provided.  After all, that's only going to affect what version of the shell
    // is launched, not what fork of the binary is launched.  We insert "arch --arch <ARCH> as part of the shell invocation
    // to do that job on OSX.
    
    if (launch_info.GetShell() == nullptr)
    {
        // We don't need to do this for ARM, and we really shouldn't now that we
        // have multiple CPU subtypes and no posix_spawnattr call that allows us
        // to set which CPU subtype to launch...
        const ArchSpec &arch_spec = launch_info.GetArchitecture();
        cpu_type_t cpu = arch_spec.GetMachOCPUType();
        cpu_type_t sub = arch_spec.GetMachOCPUSubType();
        if (cpu != 0 &&
            cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
            cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
            !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail 
        {
            size_t ocount = 0;
            error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
            if (error.Fail() || log)
                error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu, (uint64_t)ocount);

            if (error.Fail() || ocount != 1)
                return error;
        }
    }

#endif

    const char *tmp_argv[2];
    char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector();
    char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector();
    if (argv == NULL)
    {
        // posix_spawn gets very unhappy if it doesn't have at least the program
        // name in argv[0]. One of the side affects I have noticed is the environment
        // variables don't make it into the child process if "argv == NULL"!!!
        tmp_argv[0] = exe_path;
        tmp_argv[1] = NULL;
        argv = (char * const*)tmp_argv;
    }

#if !defined (__APPLE__)
    // manage the working directory
    char current_dir[PATH_MAX];
    current_dir[0] = '\0';
#endif

    FileSpec working_dir{launch_info.GetWorkingDirectory()};
    if (working_dir)
    {
#if defined (__APPLE__)
        // Set the working directory on this thread only
        if (__pthread_chdir(working_dir.GetCString()) < 0) {
            if (errno == ENOENT) {
                error.SetErrorStringWithFormat("No such file or directory: %s",
                        working_dir.GetCString());
            } else if (errno == ENOTDIR) {
                error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
                        working_dir.GetCString());
            } else {
                error.SetErrorStringWithFormat("An unknown error occurred when changing directory for process execution.");
            }
            return error;
        }
#else
        if (::getcwd(current_dir, sizeof(current_dir)) == NULL)
        {
            error.SetError(errno, eErrorTypePOSIX);
            error.LogIfError(log, "unable to save the current directory");
            return error;
        }

        if (::chdir(working_dir.GetCString()) == -1)
        {
            error.SetError(errno, eErrorTypePOSIX);
            error.LogIfError(log, "unable to change working directory to %s",
                    working_dir.GetCString());
            return error;
        }
#endif
    }

    ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
    const size_t num_file_actions = launch_info.GetNumFileActions ();
    if (num_file_actions > 0)
    {
        posix_spawn_file_actions_t file_actions;
        error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
        if (error.Fail() || log)
            error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )");
        if (error.Fail())
            return error;

        // Make a quick class that will cleanup the posix spawn attributes in case
        // we return in the middle of this function.
        lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> posix_spawn_file_actions_cleanup (&file_actions, posix_spawn_file_actions_destroy);

        for (size_t i=0; i<num_file_actions; ++i)
        {
            const FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
            if (launch_file_action)
            {
                if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, error))
                    return error;
            }
        }

        error.SetError(::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), eErrorTypePOSIX);

        if (error.Fail() || log)
        {
            error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", result_pid,
                           exe_path, static_cast<void *>(&file_actions), static_cast<void *>(&attr), reinterpret_cast<const void *>(argv),
                           reinterpret_cast<const void *>(envp));
            if (log)
            {
                for (int ii=0; argv[ii]; ++ii)
                    log->Printf("argv[%i] = '%s'", ii, argv[ii]);
            }
        }

    }
    else
    {
        error.SetError(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), eErrorTypePOSIX);

        if (error.Fail() || log)
        {
            error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )",
                           result_pid, exe_path, static_cast<void *>(&attr), reinterpret_cast<const void *>(argv),
                           reinterpret_cast<const void *>(envp));
            if (log)
            {
                for (int ii=0; argv[ii]; ++ii)
                    log->Printf("argv[%i] = '%s'", ii, argv[ii]);
            }
        }
    }
    pid = result_pid;

    if (working_dir)
    {
#if defined (__APPLE__)
        // No more thread specific current working directory
        __pthread_fchdir (-1);
#else
        if (::chdir(current_dir) == -1 && error.Success())
        {
            error.SetError(errno, eErrorTypePOSIX);
            error.LogIfError(log, "unable to change current directory back to %s",
                    current_dir);
        }
#endif
    }

    return error;
}
Exemplo n.º 4
0
bool
OperatingSystemGo::UpdateThreadList(ThreadList &old_thread_list, ThreadList &real_thread_list,
                                    ThreadList &new_thread_list)
{
    new_thread_list = real_thread_list;
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OS));

    if (!(m_allg_sp || Init(real_thread_list)) || (m_allg_sp && !m_allglen_sp) ||
        !GetGlobalPluginProperties()->GetEnableGoroutines())
    {
        return new_thread_list.GetSize(false) > 0;
    }

    if (log)
        log->Printf("OperatingSystemGo::UpdateThreadList(%d, %d, %d) fetching thread data from Go for pid %" PRIu64,
                    old_thread_list.GetSize(false), real_thread_list.GetSize(false), new_thread_list.GetSize(0),
                    m_process->GetID());
    uint64_t allglen = m_allglen_sp->GetValueAsUnsigned(0);
    if (allglen == 0)
    {
        return new_thread_list.GetSize(false) > 0;
    }
    std::vector<Goroutine> goroutines;
    // The threads that are in "new_thread_list" upon entry are the threads from the
    // lldb_private::Process subclass, no memory threads will be in this list.

    Error err;
    for (uint64_t i = 0; i < allglen; ++i)
    {
        goroutines.push_back(CreateGoroutineAtIndex(i, err));
        if (err.Fail())
        {
            err.PutToLog(log, "OperatingSystemGo::UpdateThreadList");
            return new_thread_list.GetSize(false) > 0;
        }
    }
    // Make a map so we can match goroutines with backing threads.
    std::map<uint64_t, ThreadSP> stack_map;
    for (uint32_t i = 0; i < real_thread_list.GetSize(false); ++i)
    {
        ThreadSP thread = real_thread_list.GetThreadAtIndex(i, false);
        stack_map[thread->GetRegisterContext()->GetSP()] = thread;
    }
    for (const Goroutine &goroutine : goroutines)
    {
        if (0 /* Gidle */ == goroutine.m_status || 6 /* Gdead */ == goroutine.m_status)
        {
            continue;
        }
        ThreadSP memory_thread = old_thread_list.FindThreadByID(goroutine.m_goid, false);
        if (memory_thread && IsOperatingSystemPluginThread(memory_thread) && memory_thread->IsValid())
        {
            memory_thread->ClearBackingThread();
        }
        else
        {
            memory_thread.reset(new ThreadMemory(*m_process, goroutine.m_goid, nullptr, nullptr, goroutine.m_gobuf));
        }
        // Search for the backing thread if the goroutine is running.
        if (2 == (goroutine.m_status & 0xfff))
        {
            auto backing_it = stack_map.lower_bound(goroutine.m_lostack);
            if (backing_it != stack_map.end())
            {
                if (goroutine.m_histack >= backing_it->first)
                {
                    if (log)
                        log->Printf("OperatingSystemGo::UpdateThreadList found backing thread %" PRIx64 " (%" PRIx64
                                    ") for thread %" PRIx64 "",
                                    backing_it->second->GetID(), backing_it->second->GetProtocolID(),
                                    memory_thread->GetID());
                    memory_thread->SetBackingThread(backing_it->second);
                    new_thread_list.RemoveThreadByID(backing_it->second->GetID(), false);
                }
            }
        }
        new_thread_list.AddThread(memory_thread);
    }

    return new_thread_list.GetSize(false) > 0;
}