diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:55:28 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:55:28 +0000 | 
| commit | e81d9d49145e432d917eea3a70d2ae74dcad1d89 (patch) | |
| tree | 9ed5e1a91f242e2cb5911577356e487a55c01b78 /source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp | |
| parent | 85d8ef8f1f0e0e063a8571944302be2d2026f823 (diff) | |
Notes
Diffstat (limited to 'source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp')
| -rw-r--r-- | source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp | 829 | 
1 files changed, 799 insertions, 30 deletions
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index a0458f16e558..769ccd7248ac 100644 --- a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -28,6 +28,23 @@  #include "ProcessMonitor.h"  #include "FreeBSDThread.h" +// Other libraries and framework includes +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/State.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Target.h" + +#include "lldb/Host/posix/Fcntl.h" + +  using namespace lldb;  using namespace lldb_private; @@ -45,13 +62,13 @@ namespace  // Static functions.  lldb::ProcessSP -ProcessFreeBSD::CreateInstance(Target& target, +ProcessFreeBSD::CreateInstance(lldb::TargetSP target_sp,                                 Listener &listener,                                 const FileSpec *crash_file_path)  {      lldb::ProcessSP process_sp;      if (crash_file_path == NULL) -        process_sp.reset(new ProcessFreeBSD (target, listener)); +        process_sp.reset(new ProcessFreeBSD (target_sp, listener, GetFreeBSDSignals()));      return process_sp;  } @@ -97,32 +114,6 @@ ProcessFreeBSD::GetPluginVersion()  }  void -ProcessFreeBSD::GetPluginCommandHelp(const char *command, Stream *strm) -{ -} - -Error -ProcessFreeBSD::ExecutePluginCommand(Args &command, Stream *strm) -{ -    return Error(1, eErrorTypeGeneric); -} - -Log * -ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command) -{ -    return NULL; -} - -//------------------------------------------------------------------------------ -// Constructors and destructors. - -ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener) -    : ProcessPOSIX(target, listener, GetFreeBSDSignals ()), -      m_resume_signo(0) -{ -} - -void  ProcessFreeBSD::Terminate()  {  } @@ -232,7 +223,7 @@ ProcessFreeBSD::WillResume()      m_suspend_tids.clear();      m_run_tids.clear();      m_step_tids.clear(); -    return ProcessPOSIX::WillResume(); +    return Process::WillResume();  }  void @@ -264,7 +255,7 @@ ProcessFreeBSD::SendMessage(const ProcessMessage &message)          break;      case ProcessMessage::eNewThreadMessage: -        assert(0 && "eNewThreadMessage unexpected on FreeBSD"); +        llvm_unreachable("eNewThreadMessage unexpected on FreeBSD");          break;      case ProcessMessage::eExecMessage: @@ -274,3 +265,781 @@ ProcessFreeBSD::SendMessage(const ProcessMessage &message)      m_message_queue.push(message);  } + +//------------------------------------------------------------------------------ +// Constructors and destructors. + +ProcessFreeBSD::ProcessFreeBSD(lldb::TargetSP target_sp, Listener &listener, UnixSignalsSP &unix_signals_sp) +    : Process(target_sp, listener, unix_signals_sp), +      m_byte_order(endian::InlHostByteOrder()), +      m_monitor(NULL), +      m_module(NULL), +      m_message_mutex (Mutex::eMutexTypeRecursive), +      m_exit_now(false), +      m_seen_initial_stop(), +      m_resume_signo(0) +{ +    // FIXME: Putting this code in the ctor and saving the byte order in a +    // member variable is a hack to avoid const qual issues in GetByteOrder. +    lldb::ModuleSP module = GetTarget().GetExecutableModule(); +    if (module && module->GetObjectFile()) +        m_byte_order = module->GetObjectFile()->GetByteOrder(); +} + +ProcessFreeBSD::~ProcessFreeBSD() +{ +    delete m_monitor; +} + +//------------------------------------------------------------------------------ +// Process protocol. +void +ProcessFreeBSD::Finalize() +{ +  Process::Finalize(); + +  if (m_monitor) +    m_monitor->StopMonitor(); +} + +bool +ProcessFreeBSD::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) +{ +    // For now we are just making sure the file exists for a given module +    ModuleSP exe_module_sp(target_sp->GetExecutableModule()); +    if (exe_module_sp.get()) +        return exe_module_sp->GetFileSpec().Exists(); +    // If there is no executable module, we return true since we might be preparing to attach. +    return true; +} + +Error +ProcessFreeBSD::DoAttachToProcessWithID (lldb::pid_t pid,  const ProcessAttachInfo &attach_info) +{ +    Error error; +    assert(m_monitor == NULL); + +    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); +    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) +        log->Printf ("ProcessFreeBSD::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID()); + +    m_monitor = new ProcessMonitor(this, pid, error); + +    if (!error.Success()) +        return error; + +    PlatformSP platform_sp (GetTarget().GetPlatform ()); +    assert (platform_sp.get()); +    if (!platform_sp) +        return error;  // FIXME: Detatch? + +    // Find out what we can about this process +    ProcessInstanceInfo process_info; +    platform_sp->GetProcessInfo (pid, process_info); + +    // Resolve the executable module +    ModuleSP exe_module_sp; +    FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); +    ModuleSpec exe_module_spec(process_info.GetExecutableFile(), GetTarget().GetArchitecture()); +    error = platform_sp->ResolveExecutable(exe_module_spec, +                                           exe_module_sp, +                                           executable_search_paths.GetSize() ? &executable_search_paths : NULL); +    if (!error.Success()) +        return error; + +    // Fix the target architecture if necessary +    const ArchSpec &module_arch = exe_module_sp->GetArchitecture(); +    if (module_arch.IsValid() && !GetTarget().GetArchitecture().IsExactMatch(module_arch)) +        GetTarget().SetArchitecture(module_arch); + +    // Initialize the target module list +    GetTarget().SetExecutableModule (exe_module_sp, true); + +    SetSTDIOFileDescriptor(m_monitor->GetTerminalFD()); + +    SetID(pid); + +    return error; +} + +Error +ProcessFreeBSD::WillLaunch(Module* module) +{ +    Error error; +    return error; +} + +FileSpec +ProcessFreeBSD::GetFileSpec(const lldb_private::FileAction *file_action, +                          const FileSpec &default_file_spec, +                          const FileSpec &dbg_pts_file_spec) +{ +    FileSpec file_spec{}; + +    if (file_action && file_action->GetAction() == FileAction::eFileActionOpen) +    { +        file_spec = file_action->GetFileSpec(); +        // By default the stdio paths passed in will be pseudo-terminal +        // (/dev/pts). If so, convert to using a different default path +        // instead to redirect I/O to the debugger console. This should +        // also handle user overrides to /dev/null or a different file. +        if (!file_spec || file_spec == dbg_pts_file_spec) +            file_spec = default_file_spec; +    } +    return file_spec; +} + +Error +ProcessFreeBSD::DoLaunch (Module *module, +                        ProcessLaunchInfo &launch_info) +{ +    Error error; +    assert(m_monitor == NULL); + +    FileSpec working_dir = launch_info.GetWorkingDirectory(); +    if (working_dir && +            (!working_dir.ResolvePath() || +             working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) +    { +        error.SetErrorStringWithFormat("No such file or directory: %s", +                working_dir.GetCString()); +        return error; +    } + +    SetPrivateState(eStateLaunching); + +    const lldb_private::FileAction *file_action; + +    // Default of empty will mean to use existing open file descriptors +    FileSpec stdin_file_spec{}; +    FileSpec stdout_file_spec{}; +    FileSpec stderr_file_spec{}; + +    const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false}; + +    file_action = launch_info.GetFileActionForFD (STDIN_FILENO); +    stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec); + +    file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); +    stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec); + +    file_action = launch_info.GetFileActionForFD (STDERR_FILENO); +    stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec); + +    m_monitor = new ProcessMonitor(this, +                                   module, +                                   launch_info.GetArguments().GetConstArgumentVector(), +                                   launch_info.GetEnvironmentEntries().GetConstArgumentVector(), +                                   stdin_file_spec, +                                   stdout_file_spec, +                                   stderr_file_spec, +                                   working_dir, +                                   launch_info, +                                   error); + +    m_module = module; + +    if (!error.Success()) +        return error; + +    int terminal = m_monitor->GetTerminalFD(); +    if (terminal >= 0) { +        // The reader thread will close the file descriptor when done, so we pass it a copy. +#ifdef F_DUPFD_CLOEXEC +        int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0); +        if (stdio == -1) { +            error.SetErrorToErrno(); +            return error; +        } +#else +        // Special case when F_DUPFD_CLOEXEC does not exist (Debian kFreeBSD) +        int stdio = fcntl(terminal, F_DUPFD, 0); +        if (stdio == -1) { +            error.SetErrorToErrno(); +            return error; +        } +        stdio = fcntl(terminal, F_SETFD, FD_CLOEXEC); +        if (stdio == -1) { +            error.SetErrorToErrno(); +            return error; +        } +#endif +        SetSTDIOFileDescriptor(stdio); +    } + +    SetID(m_monitor->GetPID()); +    return error; +} + +void +ProcessFreeBSD::DidLaunch() +{ +} + +addr_t +ProcessFreeBSD::GetImageInfoAddress() +{ +    Target *target = &GetTarget(); +    ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); +    Address addr = obj_file->GetImageInfoAddress(target); + +    if (addr.IsValid()) +        return addr.GetLoadAddress(target); +    return LLDB_INVALID_ADDRESS; +} + +Error +ProcessFreeBSD::DoHalt(bool &caused_stop) +{ +    Error error; + +    if (IsStopped()) +    { +        caused_stop = false; +    } +    else if (kill(GetID(), SIGSTOP)) +    { +        caused_stop = false; +        error.SetErrorToErrno(); +    } +    else +    { +        caused_stop = true; +    } +    return error; +} + +Error +ProcessFreeBSD::DoSignal(int signal) +{ +    Error error; + +    if (kill(GetID(), signal)) +        error.SetErrorToErrno(); + +    return error; +} + +Error +ProcessFreeBSD::DoDestroy() +{ +    Error error; + +    if (!HasExited()) +    { +        assert(m_monitor); +        m_exit_now = true; +        if (GetID() == LLDB_INVALID_PROCESS_ID) +        { +            error.SetErrorString("invalid process id"); +            return error; +        } +        if (!m_monitor->Kill()) +        { +            error.SetErrorToErrno(); +            return error; +        } + +        SetPrivateState(eStateExited); +    } + +    return error; +} + +void +ProcessFreeBSD::DoDidExec() +{ +    Target *target = &GetTarget(); +    if (target) +    { +        PlatformSP platform_sp (target->GetPlatform()); +        assert (platform_sp.get()); +        if (platform_sp) +        { +            ProcessInstanceInfo process_info; +            platform_sp->GetProcessInfo(GetID(), process_info); +            ModuleSP exe_module_sp; +            ModuleSpec exe_module_spec(process_info.GetExecutableFile(), target->GetArchitecture()); +            FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); +            Error error = platform_sp->ResolveExecutable(exe_module_spec, +                                                         exe_module_sp, +                                                         executable_search_paths.GetSize() ? &executable_search_paths : NULL); +            if (!error.Success()) +                return; +            target->SetExecutableModule(exe_module_sp, true); +        } +    } +} + +bool +ProcessFreeBSD::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) +{ +    bool added_to_set = false; +    ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid); +    if (it == m_seen_initial_stop.end()) +    { +        m_seen_initial_stop.insert(stop_tid); +        added_to_set = true; +    } +    return added_to_set; +} + +bool +ProcessFreeBSD::WaitingForInitialStop(lldb::tid_t stop_tid) +{ +    return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end()); +} + +FreeBSDThread * +ProcessFreeBSD::CreateNewFreeBSDThread(lldb_private::Process &process, lldb::tid_t tid) +{ +    return new FreeBSDThread(process, tid); +} + +void +ProcessFreeBSD::RefreshStateAfterStop() +{ +    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); +    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) +        log->Printf ("ProcessFreeBSD::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size()); + +    Mutex::Locker lock(m_message_mutex); + +    // This method used to only handle one message.  Changing it to loop allows +    // it to handle the case where we hit a breakpoint while handling a different +    // breakpoint. +    while (!m_message_queue.empty()) +    { +        ProcessMessage &message = m_message_queue.front(); + +        // Resolve the thread this message corresponds to and pass it along. +        lldb::tid_t tid = message.GetTID(); +        if (log) +            log->Printf ("ProcessFreeBSD::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid); + +        m_thread_list.RefreshStateAfterStop(); + +        FreeBSDThread *thread = static_cast<FreeBSDThread*>( +            GetThreadList().FindThreadByID(tid, false).get()); +        if (thread) +            thread->Notify(message); + +        if (message.GetKind() == ProcessMessage::eExitMessage) +        { +            // FIXME: We should tell the user about this, but the limbo message is probably better for that. +            if (log) +                log->Printf ("ProcessFreeBSD::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid); + +            Mutex::Locker lock(m_thread_list.GetMutex()); + +            ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false); +            thread_sp.reset(); +            m_seen_initial_stop.erase(tid); +        } + +        m_message_queue.pop(); +    } +} + +bool +ProcessFreeBSD::IsAlive() +{ +    StateType state = GetPrivateState(); +    return state != eStateDetached +        && state != eStateExited +        && state != eStateInvalid +        && state != eStateUnloaded; +} + +size_t +ProcessFreeBSD::DoReadMemory(addr_t vm_addr, +                           void *buf, size_t size, Error &error) +{ +    assert(m_monitor); +    return m_monitor->ReadMemory(vm_addr, buf, size, error); +} + +size_t +ProcessFreeBSD::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size, +                            Error &error) +{ +    assert(m_monitor); +    return m_monitor->WriteMemory(vm_addr, buf, size, error); +} + +addr_t +ProcessFreeBSD::DoAllocateMemory(size_t size, uint32_t permissions, +                               Error &error) +{ +    addr_t allocated_addr = LLDB_INVALID_ADDRESS; + +    unsigned prot = 0; +    if (permissions & lldb::ePermissionsReadable) +        prot |= eMmapProtRead; +    if (permissions & lldb::ePermissionsWritable) +        prot |= eMmapProtWrite; +    if (permissions & lldb::ePermissionsExecutable) +        prot |= eMmapProtExec; + +    if (InferiorCallMmap(this, allocated_addr, 0, size, prot, +                         eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { +        m_addr_to_mmap_size[allocated_addr] = size; +        error.Clear(); +    } else { +        allocated_addr = LLDB_INVALID_ADDRESS; +        error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions)); +    } + +    return allocated_addr; +} + +Error +ProcessFreeBSD::DoDeallocateMemory(lldb::addr_t addr) +{ +    Error error; +    MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); +    if (pos != m_addr_to_mmap_size.end() && +        InferiorCallMunmap(this, addr, pos->second)) +        m_addr_to_mmap_size.erase (pos); +    else +        error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); + +    return error; +} + +size_t +ProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) +{ +    static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; +    static const uint8_t g_i386_opcode[] = { 0xCC }; + +    ArchSpec arch = GetTarget().GetArchitecture(); +    const uint8_t *opcode = NULL; +    size_t opcode_size = 0; + +    switch (arch.GetMachine()) +    { +    default: +        assert(false && "CPU type not supported!"); +        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 == eAddressClassCodeAlternateISA +                || (addr_class == eAddressClassUnknown +                    && bp_loc_sp->GetAddress().GetOffset() & 1)) +            { +                opcode = g_thumb_breakpoint_opcode; +                opcode_size = sizeof(g_thumb_breakpoint_opcode); +            } +            else +            { +                opcode = g_arm_breakpoint_opcode; +                opcode_size = sizeof(g_arm_breakpoint_opcode); +            } +        } +        break; +    case llvm::Triple::aarch64: +        opcode = g_aarch64_opcode; +        opcode_size = sizeof(g_aarch64_opcode); +        break; + +    case llvm::Triple::x86: +    case llvm::Triple::x86_64: +        opcode = g_i386_opcode; +        opcode_size = sizeof(g_i386_opcode); +        break; +    } + +    bp_site->SetTrapOpcode(opcode, opcode_size); +    return opcode_size; +} + +Error +ProcessFreeBSD::EnableBreakpointSite(BreakpointSite *bp_site) +{ +    return EnableSoftwareBreakpoint(bp_site); +} + +Error +ProcessFreeBSD::DisableBreakpointSite(BreakpointSite *bp_site) +{ +    return DisableSoftwareBreakpoint(bp_site); +} + +Error +ProcessFreeBSD::EnableWatchpoint(Watchpoint *wp, bool notify) +{ +    Error error; +    if (wp) +    { +        user_id_t watchID = wp->GetID(); +        addr_t addr = wp->GetLoadAddress(); +        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); +        if (log) +            log->Printf ("ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 ")", +                         watchID); +        if (wp->IsEnabled()) +        { +            if (log) +                log->Printf("ProcessFreeBSD::EnableWatchpoint(watchID = %" PRIu64 +                            ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", +                            watchID, (uint64_t)addr); +            return error; +        } + +        // Try to find a vacant watchpoint slot in the inferiors' main thread +        uint32_t wp_hw_index = LLDB_INVALID_INDEX32; +        Mutex::Locker lock(m_thread_list.GetMutex()); +        FreeBSDThread *thread = static_cast<FreeBSDThread*>( +                               m_thread_list.GetThreadAtIndex(0, false).get()); + +        if (thread) +            wp_hw_index = thread->FindVacantWatchpointIndex(); + +        if (wp_hw_index == LLDB_INVALID_INDEX32) +        { +            error.SetErrorString("Setting hardware watchpoint failed."); +        } +        else +        { +            wp->SetHardwareIndex(wp_hw_index); +            bool wp_enabled = true; +            uint32_t thread_count = m_thread_list.GetSize(false); +            for (uint32_t i = 0; i < thread_count; ++i) +            { +                thread = static_cast<FreeBSDThread*>( +                         m_thread_list.GetThreadAtIndex(i, false).get()); +                if (thread) +                    wp_enabled &= thread->EnableHardwareWatchpoint(wp); +                else +                    wp_enabled = false; +            } +            if (wp_enabled) +            { +                wp->SetEnabled(true, notify); +                return error; +            } +            else +            { +                // Watchpoint enabling failed on at least one +                // of the threads so roll back all of them +                DisableWatchpoint(wp, false); +                error.SetErrorString("Setting hardware watchpoint failed"); +            } +        } +    } +    else +        error.SetErrorString("Watchpoint argument was NULL."); +    return error; +} + +Error +ProcessFreeBSD::DisableWatchpoint(Watchpoint *wp, bool notify) +{ +    Error error; +    if (wp) +    { +        user_id_t watchID = wp->GetID(); +        addr_t addr = wp->GetLoadAddress(); +        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); +        if (log) +            log->Printf("ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 ")", +                        watchID); +        if (!wp->IsEnabled()) +        { +            if (log) +                log->Printf("ProcessFreeBSD::DisableWatchpoint(watchID = %" PRIu64 +                            ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.", +                            watchID, (uint64_t)addr); +            // This is needed (for now) to keep watchpoints disabled correctly +            wp->SetEnabled(false, notify); +            return error; +        } + +        if (wp->IsHardware()) +        { +            bool wp_disabled = true; +            Mutex::Locker lock(m_thread_list.GetMutex()); +            uint32_t thread_count = m_thread_list.GetSize(false); +            for (uint32_t i = 0; i < thread_count; ++i) +            { +                FreeBSDThread *thread = static_cast<FreeBSDThread*>( +                                      m_thread_list.GetThreadAtIndex(i, false).get()); +                if (thread) +                    wp_disabled &= thread->DisableHardwareWatchpoint(wp); +                else +                    wp_disabled = false; +            } +            if (wp_disabled) +            { +                wp->SetHardwareIndex(LLDB_INVALID_INDEX32); +                wp->SetEnabled(false, notify); +                return error; +            } +            else +                error.SetErrorString("Disabling hardware watchpoint failed"); +        } +    } +    else +        error.SetErrorString("Watchpoint argument was NULL."); +    return error; +} + +Error +ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num) +{ +    Error error; +    Mutex::Locker lock(m_thread_list.GetMutex()); +    FreeBSDThread *thread = static_cast<FreeBSDThread*>( +                          m_thread_list.GetThreadAtIndex(0, false).get()); +    if (thread) +        num = thread->NumSupportedHardwareWatchpoints(); +    else +        error.SetErrorString("Process does not exist."); +    return error; +} + +Error +ProcessFreeBSD::GetWatchpointSupportInfo(uint32_t &num, bool &after) +{ +    Error error = GetWatchpointSupportInfo(num); +    // Watchpoints trigger and halt the inferior after +    // the corresponding instruction has been executed. +    after = true; +    return error; +} + +uint32_t +ProcessFreeBSD::UpdateThreadListIfNeeded() +{ +    Mutex::Locker lock(m_thread_list.GetMutex()); +    // Do not allow recursive updates. +    return m_thread_list.GetSize(false); +} + +#if 0 +bool +ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list) +{ +    Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); +    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) +        log->Printf ("ProcessFreeBSD::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID()); + +    bool has_updated = false; +    // Update the process thread list with this new thread. +    // FIXME: We should be using tid, not pid. +    assert(m_monitor); +    ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false)); +    if (!thread_sp) { +        thread_sp.reset(CreateNewFreeBSDThread(*this, GetID())); +        has_updated = true; +    } + +    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) +        log->Printf ("ProcessFreeBSD::%s() updated pid = %" PRIi64, __FUNCTION__, GetID()); +    new_thread_list.AddThread(thread_sp); + +    return has_updated; // the list has been updated +} +#endif + +ByteOrder +ProcessFreeBSD::GetByteOrder() const +{ +    // FIXME: We should be able to extract this value directly.  See comment in +    // ProcessFreeBSD(). +    return m_byte_order; +} + +size_t +ProcessFreeBSD::PutSTDIN(const char *buf, size_t len, Error &error) +{ +    ssize_t status; +    if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0)  +    { +        error.SetErrorToErrno(); +        return 0; +    } +    return status; +} + +//------------------------------------------------------------------------------ +// Utility functions. + +bool +ProcessFreeBSD::HasExited() +{ +    switch (GetPrivateState()) +    { +    default: +        break; + +    case eStateDetached: +    case eStateExited: +        return true; +    } + +    return false; +} + +bool +ProcessFreeBSD::IsStopped() +{ +    switch (GetPrivateState()) +    { +    default: +        break; + +    case eStateStopped: +    case eStateCrashed: +    case eStateSuspended: +        return true; +    } + +    return false; +} + +bool +ProcessFreeBSD::IsAThreadRunning() +{ +    bool is_running = false; +    Mutex::Locker lock(m_thread_list.GetMutex()); +    uint32_t thread_count = m_thread_list.GetSize(false); +    for (uint32_t i = 0; i < thread_count; ++i) +    { +        FreeBSDThread *thread = static_cast<FreeBSDThread*>( +            m_thread_list.GetThreadAtIndex(i, false).get()); +        StateType thread_state = thread->GetState(); +        if (thread_state == eStateRunning || thread_state == eStateStepping) +        { +            is_running = true; +            break; +        } +    } +    return is_running; +} + +const DataBufferSP +ProcessFreeBSD::GetAuxvData () +{ +    // If we're the local platform, we can ask the host for auxv data. +    PlatformSP platform_sp = GetTarget().GetPlatform (); +    if (platform_sp && platform_sp->IsHost ()) +        return lldb_private::Host::GetAuxvData(this); + +    // Somewhat unexpected - the process is not running locally or we don't have a platform. +    assert (false && "no platform or not the host - how did we get here with ProcessFreeBSD?"); +    return DataBufferSP (); +}  | 
