Beispiel #1
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;
}
Beispiel #2
0
void ProcessBase::insert(ThreadBase *thread) {
  if (!_threads
           .insert(std::make_pair(thread->tid(), static_cast<Thread *>(thread)))
           .second)
    return;

  DS2LOG(Debug, "[new Thread %" PRI_PTR " (LWP %" PRIu64 ")]",
         PRI_PTR_CAST(thread), (uint64_t)thread->tid());
}
Beispiel #3
0
void ProcessBase::removeThread(ThreadId tid) {
  auto it = _threads.find(tid);
  if (it == _threads.end())
    return;

  Thread *thread = it->second;
  _threads.erase(it);

  DS2LOG(Debug, "[delete Thread %" PRI_PTR " (LWP %" PRIu64 ") exited]",
         PRI_PTR_CAST(thread), (uint64_t)thread->tid());

  delete thread;
}
Beispiel #4
0
void PrintBacktrace() {
  static const int kStackSize = 100;
  static void *stack[kStackSize];
  int stackEntries = ::backtrace(stack, kStackSize);

  for (int i = 0; i < stackEntries; ++i) {
    Dl_info info;
    int res;

    res = ::dladdr(stack[i], &info);
    if (res < 0) {
      PrintBacktraceEntrySimple(stack[i]);
      continue;
    }

    char *demangled = nullptr;
    const char *name;
    if (info.dli_sname != nullptr) {
      demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &res);
      if (res == 0) {
        name = demangled;
      } else {
        name = info.dli_sname;
      }
    } else {
      name = "<unknown>";
    }

    DS2LOG(Error, "%" PRI_PTR " %s+%#" PRIxPTR " (%s)", PRI_PTR_CAST(stack[i]),
           name,
           static_cast<char *>(stack[i]) - static_cast<char *>(info.dli_saddr),
           info.dli_fname);

    ::free(demangled);
  }
}
Beispiel #5
0
static void PrintBacktraceEntrySimple(void *address) {
  DS2LOG(Error, "%" PRI_PTR, PRI_PTR_CAST(address));
}
Beispiel #6
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);
  }
}