Beispiel #1
0
ErrorCode PTrace::step(ProcessThreadId const &ptid, ProcessInfo const &pinfo,
                       int signal, Address const &address) {
  pid_t pid;

  if (!ptid.valid())
    return kErrorInvalidArgument;

  if (!(ptid.tid <= kAnyThreadId)) {
    pid = ptid.tid;
  } else {
    pid = ptid.pid;
  }

  //
  // Continuation from address?
  //
  if (address.valid()) {
    Architecture::CPUState state;
    ErrorCode error = readCPUState(ptid, pinfo, state);
    if (error != kSuccess)
      return error;

    state.setPC(address);

    error = writeCPUState(ptid, pinfo, state);
    if (error != kSuccess)
      return error;
  }

  // (caddr_t)1 indicate that execution is to pick up where it left off.
  if (wrapPtrace(PT_STEP, pid, (caddr_t)1, signal) < 0)
    return Platform::TranslateError();

  return kSuccess;
}
Beispiel #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;
}
Beispiel #3
0
ErrorCode Thread::readCPUState(Architecture::CPUState &state) {
  CONTEXT context;

  memset(&context, 0, sizeof(context));
  context.ContextFlags = CONTEXT_INTEGER |        // GP registers.
                         CONTEXT_CONTROL |        // Some more GP + CPSR.
                         CONTEXT_FLOATING_POINT | // FP registers.
                         CONTEXT_DEBUG_REGISTERS; // Debug registers.

  BOOL result = GetThreadContext(_handle, &context);
  if (!result) {
    return Platform::TranslateError();
  }

  // GP registers + CPSR.
  state.gp.r0 = context.R0;
  state.gp.r1 = context.R1;
  state.gp.r2 = context.R2;
  state.gp.r3 = context.R3;
  state.gp.r4 = context.R4;
  state.gp.r5 = context.R5;
  state.gp.r6 = context.R6;
  state.gp.r7 = context.R7;
  state.gp.r8 = context.R8;
  state.gp.r9 = context.R9;
  state.gp.r10 = context.R10;
  state.gp.r11 = context.R11;
  state.gp.ip = context.R12;
  state.gp.sp = context.Sp;
  state.gp.lr = context.Lr;
  state.gp.pc = context.Pc;
  state.gp.cpsr = context.Cpsr;

  // Floating point registers.
  static_assert(sizeof(context.D) == sizeof(state.vfp.dbl),
                "floating point register count mismatch");
  for (size_t i = 0; i < array_sizeof(context.D); ++i) {
    state.vfp.dbl[i].value = context.D[i];
  }
  state.vfp.fpscr = context.Fpscr;

  if (state.isThumb()) {
    if (state.gp.pc & 1ULL) {
      DS2LOG(Debug, "removing thumb bit from pc and lr");
      state.gp.pc &= ~1ULL;
    } else {
      DS2LOG(Warning,
             "CPU is in thumb mode but doesn't have thumb bit set in pc");
    }
  }

  // TODO(sas): Handle debug registers.

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

  for (auto thread : threads) {
    Architecture::CPUState state;
    if (thread->state() != Thread::kRunning) {
      thread->readCPUState(state);
    }
    DS2LOG(Debug, "tid %d state %d at pc %#" PRIx64, thread->tid(),
           thread->state(),
           thread->state() == Thread::kStopped ? (uint64_t)state.pc() : 0);
    if (thread->state() == Thread::kRunning) {
      ErrorCode error;

      DS2LOG(Debug, "suspending tid %d", thread->tid());
      error = thread->suspend();

      if (error == kSuccess) {
        DS2LOG(Debug, "suspended tid %d at pc %#" PRIx64, thread->tid(),
               (uint64_t)state.pc());
        thread->readCPUState(state);
      } else if (error == kErrorProcessNotFound) {
        //
        // Thread is dead.
        //
        removeThread(thread->tid());
        DS2LOG(Debug, "tried to suspended tid %d which is already dead",
               thread->tid());
      } else {
        return error;
      }
    } else if (thread->state() == Thread::kTerminated) {
      //
      // Thread is dead.
      //
      removeThread(thread->tid());
    }
  }

  return kSuccess;
}
Beispiel #5
0
ErrorCode PTrace::prepareAddressForResume(ProcessThreadId const &ptid,
                                          ProcessInfo const &pinfo,
                                          Address const &address) {
  if (address.valid()) {
    Architecture::CPUState state;
    ErrorCode error = readCPUState(ptid, pinfo, state);
    if (error != kSuccess) {
      return error;
    }

    state.setPC(address);

    error = writeCPUState(ptid, pinfo, state);
    if (error != kSuccess) {
      return error;
    }
  }

  return kSuccess;
}
Beispiel #6
0
ErrorCode Process::resume(int signal, std::set<Thread *> const &excluded) {
  enumerateThreads([&](Thread *thread) {
    if (excluded.find(thread) != excluded.end())
      return;

    if (thread->state() == Thread::kStopped ||
        thread->state() == Thread::kStepped) {
      Architecture::CPUState state;
      thread->readCPUState(state);
      DS2LOG(Debug, "resuming tid %I64u from pc %#I64x",
             (uint64_t)thread->tid(), (uint64_t)state.pc());
      ErrorCode error = thread->resume(signal);
      if (error != kSuccess) {
        DS2LOG(Warning, "failed resuming tid %I64u, error=%d",
               (uint64_t)thread->tid(), error);
      }
    }
  });

  return kSuccess;
}
Beispiel #7
0
ErrorCode Thread::writeCPUState(Architecture::CPUState const &state) {
  CONTEXT context;

  memset(&context, 0, sizeof(context));
  // TODO(sas): Handle debug registers.
  context.ContextFlags = CONTEXT_INTEGER |       // GP registers.
                         CONTEXT_CONTROL |       // Some more GP + CPSR.
                         CONTEXT_FLOATING_POINT; // FP registers.

  // GP registers + CPSR.
  context.R0 = state.gp.r0;
  context.R1 = state.gp.r1;
  context.R2 = state.gp.r2;
  context.R3 = state.gp.r3;
  context.R4 = state.gp.r4;
  context.R5 = state.gp.r5;
  context.R6 = state.gp.r6;
  context.R7 = state.gp.r7;
  context.R8 = state.gp.r8;
  context.R9 = state.gp.r9;
  context.R10 = state.gp.r10;
  context.R11 = state.gp.r11;
  context.R12 = state.gp.ip;
  context.Sp = state.gp.sp;
  context.Lr = state.gp.lr;
  context.Pc = state.gp.pc;
  context.Cpsr = state.gp.cpsr;

  // Floating point registers.
  for (size_t i = 0; i < array_sizeof(context.D); ++i) {
    context.D[i] = state.vfp.dbl[i].value;
  }
  context.Fpscr = state.vfp.fpscr;

  if (state.isThumb()) {
    DS2ASSERT(!(state.gp.pc & 1ULL));
    DS2LOG(Debug, "setting back thumb bit on pc and lr");
    context.Pc |= 1ULL;
  }

  BOOL result = SetThreadContext(_handle, &context);
  if (!result) {
    return Platform::TranslateError();
  }

  return kSuccess;
}
Beispiel #8
0
ErrorCode Thread::prepareSoftwareSingleStep(Address const &address) {
  Architecture::CPUState state;

  ErrorCode error = readCPUState(state);
  if (error != kSuccess)
    return error;

  bool link = false;
  bool isThumb = (state.gp.cpsr & (1 << 5));
  uint32_t pc = address.valid() ? address.value() : state.pc();
  uint32_t nextPC = pc;
  uint32_t branchPC = static_cast<uint32_t>(-1);
  uint32_t size = 0;

  //
  // We need to read 8 bytes, because of IT block
  //
  if (isThumb) {
    error = PrepareThumbSoftwareSingleStep(process(), pc, state, size, link,
                                           branchPC, nextPC);
  } else {
    error = PrepareARMSoftwareSingleStep(process(), pc, state, size, link,
                                         branchPC, nextPC);
  }

  DS2LOG(Architecture, Debug, "branchPC=%#lx[link=%s] nextPC=%#lx",
         (unsigned long)branchPC, link ? "true" : "false",
         (unsigned long)nextPC);

  if (branchPC != static_cast<uint32_t>(-1)) {
    error = process()->breakpointManager()->add(
        branchPC, BreakpointManager::kTypeTemporaryOneShot, size);
    if (error != kSuccess)
      return error;
  }

  if (nextPC != static_cast<uint32_t>(-1)) {
    if ((nextPC & ~1) == pc) {
      if (!isThumb) {
        nextPC += 4;
        size = 4;
      } else {
        uint32_t insn;

        error = process()->readMemory(pc & ~1, &insn, sizeof(insn));
        if (error != kSuccess)
          return error;

        auto inst_size = Architecture::ARM::GetThumbInstSize(insn);
        nextPC += static_cast<std::uint8_t>(inst_size);
        size = 2;
      }
    }

    error = process()->breakpointManager()->add(
        nextPC, BreakpointManager::kTypeTemporaryOneShot, size);
    if (error != kSuccess)
      return error;
  }

  return kSuccess;
}