blob: 2c4467b48af71b9464674497d191ba8aad852274 [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 <lib/async-loop/cpp/loop.h>
#include <src/lib/fxl/macros.h>
#include <src/lib/fxl/strings/string_view.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/zx/job.h>
#include <src/lib/files/unique_fd.h>
#include "garnet/lib/process/process_builder.h"
#include "delegate.h"
#include "exception_port.h"
#include "io_loop.h"
#include "process.h"
#include "thread.h"
namespace inferior_control {
// Server implements the main loop and handles client operations and inferior
// events (exceptions, etc).
//
// TODO(dje): It might be useful to separate out |Delegate| here.
// It is used as a "mixin" to simplify early clients.
//
// NOTE: This class is generally not thread safe. Care must be taken when
// calling methods such as set_current_process() and SetCurrentThread()
// which modify its internal state.
class Server : public Delegate {
public:
// Starts the main loop, and returns when the main loop exits.
// Returns true if the main loop exits cleanly, or false in the case of an
// error.
// TODO(armansito): More clearly define the error scenario.
// TODO(dje): This mightn't need to be virtual, but it provides consistency
// among the uses.
virtual bool Run() = 0;
zx_handle_t job_for_search() const { return job_for_search_.get(); }
zx_handle_t job_for_launch() const { return job_for_launch_.get(); }
// Returns a raw pointer to the current inferior. The instance pointed to by
// the returned pointer is owned by this Server instance and should not be
// deleted.
Process* current_process() const { return current_process_.get(); }
// Sets the current process. This cleans up the current process (if any) and
// takes ownership of |process|.
void set_current_process(Process* process) {
current_process_.reset(process);
}
// Returns a raw pointer to the current thread.
Thread* current_thread() const { return current_thread_.get(); }
// Assigns the current thread.
void SetCurrentThread(Thread* thread);
// Returns a mutable reference to the main message loop. The returned instance
// is owned by this Server instance and should not be deleted.
async::Loop& message_loop() { return message_loop_; }
// Returns a mutable reference to the exception port. The returned instance is
// owned by this Server instance and should not be deleted.
ExceptionPort& exception_port() { return exception_port_; }
// Accessor for the exception port's handle.
// TODO(PT-105): Delete when exceptions have handles themselves.
zx_handle_t exception_port_handle() const { return exception_port_.handle(); }
// Utility to create a new inferior via |process::ProcessBuilder|.
// Returns false if there is an error.
// |*out_builder| is returned in case the caller wants to add anything
// further to the new process. A typical example is to call
// |builder->CloneAll()| as no cloning is done yet. |*out_builder| is
// intended to be passed to |Process::InitializeFromBuilder|.
// TODO(dje): InferiorManager class to manage multiple inferiors, and
// creating them.
bool CreateProcessViaBuilder(
const std::string& path, const debugger_utils::Argv& argv,
std::unique_ptr<process::ProcessBuilder>* out_builder);
// Return a handle to a running process that can be used for debugging.
// Returns an invalid object if the process is not found or the handle is
// unobtainable.
// |pid| is looked up via |job_to_search()|.
zx::process FindProcess(zx_koid_t pid);
// Call this to schedule termination of the server.
// N.B. The Server will exit its main loop asynchronously so any
// subsequently posted tasks will be dropped.
void PostQuitMessageLoop(bool status);
// Register an async-wait for |thread| on the exception port loop.
void WaitAsync(Thread* thread);
private:
void OnProcessException(const zx_port_packet_t& packet);
void OnProcessSignal(const zx_port_packet_t& packet);
// Returns a borrowed handle of the job whose processes we may attach to.
// If this is ZX_HANDLE_INVALID then we may not attach to any process.
zx::job job_for_search_;
// Returns a borrowed handle of the job where processes are launched.
// This is not necessarily |job_for_search_|, we may be able to attach to
// any process but not necessarily want to start new processes in the root
// job itself. If this is ZX_HANDLE_INVALID then starting new processes is
// not allowed.
zx::job job_for_launch_;
// The services to pass to processes created with
// |CreateProcessViaBuilder()|.
std::shared_ptr<sys::ServiceDirectory> services_;
protected:
Server(zx::job job_for_search, zx::job job_for_launch,
std::shared_ptr<sys::ServiceDirectory> services);
virtual ~Server();
// Sets the run status and quits the main message loop.
void QuitMessageLoop(bool status);
// The current thread under debug. We only keep a weak pointer here, since the
// instance itself is owned by a Process and may get removed.
fxl::WeakPtr<Thread> current_thread_;
// The main loop.
async::Loop message_loop_;
// The ExceptionPort used by inferiors to receive exceptions.
// (This is declared after |message_loop_| since that needs to have been
// created before this can be initialized).
ExceptionPort exception_port_;
// Strong pointer to the current inferior process that is being debugged.
// NOTE: This must be declared after |exception_port_| above, since the
// process may do work in its destructor to detach itself from
// |exception_port_|.
std::unique_ptr<Process> current_process_;
// Stores the global error state. This is used to determine the return value
// for "Run()" when |message_loop_| exits.
bool run_status_;
private:
FXL_DISALLOW_COPY_AND_ASSIGN(Server);
};
// Same as Server, but provides I/O support.
// An example use-case is debugserver for gdb.
class ServerWithIO : public Server, public IOLoop::Delegate {
protected:
ServerWithIO(zx::job job_for_search, zx::job job_for_launch,
std::shared_ptr<sys::ServiceDirectory> services);
virtual ~ServerWithIO();
// The IOLoop used for blocking I/O operations over |client_sock_|.
// |message_loop_| and |client_sock_| both MUST outlive |io_loop_|. We take
// care to clean it up in the destructor.
std::unique_ptr<IOLoop> io_loop_;
// File descriptor for the socket (or terminal) used for communication.
// TODO(dje): Rename from *sock* after things are working.
fxl::UniqueFD client_sock_;
};
} // namespace inferior_control