[Go to site: main page, start]

LLDB mainline
ProcessWasm.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ProcessWasm.h"
10#include "ThreadWasm.h"
11#include "lldb/Core/Module.h"
13#include "lldb/Core/Value.h"
16#include <cstring>
17
19
20using namespace lldb;
21using namespace lldb_private;
23using namespace lldb_private::wasm;
24
26
28 : ProcessGDBRemote(target_sp, listener_sp) {
29 assert(target_sp);
30 // Wasm doesn't have any Unix-like signals as a platform concept, but pretend
31 // like it does to appease LLDB.
32 m_unix_signals_sp = UnixSignals::Create(target_sp->GetArchitecture());
33 // FIXME: LLVM's RuntimeDyld doesn't support the Wasm object format, so we
34 // can't JIT expressions for this target.
35 SetCanJIT(false);
36}
37
43
47
48llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); }
49
50llvm::StringRef ProcessWasm::GetPluginNameStatic() { return "wasm"; }
51
53 return "GDB Remote protocol based WebAssembly debugging plug-in.";
54}
55
59
61 ListenerSP listener_sp,
62 const FileSpec *crash_file_path,
63 bool can_connect) {
64 if (crash_file_path == nullptr)
65 return std::make_shared<ProcessWasm>(target_sp, listener_sp);
66 return {};
67}
68
70 bool plugin_specified_by_name) {
71 if (plugin_specified_by_name)
72 return true;
73
74 if (Module *exe_module = target_sp->GetExecutableModulePointer()) {
75 if (ObjectFile *exe_objfile = exe_module->GetObjectFile())
76 return exe_objfile->GetArchitecture().GetTriple().isWasm();
77 }
78
79 // However, if there is no wasm module, we return false, otherwise,
80 // we might use ProcessWasm to attach gdb remote.
81 return false;
82}
83
84std::shared_ptr<ThreadGDBRemote> ProcessWasm::CreateThread(lldb::tid_t tid) {
85 if (!GetTarget().GetArchitecture().GetTriple().isWasm())
87
88 return std::make_shared<ThreadWasm>(*this, tid);
89}
90
91size_t ProcessWasm::ReadGlobal(uint32_t module_id, uint32_t index, void *buf,
92 size_t size, Status &error) {
93 // FIXME: The module id is what should select the instance holding the global,
94 // but the qWasmGlobal packet takes a frame index instead, so the selected
95 // frame has to stand in for the instance. That leaves a global in an instance
96 // with no active frame out of reach. See
97 // https://github.com/llvm/llvm-project/issues/212833.
99 StackFrameSP frame =
100 thread ? thread->GetSelectedFrame(DoNoSelectMostRelevantFrame) : nullptr;
101 if (!frame) {
103 "Wasm global read failed: no frame to read global {0} of module {1:x} "
104 "from",
105 index, module_id);
106 return 0;
107 }
108
109 llvm::Expected<lldb::DataBufferSP> buffer =
110 GetWasmVariable(eWasmTagGlobal, frame->GetConcreteFrameIndex(), index);
111 if (!buffer) {
112 error = Status::FromError(buffer.takeError());
113 return 0;
114 }
115
116 // A global comes back whole. Reading more than it holds would have to come
117 // from somewhere else, and the next index is not adjacent storage.
118 const size_t global_size = (*buffer)->GetByteSize();
119 if (size > global_size) {
121 "Wasm global read failed: requested {0} bytes from a {1}-byte global",
122 size, global_size);
123 return 0;
124 }
125
126 std::memcpy(buf, (*buffer)->GetBytes(), size);
127 return size;
128}
129
130size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
131 Status &error) {
132 wasm_addr_t wasm_addr(vm_addr);
133
134 switch (wasm_addr.GetType()) {
137 return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
139 return ReadGlobal(wasm_addr.GetModuleID(), wasm_addr.GetOffset(), buf, size,
140 error);
142 break;
143 }
144
146 "Wasm read failed for invalid address {0:x} (type = {1:x}, module = "
147 "{2:x}, offset = {3:x})",
148 vm_addr, wasm_addr.GetType(), wasm_addr.GetModuleID(),
149 wasm_addr.GetOffset());
150 return 0;
151}
152
153llvm::Expected<std::vector<lldb::addr_t>>
155 StreamString packet;
156 packet.Printf("qWasmCallStack:");
157 packet.Printf("%" PRIx64, tid);
158
160 if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
162 return llvm::createStringError("failed to send qWasmCallStack");
163
164 if (!response.IsNormalResponse())
165 return llvm::createStringError("failed to get response for qWasmCallStack");
166
167 WritableDataBufferSP data_buffer_sp =
168 std::make_shared<DataBufferHeap>(response.GetStringRef().size() / 2, 0);
169 const size_t bytes = response.GetHexBytes(data_buffer_sp->GetData(), '\xcc');
170 if (bytes == 0 || bytes % sizeof(uint64_t) != 0)
171 return llvm::createStringError("invalid response for qWasmCallStack");
172
173 // To match the Wasm specification, the addresses are encoded in little endian
174 // byte order.
175 DataExtractor data(data_buffer_sp, lldb::eByteOrderLittle,
177 lldb::offset_t offset = 0;
178 std::vector<lldb::addr_t> call_stack_pcs;
179 while (offset < bytes)
180 call_stack_pcs.push_back(data.GetU64(&offset));
181
182 return call_stack_pcs;
183}
184
185llvm::Expected<lldb::DataBufferSP>
187 int index) {
188 StreamString packet;
189 switch (kind) {
190 case eWasmTagLocal:
191 packet.Printf("qWasmLocal:");
192 break;
193 case eWasmTagGlobal:
194 packet.Printf("qWasmGlobal:");
195 break;
197 packet.PutCString("qWasmStackValue:");
198 break;
200 return llvm::createStringError("not a Wasm location");
201 }
202 packet.Printf("%d;%d", frame_index, index);
203
205 if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
207 return llvm::createStringError("failed to send Wasm variable");
208
209 if (!response.IsNormalResponse())
210 return llvm::createStringError("failed to get response for Wasm variable");
211
212 WritableDataBufferSP buffer_sp(
213 new DataBufferHeap(response.GetStringRef().size() / 2, 0));
214 response.GetHexBytes(buffer_sp->GetData(), '\xcc');
215 return buffer_sp;
216}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_PLUGIN_DEFINE(PluginName)
size_t GetHexBytes(llvm::MutableArrayRef< uint8_t > dest, uint8_t fail_fill_value)
llvm::StringRef GetStringRef() const
A subclass of DataBuffer that stores a data buffer on the heap.
An data extractor class.
uint64_t GetU64(lldb::offset_t *offset_ptr) const
Extract a uint64_t value from *offset_ptr.
A file utility class.
Definition FileSpec.h:56
A class that describes an executable image and its associated object and symbol files.
Definition Module.h:91
A plug-in interface definition class for object file parsers.
Definition ObjectFile.h:46
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
ThreadList & GetThreadList()
Definition Process.h:2394
void SetCanJIT(bool can_jit)
Sets whether executing JIT-compiled code in this process is possible.
Definition Process.cpp:2755
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
Definition Process.cpp:2038
lldb::UnixSignalsSP m_unix_signals_sp
Definition Process.h:3545
uint32_t GetAddressByteSize() const
Definition Process.cpp:3930
friend class Debugger
Definition Process.h:361
Target & GetTarget()
Get the target object pointer for this module.
Definition Process.h:1258
An error handling class.
Definition Status.h:118
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
lldb::ThreadSP GetSelectedThread()
static lldb::UnixSignalsSP Create(const ArchSpec &arch)
virtual std::shared_ptr< ThreadGDBRemote > CreateThread(lldb::tid_t tid)
ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
ProcessWasm provides the access to the Wasm program state retrieved from the Wasm engine.
Definition ProcessWasm.h:21
size_t ReadGlobal(uint32_t module_id, uint32_t index, void *buf, size_t size, Status &error)
Read a WebAssembly global by its index in the global index space of the module it belongs to.
llvm::StringRef GetPluginName() override
std::shared_ptr< process_gdb_remote::ThreadGDBRemote > CreateThread(lldb::tid_t tid) override
static llvm::StringRef GetPluginNameStatic()
bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override
Check if a plug-in instance can debug the file in module.
static void DebuggerInitialize(Debugger &debugger)
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec *crash_file_path, bool can_connect)
llvm::Expected< std::vector< lldb::addr_t > > GetWasmCallStack(lldb::tid_t tid)
Retrieve the current call stack from the WebAssembly remote process.
ProcessWasm(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
llvm::Expected< lldb::DataBufferSP > GetWasmVariable(WasmVirtualRegisterKinds kind, int frame_index, int index)
Query the value of a WebAssembly variable from the WebAssembly remote process.
static llvm::StringRef GetPluginDescriptionStatic()
size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error) override
Read of memory from a process.
@ DoNoSelectMostRelevantFrame
A class that represents a running process on the host machine.
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::Thread > ThreadSP
uint64_t offset_t
Definition lldb-types.h:86
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::Listener > ListenerSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP
uint64_t tid_t
Definition lldb-types.h:85
For the purpose of debugging, we can represent all these separated 32-bit address spaces with a singl...
Definition WasmAddress.h:62
WasmAddressType GetType() const
Definition WasmAddress.h:75