[Lldb-commits] [lldb] f255ebf - [lldb] Read Wasm globals through a frame of the stub's own thread (#237195)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Nov 2 02:48:20 PST 2026
Author: Felipe de Azevedo Piovezan
Date: 2026-11-02T10:48:15Z
New Revision: f255ebf7065421c90112640aee4bc669a8b2001e
URL: https://github.com/llvm/llvm-project/commit/f255ebf7065421c90112640aee4bc669a8b2001e
DIFF: https://github.com/llvm/llvm-project/commit/f255ebf7065421c90112640aee4bc669a8b2001e.diff
LOG: [lldb] Read Wasm globals through a frame of the stub's own thread (#237195)
This commit fixes an unconditional cast from Thread to ThreadWasm, which
ignores the possibility of an OS plugin, by using the real thread list.
Note that using the qWasmGlobal variant that expects a frame index is
unlikely to succeed in the presence of a custom unwinder that presents a
different view of frames. But at the very least we shouldn't crash by
doing an invalid cast, which this fixes.
Added:
lldb/test/API/functionalities/gdb_remote_client/wasm_operating_system.py
Modified:
lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
lldb/test/API/functionalities/gdb_remote_client/TestWasm.py
Removed:
################################################################################
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
index 87c3a32f0cd5d3..be2a5266636ff8 100644
--- a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
@@ -11,7 +11,6 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Value.h"
-#include "lldb/Target/StackFrame.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "llvm/Support/ErrorExtras.h"
#include <cstring>
@@ -132,16 +131,17 @@ ProcessWasm::GetFallbackFrameIndex(uint32_t module_id) {
return llvm::createStringError(
"the global belongs to no known module instance");
- ThreadSP thread = GetThreadList().GetSelectedThread();
- StackFrameSP frame =
- thread ? thread->GetSelectedFrame(DoNoSelectMostRelevantFrame) : nullptr;
- if (frame) {
- // A frame can only stand in for the module the stub reports it executing.
- const uint32_t frame_index = frame->GetConcreteFrameIndex();
+ // Use the real thread list in case an OS plugin is providing threads.
+ if (ThreadSP thread = m_thread_list_real.GetSelectedThread()) {
ThreadWasm &wasm_thread = static_cast<ThreadWasm &>(*thread);
- if (GetWasmModuleID(wasm_thread.GetConcreteFramePC(frame_index)) ==
- module_id)
- return frame_index;
+ // A frame can only stand in for the module the stub reports it executing.
+ for (uint32_t frame_index = 0;; ++frame_index) {
+ lldb::addr_t pc = wasm_thread.GetConcreteFramePC(frame_index);
+ if (pc == LLDB_INVALID_ADDRESS)
+ break;
+ if (GetWasmModuleID(pc) == module_id)
+ return frame_index;
+ }
}
return llvm::createStringErrorV(
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py b/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py
index fb02c4eecbdbb2..6f0101014b87b5 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py
@@ -1050,6 +1050,31 @@ def test_read_global_legacy_server_other_instance(self):
self.assertPacketLogReceived(["qWasmGlobal:0;0"])
+ @skipIfAsan
+ @skipIfXmlSupportMissing
+ def test_read_global_legacy_server_os_plugin_thread(self):
+ """Test that an OS plugin thread doesn't get in the way of computing the right frame."""
+
+ call_stacks = [WasmCallStack([WasmStackFrame(0x019C)])]
+ process, globals_addr = self.connect_to_globals(
+ call_stacks, supports_instance=False
+ )
+
+ os_plugin_path = os.path.join(self.getSourceDir(), "wasm_operating_system.py")
+ self.runCmd(
+ "settings set target.process.python-os-plugin-path '%s'" % os_plugin_path
+ )
+ # The thread wasm_operating_system.py reports.
+ thread = process.GetThreadByID(0x2)
+ self.assertTrue(thread.IsValid())
+ self.assertTrue(process.SetSelectedThread(thread))
+
+ error = lldb.SBError()
+ data = process.ReadMemory(globals_addr + 0, 4, error)
+ self.assertSuccess(error)
+ self.assertEqual(int.from_bytes(data, "little"), WASM_GLOBALS[0][1])
+ self.assertPacketLogReceived(["qWasmGlobal:0;0"])
+
def reload_modules(self, modules, reloaded_modules):
"""
Connect to a fake stub holding the given modules, continue it until it
diff --git a/lldb/test/API/functionalities/gdb_remote_client/wasm_operating_system.py b/lldb/test/API/functionalities/gdb_remote_client/wasm_operating_system.py
new file mode 100644
index 00000000000000..59bcd45b00e10d
--- /dev/null
+++ b/lldb/test/API/functionalities/gdb_remote_client/wasm_operating_system.py
@@ -0,0 +1,40 @@
+import lldb
+import struct
+
+# The thread this plug-in reports. No thread of the stub backs it.
+OS_THREAD_ID = 0x2
+
+
+class OperatingSystemPlugIn(object):
+ def __init__(self, process):
+ self.process = process
+
+ def get_thread_info(self):
+ return [
+ {
+ "tid": OS_THREAD_ID,
+ "name": "os",
+ "state": "stopped",
+ "stop_reason": "none",
+ }
+ ]
+
+ def get_register_info(self):
+ return {
+ "sets": ["GPR"],
+ "registers": [
+ {
+ "name": "pc",
+ "bitsize": 64,
+ "offset": 0,
+ "encoding": "uint",
+ "format": "hex",
+ "set": 0,
+ "generic": "pc",
+ }
+ ],
+ }
+
+ def get_register_data(self, tid):
+ # A PC outside every module, so the thread executes no instance.
+ return struct.pack("Q", 0)
More information about the lldb-commits
mailing list