diff options
Diffstat (limited to 'source/Plugins/Process/Linux/SingleStepCheck.cpp')
| -rw-r--r-- | source/Plugins/Process/Linux/SingleStepCheck.cpp | 249 | 
1 files changed, 119 insertions, 130 deletions
diff --git a/source/Plugins/Process/Linux/SingleStepCheck.cpp b/source/Plugins/Process/Linux/SingleStepCheck.cpp index 8c557d4b6ff86..b23c1bd245d53 100644 --- a/source/Plugins/Process/Linux/SingleStepCheck.cpp +++ b/source/Plugins/Process/Linux/SingleStepCheck.cpp @@ -25,153 +25,142 @@  using namespace lldb_private::process_linux;  #if defined(__arm64__) || defined(__aarch64__) -namespace -{ - -void LLVM_ATTRIBUTE_NORETURN -Child() -{ -    if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1) -        _exit(1); - -    // We just do an endless loop SIGSTOPPING ourselves until killed. The tracer will fiddle with our cpu -    // affinities and monitor the behaviour. -    for (;;) -    { -        raise(SIGSTOP); - -        // Generate a bunch of instructions here, so that a single-step does not land in the -        // raise() accidentally. If single-stepping works, we will be spinning in this loop. If -        // it doesn't, we'll land in the raise() call above. -        for (volatile unsigned i = 0; i < CPU_SETSIZE; ++i) -            ; -    } +namespace { + +void LLVM_ATTRIBUTE_NORETURN Child() { +  if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1) +    _exit(1); + +  // We just do an endless loop SIGSTOPPING ourselves until killed. The tracer +  // will fiddle with our cpu +  // affinities and monitor the behaviour. +  for (;;) { +    raise(SIGSTOP); + +    // Generate a bunch of instructions here, so that a single-step does not +    // land in the +    // raise() accidentally. If single-stepping works, we will be spinning in +    // this loop. If +    // it doesn't, we'll land in the raise() call above. +    for (volatile unsigned i = 0; i < CPU_SETSIZE; ++i) +      ; +  }  } -struct ChildDeleter -{ -    ::pid_t pid; +struct ChildDeleter { +  ::pid_t pid; -    ~ChildDeleter() -    { -        int status; -        kill(pid, SIGKILL);            // Kill the child. -        waitpid(pid, &status, __WALL); // Pick up the remains. -    } +  ~ChildDeleter() { +    int status; +    kill(pid, SIGKILL);            // Kill the child. +    waitpid(pid, &status, __WALL); // Pick up the remains. +  }  };  } // end anonymous namespace -bool -impl::SingleStepWorkaroundNeeded() -{ -    // We shall spawn a child, and use it to verify the debug capabilities of the cpu. We shall -    // iterate through the cpus, bind the child to each one in turn, and verify that -    // single-stepping works on that cpu. A workaround is needed if we find at least one broken -    // cpu. - -    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); -    Error error; -    ::pid_t child_pid = fork(); -    if (child_pid == -1) -    { -        if (log) -        { -            error.SetErrorToErrno(); -            log->Printf("%s failed to fork(): %s", __FUNCTION__, error.AsCString()); -        } -        return false; +bool impl::SingleStepWorkaroundNeeded() { +  // We shall spawn a child, and use it to verify the debug capabilities of the +  // cpu. We shall +  // iterate through the cpus, bind the child to each one in turn, and verify +  // that +  // single-stepping works on that cpu. A workaround is needed if we find at +  // least one broken +  // cpu. + +  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); +  Error error; +  ::pid_t child_pid = fork(); +  if (child_pid == -1) { +    if (log) { +      error.SetErrorToErrno(); +      log->Printf("%s failed to fork(): %s", __FUNCTION__, error.AsCString()); +    } +    return false; +  } +  if (child_pid == 0) +    Child(); + +  ChildDeleter child_deleter{child_pid}; +  cpu_set_t available_cpus; +  if (sched_getaffinity(child_pid, sizeof available_cpus, &available_cpus) == +      -1) { +    if (log) { +      error.SetErrorToErrno(); +      log->Printf("%s failed to get available cpus: %s", __FUNCTION__, +                  error.AsCString()); +    } +    return false; +  } + +  int status; +  ::pid_t wpid = waitpid(child_pid, &status, __WALL); +  if (wpid != child_pid || !WIFSTOPPED(status)) { +    if (log) { +      error.SetErrorToErrno(); +      log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__, status, +                  error.AsCString());      } -    if (child_pid == 0) -        Child(); - -    ChildDeleter child_deleter{child_pid}; -    cpu_set_t available_cpus; -    if (sched_getaffinity(child_pid, sizeof available_cpus, &available_cpus) == -1) -    { -        if (log) -        { -            error.SetErrorToErrno(); -            log->Printf("%s failed to get available cpus: %s", __FUNCTION__, error.AsCString()); -        } -        return false; +    return false; +  } + +  unsigned cpu; +  for (cpu = 0; cpu < CPU_SETSIZE; ++cpu) { +    if (!CPU_ISSET(cpu, &available_cpus)) +      continue; + +    cpu_set_t cpus; +    CPU_ZERO(&cpus); +    CPU_SET(cpu, &cpus); +    if (sched_setaffinity(child_pid, sizeof cpus, &cpus) == -1) { +      if (log) { +        error.SetErrorToErrno(); +        log->Printf("%s failed to switch to cpu %u: %s", __FUNCTION__, cpu, +                    error.AsCString()); +      } +      continue;      }      int status; -    ::pid_t wpid = waitpid(child_pid, &status, __WALL); -    if (wpid != child_pid || !WIFSTOPPED(status)) -    { -        if (log) -        { -            error.SetErrorToErrno(); -            log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__, status, error.AsCString()); -        } -        return false; +    error = NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid); +    if (error.Fail()) { +      if (log) +        log->Printf("%s single step failed: %s", __FUNCTION__, +                    error.AsCString()); +      break;      } -    unsigned cpu; -    for (cpu = 0; cpu < CPU_SETSIZE; ++cpu) -    { -        if (!CPU_ISSET(cpu, &available_cpus)) -            continue; - -        cpu_set_t cpus; -        CPU_ZERO(&cpus); -        CPU_SET(cpu, &cpus); -        if (sched_setaffinity(child_pid, sizeof cpus, &cpus) == -1) -        { -            if (log) -            { -                error.SetErrorToErrno(); -                log->Printf("%s failed to switch to cpu %u: %s", __FUNCTION__, cpu, error.AsCString()); -            } -            continue; -        } - -        int status; -        error = NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid); -        if (error.Fail()) -        { -            if (log) -                log->Printf("%s single step failed: %s", __FUNCTION__, error.AsCString()); -            break; -        } - -        wpid = waitpid(child_pid, &status, __WALL); -        if (wpid != child_pid || !WIFSTOPPED(status)) -        { -            if (log) -            { -                error.SetErrorToErrno(); -                log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__, status, error.AsCString()); -            } -            break; -        } -        if (WSTOPSIG(status) != SIGTRAP) -        { -            if (log) -                log->Printf("%s single stepping on cpu %d failed with status %x", __FUNCTION__, cpu, status); -            break; -        } +    wpid = waitpid(child_pid, &status, __WALL); +    if (wpid != child_pid || !WIFSTOPPED(status)) { +      if (log) { +        error.SetErrorToErrno(); +        log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__, +                    status, error.AsCString()); +      } +      break;      } - -    // cpu is either the index of the first broken cpu, or CPU_SETSIZE. -    if (cpu == 0) -    { -        if (log) -            log->Printf("%s SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING LIKELY TO BE UNRELIABLE.", -                        __FUNCTION__); -        // No point in trying to fiddle with the affinities, just give it our best shot and see how it goes. -        return false; +    if (WSTOPSIG(status) != SIGTRAP) { +      if (log) +        log->Printf("%s single stepping on cpu %d failed with status %x", +                    __FUNCTION__, cpu, status); +      break;      } +  } + +  // cpu is either the index of the first broken cpu, or CPU_SETSIZE. +  if (cpu == 0) { +    if (log) +      log->Printf("%s SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING " +                  "LIKELY TO BE UNRELIABLE.", +                  __FUNCTION__); +    // No point in trying to fiddle with the affinities, just give it our best +    // shot and see how it goes. +    return false; +  } -    return cpu != CPU_SETSIZE; +  return cpu != CPU_SETSIZE;  }  #else // !arm64 -bool -impl::SingleStepWorkaroundNeeded() -{ -    return false; -} +bool impl::SingleStepWorkaroundNeeded() { return false; }  #endif  | 
