blob: 5042694eecd8cb0facdcd7245ed0fa47e8255ce2 [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 "src/developer/debug/zxdb/client/frame_symbol_data_provider.h"
#include <inttypes.h>
#include "src/developer/debug/shared/message_loop.h"
#include "src/developer/debug/zxdb/client/frame.h"
#include "src/developer/debug/zxdb/client/memory_dump.h"
#include "src/developer/debug/zxdb/client/process.h"
#include "src/developer/debug/zxdb/client/register.h"
#include "src/developer/debug/zxdb/client/session.h"
#include "src/developer/debug/zxdb/client/thread.h"
#include "src/developer/debug/zxdb/common/err.h"
#include "src/lib/fxl/logging.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace zxdb {
namespace {
Err CallFrameDestroyedErr() { return Err("Call frame destroyed."); }
Err RegisterUnavailableErr(debug_ipc::RegisterID id) {
return Err(fxl::StringPrintf("Register %s unavailable.", debug_ipc::RegisterIDToString(id)));
}
} // namespace
FrameSymbolDataProvider::FrameSymbolDataProvider(Frame* frame)
: ProcessSymbolDataProvider(frame->GetThread()->GetProcess()), frame_(frame) {}
FrameSymbolDataProvider::~FrameSymbolDataProvider() = default;
void FrameSymbolDataProvider::Disown() {
ProcessSymbolDataProvider::Disown();
frame_ = nullptr;
}
bool FrameSymbolDataProvider::GetRegister(debug_ipc::RegisterID id,
std::optional<uint64_t>* value) {
FXL_DCHECK(id != debug_ipc::RegisterID::kUnknown);
*value = std::nullopt;
if (!frame_)
return true; // Synchronously know we don't have the value.
if (!debug_ipc::IsGeneralRegister(id))
return false; // Don't have non-general register synchronously.
for (const auto& r : frame_->GetGeneralRegisters()) {
if (r.id() == id) {
// Currently we expect all general registers to be <= 64 bits and we're
// returning the value in 64 bits.
if (r.size() > 0 && r.size() <= sizeof(uint64_t))
*value = r.GetValue();
return true;
}
}
// Getting here means a general register we don't have was requsted and this
// can never be provided. Return "synchronously complete" (true) and leave
// *value as nullopt to indicate this state.
return true;
}
void FrameSymbolDataProvider::GetRegisterAsync(debug_ipc::RegisterID id,
GetRegisterCallback callback) {
if (!frame_) {
// Frame deleted out from under us.
debug_ipc::MessageLoop::Current()->PostTask(
FROM_HERE, [id, cb = std::move(callback)]() { cb(RegisterUnavailableErr(id), 0); });
return;
}
// General registers are stored on the frame and are synchronously available.
// Return them (or error if not available) if somebody requests them
// asynchronously.
if (debug_ipc::IsGeneralRegister(id)) {
std::optional<uint64_t> value;
GetRegister(id, &value);
debug_ipc::MessageLoop::Current()->PostTask(FROM_HERE, [id, value, cb = std::move(callback)]() {
if (value)
cb(Err(), *value);
else
cb(RegisterUnavailableErr(id), 0);
});
return;
}
// if (IsInTopPhysicalFrame()) {
// TODO Support for dynamically fetching other registers like floating point
// and vector registers here.
//}
debug_ipc::MessageLoop::Current()->PostTask(FROM_HERE, [id, cb = std::move(callback)]() {
cb(Err(fxl::StringPrintf("Register %s unavailable.", debug_ipc::RegisterIDToString(id))), 0);
});
}
std::optional<uint64_t> FrameSymbolDataProvider::GetFrameBase() {
if (!frame_)
return std::nullopt;
return frame_->GetBasePointer();
}
void FrameSymbolDataProvider::GetFrameBaseAsync(GetRegisterCallback cb) {
if (!frame_) {
debug_ipc::MessageLoop::Current()->PostTask(
FROM_HERE, [cb = std::move(cb)]() { cb(CallFrameDestroyedErr(), 0); });
return;
}
frame_->GetBasePointerAsync([cb = std::move(cb)](uint64_t value) { cb(Err(), value); });
}
uint64_t FrameSymbolDataProvider::GetCanonicalFrameAddress() const {
if (!frame_)
return 0;
return frame_->GetCanonicalFrameAddress();
}
bool FrameSymbolDataProvider::IsInTopPhysicalFrame() const {
if (!frame_)
return false;
const Stack& stack = frame_->GetThread()->GetStack();
if (stack.empty())
return false;
// Search for the first physical frame, and return true if it or anything
// above it matches the current frame.
for (size_t i = 0; i < stack.size(); i++) {
if (stack[i] == frame_)
return true;
if (!stack[i]->IsInline())
break;
}
return false;
}
} // namespace zxdb