brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.1 KiB · 1518f30 Raw
304 lines · cpp
1//===-- RNBContext.cpp ------------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//  Created by Greg Clayton on 12/12/07.10//11//===----------------------------------------------------------------------===//12 13#include "RNBContext.h"14 15#include <sstream>16#include <sys/stat.h>17 18#if defined(__APPLE__)19#include <pthread.h>20#include <sched.h>21#endif22 23#include "CFString.h"24#include "DNB.h"25#include "DNBLog.h"26#include "RNBRemote.h"27#include "MacOSX/MachException.h"28 29// Destructor30RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); }31 32// RNBContext constructor33 34const char *RNBContext::EnvironmentAtIndex(size_t index) {35  if (index < m_env_vec.size())36    return m_env_vec[index].c_str();37  else38    return NULL;39}40 41static std::string GetEnvironmentKey(const std::string &env) {42  std::string key = env.substr(0, env.find('='));43  if (!key.empty() && key.back() == '=')44    key.pop_back();45  return key;46}47 48void RNBContext::PushEnvironmentIfNeeded(const char *arg) {49  if (!arg)50    return;51  std::string arg_key = GetEnvironmentKey(arg);52 53  for (const std::string &entry: m_env_vec) {54    if (arg_key == GetEnvironmentKey(entry))55      return;56  }57  m_env_vec.push_back(arg);58}59 60const char *RNBContext::ArgumentAtIndex(size_t index) {61  if (index < m_arg_vec.size())62    return m_arg_vec[index].c_str();63  else64    return NULL;65}66 67bool RNBContext::SetWorkingDirectory(const char *path) {68  struct stat working_directory_stat;69  if (::stat(path, &working_directory_stat) != 0) {70    m_working_directory.clear();71    return false;72  }73  m_working_directory.assign(path);74  return true;75}76 77void RNBContext::SetProcessID(nub_process_t pid) {78  // Delete and events we created79  if (m_pid != INVALID_NUB_PROCESS) {80    StopProcessStatusThread();81    // Unregister this context as a client of the process's events.82  }83  // Assign our new process ID84  m_pid = pid;85 86  if (pid != INVALID_NUB_PROCESS) {87    StartProcessStatusThread();88  }89}90 91void RNBContext::StartProcessStatusThread() {92  DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);93  if ((m_events.GetEventBits() & event_proc_thread_running) == 0) {94    int err = ::pthread_create(&m_pid_pthread, NULL,95                               ThreadFunctionProcessStatus, this);96    if (err == 0) {97      // Our thread was successfully kicked off, wait for it to98      // set the started event so we can safely continue99      m_events.WaitForSetEvents(event_proc_thread_running);100      DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!",101                       __FUNCTION__);102    } else {103      DNBLogThreadedIf(LOG_RNB_PROC,104                       "RNBContext::%s thread failed to start: err = %i",105                       __FUNCTION__, err);106      m_events.ResetEvents(event_proc_thread_running);107      m_events.SetEvents(event_proc_thread_exiting);108    }109  }110}111 112void RNBContext::StopProcessStatusThread() {113  DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__);114  if ((m_events.GetEventBits() & event_proc_thread_running) ==115      event_proc_thread_running) {116    struct timespec timeout_abstime;117    DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0);118    // Wait for 2 seconds for the rx thread to exit119    if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting,120                                  &timeout_abstime) ==121        RNBContext::event_proc_thread_exiting) {122      DNBLogThreadedIf(LOG_RNB_PROC,123                       "RNBContext::%s thread stopped as requeseted",124                       __FUNCTION__);125    } else {126      DNBLogThreadedIf(LOG_RNB_PROC,127                       "RNBContext::%s thread did not stop in 2 seconds...",128                       __FUNCTION__);129      // Kill the RX thread???130    }131  }132}133 134// This thread's sole purpose is to watch for any status changes in the135// child process.136void *RNBContext::ThreadFunctionProcessStatus(void *arg) {137  RNBRemoteSP remoteSP(g_remoteSP);138  RNBRemote *remote = remoteSP.get();139  if (remote == NULL)140    return NULL;141  RNBContext &ctx = remote->Context();142 143  nub_process_t pid = ctx.ProcessID();144  DNBLogThreadedIf(LOG_RNB_PROC,145                   "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...",146                   __FUNCTION__, arg, pid);147  ctx.Events().SetEvents(RNBContext::event_proc_thread_running);148 149#if defined(__APPLE__)150  pthread_setname_np("child process status watcher thread");151#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)152  struct sched_param thread_param;153  int thread_sched_policy;154  if (pthread_getschedparam(pthread_self(), &thread_sched_policy,155                            &thread_param) == 0) {156    thread_param.sched_priority = 47;157    pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param);158  }159#endif160#endif161 162  bool done = false;163  while (!done) {164    DNBLogThreadedIf(LOG_RNB_PROC,165                     "RNBContext::%s calling DNBProcessWaitForEvent(pid, "166                     "eEventProcessRunningStateChanged | "167                     "eEventProcessStoppedStateChanged | eEventStdioAvailable "168                     "| eEventProfileDataAvailable, true)...",169                     __FUNCTION__);170    nub_event_t pid_status_event = DNBProcessWaitForEvents(171        pid,172        eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged |173            eEventStdioAvailable | eEventProfileDataAvailable,174        true, NULL);175    DNBLogThreadedIf(LOG_RNB_PROC,176                     "RNBContext::%s calling DNBProcessWaitForEvent(pid, "177                     "eEventProcessRunningStateChanged | "178                     "eEventProcessStoppedStateChanged | eEventStdioAvailable "179                     "| eEventProfileDataAvailable, true) => 0x%8.8x",180                     __FUNCTION__, pid_status_event);181 182    if (pid_status_event == 0) {183      DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back "184                                     "from DNBProcessWaitForEvent....",185                       __FUNCTION__, pid);186      //    done = true;187    } else {188      if (pid_status_event & eEventStdioAvailable) {189        DNBLogThreadedIf(190            LOG_RNB_PROC,191            "RNBContext::%s (pid=%4.4x) got stdio available event....",192            __FUNCTION__, pid);193        ctx.Events().SetEvents(RNBContext::event_proc_stdio_available);194        // Wait for the main thread to consume this notification if it requested195        // we wait for it196        ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available);197      }198 199      if (pid_status_event & eEventProfileDataAvailable) {200        DNBLogThreadedIf(201            LOG_RNB_PROC,202            "RNBContext::%s (pid=%4.4x) got profile data event....",203            __FUNCTION__, pid);204        ctx.Events().SetEvents(RNBContext::event_proc_profile_data);205        // Wait for the main thread to consume this notification if it requested206        // we wait for it207        ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data);208      }209 210      if (pid_status_event & (eEventProcessRunningStateChanged |211                              eEventProcessStoppedStateChanged)) {212        nub_state_t pid_state = DNBProcessGetState(pid);213        DNBLogThreadedIf(214            LOG_RNB_PROC,215            "RNBContext::%s (pid=%4.4x) got process state change: %s",216            __FUNCTION__, pid, DNBStateAsString(pid_state));217 218        // Let the main thread know there is a process state change to see219        ctx.Events().SetEvents(RNBContext::event_proc_state_changed);220        // Wait for the main thread to consume this notification if it requested221        // we wait for it222        ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed);223 224        switch (pid_state) {225        case eStateStopped:226          break;227 228        case eStateInvalid:229        case eStateExited:230        case eStateDetached:231          done = true;232          break;233        default:234          break;235        }236      }237 238      // Reset any events that we consumed.239      DNBProcessResetEvents(pid, pid_status_event);240    }241  }242  DNBLogThreadedIf(LOG_RNB_PROC,243                   "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...",244                   __FUNCTION__, arg, pid);245  ctx.Events().ResetEvents(event_proc_thread_running);246  ctx.Events().SetEvents(event_proc_thread_exiting);247  return NULL;248}249 250const char *RNBContext::EventsAsString(nub_event_t events, std::string &s) {251  s.clear();252  if (events & event_proc_state_changed)253    s += "proc_state_changed ";254  if (events & event_proc_thread_running)255    s += "proc_thread_running ";256  if (events & event_proc_thread_exiting)257    s += "proc_thread_exiting ";258  if (events & event_proc_stdio_available)259    s += "proc_stdio_available ";260  if (events & event_proc_profile_data)261    s += "proc_profile_data ";262  if (events & event_read_packet_available)263    s += "read_packet_available ";264  if (events & event_read_thread_running)265    s += "read_thread_running ";266  if (events & event_read_thread_running)267    s += "read_thread_running ";268  return s.c_str();269}270 271const char *RNBContext::LaunchStatusAsString(std::string &s) {272  s.clear();273 274  const char *err_str = m_launch_status.AsString();275  if (err_str)276    s = err_str;277  else {278    char error_num_str[64];279    snprintf(error_num_str, sizeof(error_num_str), "%u",280             m_launch_status.Status());281    s = error_num_str;282  }283  return s.c_str();284}285 286bool RNBContext::ProcessStateRunning() const {287  nub_state_t pid_state = DNBProcessGetState(m_pid);288  return pid_state == eStateRunning || pid_state == eStateStepping;289}290 291bool RNBContext::AddIgnoredException(const char *exception_name) {292  exception_mask_t exc_mask = MachException::ExceptionMask(exception_name);293  if (exc_mask == 0)294    return false;295  m_ignored_exceptions.push_back(exc_mask);296  return true;297}298 299void RNBContext::AddDefaultIgnoredExceptions() {300  m_ignored_exceptions.push_back(EXC_MASK_BAD_ACCESS);301  m_ignored_exceptions.push_back(EXC_MASK_BAD_INSTRUCTION);302  m_ignored_exceptions.push_back(EXC_MASK_ARITHMETIC);303}304