blob: ed085a1994c69c8baa66f78f5cde0009fa073e65 [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.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_SYMBOL_DATA_PROVIDER_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_SYMBOL_DATA_PROVIDER_H_
#include <stdint.h>
#include <map>
#include <optional>
#include <vector>
#include "lib/fit/function.h"
#include "src/developer/debug/shared/arch.h"
#include "src/developer/debug/shared/register_id.h"
#include "src/developer/debug/zxdb/common/err_or.h"
#include "src/developer/debug/zxdb/common/int128_t.h"
#include "src/developer/debug/zxdb/symbols/symbol.h"
#include "src/lib/containers/cpp/array_view.h"
#include "src/lib/fxl/memory/ref_counted.h"
namespace zxdb {
class Err;
class SymbolContext;
// This interface is how the debugger backend provides memory and register data to the symbol system
// to evaluate expressions.
//
// By default, this class returns no information. In this form it can be used to evaluate
// expressions in contexts without a running process. To access data, most callers will want to use
// the implementation associated with a frame or a process.
//
// 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 = fit::callback<void(const Err&, std::vector<uint8_t>)>;
using GetTLSSegmentCallback = fit::callback<void(ErrOr<uint64_t>)>;
// The Err indicates whether the operation was successful. Common failure cases are the thread is
// running or this register wasn't saved on the stack frame.
using GetRegisterCallback = fit::callback<void(const Err&, std::vector<uint8_t>)>;
// CAllback for multiple register values. The map will contain the requested register values when
// the error is not set.
using GetRegistersCallback =
fit::callback<void(const Err&, std::map<debug::RegisterID, std::vector<uint8_t>>)>;
using GetFrameBaseCallback = fit::callback<void(const Err&, uint64_t value)>;
using WriteCallback = fit::callback<void(const Err&)>;
virtual debug::Arch GetArch();
// Returns a SymbolDataProvider that will retrieve register values from the entrypoint of the
// current function.
//
// Returns null if there is no entrypoint (like maybe there's no current function) or can't have
// registers retrieved from it. This data provider is used to evaluate DW_OP_entry_value
// expressions.
virtual fxl::RefPtr<SymbolDataProvider> GetEntryDataProvider() const;
// Request for synchronous register data if possible.
//
// If the value is not synchronously known, the return value will be std::nullopt. In this case,
// GetRegisterAsync() should be called to retrieve the value.
//
// The return value can be an empty view if the implementation knows synchronously that we don't
// know the value. An example is an unsaved register in a non-topmost stack frame.
//
// On successful data return, the data is owned by the implementor and should not be saved.
virtual std::optional<containers::array_view<uint8_t>> GetRegister(debug::RegisterID id);
// Request for register data with an asynchronous callback. The callback will be issued when the
// register data is available.
virtual void GetRegisterAsync(debug::RegisterID id, GetRegisterCallback callback);
// A wrapper around GetRegister and GetRegisterAsync that collects all the requested register
// values. The callback will be issued with all collected values. If all values are known
// synchronously, the callback will be called reentrantly.
void GetRegisters(const std::vector<debug::RegisterID>& regs, GetRegistersCallback cb);
// Writes the given canonical register ID.
//
// This must be a canonical register as identified by debug::RegisterInfo::canonical_id, which
// means that it's a whole hardware register and needs no shifting nor masking.
virtual void WriteRegister(debug::RegisterID id, std::vector<uint8_t> data, WriteCallback cb);
// 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();
// Asynchronous version of GetFrameBase.
virtual void GetFrameBaseAsync(GetFrameBaseCallback callback);
// Returns the canonical frame address of the current frame. Returns 0 if it is not known. See
// Frame::GetCanonicalFrameAddress().
virtual uint64_t GetCanonicalFrameAddress() const;
// Synchronously returns the debug address for a symbol context if available.
virtual std::optional<uint64_t> GetDebugAddressForContext(const SymbolContext& context) const;
// Get the address of the TLS segment for the given context. The TLS segment is where thread-local
// variables live.
virtual void GetTLSSegment(const SymbolContext& symbol_context, GetTLSSegmentCallback cb);
// 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);
// 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, WriteCallback cb);
protected:
FRIEND_MAKE_REF_COUNTED(SymbolDataProvider);
FRIEND_REF_COUNTED_THREAD_SAFE(SymbolDataProvider);
SymbolDataProvider() = default;
virtual ~SymbolDataProvider() = default;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_SYMBOL_DATA_PROVIDER_H_