Exemple #1
0
ErrorCode Platform::TranslateError(DWORD error) {
  switch (error) {
  case ERROR_FILE_NOT_FOUND:
  case ERROR_PATH_NOT_FOUND:
    return ds2::kErrorNotFound;
  case ERROR_TOO_MANY_OPEN_FILES:
    return ds2::kErrorTooManySystemFiles;
  case ERROR_ACCESS_DENIED:
    return ds2::kErrorAccessDenied;
  case ERROR_INVALID_HANDLE:
    return ds2::kErrorInvalidHandle;
  case ERROR_NOT_ENOUGH_MEMORY:
  case ERROR_OUTOFMEMORY:
    return ds2::kErrorNoMemory;
  case ERROR_WRITE_PROTECT:
    return ds2::kErrorNotWriteable;
  case ERROR_READ_FAULT:
  case ERROR_WRITE_FAULT:
  case ERROR_INVALID_ADDRESS:
  case ERROR_NOACCESS:
    return ds2::kErrorInvalidAddress;
  case ERROR_NOT_SUPPORTED:
    return ds2::kErrorUnsupported;
  case ERROR_FILE_EXISTS:
    return ds2::kErrorAlreadyExist;
  case ERROR_INVALID_PARAMETER:
    return ds2::kErrorInvalidArgument;
  case ERROR_BAD_EXE_FORMAT:
    return ds2::kErrorInvalidArgument;
  case ERROR_PARTIAL_COPY:
    return ds2::kErrorNoSpace;
  default:
    DS2BUG("unknown error code: %#lx", error);
  }
}
Exemple #2
0
ErrorCode ProcessBase::resume(int signal, std::set<Thread *> const &excluded) {
  enumerateThreads([&](Thread *thread) {
    if (excluded.find(thread) != excluded.end())
      return;

    switch (thread->state()) {
    case Thread::kInvalid:
    case Thread::kTerminated:
      DS2BUG("trying to resume tid %" PRI_PID " in state %s", thread->tid(),
             Stringify::ThreadState(thread->state()));
      break;

    case Thread::kRunning:
      DS2LOG(Debug, "not resuming tid %" PRI_PID ", already in state %s",
             thread->tid(), Stringify::ThreadState(thread->state()));
      break;

    case Thread::kStopped:
    case Thread::kStepped: {
      Architecture::CPUState state;
      thread->readCPUState(state);
      DS2LOG(Debug,
             "resuming tid %" PRI_PID " from pc %" PRI_PTR " with signal %d",
             thread->tid(), PRI_PTR_CAST(state.pc()), signal);
      ErrorCode error = thread->resume(signal);
      if (error != kSuccess) {
        DS2LOG(Warning, "failed resuming tid %" PRI_PID ", error=%s",
               thread->tid(), Stringify::Error(error));
      }
    } break;
    }
  });

  return kSuccess;
}
void SoftwareBreakpointManager::getOpcode(uint32_t type,
                                          std::string &opcode) const {
  switch (type) {
#if defined(ARCH_ARM)
  case 2: // udf #1
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    opcode += '\xde';
    opcode += '\x01';
#else
    opcode += '\x01';
    opcode += '\xde';
#endif
    break;
  case 3: // udf.w #0
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    opcode += '\xa0';
    opcode += '\x00';
    opcode += '\xf7';
    opcode += '\xf0';
#else
    opcode += '\xf0';
    opcode += '\xf7';
    opcode += '\x00';
    opcode += '\xa0';
#endif
    break;
  case 4: // udf #16
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    opcode += '\xe7';
    opcode += '\xf0';
    opcode += '\x01';
    opcode += '\xf0';
#else
    opcode += '\xf0';
    opcode += '\x01';
    opcode += '\xf0';
    opcode += '\xe7';
#endif
    break;
#elif defined(ARCH_ARM64)
  case 4:
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    opcode += '\xd4';
    opcode += '\x20';
    opcode += '\x20';
    opcode += '\x00';
#else
    opcode += '\x00';
    opcode += '\x20';
    opcode += '\x20';
    opcode += '\xd4';
#endif
    break;
#endif
  default:
    DS2LOG(Error, "invalid breakpoint type %d", type);
    DS2BUG("invalid breakpoint type");
    break;
  }
}
Exemple #4
0
ErrorCode PTrace::step(ProcessThreadId const &ptid, ProcessInfo const &pinfo,
                       int signal, Address const &address) {
#if defined(ARCH_ARM)
  DS2BUG("single stepping for ARM must be implemented in software");
#endif

  ErrorCode error = prepareAddressForResume(ptid, pinfo, address);
  if (error != kSuccess) {
    return error;
  }

  return super::step(ptid, pinfo, signal);
}
Exemple #5
0
ErrorCode PTrace::kill(ProcessThreadId const &ptid, int signal) {
  if (!ptid.valid())
    return kErrorInvalidArgument;

  int rc;
  if (!(ptid.tid <= kAnyThreadId)) {
    DS2BUG("not implemented");
  } else {
    rc = ::kill(ptid.pid, signal);
  }

  if (rc < 0)
    return Platform::TranslateError();

  return kSuccess;
}
Exemple #6
0
ErrorCode ProcessBase::suspend() {
  std::set<Thread *> threads;
  enumerateThreads([&](Thread *thread) { threads.insert(thread); });

  for (auto thread : threads) {
    switch (thread->state()) {
    case Thread::kInvalid:
      DS2BUG("trying to suspend tid %" PRI_PID " in state %s", thread->tid(),
             Stringify::ThreadState(thread->state()));
      break;

    case Thread::kStepped:
    case Thread::kStopped:
    case Thread::kTerminated:
      DS2LOG(Debug, "not suspending tid %" PRI_PID ", already in state %s",
             thread->tid(), Stringify::ThreadState(thread->state()));
      if (thread->state() == Thread::kTerminated) {
        removeThread(thread->tid());
      }
      break;

    case Thread::kRunning: {
      DS2LOG(Debug, "suspending tid %" PRI_PID, thread->tid());
      ErrorCode error = thread->suspend();
      switch (error) {
      case kSuccess:
        break;

      case kErrorProcessNotFound:
        DS2LOG(Debug,
               "tried to suspended tid %" PRI_PID " which is already dead",
               thread->tid());
        removeThread(thread->tid());
        return error;

      default:
        DS2LOG(Warning, "failed suspending tid %" PRI_PID ", error=%s",
               thread->tid(), Stringify::Error(error));
        return error;
      }
    } break;
    }
  }

  return kSuccess;
}
Exemple #7
0
ErrorCode Process::wait(int *status, bool hang) {
  DEBUG_EVENT de;

  BOOL result = WaitForDebugEvent(&de, hang ? INFINITE : 0);
  if (!result)
    return Platform::TranslateError();

  switch (de.dwDebugEventCode) {
  case CREATE_PROCESS_DEBUG_EVENT:
#define CHECK_AND_CLOSE(HAN)                                                   \
  do {                                                                         \
    if ((de.u.CreateProcessInfo.HAN) != NULL)                                  \
      CloseHandle(de.u.CreateProcessInfo.HAN);                                 \
  } while (0)
    CHECK_AND_CLOSE(hFile);
    CHECK_AND_CLOSE(hProcess);
    CHECK_AND_CLOSE(hThread);
#undef CHECK_AND_CLOSE
    return kSuccess;

  case EXIT_PROCESS_DEBUG_EVENT:
    _terminated = true;
    return kSuccess;

  case CREATE_THREAD_DEBUG_EVENT:
    DS2LOG(Fatal, "debug event CREATE_THREAD");
  case EXIT_THREAD_DEBUG_EVENT:
    DS2LOG(Fatal, "debug event EXIT_THREAD");
  case RIP_EVENT:
    DS2LOG(Fatal, "debug event RIP");

  case EXCEPTION_DEBUG_EVENT:
  case LOAD_DLL_DEBUG_EVENT:
  case UNLOAD_DLL_DEBUG_EVENT:
  case OUTPUT_DEBUG_STRING_EVENT: {
    auto threadIt = _threads.find(de.dwThreadId);
    DS2ASSERT(threadIt != _threads.end());
    threadIt->second->updateState(de);
  } break;

  default:
    DS2BUG("unknown debug event code: %d", de.dwDebugEventCode);
  }

  return kSuccess;
}
Exemple #8
0
ErrorCode Platform::TranslateError(int error) {
  switch (error) {
  case EBUSY:
    return ds2::kErrorBusy;
  case ESRCH:
    return ds2::kErrorProcessNotFound;
  case EFAULT:
  case EIO:
    return ds2::kErrorInvalidAddress;
  case EPERM:
    return ds2::kErrorNoPermission;
  case EEXIST:
    return ds2::kErrorAlreadyExist;
  default:
    DS2BUG("unknown error code: %d", error);
  }
}
Exemple #9
0
ErrorCode Platform::TranslateKernError(kern_return_t kret) {
  switch (kret) {
  case KERN_SUCCESS:
    return ds2::kSuccess;
  case KERN_FAILURE:
    return ds2::kErrorUnknown;
  case KERN_MEMORY_FAILURE:
  case KERN_INVALID_ADDRESS:
  case KERN_PROTECTION_FAILURE:
    return ds2::kErrorInvalidAddress;
  case KERN_NO_ACCESS:
    return ds2::kErrorNoPermission;
  case KERN_RESOURCE_SHORTAGE:
    return ds2::kErrorNoMemory;
  default:
    DS2BUG("unknown error code: %d [%s]", kret, mach_error_string(kret));
  }
}
Exemple #10
0
ErrorCode Process::attach(int waitStatus) {

  if (waitStatus <= 0) {
    ErrorCode error = ptrace().attach(_pid);
    if (error != kSuccess) {
      return error;
    }

    _flags |= kFlagAttachedProcess;

    error = ptrace().wait(_pid, &waitStatus);
    if (error != kSuccess)
      return error;
    ptrace().traceThat(_pid);
  }

  if (_flags & kFlagAttachedProcess) {
    //
    // Enumerate all the tasks and create a Thread
    // object for every entry.
    //
    bool keep_going = true;

    //
    // Try to find threads of the newly attached process in multiple
    // rounds so that we avoid race conditions with threads being
    // created before we stop the creator.
    //
    while (keep_going) {
      keep_going = false;

      DS2BUG("not implemented");
    }
  }

  //
  // Create the main thread, ourselves.
  //
  _currentThread = new Thread(this, _pid);
  _currentThread->updateStopInfo(waitStatus);

  return kSuccess;
}
Exemple #11
0
ErrorCode Thread::resume(int signal, Address const &address) {
  // TODO(sas): Not sure how to translate the signal concept to Windows yet.
  // We'll probably have to get rid of these at some point.
  DS2ASSERT(signal == 0);

  if (address.valid()) {
    CHK(modifyRegisters(
        [&address](Architecture::CPUState &state) { state.setPC(address); }));
  }

  switch (_state) {
  case kInvalid:
  case kRunning:
    DS2BUG("trying to suspend tid %" PRI_PID " in state %s", tid(),
           Stringify::ThreadState(_state));
    break;

  case kTerminated:
    return kErrorProcessNotFound;

  case kStopped:
  case kStepped: {
    if (_stopInfo.event == StopInfo::kEventStop &&
        _stopInfo.reason == StopInfo::kReasonNone) {
      DWORD result = ::ResumeThread(_handle);
      if (result == (DWORD)-1) {
        return Platform::TranslateError();
      }
    } else {
      BOOL result = ::ContinueDebugEvent(_process->pid(), _tid, DBG_CONTINUE);
      if (!result) {
        return Platform::TranslateError();
      }
    }

    _state = kRunning;
    return kSuccess;
  }
  }

  // Silence warnings without using a `default:` case for the above switch.
  DS2_UNREACHABLE();
}
Exemple #12
0
ErrorCode Process::wait(int *rstatus) {
  int status, signal;
  ProcessInfo info;
  ErrorCode err;
  pid_t tid;

  // We have at least one thread when we start waiting on a process.
  DS2ASSERT(!_threads.empty());

continue_waiting:
  err = super::wait(&status);
  if (err != kSuccess)
    return err;

  DS2LOG(Debug, "stopped: status=%d", status);

  if (WIFEXITED(status)) {
    err = super::wait(&status);
    DS2LOG(Debug, "exited: status=%d", status);
    _currentThread->updateStopInfo(status);
    _terminated = true;
    if (rstatus != nullptr) {
      *rstatus = status;
    }

    return kSuccess;
  }

  DS2BUG("not implemented");
  switch (_currentThread->_stopInfo.event) {
  case StopInfo::kEventNone:
    switch (_currentThread->_stopInfo.reason) {
    case StopInfo::kReasonNone:
      ptrace().resume(ProcessThreadId(_pid, tid), info);
      goto continue_waiting;
    default:
      DS2ASSERT(false);
      goto continue_waiting;
    }

  case StopInfo::kEventExit:
  case StopInfo::kEventKill:
    DS2LOG(Debug, "thread %d is exiting", tid);

    //
    // Killing the main thread?
    //
    // Note(sas): This might be buggy; the main thread exiting
    // doesn't mean that the process is dying.
    //
    if (tid == _pid && _threads.size() == 1) {
      DS2LOG(Debug, "last thread is exiting");
      break;
    }

    //
    // Remove and release the thread associated with this pid.
    //
    removeThread(tid);
    goto continue_waiting;

  case StopInfo::kEventStop:
    if (getInfo(info) != kSuccess) {
      DS2LOG(Error, "couldn't get process info for pid %d", _pid);
      goto continue_waiting;
    }

    signal = _currentThread->_stopInfo.signal;

    if (signal == SIGSTOP || signal == SIGCHLD) {
      //
      // Silently ignore SIGSTOP, SIGCHLD and SIGRTMIN (this
      // last one used for thread cancellation) and continue.
      //
      // Note(oba): The SIGRTMIN defines expands to a glibc
      // call, this due to the fact the POSIX standard does
      // not mandate that SIGRT* defines to be user-land
      // constants.
      //
      // Note(sas): This is probably partially dead code as
      // ptrace().step() doesn't work on ARM.
      //
      // Note(sas): Single-step detection should be higher up, not
      // only for SIGSTOP, SIGCHLD and SIGRTMIN, but for every
      // signal that we choose to ignore.
      //
      bool stepping = (_currentThread->state() == Thread::kStepped);

      if (signal == SIGSTOP) {
        signal = 0;
      } else {
        DS2LOG(Debug, "%s due to special signal, tid=%d status=%#x signal=%s",
               stepping ? "stepping" : "resuming", tid, status,
               strsignal(signal));
      }

      ErrorCode error;
      if (stepping) {
        error = ptrace().step(ProcessThreadId(_pid, tid), info, signal);
      } else {
        error = ptrace().resume(ProcessThreadId(_pid, tid), info, signal);
      }

      if (error != kSuccess) {
        DS2LOG(Warning, "cannot resume thread %d error=%d", tid, error);
      }

      goto continue_waiting;
    } else if (_passthruSignals.find(signal) != _passthruSignals.end()) {
      ptrace().resume(ProcessThreadId(_pid, tid), info, signal);
      goto continue_waiting;
    } else {
      //
      // This is a signal that we want to transmit back to the
      // debugger.
      //
      break;
    }
  }

  if (!(WIFEXITED(status) || WIFSIGNALED(status))) {
    //
    // Suspend the process, this must be done after updating
    // the thread trap info.
    //
    suspend();
  }

  if ((WIFEXITED(status) || WIFSIGNALED(status))) {
    _terminated = true;
  }

  if (rstatus != nullptr) {
    *rstatus = status;
  }

  return kSuccess;
}
Exemple #13
0
uint64_t MachOProcess::getAuxiliaryVectorValue(uint64_t type) {
  DS2BUG("not implemented");
}
Exemple #14
0
//
// Enumerates the linkmap of this MachO process.
//
ErrorCode MachOProcess::enumerateSharedLibraries(
    std::function<void(SharedLibraryInfo const &)> const &cb) {
  Address address;
  CHK(getSharedLibraryInfoAddress(address));
  DS2BUG("not implemented");
}
Exemple #15
0
void LibProc::EnumerateProcesses(
    bool allUsers, UserId const &uid,
    std::function<void(pid_t pid, uid_t uid)> const &cb) {
  DS2BUG("not implemented");
}
Exemple #16
0
void SoftwareBreakpointManager::getOpcode(uint32_t type,
                                          ByteVector &opcode) const {
#if defined(OS_WIN32) && defined(ARCH_ARM)
  if (type == 4) {
    static const uint32_t WinARMBPType = 2;
    DS2LOG(Warning,
           "requesting a breakpoint of size %u on Windows ARM, "
           "adjusting to type %u",
           type, WinARMBPType);
    type = WinARMBPType;
  }
#endif

  opcode.clear();

  // TODO: We shouldn't have preprocessor checks for ARCH_ARM vs ARCH_ARM64
  // because we might be an ARM64 binary debugging an ARM inferior.
  switch (type) {
#if defined(ARCH_ARM)
  case 2: // udf #1
    opcode.push_back('\xde');
#if defined(OS_POSIX)
    opcode.push_back('\x01');
#elif defined(OS_WIN32)
    opcode.push_back('\xfe');
#endif
    break;
  case 3: // udf.w #0
    opcode.push_back('\xa0');
    opcode.push_back('\x00');
    opcode.push_back('\xf7');
    opcode.push_back('\xf0');
    break;
  case 4: // udf #16
    opcode.push_back('\xe7');
    opcode.push_back('\xf0');
    opcode.push_back('\x01');
    opcode.push_back('\xf0');
    break;
#elif defined(ARCH_ARM64)
  case 4:
    opcode.push_back('\xd4');
    opcode.push_back('\x20');
    opcode.push_back('\x20');
    opcode.push_back('\x00');
    break;
#endif
  default:
    DS2LOG(Error, "invalid breakpoint type %d", type);
    DS2BUG("invalid breakpoint type");
    break;
  }

#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
#error "Target not supported."
#endif

#if defined(ENDIAN_LITTLE)
  std::reverse(opcode.begin(), opcode.end());
#endif
}
Exemple #17
0
ErrorCode PTrace::writeMemory(ProcessThreadId const &ptid,
                              Address const &address, void const *buffer,
                              size_t length, size_t *count) {
  DS2BUG("not implemented");
  return kErrorUnsupported;
}
Exemple #18
0
void Thread::updateState(DEBUG_EVENT const &de) {
  DS2ASSERT(de.dwThreadId == _tid);

  switch (de.dwDebugEventCode) {
  case EXCEPTION_DEBUG_EVENT:
    _state = kStopped;

    DS2LOG(
        Debug, "exception from inferior, tid=%lu, code=%s, address=%" PRI_PTR,
        tid(),
        Stringify::ExceptionCode(de.u.Exception.ExceptionRecord.ExceptionCode),
        PRI_PTR_CAST(de.u.Exception.ExceptionRecord.ExceptionAddress));

    switch (de.u.Exception.ExceptionRecord.ExceptionCode) {
    case STATUS_BREAKPOINT:
    case STATUS_SINGLE_STEP:
      _stopInfo.event = StopInfo::kEventStop;
      _stopInfo.reason = StopInfo::kReasonBreakpoint;
      break;

    case STATUS_ACCESS_VIOLATION:
    case STATUS_ARRAY_BOUNDS_EXCEEDED:
    case STATUS_IN_PAGE_ERROR:
    case STATUS_STACK_OVERFLOW:
    case STATUS_STACK_BUFFER_OVERRUN:
      _stopInfo.event = StopInfo::kEventStop;
      _stopInfo.reason = StopInfo::kReasonMemoryError;
      break;

    case STATUS_DATATYPE_MISALIGNMENT:
      _stopInfo.event = StopInfo::kEventStop;
      _stopInfo.reason = StopInfo::kReasonMemoryAlignment;
      break;

    case STATUS_FLOAT_DENORMAL_OPERAND:
    case STATUS_FLOAT_DIVIDE_BY_ZERO:
    case STATUS_FLOAT_INEXACT_RESULT:
    case STATUS_FLOAT_INVALID_OPERATION:
    case STATUS_FLOAT_OVERFLOW:
    case STATUS_FLOAT_STACK_CHECK:
    case STATUS_FLOAT_UNDERFLOW:
    case STATUS_INTEGER_DIVIDE_BY_ZERO:
    case STATUS_INTEGER_OVERFLOW:
      _stopInfo.event = StopInfo::kEventStop;
      _stopInfo.reason = StopInfo::kReasonMathError;
      break;

    case STATUS_ILLEGAL_INSTRUCTION:
    case STATUS_PRIVILEGED_INSTRUCTION:
      _stopInfo.event = StopInfo::kEventStop;
      _stopInfo.reason = StopInfo::kReasonInstructionError;
      break;

    default:
      DS2LOG(Warning, "unsupported exception code: %lx",
             de.u.Exception.ExceptionRecord.ExceptionCode);

    case STATUS_INVALID_DISPOSITION:
    case STATUS_NONCONTINUABLE_EXCEPTION:
    case DS2_EXCEPTION_UNCAUGHT_COM:
    case DS2_EXCEPTION_UNCAUGHT_USER:
    case DS2_EXCEPTION_UNCAUGHT_WINRT:
      _stopInfo.event = StopInfo::kEventStop;
      _stopInfo.reason = StopInfo::kReasonInstructionError;
      break;
    }

    break;

  case LOAD_DLL_DEBUG_EVENT: {
#define CHK_SKIP(C) CHK_ACTION(C, goto skip_name)

    std::wstring name = L"<unknown>";

    ProcessInfo pi;
    CHK_SKIP(process()->getInfo(pi));

    if (de.u.LoadDll.lpImageName == nullptr) {
      goto skip_name;
    }

    uint64_t ptr;
    // ptr needs to be set to 0 or `if (ptr != 0)` might be true even if the
    // pointer is null, on 32-bit targets.
    ptr = 0;
    CHK_SKIP(process()->readMemory(
        reinterpret_cast<uint64_t>(de.u.LoadDll.lpImageName), &ptr,
        pi.pointerSize));

    if (ptr == 0) {
      goto skip_name;
    }

    // It seems like all strings passed by the kernel here are guaranteed to be
    // unicode.
    DS2ASSERT(de.u.LoadDll.fUnicode);

    name.clear();
    wchar_t c;
    do {
      if (process()->readMemory(ptr, &c, sizeof(c)) != kSuccess) {
        break;
      }
      name.append(1, c);

      ptr += sizeof(c);
    } while (c != '\0');

  skip_name:
    DS2LOG(Debug, "new DLL loaded: %s, base=%" PRI_PTR,
           Host::Platform::WideToNarrowString(name).c_str(),
           PRI_PTR_CAST(de.u.LoadDll.lpBaseOfDll));

    if (de.u.LoadDll.hFile != NULL) {
      ::CloseHandle(de.u.LoadDll.hFile);
    }

    _state = kStopped;
    _stopInfo.event = StopInfo::kEventStop;
    _stopInfo.reason = StopInfo::kReasonLibraryEvent;
  } break;

  case UNLOAD_DLL_DEBUG_EVENT:
    DS2LOG(Debug, "DLL unloaded, base=%" PRI_PTR,
           PRI_PTR_CAST(de.u.UnloadDll.lpBaseOfDll));
    _state = kStopped;
    _stopInfo.event = StopInfo::kEventStop;
    _stopInfo.reason = StopInfo::kReasonLibraryEvent;
    break;

  case EXIT_THREAD_DEBUG_EVENT:
    _state = kStopped;
    _stopInfo.event = StopInfo::kEventStop;
    _stopInfo.reason = StopInfo::kReasonThreadExit;
    break;

  case OUTPUT_DEBUG_STRING_EVENT: {
    auto const &dsInfo = de.u.DebugString;
    DS2LOG(Debug, "inferior output a debug string: %" PRI_PTR "[%d]",
           PRI_PTR_CAST(dsInfo.lpDebugStringData), dsInfo.nDebugStringLength);

    // The length includes terminating null character.
    DS2ASSERT(dsInfo.nDebugStringLength >= 1);
    std::string buffer((dsInfo.fUnicode ? sizeof(WCHAR) : 1) *
                           (dsInfo.nDebugStringLength - 1),
                       0);

    CHKV(process()->readMemory(
        reinterpret_cast<uint64_t>(dsInfo.lpDebugStringData),
        const_cast<char *>(buffer.c_str()), buffer.size()));

    _stopInfo.debugString =
        dsInfo.fUnicode ? Platform::WideToNarrowString(std::wstring(
                              reinterpret_cast<const wchar_t *>(buffer.c_str()),
                              dsInfo.nDebugStringLength - 1))
                        : std::move(buffer);

    _state = kStopped;
    _stopInfo.event = StopInfo::kEventStop;
    _stopInfo.reason = StopInfo::kReasonDebugOutput;
  } break;

  default:
    DS2BUG("unknown debug event code: %lu", de.dwDebugEventCode);
  }
}
Exemple #19
0
void Thread::updateState(DEBUG_EVENT const &de) {
  DS2ASSERT(de.dwThreadId == _tid);

  switch (de.dwDebugEventCode) {
  case EXCEPTION_DEBUG_EVENT:
    _state = kStopped;
    _trap.event = StopInfo::kEventTrap;
    _trap.reason = StopInfo::kReasonNone;
    break;

  case LOAD_DLL_DEBUG_EVENT: {
    ErrorCode error;
    std::wstring name = L"<NONAME>";

    ProcessInfo pi;
    error = process()->getInfo(pi);
    if (error != kSuccess)
      goto noname;

    if (de.u.LoadDll.lpImageName == nullptr)
      goto noname;

    uint64_t ptr = 0;
    error = process()->readMemory(
        reinterpret_cast<uint64_t>(de.u.LoadDll.lpImageName), &ptr,
        pi.pointerSize);
    if (error != kSuccess)
      goto noname;

    if (ptr == 0)
      goto noname;

    // It seems like all strings passed by the kernel here are guaranteed to be
    // unicode.
    DS2ASSERT(de.u.LoadDll.fUnicode);

    name.clear();
    wchar_t c;
    do {
      error = process()->readMemory(ptr, &c, sizeof(c));
      if (error != kSuccess)
        break;
      name.append(1, c);

      ptr += sizeof(c);
    } while (c != '\0');

  noname:
    DS2LOG(Debug, "new DLL loaded: %s",
           Host::Platform::WideToNarrowString(name).c_str());

    if (de.u.LoadDll.hFile != NULL)
      CloseHandle(de.u.LoadDll.hFile);
  }

  case UNLOAD_DLL_DEBUG_EVENT:
  case OUTPUT_DEBUG_STRING_EVENT:
    _state = kStopped;
    _trap.event = StopInfo::kEventNone;
    _trap.reason = StopInfo::kReasonNone;
    break;

  default:
    DS2BUG("unknown debug event code: %d", de.dwDebugEventCode);
  }
}
Exemple #20
0
size_t SoftwareBreakpointManager::chooseBreakpointSize() const {
  DS2BUG(
      "Choosing a software breakpoint size on ARM is an unsupported operation");
}
Exemple #21
0
ErrorCode Process::wait(int *status, bool hang) {
  if (_terminated)
    return kSuccess;

  DEBUG_EVENT de;
  bool keepGoing = true;

  while (keepGoing) {
    BOOL result = WaitForDebugEvent(&de, hang ? INFINITE : 0);
    if (!result)
      return Platform::TranslateError();

    keepGoing = false;

    switch (de.dwDebugEventCode) {
    case CREATE_PROCESS_DEBUG_EVENT:
#define CHECK_AND_CLOSE(HAN)                                                   \
  do {                                                                         \
    if ((de.u.CreateProcessInfo.HAN) != NULL)                                  \
      CloseHandle(de.u.CreateProcessInfo.HAN);                                 \
  } while (0)
      CHECK_AND_CLOSE(hFile);
      CHECK_AND_CLOSE(hProcess);
      CHECK_AND_CLOSE(hThread);
#undef CHECK_AND_CLOSE
      return kSuccess;

    case EXIT_PROCESS_DEBUG_EVENT:
      _terminated = true;
      return kSuccess;

    case CREATE_THREAD_DEBUG_EVENT: {
      auto threadHandle = de.u.CreateThread.hThread;
      auto tid = GetThreadId(threadHandle);
      // No need to save the new thread pointer, as it gets added automatically
      // to the process.
      new Thread(this, tid, threadHandle);
      resume();
      keepGoing = true;
    } break;

    case EXIT_THREAD_DEBUG_EVENT: {
      auto threadIt = _threads.find(de.dwThreadId);
      DS2ASSERT(threadIt != _threads.end());
      auto tid = threadIt->second->tid();
      ContinueDebugEvent(_pid, tid, DBG_CONTINUE);
      removeThread(threadIt->second->tid());
      keepGoing = true;
    } break;

    case RIP_EVENT:
      DS2LOG(Fatal, "debug event RIP");

    case EXCEPTION_DEBUG_EVENT:
    case LOAD_DLL_DEBUG_EVENT:
    case UNLOAD_DLL_DEBUG_EVENT:
    case OUTPUT_DEBUG_STRING_EVENT: {
      auto threadIt = _threads.find(de.dwThreadId);
      DS2ASSERT(threadIt != _threads.end());
      threadIt->second->updateState(de);
    } break;

    default:
      DS2BUG("unknown debug event code: %lu", de.dwDebugEventCode);
    }
  }

  return kSuccess;
}