blob: 9841c44d06401c09a5725c41bd341e8ce54acf82 [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.
#include "garnet/bin/zxdb/symbols/mock_symbol_data_provider.h"
#include <inttypes.h>
#include <algorithm>
#include "garnet/bin/zxdb/common/err.h"
#include "garnet/lib/debug_ipc/helper/message_loop.h"
#include "lib/fxl/strings/string_printf.h"
namespace zxdb {
MockSymbolDataProvider::MockSymbolDataProvider() : weak_factory_(this) {}
void MockSymbolDataProvider::AddRegisterValue(int register_num,
bool synchronous,
uint64_t value) {
regs_[register_num] = RegData(synchronous, value);
}
void MockSymbolDataProvider::AddMemory(uint64_t address,
std::vector<uint8_t> data) {
mem_[address] = std::move(data);
}
std::optional<uint64_t> MockSymbolDataProvider::GetRegister(
int dwarf_register_number) {
if (dwarf_register_number == kRegisterIP)
return ip_;
const auto& found = regs_.find(dwarf_register_number);
if (found == regs_.end())
return std::nullopt;
if (!found->second.synchronous)
return std::nullopt; // Force synchronous query.
return found->second.value;
}
void MockSymbolDataProvider::GetRegisterAsync(int dwarf_register_number,
GetRegisterCallback callback) {
debug_ipc::MessageLoop::Current()->PostTask(
FROM_HERE, [callback, weak_provider = weak_factory_.GetWeakPtr(),
dwarf_register_number]() {
if (!weak_provider) {
// Destroyed before callback ready.
return;
}
const auto& found = weak_provider->regs_.find(dwarf_register_number);
if (found == weak_provider->regs_.end())
callback(Err("Failed"), 0);
callback(Err(), found->second.value);
});
}
std::optional<uint64_t> MockSymbolDataProvider::GetFrameBase() { return bp_; }
void MockSymbolDataProvider::GetFrameBaseAsync(GetRegisterCallback callback) {
debug_ipc::MessageLoop::Current()->PostTask(
FROM_HERE, [callback, weak_provider = weak_factory_.GetWeakPtr()]() {
if (!weak_provider) {
// Destroyed before callback ready.
return;
}
callback(Err(), weak_provider->bp_);
});
}
void MockSymbolDataProvider::GetMemoryAsync(uint64_t address, uint32_t size,
GetMemoryCallback callback) {
auto found = FindBlockForAddress(address);
if (found == mem_.end()) {
debug_ipc::MessageLoop::Current()->PostTask(FROM_HERE, [callback]() {
// The API states that invalid memory is not an error, it just does a
// short read.
callback(Err(), std::vector<uint8_t>());
});
} else {
size_t offset = address - found->first;
uint32_t size_to_return =
std::min(size, static_cast<uint32_t>(found->second.size() - offset));
std::vector<uint8_t> subset;
subset.resize(size_to_return);
memcpy(&subset[0], &found->second[offset], size_to_return);
debug_ipc::MessageLoop::Current()->PostTask(
FROM_HERE, [callback, subset]() { callback(Err(), subset); });
}
}
void MockSymbolDataProvider::WriteMemory(uint64_t address,
std::vector<uint8_t> data,
std::function<void(const Err&)> cb) {
memory_writes_.emplace_back(address, std::move(data));
// Declare success.
debug_ipc::MessageLoop::Current()->PostTask(FROM_HERE, [cb]() { cb(Err()); });
}
MockSymbolDataProvider::RegisteredMemory::const_iterator
MockSymbolDataProvider::FindBlockForAddress(uint64_t address) const {
// Finds the first block >= address.
auto found = mem_.lower_bound(address);
// We need the first block <= address.
if (found != mem_.end() && found->first == address)
return found; // Got exact match.
// Now find the first block < address.
if (found == mem_.begin())
return mem_.end(); // Nothing before the address.
--found;
if (address >= found->first + found->second.size())
return mem_.end(); // Address is after this range.
return found;
}
} // namespace zxdb