blob: 93c5a8ddc5e377db1025357b54a847d5beb4e129 [file] [log] [blame]
// Copyright 2018 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 <stdint.h>
#include <functional>
#include <optional>
#include <vector>
#include "lib/fxl/memory/ref_counted.h"
namespace zxdb {
class Err;
// This interface is how the debugger backend provides memory and register data
// to the symbol system to evaluate expressions.
//
// Registers are the most commonly accessed data type and they are often
// available synchronously. So the interface provides a synchronous main
// register getter function and a fallback asynchronous one. They are separated
// to avoid overhead of closure creation in the synchronous case, and to
// avoid having a callback that's never issued.
//
// This object is reference counted since evaluating a DWARF expression is
// asynchronous.
class SymbolDataProvider
: public fxl::RefCountedThreadSafe<SymbolDataProvider> {
public:
using GetMemoryCallback =
std::function<void(const Err&, std::vector<uint8_t>)>;
using GetRegisterCallback = std::function<void(const Err&, uint64_t)>;
// Special register numbers (normal DWARF registers are never negative).
// These will be mapped to the corresponding platform-specific registers for
// the current platform.
//
// These are guaranteed available synchronously. If the synchronous getter
// returns failure for them, it means the register isn't available in the
// current context.
static constexpr int kRegisterIP = -1;
// Request for synchronous register data. If the register data can be provided
// synchronously, the data will be returned. If synchronous data is not
// available, the caller should call GetRegisterAsync().
virtual std::optional<uint64_t> GetRegister(int dwarf_register_number) = 0;
// Request for register data with an asynchronous callback. The callback will
// be issued when the register data is available.
//
// The success parameter indicates whether the operation was successful. If
// the register is not available now (maybe the thread is running), success
// will be set to false. When the register value contains valid data, success
// will indicate true.
virtual void GetRegisterAsync(int dwarf_register_number,
GetRegisterCallback callback) = 0;
// Synchronously returns the frame base pointer if possible. As with
// GetRegister, if this is not available the implementation should call
// GetFrameBaseAsync().
//
// The frame base is the DW_AT_frame_base for the current function. Often
// this will be the "base pointer" register in the CPU, but could be other
// registers, especially if compiled without full stack frames. Getting this
// value may involve evaluating another DWARF expression which may or may not
// be asynchronous.
virtual std::optional<uint64_t> GetFrameBase() = 0;
// Asynchronous version of GetFrameBase.
virtual void GetFrameBaseAsync(GetRegisterCallback callback) = 0;
// Request to retrieve a memory block from the debugged process. On success,
// the implementation will call the callback with the retrieved data pointer.
//
// It will read valid memory up to the maximum. It will do short reads if it
// encounters invalid memory, so the result may be shorter than requested
// or empty (if the first byte is invalid).
virtual void GetMemoryAsync(uint64_t address, uint32_t size,
GetMemoryCallback callback) = 0;
// Asynchronously writes to the given memory. The callback will be issued
// when the write is complete.
virtual void WriteMemory(uint64_t address, std::vector<uint8_t> data,
std::function<void(const Err&)> cb) = 0;
protected:
FRIEND_REF_COUNTED_THREAD_SAFE(SymbolDataProvider);
virtual ~SymbolDataProvider() = default;
};
} // namespace zxdb