When implementing the WebAssembly Process Plugin, I initially added WasmGDBRemoteRegisterContext as a placeholder in the UnwindWasm TU. After implementing RegisterContextWasm (#151056), I forgot to switch over to the new implementation. This meant we were using the wrong register context for all frames, except frame 0. The register context deals with the virtual registers, so this only becomes an issue when trying to evaluate a `DW_OP_WASM_location`, which is why this went unnoticed. This PR removes the WasmGDBRemoteRegisterContext placeholder and updates UnwindWasm to use RegisterContextWasm instead for all frames. In terms of testing, I considered updating TestWasm but that would require adding even more state to the already complicated GDB stub. This doesn't scale and my focus over the next weeks/months will be coming up with a comprehensive testing strategy that involves running (a subset of the) API tests under a Wasm runtime, which will cover this and much more. rdar://159297244
72 lines
2.3 KiB
C++
72 lines
2.3 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "UnwindWasm.h"
|
|
#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h"
|
|
#include "ProcessWasm.h"
|
|
#include "RegisterContextWasm.h"
|
|
#include "ThreadWasm.h"
|
|
#include "lldb/Utility/LLDBLog.h"
|
|
#include "lldb/Utility/Log.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace process_gdb_remote;
|
|
using namespace wasm;
|
|
|
|
lldb::RegisterContextSP
|
|
UnwindWasm::DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) {
|
|
if (m_frames.size() <= frame->GetFrameIndex())
|
|
return lldb::RegisterContextSP();
|
|
|
|
ThreadSP thread = frame->GetThread();
|
|
ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread.get());
|
|
ProcessWasm *wasm_process =
|
|
static_cast<ProcessWasm *>(thread->GetProcess().get());
|
|
|
|
return std::make_shared<RegisterContextWasm>(*gdb_thread,
|
|
frame->GetConcreteFrameIndex(),
|
|
wasm_process->GetRegisterInfo());
|
|
}
|
|
|
|
uint32_t UnwindWasm::DoGetFrameCount() {
|
|
if (m_unwind_complete)
|
|
return m_frames.size();
|
|
|
|
m_unwind_complete = true;
|
|
m_frames.clear();
|
|
|
|
ThreadWasm &wasm_thread = static_cast<ThreadWasm &>(GetThread());
|
|
llvm::Expected<std::vector<lldb::addr_t>> call_stack_pcs =
|
|
wasm_thread.GetWasmCallStack();
|
|
if (!call_stack_pcs) {
|
|
LLDB_LOG_ERROR(GetLog(LLDBLog::Unwind), call_stack_pcs.takeError(),
|
|
"Failed to get Wasm callstack: {0}");
|
|
m_frames.clear();
|
|
return 0;
|
|
}
|
|
|
|
m_frames = *call_stack_pcs;
|
|
return m_frames.size();
|
|
}
|
|
|
|
bool UnwindWasm::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
|
|
lldb::addr_t &pc,
|
|
bool &behaves_like_zeroth_frame) {
|
|
if (m_frames.size() == 0)
|
|
DoGetFrameCount();
|
|
|
|
if (frame_idx >= m_frames.size())
|
|
return false;
|
|
|
|
behaves_like_zeroth_frame = (frame_idx == 0);
|
|
cfa = 0;
|
|
pc = m_frames[frame_idx];
|
|
return true;
|
|
}
|