blob: dfa329d39fadb468560c53e54cbe6c48a4fb781b [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <memory>
#include <string>
#include <src/lib/fxl/macros.h>
#include <src/lib/fxl/memory/weak_ptr.h>
#include <lib/zx/suspend_token.h>
#include <zircon/syscalls/exception.h>
#include <zircon/types.h>
#include "arch.h"
#include "breakpoint.h"
#include "registers.h"
namespace inferior_control {
class Process;
// Represents a thread that is owned by a Process instance.
class Thread final {
public:
enum class State {
kNew,
kInException,
kSuspended,
kRunning,
kStepping,
kExiting,
kGone,
};
Thread(Process* process, zx_handle_t handle, zx_koid_t id);
~Thread();
Process* process() const { return process_; }
zx_handle_t handle() const { return handle_; }
zx_koid_t id() const { return id_; }
const std::string& name() const { return name_; }
std::string GetName() const;
// Same as GetName() except includes the ids in hex.
// This helps matching with thread names in packets.
std::string GetDebugName() const;
// Returns a weak pointer to this Thread instance.
fxl::WeakPtr<Thread> AsWeakPtr();
// Returns a pointer to the arch::Registers object associated with this
// thread. The returned pointer is owned by this Thread instance and should
// not be deleted by the caller.
Registers* registers() const { return registers_.get(); }
// Returns the current state of this thread.
State state() const { return state_; }
// Returns true if thread is alive. It could be stopped, but it's still
// alive.
bool IsLive() const;
static const char* StateName(Thread::State state);
// Returns a GDB signal number based on the current exception context. If no
// exception context was set on this Thread or if the exception data from the
// context does not map to a meaningful GDB signal number, this method returns
// GdbSignal::kUnsupported.
// TODO(dje): kNone might be a better value if there is no exception.
GdbSignal GetGdbSignal() const;
// Called when the thread gets an exception.
void OnException(const zx_excp_type_t type,
const zx_exception_context_t& context);
// Called when the thread gets a signal.
void OnSignal(zx_signals_t signal);
// Pass the exception on to the next handler.
// TODO(PT-105): The passing of |eport| will change.
bool TryNext(zx_handle_t eport);
// Resumes the thread from a "stopped in exception" state.
// The thread state on successful return is kRunning.
// TODO(PT-105): The passing of |eport| will change.
bool ResumeFromException(zx_handle_t eport);
// Assuming the thread stopped at a s/w breakpoint instruction, advance the
// pc to after the instruction and resume.
// Note that this is not for resuming afterware a tool-introduced
// s/w breakpoint. This is for resuming after a s/w breakpoint instruction
// that is part of the program itself.
bool ResumeAfterSoftwareBreakpointInstruction(zx_handle_t eport);
// Resumes the thread from an ZX_EXCP_THREAD_EXITING exception.
// The thread state on entry must one of kNew, kInException, kExiting.
// The thread state on return is kGone.
// TODO(PT-105): The passing of |eport| will change.
void ResumeForExit(zx_handle_t eport);
// Request the thread to suspend.
// This doesn't wait for it to suspend, just requests it.
// It is up to the app's server loop to wait for the thread to suspend if
// it wants to.
bool RequestSuspend();
// Resume after having been suspended.
void ResumeFromSuspension();
// Steps the thread from a "stopped in exception" state. Returns true on
// success, false on failure.
bool Step();
// Assuming the thread is stopped in an exception, return the exception
// report.
// Normally this returns ZX_OK, but it can return ZX_ERR_BAD_STATE if the
// process has terminated before we read the report.
zx_status_t GetExceptionReport(zx_exception_report_t* report) const;
// Print an Inspector-style dump of the thread.
// Threads that are not currently in an exception or suspended are ignored.
// It is the caller's responsibility to stop threads first (and wait for them
// to stop).
void Dump();
// Convert an exception to a user-friendly description.
// This is for log messages and interactive programs that wish to report
// the exception.
std::string ExceptionToString(zx_excp_type_t type,
const zx_exception_context_t& context) const;
// Convert a thread signal (or signals) to a user-friendly description.
// This is for log messages and interactive programs that wish to report
// the signal.
std::string SignalsToString(zx_signals_t signals) const;
#ifdef __x86_64__
// Intel PT buffer access
int32_t ipt_buffer() const { return ipt_buffer_; }
void set_ipt_buffer(int32_t ipt_buffer) { ipt_buffer_ = ipt_buffer; }
#endif
private:
friend class Process;
// Called by Process to set the state of its threads.
void set_state(State state);
// Release all resources held by the thread.
// Called after all other processing of a thread exit has been done.
void Clear();
zx_handle_t GetExceptionPortHandle();
// Handlers for individual signals.
void OnTermination();
void OnSuspension();
void OnResumption();
// Our process (non-owning pointer).
Process* process_;
// The debug-capable handle that we use to invoke zx_debug_* syscalls.
zx_handle_t handle_;
// The thread ID (also the kernel object ID) of this thread.
zx_koid_t id_;
// The name of the thread, from ZX_PROP_NAME.
std::string name_;
// The arch::Registers object associated with this thread.
std::unique_ptr<Registers> registers_;
// The current state of the this thread.
State state_;
// Suspend token when thread is suspended.
zx::suspend_token suspend_token_;
#ifdef __x86_64__
// The Intel Processor Trace buffer descriptor attached to this thread,
// or -1 if none.
int32_t ipt_buffer_;
#endif
// The collection of breakpoints that belong to this thread.
ThreadBreakpointSet breakpoints_;
// Pointer to the most recent exception context that this Thread received via
// an architectural exception. Contains nullptr if the thread never received
// an exception.
std::unique_ptr<zx_exception_context_t> exception_context_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
fxl::WeakPtrFactory<Thread> weak_ptr_factory_;
FXL_DISALLOW_COPY_AND_ASSIGN(Thread);
};
} // namespace inferior_control