aboutsummaryrefslogtreecommitdiff
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/CMakeLists.txt2
-rw-r--r--lldb/source/Commands/CommandObjectDWIMPrint.cpp47
-rw-r--r--lldb/source/Expression/DWARFExpression.cpp10
-rw-r--r--lldb/source/Expression/Materializer.cpp21
-rw-r--r--lldb/source/Host/common/Host.cpp9
-rw-r--r--lldb/source/Host/windows/Host.cpp63
-rw-r--r--lldb/source/Interpreter/ScriptInterpreter.cpp2
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp2
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp2
-rw-r--r--lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp6
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp6
-rw-r--r--lldb/source/Plugins/Process/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/Utility/AuxVector.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/AuxVector.h4
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp9
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h2
-rw-r--r--lldb/source/Plugins/Process/wasm/CMakeLists.txt11
-rw-r--r--lldb/source/Plugins/Process/wasm/ProcessWasm.cpp166
-rw-r--r--lldb/source/Plugins/Process/wasm/ProcessWasm.h99
-rw-r--r--lldb/source/Plugins/Process/wasm/RegisterContextWasm.cpp109
-rw-r--r--lldb/source/Plugins/Process/wasm/RegisterContextWasm.h69
-rw-r--r--lldb/source/Plugins/Process/wasm/ThreadWasm.cpp51
-rw-r--r--lldb/source/Plugins/Process/wasm/ThreadWasm.h41
-rw-r--r--lldb/source/Plugins/Process/wasm/UnwindWasm.cpp85
-rw-r--r--lldb/source/Plugins/Process/wasm/UnwindWasm.h51
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp28
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h8
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h3
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp8
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h3
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp100
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h34
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp6
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp5
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp5
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp24
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h4
-rw-r--r--lldb/source/Target/Platform.cpp7
-rw-r--r--lldb/source/Utility/WasmVirtualRegisters.h53
43 files changed, 1083 insertions, 86 deletions
diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt
index 0687c84..fdd6b3b 100644
--- a/lldb/source/API/CMakeLists.txt
+++ b/lldb/source/API/CMakeLists.txt
@@ -327,6 +327,7 @@ foreach(header
endif()
add_custom_target(liblldb-stage-header-${basename} DEPENDS ${staged_header})
+ add_dependencies(liblldb-stage-header-${basename} lldb-sbapi-dwarf-enums)
add_dependencies(liblldb-header-staging liblldb-stage-header-${basename})
add_custom_command(
DEPENDS ${header} OUTPUT ${staged_header}
@@ -339,6 +340,7 @@ foreach(header
set(output_header $<TARGET_FILE_DIR:liblldb>/Headers/${basename})
add_custom_target(lldb-framework-fixup-header-${basename} DEPENDS ${staged_header})
+ add_dependencies(lldb-framework-fixup-header-${basename} liblldb-stage-header-${basename})
add_dependencies(lldb-framework-fixup-all-headers lldb-framework-fixup-header-${basename})
add_custom_command(TARGET lldb-framework-fixup-header-${basename} POST_BUILD
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index a2c004d..d7589cc 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -18,11 +18,14 @@
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
#include "lldb/ValueObject/ValueObject.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include <regex>
@@ -132,27 +135,22 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
};
// Dump `valobj` according to whether `po` was requested or not.
- auto dump_val_object = [&](ValueObject &valobj) {
+ auto dump_val_object = [&](ValueObject &valobj) -> Error {
if (is_po) {
StreamString temp_result_stream;
- if (llvm::Error error = valobj.Dump(temp_result_stream, dump_options)) {
- result.AppendError(toString(std::move(error)));
- return;
- }
+ if (Error err = valobj.Dump(temp_result_stream, dump_options))
+ return err;
llvm::StringRef output = temp_result_stream.GetString();
maybe_add_hint(output);
result.GetOutputStream() << output;
} else {
- llvm::Error error =
- valobj.Dump(result.GetOutputStream(), dump_options);
- if (error) {
- result.AppendError(toString(std::move(error)));
- return;
- }
+ if (Error err = valobj.Dump(result.GetOutputStream(), dump_options))
+ return err;
}
m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(),
m_cmd_name);
result.SetStatus(eReturnStatusSuccessFinishResult);
+ return Error::success();
};
// First, try `expr` as a _limited_ frame variable expression path: only the
@@ -186,8 +184,13 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
expr);
}
- dump_val_object(*valobj_sp);
- return;
+ Error err = dump_val_object(*valobj_sp);
+ if (!err)
+ return;
+
+ // Dump failed, continue on to expression evaluation.
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), std::move(err),
+ "could not print frame variable '{1}': {0}", expr);
}
}
@@ -196,8 +199,14 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
if (auto *state = target.GetPersistentExpressionStateForLanguage(language))
if (auto var_sp = state->GetVariable(expr))
if (auto valobj_sp = var_sp->GetValueObject()) {
- dump_val_object(*valobj_sp);
- return;
+ Error err = dump_val_object(*valobj_sp);
+ if (!err)
+ return;
+
+ // Dump failed, continue on to expression evaluation.
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), std::move(err),
+ "could not print persistent variable '{1}': {0}",
+ expr);
}
// Third, and lastly, try `expr` as a source expression to evaluate.
@@ -248,10 +257,12 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
result.AppendNoteWithFormatv("ran `expression {0}{1}`", flags, expr);
}
- if (valobj_sp->GetError().GetError() != UserExpression::kNoResult)
- dump_val_object(*valobj_sp);
- else
+ if (valobj_sp->GetError().GetError() != UserExpression::kNoResult) {
+ if (Error err = dump_val_object(*valobj_sp))
+ result.SetError(std::move(err));
+ } else {
result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
if (suppress_result)
if (auto result_var_sp =
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 79bc6c8..391e277 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -91,9 +91,10 @@ void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) {
m_reg_kind = reg_kind;
}
-static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
- lldb::RegisterKind reg_kind,
- uint32_t reg_num, Value &value) {
+llvm::Error
+DWARFExpression::ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
+ lldb::RegisterKind reg_kind,
+ uint32_t reg_num, Value &value) {
if (reg_ctx == nullptr)
return llvm::createStringError("no register context in frame");
@@ -2302,7 +2303,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
default:
if (dwarf_cu) {
- if (dwarf_cu->ParseVendorDWARFOpcode(op, opcodes, offset, stack)) {
+ if (dwarf_cu->ParseVendorDWARFOpcode(op, opcodes, offset, reg_ctx,
+ reg_kind, stack)) {
break;
}
}
diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp
index 17ea159..329768d 100644
--- a/lldb/source/Expression/Materializer.cpp
+++ b/lldb/source/Expression/Materializer.cpp
@@ -102,22 +102,23 @@ public:
m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
map.GetAddressByteSize());
- if (m_persistent_variable_sp->m_flags &
- ExpressionVariable::EVKeepInTarget) {
- if (used_policy == IRMemoryMap::eAllocationPolicyMirror) {
+ if (used_policy == IRMemoryMap::eAllocationPolicyMirror) {
+ if (m_persistent_variable_sp->m_flags &
+ ExpressionVariable::EVKeepInTarget) {
// Clear the flag if the variable will never be deallocated.
Status leak_error;
map.Leak(mem, leak_error);
m_persistent_variable_sp->m_flags &=
~ExpressionVariable::EVNeedsAllocation;
- } else {
- // If the variable cannot be kept in target, clear this flag...
- m_persistent_variable_sp->m_flags &=
- ~ExpressionVariable::EVKeepInTarget;
- // ...and set the flag to copy the value during dematerialization.
- m_persistent_variable_sp->m_flags |=
- ExpressionVariable::EVNeedsFreezeDry;
}
+ } else {
+ // If we cannot allocate memory in the process,
+ // - clear the 'EVKeepInTarget' flag to ensure that 'm_live_sp' is reset
+ // during dematerialization,
+ m_persistent_variable_sp->m_flags &= ~ExpressionVariable::EVKeepInTarget;
+ // - set the 'EVNeedsFreezeDry' flag so that the value is copied to
+ // 'm_frozen_sp' during dematerialization.
+ m_persistent_variable_sp->m_flags |= ExpressionVariable::EVNeedsFreezeDry;
}
// Write the contents of the variable to the area.
diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp
index 5992b54..510f9c7 100644
--- a/lldb/source/Host/common/Host.cpp
+++ b/lldb/source/Host/common/Host.cpp
@@ -82,10 +82,11 @@ int __pthread_fchdir(int fildes);
using namespace lldb;
using namespace lldb_private;
-#if !defined(__APPLE__)
-// The system log is currently only meaningful on Darwin, where this means
-// os_log. The meaning of a "system log" isn't as clear on other platforms, and
-// therefore we don't providate a default implementation. Vendors are free to
+#if !defined(__APPLE__) && !defined(_WIN32)
+// The system log is currently only meaningful on Darwin and Windows.
+// On Darwin, this means os_log. On Windows this means Events Viewer.
+// The meaning of a "system log" isn't as clear on other platforms, and
+// therefore we don't providate a default implementation. Vendors are free
// to implement this function if they have a use for it.
void Host::SystemLog(Severity severity, llvm::StringRef message) {}
#endif
diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp
index a7369e7..4e747f7 100644
--- a/lldb/source/Host/windows/Host.cpp
+++ b/lldb/source/Host/windows/Host.cpp
@@ -22,7 +22,9 @@
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ManagedStatic.h"
// Windows includes
#include <tlhelp32.h>
@@ -302,3 +304,64 @@ Environment Host::GetEnvironment() {
}
return env;
}
+
+/// Manages the lifecycle of a Windows Event's Source.
+/// The destructor will call DeregisterEventSource.
+/// This class is meant to be used with \ref llvm::ManagedStatic.
+class WindowsEventLog {
+public:
+ WindowsEventLog() : handle(RegisterEventSource(nullptr, L"lldb")) {}
+
+ ~WindowsEventLog() {
+ if (handle)
+ DeregisterEventSource(handle);
+ }
+
+ HANDLE GetHandle() const { return handle; }
+
+private:
+ HANDLE handle;
+};
+
+static llvm::ManagedStatic<WindowsEventLog> event_log;
+
+static std::wstring AnsiToUtf16(const std::string &ansi) {
+ if (ansi.empty())
+ return {};
+
+ const int unicode_length =
+ MultiByteToWideChar(CP_ACP, 0, ansi.c_str(), -1, nullptr, 0);
+ if (unicode_length == 0)
+ return {};
+
+ std::wstring unicode(unicode_length, L'\0');
+ MultiByteToWideChar(CP_ACP, 0, ansi.c_str(), -1, &unicode[0], unicode_length);
+ return unicode;
+}
+
+void Host::SystemLog(Severity severity, llvm::StringRef message) {
+ HANDLE h = event_log->GetHandle();
+ if (!h)
+ return;
+
+ std::wstring wide_message = AnsiToUtf16(message.str());
+ if (wide_message.empty())
+ return;
+
+ LPCWSTR msg_ptr = wide_message.c_str();
+
+ WORD event_type;
+ switch (severity) {
+ case lldb::eSeverityWarning:
+ event_type = EVENTLOG_WARNING_TYPE;
+ break;
+ case lldb::eSeverityError:
+ event_type = EVENTLOG_ERROR_TYPE;
+ break;
+ case lldb::eSeverityInfo:
+ default:
+ event_type = EVENTLOG_INFORMATION_TYPE;
+ }
+
+ ReportEventW(h, event_type, 0, 0, nullptr, 1, 0, &msg_ptr, nullptr);
+}
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 5ee19ff..6a654a0 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -119,7 +119,7 @@ lldb::StreamSP ScriptInterpreter::GetOpaqueTypeFromSBStream(
SymbolContext ScriptInterpreter::GetOpaqueTypeFromSBSymbolContext(
const lldb::SBSymbolContext &sb_sym_ctx) const {
if (sb_sym_ctx.m_opaque_up)
- return *sb_sym_ctx.m_opaque_up.get();
+ return *sb_sym_ctx.m_opaque_up;
return {};
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 9f77fbc..214e260 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1991,7 +1991,7 @@ void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
const bool is_artificial = false;
CXXMethodDecl *method_decl = m_clang_ast_context->AddMethodToCXXRecordType(
- copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr,
+ copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", /*asm_label=*/{},
method_type, lldb::eAccessPublic, is_virtual, is_static, is_inline,
is_explicit, is_attr_used, is_artificial);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 3995bc0..e5a1d2d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -894,7 +894,7 @@ ClangExpressionParser::ClangExpressionParser(
m_llvm_context = std::make_unique<LLVMContext>();
m_code_generator.reset(CreateLLVMCodeGen(
m_compiler->getDiagnostics(), module_name,
- &m_compiler->getVirtualFileSystem(), m_compiler->getHeaderSearchOpts(),
+ m_compiler->getVirtualFileSystemPtr(), m_compiler->getHeaderSearchOpts(),
m_compiler->getPreprocessorOpts(), m_compiler->getCodeGenOpts(),
*m_llvm_context));
}
diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
index 2adde02..5e429a9 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -1807,7 +1807,7 @@ RISCVSingleStepBreakpointLocationsPredictor::GetBreakpointLocations(
Log *log = GetLog(LLDBLog::Unwind);
LLDB_LOGF(log,
"RISCVSingleStepBreakpointLocationsPredictor::%s: can't find "
- "corresponding load reserve insturuction",
+ "corresponding load reserve instruction",
__FUNCTION__);
return {*pc + (inst->is_rvc ? 2u : 4u)};
}
@@ -1839,7 +1839,7 @@ RISCVSingleStepBreakpointLocationsPredictor::HandleAtomicSequence(
EmulateInstructionRISCV *riscv_emulator =
static_cast<EmulateInstructionRISCV *>(m_emulator_up.get());
- // Handle instructions between LR and SC. According to unprivilleged
+ // Handle instructions between LR and SC. According to unprivileged
// RISC-V ISA there can be at most 16 instructions in the sequence.
lldb::addr_t entry_pc = pc; // LR instruction address
@@ -1872,7 +1872,7 @@ RISCVSingleStepBreakpointLocationsPredictor::HandleAtomicSequence(
Log *log = GetLog(LLDBLog::Unwind);
LLDB_LOGF(log,
"RISCVSingleStepBreakpointLocationsPredictor::%s: can't find "
- "corresponding store conditional insturuction",
+ "corresponding store conditional instruction",
__FUNCTION__);
return {entry_pc + (lr_inst->is_rvc ? 2u : 4u)};
}
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index 67963a7..b1efd25 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -376,9 +376,13 @@ DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
DataBufferSP buffer_sp(data_up.release());
data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
}
+ } else if (offset < m_data.GetByteSize()) {
+ size =
+ std::min(static_cast<uint64_t>(size), m_data.GetByteSize() - offset);
+ return DataExtractor(m_data.GetDataStart() + offset, size, GetByteOrder(),
+ GetAddressByteSize());
}
}
-
data.SetByteOrder(GetByteOrder());
return data;
}
diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt
index bd9b1b8..3413360 100644
--- a/lldb/source/Plugins/Process/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/CMakeLists.txt
@@ -29,3 +29,4 @@ add_subdirectory(elf-core)
add_subdirectory(mach-core)
add_subdirectory(minidump)
add_subdirectory(FreeBSDKernel)
+add_subdirectory(wasm)
diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.cpp b/lldb/source/Plugins/Process/Utility/AuxVector.cpp
index 50500a85..d660bfe 100644
--- a/lldb/source/Plugins/Process/Utility/AuxVector.cpp
+++ b/lldb/source/Plugins/Process/Utility/AuxVector.cpp
@@ -92,6 +92,8 @@ const char *AuxVector::GetEntryName(EntryType type) const {
case ENTRY_NAME(AUXV_AT_L1D_CACHESHAPE); break;
case ENTRY_NAME(AUXV_AT_L2_CACHESHAPE); break;
case ENTRY_NAME(AUXV_AT_L3_CACHESHAPE); break;
+ case ENTRY_NAME(AUXV_FREEBSD_AT_HWCAP3); break;
+ case ENTRY_NAME(AUXV_FREEBSD_AT_HWCAP4); break;
}
#undef ENTRY_NAME
diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h
index 7733e0f..ad6b70e 100644
--- a/lldb/source/Plugins/Process/Utility/AuxVector.h
+++ b/lldb/source/Plugins/Process/Utility/AuxVector.h
@@ -70,6 +70,10 @@ public:
// Platform specific values which may overlap the Linux values.
AUXV_FREEBSD_AT_HWCAP = 25, ///< FreeBSD specific AT_HWCAP value.
+ // FreeBSD and Linux use the same AT_HWCAP2 value.
+ AUXV_FREEBSD_AT_HWCAP3 = 38, ///< FreeBSD specific AT_HWCAP3 value.
+ AUXV_FREEBSD_AT_HWCAP4 = 39, ///< FreeBSD specific AT_HWCAP4 value.
+
};
std::optional<uint64_t> GetAuxValue(enum EntryType entry_type) const;
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 36e7409..f610422 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -323,6 +323,11 @@ ProcessGDBRemote::~ProcessGDBRemote() {
KillDebugserverProcess();
}
+std::shared_ptr<ThreadGDBRemote>
+ProcessGDBRemote::CreateThread(lldb::tid_t tid) {
+ return std::make_shared<ThreadGDBRemote>(*this, tid);
+}
+
bool ProcessGDBRemote::ParsePythonTargetDefinition(
const FileSpec &target_definition_fspec) {
ScriptInterpreter *interpreter =
@@ -1594,7 +1599,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list,
ThreadSP thread_sp(
old_thread_list_copy.RemoveThreadByProtocolID(tid, false));
if (!thread_sp) {
- thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid);
+ thread_sp = CreateThread(tid);
LLDB_LOGV(log, "Making new thread: {0} for thread ID: {1:x}.",
thread_sp.get(), thread_sp->GetID());
} else {
@@ -1726,7 +1731,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
if (!thread_sp) {
// Create the thread if we need to
- thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid);
+ thread_sp = CreateThread(tid);
m_thread_list_real.AddThread(thread_sp);
}
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 7ae3383..7c3dfb1 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -246,6 +246,8 @@ protected:
ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
+ virtual std::shared_ptr<ThreadGDBRemote> CreateThread(lldb::tid_t tid);
+
bool SupportsMemoryTagging() override;
/// Broadcaster event bits definitions.
diff --git a/lldb/source/Plugins/Process/wasm/CMakeLists.txt b/lldb/source/Plugins/Process/wasm/CMakeLists.txt
new file mode 100644
index 0000000..779b97e
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_lldb_library(lldbPluginProcessWasm PLUGIN
+ ProcessWasm.cpp
+ RegisterContextWasm.cpp
+ ThreadWasm.cpp
+ UnwindWasm.cpp
+
+ LINK_LIBS
+ lldbCore
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
new file mode 100644
index 0000000..580e8c1
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
@@ -0,0 +1,166 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "ProcessWasm.h"
+#include "ThreadWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Utility/DataBufferHeap.h"
+
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private::wasm;
+
+LLDB_PLUGIN_DEFINE(ProcessWasm)
+
+ProcessWasm::ProcessWasm(lldb::TargetSP target_sp, ListenerSP listener_sp)
+ : ProcessGDBRemote(target_sp, listener_sp) {
+ assert(target_sp);
+ // Wasm doesn't have any Unix-like signals as a platform concept, but pretend
+ // like it does to appease LLDB.
+ m_unix_signals_sp = UnixSignals::Create(target_sp->GetArchitecture());
+}
+
+void ProcessWasm::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+ });
+}
+
+void ProcessWasm::DebuggerInitialize(Debugger &debugger) {
+ ProcessGDBRemote::DebuggerInitialize(debugger);
+}
+
+llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); }
+
+llvm::StringRef ProcessWasm::GetPluginNameStatic() { return "wasm"; }
+
+llvm::StringRef ProcessWasm::GetPluginDescriptionStatic() {
+ return "GDB Remote protocol based WebAssembly debugging plug-in.";
+}
+
+void ProcessWasm::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessWasm::CreateInstance);
+}
+
+lldb::ProcessSP ProcessWasm::CreateInstance(lldb::TargetSP target_sp,
+ ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect) {
+ if (crash_file_path == nullptr)
+ return std::make_shared<ProcessWasm>(target_sp, listener_sp);
+ return {};
+}
+
+bool ProcessWasm::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ if (plugin_specified_by_name)
+ return true;
+
+ if (Module *exe_module = target_sp->GetExecutableModulePointer()) {
+ if (ObjectFile *exe_objfile = exe_module->GetObjectFile())
+ return exe_objfile->GetArchitecture().GetMachine() ==
+ llvm::Triple::wasm32;
+ }
+
+ // However, if there is no wasm module, we return false, otherwise,
+ // we might use ProcessWasm to attach gdb remote.
+ return false;
+}
+
+std::shared_ptr<ThreadGDBRemote> ProcessWasm::CreateThread(lldb::tid_t tid) {
+ return std::make_shared<ThreadWasm>(*this, tid);
+}
+
+size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Status &error) {
+ wasm_addr_t wasm_addr(vm_addr);
+
+ switch (wasm_addr.GetType()) {
+ case WasmAddressType::Memory:
+ case WasmAddressType::Object:
+ return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+ case WasmAddressType::Invalid:
+ error.FromErrorStringWithFormat(
+ "Wasm read failed for invalid address 0x%" PRIx64, vm_addr);
+ return 0;
+ }
+}
+
+llvm::Expected<std::vector<lldb::addr_t>>
+ProcessWasm::GetWasmCallStack(lldb::tid_t tid) {
+ StreamString packet;
+ packet.Printf("qWasmCallStack:");
+ packet.Printf("%" PRIx64, tid);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success)
+ return llvm::createStringError("failed to send qWasmCallStack");
+
+ if (!response.IsNormalResponse())
+ return llvm::createStringError("failed to get response for qWasmCallStack");
+
+ WritableDataBufferSP data_buffer_sp =
+ std::make_shared<DataBufferHeap>(response.GetStringRef().size() / 2, 0);
+ const size_t bytes = response.GetHexBytes(data_buffer_sp->GetData(), '\xcc');
+ if (bytes == 0 || bytes % sizeof(uint64_t) != 0)
+ return llvm::createStringError("invalid response for qWasmCallStack");
+
+ // To match the Wasm specification, the addresses are encoded in little endian
+ // byte order.
+ DataExtractor data(data_buffer_sp, lldb::eByteOrderLittle,
+ GetAddressByteSize());
+ lldb::offset_t offset = 0;
+ std::vector<lldb::addr_t> call_stack_pcs;
+ while (offset < bytes)
+ call_stack_pcs.push_back(data.GetU64(&offset));
+
+ return call_stack_pcs;
+}
+
+llvm::Expected<lldb::DataBufferSP>
+ProcessWasm::GetWasmVariable(WasmVirtualRegisterKinds kind, int frame_index,
+ int index) {
+ StreamString packet;
+ switch (kind) {
+ case eWasmTagLocal:
+ packet.Printf("qWasmLocal:");
+ break;
+ case eWasmTagGlobal:
+ packet.Printf("qWasmGlobal:");
+ break;
+ case eWasmTagOperandStack:
+ packet.PutCString("qWasmStackValue:");
+ break;
+ case eWasmTagNotAWasmLocation:
+ return llvm::createStringError("not a Wasm location");
+ }
+ packet.Printf("%d;%d", frame_index, index);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success)
+ return llvm::createStringError("failed to send Wasm variable");
+
+ if (!response.IsNormalResponse())
+ return llvm::createStringError("failed to get response for Wasm variable");
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ return buffer_sp;
+}
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
new file mode 100644
index 0000000..22effe7
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H
+
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "Utility/WasmVirtualRegisters.h"
+
+namespace lldb_private {
+namespace wasm {
+
+/// Each WebAssembly module has separated address spaces for Code and Memory.
+/// A WebAssembly module also has a Data section which, when the module is
+/// loaded, gets mapped into a region in the module Memory.
+enum WasmAddressType : uint8_t { Memory = 0x00, Object = 0x01, Invalid = 0xff };
+
+/// For the purpose of debugging, we can represent all these separated 32-bit
+/// address spaces with a single virtual 64-bit address space. The
+/// wasm_addr_t provides this encoding using bitfields.
+struct wasm_addr_t {
+ uint64_t offset : 32;
+ uint64_t module_id : 30;
+ uint64_t type : 2;
+
+ wasm_addr_t(lldb::addr_t addr)
+ : offset(addr & 0x00000000ffffffff),
+ module_id((addr & 0x00ffffff00000000) >> 32), type(addr >> 62) {}
+
+ wasm_addr_t(WasmAddressType type, uint32_t module_id, uint32_t offset)
+ : offset(offset), module_id(module_id), type(type) {}
+
+ WasmAddressType GetType() { return static_cast<WasmAddressType>(type); }
+
+ operator lldb::addr_t() { return *(uint64_t *)this; }
+};
+
+static_assert(sizeof(wasm_addr_t) == 8, "");
+
+/// ProcessWasm provides the access to the Wasm program state
+/// retrieved from the Wasm engine.
+class ProcessWasm : public process_gdb_remote::ProcessGDBRemote {
+public:
+ ProcessWasm(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
+ ~ProcessWasm() override = default;
+
+ static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect);
+
+ static void Initialize();
+ static void DebuggerInitialize(Debugger &debugger);
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic();
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ llvm::StringRef GetPluginName() override;
+
+ size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Status &error) override;
+
+ bool CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+ /// Retrieve the current call stack from the WebAssembly remote process.
+ llvm::Expected<std::vector<lldb::addr_t>> GetWasmCallStack(lldb::tid_t tid);
+
+ /// Query the value of a WebAssembly variable from the WebAssembly
+ /// remote process.
+ llvm::Expected<lldb::DataBufferSP>
+ GetWasmVariable(WasmVirtualRegisterKinds kind, int frame_index, int index);
+
+protected:
+ std::shared_ptr<process_gdb_remote::ThreadGDBRemote>
+ CreateThread(lldb::tid_t tid) override;
+
+private:
+ friend class UnwindWasm;
+ friend class ThreadWasm;
+
+ process_gdb_remote::GDBRemoteDynamicRegisterInfoSP &GetRegisterInfo() {
+ return m_register_info_sp;
+ }
+
+ ProcessWasm(const ProcessWasm &);
+ const ProcessWasm &operator=(const ProcessWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif
diff --git a/lldb/source/Plugins/Process/wasm/RegisterContextWasm.cpp b/lldb/source/Plugins/Process/wasm/RegisterContextWasm.cpp
new file mode 100644
index 0000000..b468171
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/RegisterContextWasm.cpp
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "RegisterContextWasm.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h"
+#include "ProcessWasm.h"
+#include "ThreadWasm.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private::wasm;
+
+RegisterContextWasm::RegisterContextWasm(
+ wasm::ThreadWasm &thread, uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfoSP reg_info_sp)
+ : GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false,
+ false) {}
+
+RegisterContextWasm::~RegisterContextWasm() = default;
+
+uint32_t RegisterContextWasm::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ return num;
+}
+
+size_t RegisterContextWasm::GetRegisterCount() {
+ // Wasm has no registers.
+ return 0;
+}
+
+const RegisterInfo *RegisterContextWasm::GetRegisterInfoAtIndex(size_t reg) {
+ uint32_t tag = GetWasmVirtualRegisterTag(reg);
+ if (tag == eWasmTagNotAWasmLocation)
+ return m_reg_info_sp->GetRegisterInfoAtIndex(
+ GetWasmVirtualRegisterIndex(reg));
+
+ auto it = m_register_map.find(reg);
+ if (it == m_register_map.end()) {
+ WasmVirtualRegisterKinds kind = static_cast<WasmVirtualRegisterKinds>(tag);
+ std::tie(it, std::ignore) = m_register_map.insert(
+ {reg, std::make_unique<WasmVirtualRegisterInfo>(
+ kind, GetWasmVirtualRegisterIndex(reg))});
+ }
+ return it->second.get();
+}
+
+size_t RegisterContextWasm::GetRegisterSetCount() { return 0; }
+
+const RegisterSet *RegisterContextWasm::GetRegisterSet(size_t reg_set) {
+ // Wasm has no registers.
+ return nullptr;
+}
+
+bool RegisterContextWasm::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ // The only real registers is the PC.
+ if (reg_info->name)
+ return GDBRemoteRegisterContext::ReadRegister(reg_info, value);
+
+ // Read the virtual registers.
+ ThreadWasm *thread = static_cast<ThreadWasm *>(&GetThread());
+ ProcessWasm *process = static_cast<ProcessWasm *>(thread->GetProcess().get());
+ if (!thread)
+ return false;
+
+ uint32_t frame_index = m_concrete_frame_idx;
+ WasmVirtualRegisterInfo *wasm_reg_info =
+ static_cast<WasmVirtualRegisterInfo *>(
+ const_cast<RegisterInfo *>(reg_info));
+
+ llvm::Expected<DataBufferSP> maybe_buffer = process->GetWasmVariable(
+ wasm_reg_info->kind, frame_index, wasm_reg_info->index);
+ if (!maybe_buffer) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Process), maybe_buffer.takeError(),
+ "Failed to read Wasm local: {0}");
+ return false;
+ }
+
+ DataBufferSP buffer_sp = *maybe_buffer;
+ DataExtractor reg_data(buffer_sp, process->GetByteOrder(),
+ process->GetAddressByteSize());
+ wasm_reg_info->byte_size = buffer_sp->GetByteSize();
+ wasm_reg_info->encoding = lldb::eEncodingUint;
+
+ Status error = value.SetValueFromData(
+ *reg_info, reg_data, reg_info->byte_offset, /*partial_data_ok=*/false);
+ return error.Success();
+}
+
+void RegisterContextWasm::InvalidateAllRegisters() {}
+
+bool RegisterContextWasm::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ // The only real registers is the PC.
+ if (reg_info->name)
+ return GDBRemoteRegisterContext::WriteRegister(reg_info, value);
+ return false;
+}
diff --git a/lldb/source/Plugins/Process/wasm/RegisterContextWasm.h b/lldb/source/Plugins/Process/wasm/RegisterContextWasm.h
new file mode 100644
index 0000000..7e63eb8
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/RegisterContextWasm.h
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_WASM_REGISTERCONTEXTWASM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_REGISTERCONTEXTWASM_H
+
+#include "Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h"
+#include "ThreadWasm.h"
+#include "Utility/WasmVirtualRegisters.h"
+#include "lldb/lldb-private-types.h"
+#include <unordered_map>
+
+namespace lldb_private {
+namespace wasm {
+
+class RegisterContextWasm;
+
+typedef std::shared_ptr<RegisterContextWasm> RegisterContextWasmSP;
+
+struct WasmVirtualRegisterInfo : public RegisterInfo {
+ WasmVirtualRegisterKinds kind;
+ uint32_t index;
+
+ WasmVirtualRegisterInfo(WasmVirtualRegisterKinds kind, uint32_t index)
+ : RegisterInfo(), kind(kind), index(index) {}
+};
+
+class RegisterContextWasm
+ : public process_gdb_remote::GDBRemoteRegisterContext {
+public:
+ RegisterContextWasm(
+ wasm::ThreadWasm &thread, uint32_t concrete_frame_idx,
+ process_gdb_remote::GDBRemoteDynamicRegisterInfoSP reg_info_sp);
+
+ ~RegisterContextWasm() override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const RegisterSet *GetRegisterSet(size_t reg_set) override;
+
+ bool ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) override;
+
+private:
+ std::unordered_map<size_t, std::unique_ptr<WasmVirtualRegisterInfo>>
+ m_register_map;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif
diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
new file mode 100644
index 0000000..0666b75
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "ThreadWasm.h"
+
+#include "ProcessWasm.h"
+#include "RegisterContextWasm.h"
+#include "UnwindWasm.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+Unwind &ThreadWasm::GetUnwinder() {
+ if (!m_unwinder_up) {
+ assert(CalculateTarget()->GetArchitecture().GetMachine() ==
+ llvm::Triple::wasm32);
+ m_unwinder_up.reset(new wasm::UnwindWasm(*this));
+ }
+ return *m_unwinder_up;
+}
+
+llvm::Expected<std::vector<lldb::addr_t>> ThreadWasm::GetWasmCallStack() {
+ if (ProcessSP process_sp = GetProcess()) {
+ ProcessWasm *wasm_process = static_cast<ProcessWasm *>(process_sp.get());
+ return wasm_process->GetWasmCallStack(GetID());
+ }
+ return llvm::createStringError("no process");
+}
+
+lldb::RegisterContextSP
+ThreadWasm::CreateRegisterContextForFrame(StackFrame *frame) {
+ uint32_t concrete_frame_idx = 0;
+ ProcessSP process_sp(GetProcess());
+ ProcessWasm *wasm_process = static_cast<ProcessWasm *>(process_sp.get());
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0)
+ return std::make_shared<RegisterContextWasm>(
+ *this, concrete_frame_idx, wasm_process->GetRegisterInfo());
+
+ return GetUnwinder().CreateRegisterContextForFrame(frame);
+}
diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.h b/lldb/source/Plugins/Process/wasm/ThreadWasm.h
new file mode 100644
index 0000000..c2f5762
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.h
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H
+
+#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h"
+
+namespace lldb_private {
+namespace wasm {
+
+/// ProcessWasm provides the access to the Wasm program state
+/// retrieved from the Wasm engine.
+class ThreadWasm : public process_gdb_remote::ThreadGDBRemote {
+public:
+ ThreadWasm(Process &process, lldb::tid_t tid)
+ : process_gdb_remote::ThreadGDBRemote(process, tid) {}
+ ~ThreadWasm() override = default;
+
+ /// Retrieve the current call stack from the WebAssembly remote process.
+ llvm::Expected<std::vector<lldb::addr_t>> GetWasmCallStack();
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(StackFrame *frame) override;
+
+protected:
+ Unwind &GetUnwinder() override;
+
+ ThreadWasm(const ThreadWasm &);
+ const ThreadWasm &operator=(const ThreadWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H
diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
new file mode 100644
index 0000000..99845dd
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "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;
+
+class WasmGDBRemoteRegisterContext : public GDBRemoteRegisterContext {
+public:
+ WasmGDBRemoteRegisterContext(ThreadGDBRemote &thread,
+ uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfoSP &reg_info_sp,
+ uint64_t pc)
+ : GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false,
+ false) {
+ // Wasm does not have a fixed set of registers but relies on a mechanism
+ // named local and global variables to store information such as the stack
+ // pointer. The only actual register is the PC.
+ PrivateSetRegisterValue(0, pc);
+ }
+};
+
+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<WasmGDBRemoteRegisterContext>(
+ *gdb_thread, frame->GetConcreteFrameIndex(),
+ wasm_process->GetRegisterInfo(), m_frames[frame->GetFrameIndex()]);
+}
+
+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;
+}
diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.h b/lldb/source/Plugins/Process/wasm/UnwindWasm.h
new file mode 100644
index 0000000..ff5e06d
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.h
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_WASM_UNWINDWASM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_UNWINDWASM_H
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Unwind.h"
+#include <vector>
+
+namespace lldb_private {
+namespace wasm {
+
+/// UnwindWasm manages stack unwinding for a WebAssembly process.
+class UnwindWasm : public lldb_private::Unwind {
+public:
+ UnwindWasm(lldb_private::Thread &thread) : Unwind(thread) {}
+ ~UnwindWasm() override = default;
+
+protected:
+ void DoClear() override {
+ m_frames.clear();
+ m_unwind_complete = false;
+ }
+
+ uint32_t DoGetFrameCount() override;
+
+ bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
+ lldb::addr_t &pc,
+ bool &behaves_like_zeroth_frame) override;
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+private:
+ std::vector<lldb::addr_t> m_frames;
+ bool m_unwind_complete = false;
+
+ UnwindWasm(const UnwindWasm &);
+ const UnwindWasm &operator=(const UnwindWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt
index 212cc36..c3f1bb5 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt
+++ b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt
@@ -35,6 +35,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN
SymbolFileDWARF.cpp
SymbolFileDWARFDwo.cpp
SymbolFileDWARFDebugMap.cpp
+ SymbolFileWasm.cpp
UniqueDWARFASTType.cpp
LINK_COMPONENTS
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index ba65f50..e58e28a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -249,6 +249,14 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
return cv_quals;
}
+static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
+ char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
+ if (!name)
+ return {};
+
+ return name;
+}
+
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
const DWARFDIE &die,
Log *log) {
@@ -1231,7 +1239,7 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
- attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
+ MakeLLDBFuncAsmLabel(die), clang_type, accessibility, attrs.is_virtual,
is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
attrs.is_artificial);
@@ -1384,7 +1392,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
ignore_containing_context ? m_ast.GetTranslationUnitDecl()
: containing_decl_ctx,
GetOwningClangModule(die), name, clang_type, attrs.storage,
- attrs.is_inline);
+ attrs.is_inline, MakeLLDBFuncAsmLabel(die));
std::free(name_buf);
if (has_template_params) {
@@ -1394,7 +1402,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
ignore_containing_context ? m_ast.GetTranslationUnitDecl()
: containing_decl_ctx,
GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type,
- attrs.storage, attrs.is_inline);
+ attrs.storage, attrs.is_inline, /*asm_label=*/{});
clang::FunctionTemplateDecl *func_template_decl =
m_ast.CreateFunctionTemplateDecl(
containing_decl_ctx, GetOwningClangModule(die),
@@ -1406,20 +1414,6 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
lldbassert(function_decl);
if (function_decl) {
- // Attach an asm(<mangled_name>) label to the FunctionDecl.
- // This ensures that clang::CodeGen emits function calls
- // using symbols that are mangled according to the DW_AT_linkage_name.
- // If we didn't do this, the external symbols wouldn't exactly
- // match the mangled name LLDB knows about and the IRExecutionUnit
- // would have to fall back to searching object files for
- // approximately matching function names. The motivating
- // example is generating calls to ABI-tagged template functions.
- // This is done separately for member functions in
- // AddMethodToCXXRecordType.
- if (attrs.mangled_name)
- function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
- m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false));
-
LinkDeclContextToDIE(function_decl, die);
const clang::FunctionProtoType *function_prototype(
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index a66af5b..94fc2e83 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -736,9 +736,11 @@ DWARFUnit::GetVendorDWARFOpcodeSize(const DataExtractor &data,
bool DWARFUnit::ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
lldb::offset_t &offset,
+ RegisterContext *reg_ctx,
+ lldb::RegisterKind reg_kind,
std::vector<Value> &stack) const {
return GetSymbolFileDWARF().ParseVendorDWARFOpcode(op, opcodes, offset,
- stack);
+ reg_ctx, reg_kind, stack);
}
bool DWARFUnit::ParseDWARFLocationList(
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index f55400e..91a6938 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -164,9 +164,11 @@ public:
const lldb::offset_t data_offset,
const uint8_t op) const override;
- bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
- lldb::offset_t &offset,
- std::vector<Value> &stack) const override;
+ virtual bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
+ lldb::offset_t &offset,
+ RegisterContext *reg_ctx,
+ lldb::RegisterKind reg_kind,
+ std::vector<Value> &stack) const override;
bool ParseDWARFLocationList(const DataExtractor &data,
DWARFExpressionList &loc_list) const;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 4b4a582..41ab8d1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -41,6 +41,7 @@
#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileWasm.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/CompileUnit.h"
@@ -327,6 +328,9 @@ llvm::StringRef SymbolFileDWARF::GetPluginDescriptionStatic() {
}
SymbolFile *SymbolFileDWARF::CreateInstance(ObjectFileSP objfile_sp) {
+ if (objfile_sp->GetArchitecture().GetTriple().isWasm())
+ return new SymbolFileWasm(std::move(objfile_sp),
+ /*dwo_section_list*/ nullptr);
return new SymbolFileDWARF(std::move(objfile_sp),
/*dwo_section_list*/ nullptr);
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 2dc862c..56d8ccb 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -329,6 +329,8 @@ public:
virtual bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
lldb::offset_t &offset,
+ RegisterContext *reg_ctx,
+ lldb::RegisterKind reg_kind,
std::vector<Value> &stack) const {
return false;
}
@@ -556,6 +558,7 @@ protected:
/// an index that identifies the .DWO or .o file.
std::optional<uint64_t> m_file_index;
};
+
} // namespace dwarf
} // namespace lldb_private::plugin
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
index c1829ab..52de3ab 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
@@ -97,9 +97,11 @@ uint64_t SymbolFileDWARFDwo::GetDebugInfoSize(bool load_all_debug_info) {
}
bool SymbolFileDWARFDwo::ParseVendorDWARFOpcode(
- uint8_t op, const lldb_private::DataExtractor &opcodes,
- lldb::offset_t &offset, std::vector<lldb_private::Value> &stack) const {
- return GetBaseSymbolFile().ParseVendorDWARFOpcode(op, opcodes, offset, stack);
+ uint8_t op, const DataExtractor &opcodes, lldb::offset_t &offset,
+ RegisterContext *reg_ctx, lldb::RegisterKind reg_kind,
+ std::vector<Value> &stack) const {
+ return GetBaseSymbolFile().ParseVendorDWARFOpcode(op, opcodes, offset,
+ reg_ctx, reg_kind, stack);
}
llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> &
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
index 75f5986..1ab6494 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
@@ -50,7 +50,8 @@ public:
uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
- lldb::offset_t &offset,
+ lldb::offset_t &offset, RegisterContext *reg_ctx,
+ lldb::RegisterKind reg_kind,
std::vector<Value> &stack) const override;
void FindGlobalVariables(ConstString name,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp
new file mode 100644
index 0000000..e25a89c
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "SymbolFileWasm.h"
+#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
+#include "Utility/WasmVirtualRegisters.h"
+#include "lldb/Utility/LLDBLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::plugin::dwarf;
+
+SymbolFileWasm::SymbolFileWasm(ObjectFileSP objfile_sp,
+ SectionList *dwo_section_list)
+ : SymbolFileDWARF(objfile_sp, dwo_section_list) {}
+
+SymbolFileWasm::~SymbolFileWasm() = default;
+
+lldb::offset_t
+SymbolFileWasm::GetVendorDWARFOpcodeSize(const DataExtractor &data,
+ const lldb::offset_t data_offset,
+ const uint8_t op) const {
+ if (op != llvm::dwarf::DW_OP_WASM_location)
+ return LLDB_INVALID_OFFSET;
+
+ lldb::offset_t offset = data_offset;
+ const uint8_t wasm_op = data.GetU8(&offset);
+ switch (wasm_op) {
+ case 0: // LOCAL
+ case 1: // GLOBAL_FIXED
+ case 2: // OPERAND_STACK
+ data.GetULEB128(&offset);
+ break;
+ case 3: // GLOBAL_RELOC
+ data.GetU32(&offset);
+ break;
+ default:
+ return LLDB_INVALID_OFFSET;
+ }
+
+ return offset - data_offset;
+}
+
+bool SymbolFileWasm::ParseVendorDWARFOpcode(uint8_t op,
+ const DataExtractor &opcodes,
+ lldb::offset_t &offset,
+ RegisterContext *reg_ctx,
+ lldb::RegisterKind reg_kind,
+ std::vector<Value> &stack) const {
+ if (op != llvm::dwarf::DW_OP_WASM_location)
+ return false;
+
+ uint32_t index = 0;
+ uint8_t tag = eWasmTagNotAWasmLocation;
+
+ /// |DWARF Location Index | WebAssembly Construct |
+ /// |---------------------|-----------------------|
+ /// |0 | Local |
+ /// |1 or 3 | Global |
+ /// |2 | Operand Stack |
+ const uint8_t wasm_op = opcodes.GetU8(&offset);
+ switch (wasm_op) {
+ case 0: // LOCAL
+ index = opcodes.GetULEB128(&offset);
+ tag = eWasmTagLocal;
+ break;
+ case 1: // GLOBAL_FIXED
+ index = opcodes.GetULEB128(&offset);
+ tag = eWasmTagGlobal;
+ break;
+ case 2: // OPERAND_STACK
+ index = opcodes.GetULEB128(&offset);
+ tag = eWasmTagOperandStack;
+ break;
+ case 3: // GLOBAL_RELOC
+ index = opcodes.GetU32(&offset);
+ tag = eWasmTagGlobal;
+ break;
+ default:
+ return false;
+ }
+
+ const uint32_t reg_num = GetWasmRegister(tag, index);
+
+ Value tmp;
+ llvm::Error error = DWARFExpression::ReadRegisterValueAsScalar(
+ reg_ctx, reg_kind, reg_num, tmp);
+ if (error) {
+ LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), std::move(error), "{0}");
+ return false;
+ }
+
+ stack.push_back(tmp);
+ return true;
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h
new file mode 100644
index 0000000..0e0b742
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEWASM_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEWASM_H
+
+#include "SymbolFileDWARF.h"
+
+namespace lldb_private::plugin {
+namespace dwarf {
+class SymbolFileWasm : public SymbolFileDWARF {
+public:
+ SymbolFileWasm(lldb::ObjectFileSP objfile_sp, SectionList *dwo_section_list);
+
+ ~SymbolFileWasm() override;
+
+ lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data,
+ const lldb::offset_t data_offset,
+ const uint8_t op) const override;
+
+ bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
+ lldb::offset_t &offset, RegisterContext *reg_ctx,
+ lldb::RegisterKind reg_kind,
+ std::vector<Value> &stack) const override;
+};
+} // namespace dwarf
+} // namespace lldb_private::plugin
+
+#endif
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 702ec5e..8137622 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -88,7 +88,7 @@ struct CreateMethodDecl : public TypeVisitorCallbacks {
MethodOptions::CompilerGenerated;
function_decl = m_clang.AddMethodToCXXRecordType(
parent_ty, proc_name,
- /*mangled_name=*/nullptr, func_ct, /*access=*/access_type,
+ /*asm_label=*/{}, func_ct, /*access=*/access_type,
/*is_virtual=*/is_virtual, /*is_static=*/is_static,
/*is_inline=*/false, /*is_explicit=*/false,
/*is_attr_used=*/false, /*is_artificial=*/is_artificial);
@@ -903,7 +903,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
if (!function_decl) {
function_decl = m_clang.AddMethodToCXXRecordType(
parent_opaque_ty, func_name,
- /*mangled_name=*/nullptr, func_ct,
+ /*asm_label=*/{}, func_ct,
/*access=*/lldb::AccessType::eAccessPublic,
/*is_virtual=*/false, /*is_static=*/false,
/*is_inline=*/false, /*is_explicit=*/false,
@@ -913,7 +913,7 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
} else {
function_decl = m_clang.CreateFunctionDeclaration(
parent, OptionalClangModuleID(), func_name, func_ct, func_storage,
- is_inline);
+ is_inline, /*asm_label=*/{});
CreateFunctionParameters(func_id, *function_decl, param_count);
}
return function_decl;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
index 1f888f4..98b965c 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -65,7 +65,7 @@ struct CVTagRecord {
}
llvm::StringRef name() const {
- if (m_kind == Struct || m_kind == Union)
+ if (m_kind == Struct || m_kind == Class)
return cvclass.Name;
if (m_kind == Enum)
return cvenum.Name;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 807ee5b..1c575e9 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -111,9 +111,8 @@ void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx,
bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
MethodOptions::CompilerGenerated;
m_ast_builder.clang().AddMethodToCXXRecordType(
- derived_opaque_ty, name.data(), nullptr, method_ct,
- access_type, attrs.isVirtual(), attrs.isStatic(), false, false, false,
- is_artificial);
+ derived_opaque_ty, name.data(), /*asm_label=*/{}, method_ct, access_type,
+ attrs.isVirtual(), attrs.isStatic(), false, false, false, is_artificial);
m_cxx_record_map[derived_opaque_ty].insert({name, method_ct});
}
diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
index 0090d8f..8b8eac6e 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -954,7 +954,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
auto decl = m_ast.CreateFunctionDeclaration(
decl_context, OptionalClangModuleID(), name,
- type->GetForwardCompilerType(), storage, func->hasInlineAttribute());
+ type->GetForwardCompilerType(), storage, func->hasInlineAttribute(),
+ /*asm_label=*/{});
std::vector<clang::ParmVarDecl *> params;
if (std::unique_ptr<PDBSymbolTypeFunctionSig> sig = func->getSignature()) {
@@ -1446,7 +1447,7 @@ PDBASTParser::AddRecordMethod(lldb_private::SymbolFile &symbol_file,
// TODO: get mangled name for the method.
return m_ast.AddMethodToCXXRecordType(
record_type.GetOpaqueQualType(), name.c_str(),
- /*mangled_name*/ nullptr, method_comp_type, access, method.isVirtual(),
+ /*asm_label=*/{}, method_comp_type, access, method.isVirtual(),
method.isStatic(), method.hasInlineAttribute(),
/*is_explicit*/ false, // FIXME: Need this field in CodeView.
/*is_attr_used*/ false,
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 256952dc..836f9fe 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2137,7 +2137,7 @@ std::string TypeSystemClang::GetTypeNameForDecl(const NamedDecl *named_decl,
FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
llvm::StringRef name, const CompilerType &function_clang_type,
- clang::StorageClass storage, bool is_inline) {
+ clang::StorageClass storage, bool is_inline, llvm::StringRef asm_label) {
FunctionDecl *func_decl = nullptr;
ASTContext &ast = getASTContext();
if (!decl_ctx)
@@ -2158,6 +2158,21 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
func_decl->setConstexprKind(isConstexprSpecified
? ConstexprSpecKind::Constexpr
: ConstexprSpecKind::Unspecified);
+
+ // Attach an asm(<mangled_name>) label to the FunctionDecl.
+ // This ensures that clang::CodeGen emits function calls
+ // using symbols that are mangled according to the DW_AT_linkage_name.
+ // If we didn't do this, the external symbols wouldn't exactly
+ // match the mangled name LLDB knows about and the IRExecutionUnit
+ // would have to fall back to searching object files for
+ // approximately matching function names. The motivating
+ // example is generating calls to ABI-tagged template functions.
+ // This is done separately for member functions in
+ // AddMethodToCXXRecordType.
+ if (!asm_label.empty())
+ func_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(ast, asm_label,
+ /*literal=*/true));
+
SetOwningModule(func_decl, owning_module);
decl_ctx->addDecl(func_decl);
@@ -7651,7 +7666,7 @@ TypeSystemClang::CreateParameterDeclarations(
clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
lldb::opaque_compiler_type_t type, llvm::StringRef name,
- const char *mangled_name, const CompilerType &method_clang_type,
+ llvm::StringRef asm_label, const CompilerType &method_clang_type,
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
bool is_explicit, bool is_attr_used, bool is_artificial) {
if (!type || !method_clang_type.IsValid() || name.empty())
@@ -7784,10 +7799,9 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
if (is_attr_used)
cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext()));
- if (mangled_name != nullptr) {
+ if (!asm_label.empty())
cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
- getASTContext(), mangled_name, /*literal=*/false));
- }
+ getASTContext(), asm_label, /*literal=*/true));
// Parameters on member function declarations in DWARF generally don't
// have names, so we omit them when creating the ParmVarDecls.
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 63dee9d..de66bb68 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -477,7 +477,7 @@ public:
clang::FunctionDecl *CreateFunctionDeclaration(
clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
llvm::StringRef name, const CompilerType &function_Type,
- clang::StorageClass storage, bool is_inline);
+ clang::StorageClass storage, bool is_inline, llvm::StringRef asm_label);
CompilerType
CreateFunctionType(const CompilerType &result_type,
@@ -1001,7 +1001,7 @@ public:
clang::CXXMethodDecl *AddMethodToCXXRecordType(
lldb::opaque_compiler_type_t type, llvm::StringRef name,
- const char *mangled_name, const CompilerType &method_type,
+ llvm::StringRef asm_label, const CompilerType &method_type,
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
bool is_explicit, bool is_attr_used, bool is_artificial);
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 8000cd0..e9d9c8f 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -2076,6 +2076,13 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
trap_opcode_size = sizeof(g_loongarch_opcode);
} break;
+ case llvm::Triple::wasm32: {
+ // Unreachable (0x00) triggers an unconditional trap.
+ static const uint8_t g_wasm_opcode[] = {0x00};
+ trap_opcode = g_wasm_opcode;
+ trap_opcode_size = sizeof(g_wasm_opcode);
+ } break;
+
default:
return 0;
}
diff --git a/lldb/source/Utility/WasmVirtualRegisters.h b/lldb/source/Utility/WasmVirtualRegisters.h
new file mode 100644
index 0000000..404a5ae
--- /dev/null
+++ b/lldb/source/Utility/WasmVirtualRegisters.h
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_UTILITY_WASM_VIRTUAL_REGISTERS_H
+#define LLDB_SOURCE_UTILITY_WASM_VIRTUAL_REGISTERS_H
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+// LLDB doesn't have an address space to represents WebAssembly locals,
+// globals and operand stacks. We encode these elements into virtual
+// registers:
+//
+// | tag: 2 bits | index: 30 bits |
+//
+// Where tag is:
+// 0: Not a Wasm location
+// 1: Local
+// 2: Global
+// 3: Operand stack value
+enum WasmVirtualRegisterKinds {
+ eWasmTagNotAWasmLocation = 0,
+ eWasmTagLocal = 1,
+ eWasmTagGlobal = 2,
+ eWasmTagOperandStack = 3,
+};
+
+static const uint32_t kWasmVirtualRegisterTagMask = 0x03;
+static const uint32_t kWasmVirtualRegisterIndexMask = 0x3fffffff;
+static const uint32_t kWasmVirtualRegisterTagShift = 30;
+
+inline uint32_t GetWasmVirtualRegisterTag(size_t reg) {
+ return (reg >> kWasmVirtualRegisterTagShift) & kWasmVirtualRegisterTagMask;
+}
+
+inline uint32_t GetWasmVirtualRegisterIndex(size_t reg) {
+ return reg & kWasmVirtualRegisterIndexMask;
+}
+
+inline uint32_t GetWasmRegister(uint8_t tag, uint32_t index) {
+ return ((tag & kWasmVirtualRegisterTagMask) << kWasmVirtualRegisterTagShift) |
+ (index & kWasmVirtualRegisterIndexMask);
+}
+
+} // namespace lldb_private
+
+#endif