aboutsummaryrefslogtreecommitdiff
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/SBFrame.cpp900
-rw-r--r--lldb/source/API/SBFunction.cpp9
-rw-r--r--lldb/source/API/SBHostOS.cpp10
-rw-r--r--lldb/source/API/SBModule.cpp8
-rw-r--r--lldb/source/API/SBStructuredData.cpp44
-rw-r--r--lldb/source/API/SBSymbol.cpp37
-rw-r--r--lldb/source/API/SBTarget.cpp58
-rw-r--r--lldb/source/API/SBThread.cpp577
-rw-r--r--lldb/source/Breakpoint/BreakpointResolver.cpp39
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverAddress.cpp5
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverName.cpp15
-rw-r--r--lldb/source/Commands/CommandObjectDWIMPrint.cpp49
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.cpp11
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.h1
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp8
-rw-r--r--lldb/source/Commands/CommandObjectFrame.cpp3
-rw-r--r--lldb/source/Commands/CommandObjectProtocolServer.cpp15
-rw-r--r--lldb/source/Commands/CommandObjectSettings.cpp47
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp3
-rw-r--r--lldb/source/Commands/Options.td140
-rw-r--r--lldb/source/Core/Disassembler.cpp166
-rw-r--r--lldb/source/Core/DynamicLoader.cpp2
-rw-r--r--lldb/source/Core/Mangled.cpp15
-rw-r--r--lldb/source/Core/ModuleList.cpp224
-rw-r--r--lldb/source/Core/ProtocolServer.cpp34
-rw-r--r--lldb/source/Core/Section.cpp3
-rw-r--r--lldb/source/Core/Value.cpp11
-rw-r--r--lldb/source/DataFormatters/DumpValueObjectOptions.cpp17
-rw-r--r--lldb/source/DataFormatters/ValueObjectPrinter.cpp100
-rw-r--r--lldb/source/Expression/DWARFExpression.cpp8
-rw-r--r--lldb/source/Expression/IRExecutionUnit.cpp2
-rw-r--r--lldb/source/Expression/Materializer.cpp25
-rw-r--r--lldb/source/Expression/REPL.cpp2
-rw-r--r--lldb/source/Host/CMakeLists.txt2
-rw-r--r--lldb/source/Host/common/Editline.cpp15
-rw-r--r--lldb/source/Host/common/HostInfoBase.cpp38
-rw-r--r--lldb/source/Host/common/JSONTransport.cpp163
-rw-r--r--lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm12
-rw-r--r--lldb/source/Host/windows/Host.cpp30
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp54
-rw-r--r--lldb/source/Interpreter/CommandObject.cpp6
-rw-r--r--lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp13
-rw-r--r--lldb/source/Interpreter/OptionValueArch.cpp7
-rw-r--r--lldb/source/Interpreter/OptionValueArray.cpp12
-rw-r--r--lldb/source/Interpreter/OptionValueBoolean.cpp6
-rw-r--r--lldb/source/Interpreter/OptionValueChar.cpp18
-rw-r--r--lldb/source/Interpreter/OptionValueDictionary.cpp8
-rw-r--r--lldb/source/Interpreter/OptionValueEnumeration.cpp24
-rw-r--r--lldb/source/Interpreter/OptionValueFileSpec.cpp8
-rw-r--r--lldb/source/Interpreter/OptionValueFileSpecList.cpp13
-rw-r--r--lldb/source/Interpreter/OptionValueFormat.cpp6
-rw-r--r--lldb/source/Interpreter/OptionValueFormatEntity.cpp20
-rw-r--r--lldb/source/Interpreter/OptionValueLanguage.cpp9
-rw-r--r--lldb/source/Interpreter/OptionValuePathMappings.cpp12
-rw-r--r--lldb/source/Interpreter/OptionValueRegex.cpp7
-rw-r--r--lldb/source/Interpreter/OptionValueSInt64.cpp6
-rw-r--r--lldb/source/Interpreter/OptionValueString.cpp40
-rw-r--r--lldb/source/Interpreter/OptionValueUInt64.cpp6
-rw-r--r--lldb/source/Interpreter/Options.cpp13
-rw-r--r--lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp3
-rw-r--r--lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp7
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp152
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h4
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp5
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp4
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp6
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp2
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp6
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp6
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp2
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp19
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h8
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp326
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h70
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp24
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp67
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.h17
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp29
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp59
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp12
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp7
-rw-r--r--lldb/source/Plugins/Language/ObjC/NSDictionary.cpp3
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp2
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp2
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp3
-rw-r--r--lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp25
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp41
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp123
-rw-r--r--lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp53
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp451
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h13
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp13
-rw-r--r--lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt2
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp557
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h53
-rw-r--r--lldb/source/Plugins/Process/Utility/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/Utility/HistoryThread.cpp5
-rw-r--r--lldb/source/Plugins/Process/Utility/HistoryThread.h6
-rw-r--r--lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp21
-rw-r--r--lldb/source/Plugins/Process/Utility/HistoryUnwind.h6
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp11
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h11
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp117
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h42
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp2
-rw-r--r--lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp152
-rw-r--r--lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h24
-rw-r--r--lldb/source/Plugins/Protocol/MCP/Resource.cpp15
-rw-r--r--lldb/source/Plugins/Protocol/MCP/Resource.h15
-rw-r--r--lldb/source/Plugins/Protocol/MCP/Tool.cpp12
-rw-r--r--lldb/source/Plugins/Protocol/MCP/Tool.h8
-rw-r--r--lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp4
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp28
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp46
-rw-r--r--lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp9
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp61
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h7
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp11
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp235
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h24
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp11
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp6
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp249
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h9
-rw-r--r--lldb/source/Protocol/MCP/CMakeLists.txt1
-rw-r--r--lldb/source/Protocol/MCP/MCPError.cpp6
-rw-r--r--lldb/source/Protocol/MCP/Protocol.cpp335
-rw-r--r--lldb/source/Protocol/MCP/Server.cpp210
-rw-r--r--lldb/source/Symbol/ObjectFile.cpp1
-rw-r--r--lldb/source/Symbol/Symbol.cpp144
-rw-r--r--lldb/source/Target/ExecutionContext.cpp54
-rw-r--r--lldb/source/Target/RegisterContextUnwind.cpp1
-rw-r--r--lldb/source/Target/StackFrame.cpp42
-rw-r--r--lldb/source/Target/StackID.cpp18
-rw-r--r--lldb/source/Target/Target.cpp56
-rw-r--r--lldb/source/Utility/ArchSpec.cpp4
-rw-r--r--lldb/source/Utility/XcodeSDK.cpp23
-rw-r--r--lldb/source/ValueObject/DILAST.cpp9
-rw-r--r--lldb/source/ValueObject/DILEval.cpp254
-rw-r--r--lldb/source/ValueObject/DILLexer.cpp57
-rw-r--r--lldb/source/ValueObject/DILParser.cpp67
143 files changed, 4675 insertions, 3073 deletions
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
index 5b69cf1..b12cfce 100644
--- a/lldb/source/API/SBFrame.cpp
+++ b/lldb/source/API/SBFrame.cpp
@@ -97,226 +97,176 @@ bool SBFrame::IsValid() const {
}
SBFrame::operator bool() const {
LLDB_INSTRUMENT_VA(this);
-
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock()))
- return GetFrameSP().get() != nullptr;
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
}
- // Without a target & process we can't have a valid stack frame.
- return false;
+ return GetFrameSP().get() != nullptr;
}
SBSymbolContext SBFrame::GetSymbolContext(uint32_t resolve_scope) const {
LLDB_INSTRUMENT_VA(this, resolve_scope);
SBSymbolContext sb_sym_ctx;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
- SymbolContextItem scope = static_cast<SymbolContextItem>(resolve_scope);
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- if (StackFrame *frame = exe_ctx.GetFramePtr())
- sb_sym_ctx = frame->GetSymbolContext(scope);
- }
+
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return sb_sym_ctx;
}
+ SymbolContextItem scope = static_cast<SymbolContextItem>(resolve_scope);
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ sb_sym_ctx = frame->GetSymbolContext(scope);
+
return sb_sym_ctx;
}
SBModule SBFrame::GetModule() const {
LLDB_INSTRUMENT_VA(this);
- SBModule sb_module;
- ModuleSP module_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- module_sp = frame->GetSymbolContext(eSymbolContextModule).module_sp;
- sb_module.SetSP(module_sp);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBModule();
}
+ ModuleSP module_sp;
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ if (!frame)
+ return SBModule();
+
+ SBModule sb_module;
+ module_sp = frame->GetSymbolContext(eSymbolContextModule).module_sp;
+ sb_module.SetSP(module_sp);
return sb_module;
}
SBCompileUnit SBFrame::GetCompileUnit() const {
LLDB_INSTRUMENT_VA(this);
- SBCompileUnit sb_comp_unit;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- sb_comp_unit.reset(
- frame->GetSymbolContext(eSymbolContextCompUnit).comp_unit);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBCompileUnit();
}
- return sb_comp_unit;
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return SBCompileUnit(
+ frame->GetSymbolContext(eSymbolContextCompUnit).comp_unit);
+ return SBCompileUnit();
}
SBFunction SBFrame::GetFunction() const {
LLDB_INSTRUMENT_VA(this);
- SBFunction sb_function;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- sb_function.reset(
- frame->GetSymbolContext(eSymbolContextFunction).function);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBFunction();
}
- return sb_function;
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return SBFunction(frame->GetSymbolContext(eSymbolContextFunction).function);
+ return SBFunction();
}
SBSymbol SBFrame::GetSymbol() const {
LLDB_INSTRUMENT_VA(this);
- SBSymbol sb_symbol;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- sb_symbol.reset(frame->GetSymbolContext(eSymbolContextSymbol).symbol);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBSymbol();
}
- return sb_symbol;
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return SBSymbol(frame->GetSymbolContext(eSymbolContextSymbol).symbol);
+ return SBSymbol();
}
SBBlock SBFrame::GetBlock() const {
LLDB_INSTRUMENT_VA(this);
- SBBlock sb_block;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame)
- sb_block.SetPtr(frame->GetSymbolContext(eSymbolContextBlock).block);
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBBlock();
}
- return sb_block;
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return SBBlock(frame->GetSymbolContext(eSymbolContextBlock).block);
+ return SBBlock();
}
SBBlock SBFrame::GetFrameBlock() const {
LLDB_INSTRUMENT_VA(this);
- SBBlock sb_block;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame)
- sb_block.SetPtr(frame->GetFrameBlock());
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBBlock();
}
- return sb_block;
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return SBBlock(frame->GetFrameBlock());
+ return SBBlock();
}
SBLineEntry SBFrame::GetLineEntry() const {
LLDB_INSTRUMENT_VA(this);
- SBLineEntry sb_line_entry;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- sb_line_entry.SetLineEntry(
- frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBLineEntry();
}
- return sb_line_entry;
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return SBLineEntry(
+ &frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
+ return SBLineEntry();
}
uint32_t SBFrame::GetFrameID() const {
LLDB_INSTRUMENT_VA(this);
- uint32_t frame_idx = UINT32_MAX;
-
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ constexpr uint32_t error_frame_idx = UINT32_MAX;
- StackFrame *frame = exe_ctx.GetFramePtr();
- if (frame)
- frame_idx = frame->GetFrameIndex();
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return error_frame_idx;
+ }
- return frame_idx;
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return frame->GetFrameIndex();
+ return error_frame_idx;
}
lldb::addr_t SBFrame::GetCFA() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return LLDB_INVALID_ADDRESS;
+ }
- StackFrame *frame = exe_ctx.GetFramePtr();
- if (frame)
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
return frame->GetStackID().GetCallFrameAddress();
return LLDB_INVALID_ADDRESS;
}
@@ -325,114 +275,86 @@ addr_t SBFrame::GetPC() const {
LLDB_INSTRUMENT_VA(this);
addr_t addr = LLDB_INVALID_ADDRESS;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- addr = frame->GetFrameCodeAddress().GetOpcodeLoadAddress(
- target, AddressClass::eCode);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return addr;
}
+ Target *target = exe_ctx->GetTargetPtr();
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return frame->GetFrameCodeAddress().GetOpcodeLoadAddress(
+ target, AddressClass::eCode);
+
return addr;
}
bool SBFrame::SetPC(addr_t new_pc) {
LLDB_INSTRUMENT_VA(this, new_pc);
- bool ret_val = false;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- if (StackFrame *frame = exe_ctx.GetFramePtr()) {
- if (RegisterContextSP reg_ctx_sp = frame->GetRegisterContext()) {
- ret_val = reg_ctx_sp->SetPC(new_pc);
- }
- }
- }
+ constexpr bool error_ret_val = false;
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return error_ret_val;
}
- return ret_val;
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ if (RegisterContextSP reg_ctx_sp = frame->GetRegisterContext())
+ return reg_ctx_sp->SetPC(new_pc);
+
+ return error_ret_val;
}
addr_t SBFrame::GetSP() const {
LLDB_INSTRUMENT_VA(this);
- addr_t addr = LLDB_INVALID_ADDRESS;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- if (StackFrame *frame = exe_ctx.GetFramePtr()) {
- if (RegisterContextSP reg_ctx_sp = frame->GetRegisterContext()) {
- addr = reg_ctx_sp->GetSP();
- }
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return LLDB_INVALID_ADDRESS;
}
- return addr;
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ if (RegisterContextSP reg_ctx_sp = frame->GetRegisterContext())
+ return reg_ctx_sp->GetSP();
+
+ return LLDB_INVALID_ADDRESS;
}
addr_t SBFrame::GetFP() const {
LLDB_INSTRUMENT_VA(this);
- addr_t addr = LLDB_INVALID_ADDRESS;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- if (StackFrame *frame = exe_ctx.GetFramePtr()) {
- if (RegisterContextSP reg_ctx_sp = frame->GetRegisterContext()) {
- addr = reg_ctx_sp->GetFP();
- }
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return LLDB_INVALID_ADDRESS;
}
- return addr;
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ if (RegisterContextSP reg_ctx_sp = frame->GetRegisterContext())
+ return reg_ctx_sp->GetFP();
+
+ return LLDB_INVALID_ADDRESS;
}
SBAddress SBFrame::GetPCAddress() const {
LLDB_INSTRUMENT_VA(this);
- SBAddress sb_addr;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = exe_ctx.GetFramePtr();
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame)
- sb_addr.SetAddress(frame->GetFrameCodeAddress());
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBAddress();
}
- return sb_addr;
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return SBAddress(frame->GetFrameCodeAddress());
+ return SBAddress();
}
void SBFrame::Clear() {
@@ -445,12 +367,14 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path) {
LLDB_INSTRUMENT_VA(this, var_path);
SBValue sb_value;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return sb_value;
+ }
- StackFrame *frame = exe_ctx.GetFramePtr();
- Target *target = exe_ctx.GetTargetPtr();
- if (frame && target) {
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
lldb::DynamicValueType use_dynamic =
frame->CalculateTarget()->GetPreferDynamicValue();
sb_value = GetValueForVariablePath(var_path, use_dynamic);
@@ -467,27 +391,22 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path,
return sb_value;
}
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- VariableSP var_sp;
- Status error;
- ValueObjectSP value_sp(frame->GetValueForVariableExpressionPath(
- var_path, eNoDynamicValues,
- StackFrame::eExpressionPathOptionCheckPtrVsMember |
- StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
- var_sp, error));
- sb_value.SetSP(value_sp, use_dynamic);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return sb_value;
+ }
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
+ VariableSP var_sp;
+ Status error;
+ ValueObjectSP value_sp(frame->GetValueForVariableExpressionPath(
+ var_path, eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
+ var_sp, error));
+ sb_value.SetSP(value_sp, use_dynamic);
}
return sb_value;
}
@@ -495,18 +414,19 @@ lldb::SBValue SBFrame::GetValueForVariablePath(const char *var_path,
SBValue SBFrame::FindVariable(const char *name) {
LLDB_INSTRUMENT_VA(this, name);
- SBValue value;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBValue();
+ }
- StackFrame *frame = exe_ctx.GetFramePtr();
- Target *target = exe_ctx.GetTargetPtr();
- if (frame && target) {
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
lldb::DynamicValueType use_dynamic =
frame->CalculateTarget()->GetPreferDynamicValue();
- value = FindVariable(name, use_dynamic);
+ return FindVariable(name, use_dynamic);
}
- return value;
+ return SBValue();
}
SBValue SBFrame::FindVariable(const char *name,
@@ -520,26 +440,17 @@ SBValue SBFrame::FindVariable(const char *name,
return sb_value;
}
- ValueObjectSP value_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- value_sp = frame->FindVariable(ConstString(name));
-
- if (value_sp)
- sb_value.SetSP(value_sp, use_dynamic);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return sb_value;
}
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ if (ValueObjectSP value_sp = frame->FindVariable(ConstString(name)))
+ sb_value.SetSP(value_sp, use_dynamic);
+
return sb_value;
}
@@ -547,12 +458,14 @@ SBValue SBFrame::FindValue(const char *name, ValueType value_type) {
LLDB_INSTRUMENT_VA(this, name, value_type);
SBValue value;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return value;
+ }
- StackFrame *frame = exe_ctx.GetFramePtr();
- Target *target = exe_ctx.GetTargetPtr();
- if (frame && target) {
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
lldb::DynamicValueType use_dynamic =
frame->CalculateTarget()->GetPreferDynamicValue();
value = FindValue(name, value_type, use_dynamic);
@@ -571,17 +484,17 @@ SBValue SBFrame::FindValue(const char *name, ValueType value_type,
}
ValueObjectSP value_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return value_sp;
+ } else {
+ Target *target = exe_ctx->GetTargetPtr();
+ Process *process = exe_ctx->GetProcessPtr();
+ if (target && process) { // FIXME: this check is redundant.
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
VariableList variable_list;
switch (value_type) {
@@ -698,10 +611,14 @@ bool SBFrame::operator!=(const SBFrame &rhs) const {
SBThread SBFrame::GetThread() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBThread();
+ }
- ThreadSP thread_sp(exe_ctx.GetThreadSP());
+ ThreadSP thread_sp(exe_ctx->GetThreadSP());
SBThread sb_thread(thread_sp);
return sb_thread;
@@ -710,19 +627,16 @@ SBThread SBFrame::GetThread() const {
const char *SBFrame::Disassemble() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (!target || !process)
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
return nullptr;
-
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- if (auto *frame = exe_ctx.GetFramePtr())
- return ConstString(frame->Disassemble()).GetCString();
}
+ if (auto *frame = exe_ctx->GetFramePtr())
+ return ConstString(frame->Disassemble()).GetCString();
+
return nullptr;
}
@@ -731,12 +645,15 @@ SBValueList SBFrame::GetVariables(bool arguments, bool locals, bool statics,
LLDB_INSTRUMENT_VA(this, arguments, locals, statics, in_scope_only);
SBValueList value_list;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return value_list;
+ }
- StackFrame *frame = exe_ctx.GetFramePtr();
- Target *target = exe_ctx.GetTargetPtr();
- if (frame && target) {
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
+ Target *target = exe_ctx->GetTargetPtr();
lldb::DynamicValueType use_dynamic =
frame->CalculateTarget()->GetPreferDynamicValue();
const bool include_runtime_support_values =
@@ -761,12 +678,16 @@ lldb::SBValueList SBFrame::GetVariables(bool arguments, bool locals,
LLDB_INSTRUMENT_VA(this, arguments, locals, statics, in_scope_only,
use_dynamic);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBValueList();
+ }
- Target *target = exe_ctx.GetTargetPtr();
+ Target *target = exe_ctx->GetTargetPtr();
const bool include_runtime_support_values =
- target ? target->GetDisplayRuntimeSupportValues() : false;
+ target->GetDisplayRuntimeSupportValues();
SBVariablesOptions options;
options.SetIncludeArguments(arguments);
options.SetIncludeLocals(locals);
@@ -781,30 +702,26 @@ SBValueList SBFrame::GetVariables(const lldb::SBVariablesOptions &options) {
LLDB_INSTRUMENT_VA(this, options);
SBValueList value_list;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
-
- const bool statics = options.GetIncludeStatics();
- const bool arguments = options.GetIncludeArguments();
- const bool recognized_arguments =
- options.GetIncludeRecognizedArguments(SBTarget(exe_ctx.GetTargetSP()));
- const bool locals = options.GetIncludeLocals();
- const bool in_scope_only = options.GetInScopeOnly();
- const bool include_runtime_support_values =
- options.GetIncludeRuntimeSupportValues();
- const lldb::DynamicValueType use_dynamic = options.GetUseDynamic();
-
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBValueList();
+ } else {
+ const bool statics = options.GetIncludeStatics();
+ const bool arguments = options.GetIncludeArguments();
+ const bool recognized_arguments =
+ options.GetIncludeRecognizedArguments(SBTarget(exe_ctx->GetTargetSP()));
+ const bool locals = options.GetIncludeLocals();
+ const bool in_scope_only = options.GetInScopeOnly();
+ const bool include_runtime_support_values =
+ options.GetIncludeRuntimeSupportValues();
+ const lldb::DynamicValueType use_dynamic = options.GetUseDynamic();
- std::set<VariableSP> variable_set;
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
+ std::set<VariableSP> variable_set;
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process) { // FIXME: this check is redundant.
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
Debugger &dbg = process->GetTarget().GetDebugger();
VariableList *variable_list = nullptr;
Status var_error;
@@ -892,17 +809,16 @@ SBValueList SBFrame::GetRegisters() {
LLDB_INSTRUMENT_VA(this);
SBValueList value_list;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBValueList();
+ } else {
+ Target *target = exe_ctx->GetTargetPtr();
+ Process *process = exe_ctx->GetProcessPtr();
+ if (target && process) { // FIXME: this check is redundant.
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
RegisterContextSP reg_ctx(frame->GetRegisterContext());
if (reg_ctx) {
const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
@@ -923,17 +839,16 @@ SBValue SBFrame::FindRegister(const char *name) {
SBValue result;
ValueObjectSP value_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBValue();
+ } else {
+ Target *target = exe_ctx->GetTargetPtr();
+ Process *process = exe_ctx->GetProcessPtr();
+ if (target && process) { // FIXME: this check is redundant.
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
RegisterContextSP reg_ctx(frame->GetRegisterContext());
if (reg_ctx) {
if (const RegisterInfo *reg_info =
@@ -953,12 +868,11 @@ SBError SBFrame::GetDescriptionWithFormat(const SBFormat &format,
SBStream &output) {
Stream &strm = output.ref();
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx)
+ return Status::FromError(exe_ctx.takeError());
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
SBError error;
if (!format) {
@@ -966,16 +880,9 @@ SBError SBFrame::GetDescriptionWithFormat(const SBFormat &format,
return error;
}
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame &&
- frame->DumpUsingFormat(strm, format.GetFormatEntrySP().get())) {
- return error;
- }
- }
- }
+ if (StackFrame *frame = exe_ctx->GetFramePtr();
+ frame && frame->DumpUsingFormat(strm, format.GetFormatEntrySP().get()))
+ return error;
error.SetErrorStringWithFormat(
"It was not possible to generate a frame "
"description with the given format string '%s'",
@@ -988,23 +895,16 @@ bool SBFrame::GetDescription(SBStream &description) {
Stream &strm = description.ref();
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- frame->DumpUsingSettingsFormat(&strm);
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ strm.PutCString("Error: process is not stopped.");
+ return true;
+ }
- } else
- strm.PutCString("No value");
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ frame->DumpUsingSettingsFormat(&strm);
return true;
}
@@ -1012,22 +912,24 @@ bool SBFrame::GetDescription(SBStream &description) {
SBValue SBFrame::EvaluateExpression(const char *expr) {
LLDB_INSTRUMENT_VA(this, expr);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return CreateProcessIsRunningExprEvalError();
+ }
- StackFrame *frame = exe_ctx.GetFramePtr();
- Target *target = exe_ctx.GetTargetPtr();
SBExpressionOptions options;
- if (frame && target) {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ if (frame) {
lldb::DynamicValueType fetch_dynamic_value =
frame->CalculateTarget()->GetPreferDynamicValue();
options.SetFetchDynamicValue(fetch_dynamic_value);
}
options.SetUnwindOnError(true);
options.SetIgnoreBreakpoints(true);
- SourceLanguage language;
- if (target)
- language = target->GetLanguage();
+ Target *target = exe_ctx->GetTargetPtr();
+ SourceLanguage language = target->GetLanguage();
if (!language && frame)
language = frame->GetLanguage();
options.SetLanguage((SBSourceLanguageName)language.name, language.version);
@@ -1043,14 +945,16 @@ SBFrame::EvaluateExpression(const char *expr,
options.SetFetchDynamicValue(fetch_dynamic_value);
options.SetUnwindOnError(true);
options.SetIgnoreBreakpoints(true);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = exe_ctx.GetFramePtr();
- Target *target = exe_ctx.GetTargetPtr();
- SourceLanguage language;
- if (target)
- language = target->GetLanguage();
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return CreateProcessIsRunningExprEvalError();
+ }
+
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ Target *target = exe_ctx->GetTargetPtr();
+ SourceLanguage language = target->GetLanguage();
if (!language && frame)
language = frame->GetLanguage();
options.SetLanguage((SBSourceLanguageName)language.name, language.version);
@@ -1063,23 +967,35 @@ SBValue SBFrame::EvaluateExpression(const char *expr,
LLDB_INSTRUMENT_VA(this, expr, fetch_dynamic_value, unwind_on_error);
SBExpressionOptions options;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return CreateProcessIsRunningExprEvalError();
+ }
options.SetFetchDynamicValue(fetch_dynamic_value);
options.SetUnwindOnError(unwind_on_error);
options.SetIgnoreBreakpoints(true);
- StackFrame *frame = exe_ctx.GetFramePtr();
- Target *target = exe_ctx.GetTargetPtr();
- SourceLanguage language;
- if (target)
- language = target->GetLanguage();
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ Target *target = exe_ctx->GetTargetPtr();
+ SourceLanguage language = target->GetLanguage();
if (!language && frame)
language = frame->GetLanguage();
options.SetLanguage((SBSourceLanguageName)language.name, language.version);
return EvaluateExpression(expr, options);
}
+lldb::SBValue SBFrame::CreateProcessIsRunningExprEvalError() {
+ auto error = Status::FromErrorString("can't evaluate expressions when the "
+ "process is running.");
+ ValueObjectSP expr_value_sp =
+ ValueObjectConstResult::Create(nullptr, std::move(error));
+ SBValue expr_result;
+ expr_result.SetSP(expr_value_sp, false);
+ return expr_result;
+}
+
lldb::SBValue SBFrame::EvaluateExpression(const char *expr,
const SBExpressionOptions &options) {
LLDB_INSTRUMENT_VA(this, expr, options);
@@ -1094,18 +1010,16 @@ lldb::SBValue SBFrame::EvaluateExpression(const char *expr,
ValueObjectSP expr_value_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
-
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ expr_result = CreateProcessIsRunningExprEvalError();
+ } else {
+ Target *target = exe_ctx->GetTargetPtr();
+ Process *process = exe_ctx->GetProcessPtr();
+ if (target && process) { // FIXME: this check is redundant.
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
std::unique_ptr<llvm::PrettyStackTraceFormat> stack_trace;
if (target->GetDisplayExpressionsInCrashlogs()) {
StreamString frame_description;
@@ -1122,16 +1036,10 @@ lldb::SBValue SBFrame::EvaluateExpression(const char *expr,
}
} else {
Status error;
- error = Status::FromErrorString("can't evaluate expressions when the "
- "process is running.");
- expr_value_sp = ValueObjectConstResult::Create(nullptr, std::move(error));
- expr_result.SetSP(expr_value_sp, false);
- }
- } else {
- Status error;
error = Status::FromErrorString("sbframe object is not valid.");
expr_value_sp = ValueObjectConstResult::Create(nullptr, std::move(error));
expr_result.SetSP(expr_value_sp, false);
+ }
}
if (expr_result.GetError().Success())
@@ -1152,9 +1060,13 @@ SBStructuredData SBFrame::GetLanguageSpecificData() const {
LLDB_INSTRUMENT_VA(this);
SBStructuredData sb_data;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
- StackFrame *frame = exe_ctx.GetFramePtr();
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return sb_data;
+ }
+ StackFrame *frame = exe_ctx->GetFramePtr();
if (!frame)
return sb_data;
@@ -1172,20 +1084,15 @@ bool SBFrame::IsInlined() {
bool SBFrame::IsInlined() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame)
- return frame->IsInlined();
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
}
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return frame->IsInlined();
return false;
}
@@ -1198,10 +1105,14 @@ bool SBFrame::IsArtificial() {
bool SBFrame::IsArtificial() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
+ }
- if (StackFrame *frame = exe_ctx.GetFramePtr())
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
return frame->IsArtificial();
return false;
@@ -1210,10 +1121,14 @@ bool SBFrame::IsArtificial() const {
bool SBFrame::IsHidden() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
+ }
- if (StackFrame *frame = exe_ctx.GetFramePtr())
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
return frame->IsHidden();
return false;
@@ -1228,63 +1143,44 @@ const char *SBFrame::GetFunctionName() {
lldb::LanguageType SBFrame::GuessLanguage() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame) {
- return frame->GuessLanguage().AsLanguageType();
- }
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return eLanguageTypeUnknown;
}
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return frame->GuessLanguage().AsLanguageType();
return eLanguageTypeUnknown;
}
const char *SBFrame::GetFunctionName() const {
LLDB_INSTRUMENT_VA(this);
- const char *name = nullptr;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame)
- return frame->GetFunctionName();
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return nullptr;
}
- return name;
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return frame->GetFunctionName();
+ return nullptr;
}
const char *SBFrame::GetDisplayFunctionName() {
LLDB_INSTRUMENT_VA(this);
- const char *name = nullptr;
-
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- StackFrame *frame = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock())) {
- frame = exe_ctx.GetFramePtr();
- if (frame)
- return frame->GetDisplayFunctionName();
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return nullptr;
}
- return name;
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return frame->GetDisplayFunctionName();
+ return nullptr;
}
diff --git a/lldb/source/API/SBFunction.cpp b/lldb/source/API/SBFunction.cpp
index 19861f6..65b02d6 100644
--- a/lldb/source/API/SBFunction.cpp
+++ b/lldb/source/API/SBFunction.cpp
@@ -79,6 +79,15 @@ const char *SBFunction::GetMangledName() const {
return nullptr;
}
+const char *SBFunction::GetBaseName() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (!m_opaque_ptr)
+ return nullptr;
+
+ return m_opaque_ptr->GetMangled().GetBaseName().AsCString();
+}
+
bool SBFunction::operator==(const SBFunction &rhs) const {
LLDB_INSTRUMENT_VA(this, rhs);
diff --git a/lldb/source/API/SBHostOS.cpp b/lldb/source/API/SBHostOS.cpp
index a77a703..cd9b857 100644
--- a/lldb/source/API/SBHostOS.cpp
+++ b/lldb/source/API/SBHostOS.cpp
@@ -86,15 +86,7 @@ SBFileSpec SBHostOS::GetLLDBPath(lldb::PathType path_type) {
SBFileSpec SBHostOS::GetUserHomeDirectory() {
LLDB_INSTRUMENT();
-
- FileSpec homedir;
- FileSystem::Instance().GetHomeDirectory(homedir);
- FileSystem::Instance().Resolve(homedir);
-
- SBFileSpec sb_fspec;
- sb_fspec.SetFileSpec(homedir);
-
- return sb_fspec;
+ return HostInfo::GetUserHomeDir();
}
lldb::thread_t SBHostOS::ThreadCreate(const char *name,
diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp
index 985107e..5a57f45 100644
--- a/lldb/source/API/SBModule.cpp
+++ b/lldb/source/API/SBModule.cpp
@@ -671,3 +671,11 @@ void SBModule::GarbageCollectAllocatedModules() {
const bool mandatory = false;
ModuleList::RemoveOrphanSharedModules(mandatory);
}
+
+const char *SBModule::GetObjectName() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (!m_opaque_sp)
+ return nullptr;
+ return m_opaque_sp->GetObjectName().AsCString();
+}
diff --git a/lldb/source/API/SBStructuredData.cpp b/lldb/source/API/SBStructuredData.cpp
index b891a34..8e2c18e 100644
--- a/lldb/source/API/SBStructuredData.cpp
+++ b/lldb/source/API/SBStructuredData.cpp
@@ -232,3 +232,47 @@ lldb::SBScriptObject SBStructuredData::GetGenericValue() const {
return {m_impl_up->GetGenericValue(), eScriptLanguageDefault};
}
+
+void SBStructuredData::SetValueForKey(const char *key,
+ SBStructuredData &value) {
+ LLDB_INSTRUMENT_VA(this, key, value);
+
+ if (StructuredData::ObjectSP obj_sp = value.m_impl_up->GetObjectSP())
+ m_impl_up->SetValueForKey(key, obj_sp);
+}
+
+void SBStructuredData::SetUnsignedIntegerValue(uint64_t value) {
+ LLDB_INSTRUMENT_VA(this, value);
+
+ m_impl_up->SetUnsignedIntegerValue(value);
+}
+
+void SBStructuredData::SetSignedIntegerValue(int64_t value) {
+ LLDB_INSTRUMENT_VA(this, value);
+
+ m_impl_up->SetSignedIntegerValue(value);
+}
+
+void SBStructuredData::SetFloatValue(double value) {
+ LLDB_INSTRUMENT_VA(this, value);
+
+ m_impl_up->SetFloatValue(value);
+}
+
+void SBStructuredData::SetBooleanValue(bool value) {
+ LLDB_INSTRUMENT_VA(this, value);
+
+ m_impl_up->SetBooleanValue(value);
+}
+
+void SBStructuredData::SetStringValue(const char *value) {
+ LLDB_INSTRUMENT_VA(this, value);
+
+ m_impl_up->SetStringValue(value);
+}
+
+void SBStructuredData::SetGenericValue(SBScriptObject value) {
+ LLDB_INSTRUMENT_VA(this, value);
+
+ m_impl_up->SetGenericValue(value.GetPointer());
+}
diff --git a/lldb/source/API/SBSymbol.cpp b/lldb/source/API/SBSymbol.cpp
index 79477dd..3030c83 100644
--- a/lldb/source/API/SBSymbol.cpp
+++ b/lldb/source/API/SBSymbol.cpp
@@ -79,6 +79,15 @@ const char *SBSymbol::GetMangledName() const {
return name;
}
+const char *SBSymbol::GetBaseName() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (!m_opaque_ptr)
+ return nullptr;
+
+ return m_opaque_ptr->GetMangled().GetBaseName().AsCString();
+}
+
bool SBSymbol::operator==(const SBSymbol &rhs) const {
LLDB_INSTRUMENT_VA(this, rhs);
@@ -193,6 +202,14 @@ SymbolType SBSymbol::GetType() {
return eSymbolTypeInvalid;
}
+uint32_t SBSymbol::GetID() {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetID();
+ return 0;
+}
+
bool SBSymbol::IsExternal() {
LLDB_INSTRUMENT_VA(this);
@@ -208,3 +225,23 @@ bool SBSymbol::IsSynthetic() {
return m_opaque_ptr->IsSynthetic();
return false;
}
+
+bool SBSymbol::IsDebug() {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (m_opaque_ptr)
+ return m_opaque_ptr->IsDebug();
+ return false;
+}
+
+const char *SBSymbol::GetTypeAsString(lldb::SymbolType symbol_type) {
+ LLDB_INSTRUMENT_VA(symbol_type);
+
+ return Symbol::GetTypeAsString(symbol_type);
+}
+
+lldb::SymbolType SBSymbol::GetTypeFromString(const char *str) {
+ LLDB_INSTRUMENT_VA(str);
+
+ return Symbol::GetTypeFromString(str);
+}
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index f26f795..eb56337 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -766,16 +766,19 @@ SBBreakpoint SBTarget::BreakpointCreateByName(const char *symbol_name,
const bool hardware = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
const lldb::addr_t offset = 0;
+ const bool offset_is_insn_count = false;
if (module_name && module_name[0]) {
FileSpecList module_spec_list;
module_spec_list.Append(FileSpec(module_name));
sb_bp = target_sp->CreateBreakpoint(
&module_spec_list, nullptr, symbol_name, eFunctionNameTypeAuto,
- eLanguageTypeUnknown, offset, skip_prologue, internal, hardware);
+ eLanguageTypeUnknown, offset, offset_is_insn_count, skip_prologue,
+ internal, hardware);
} else {
sb_bp = target_sp->CreateBreakpoint(
nullptr, nullptr, symbol_name, eFunctionNameTypeAuto,
- eLanguageTypeUnknown, offset, skip_prologue, internal, hardware);
+ eLanguageTypeUnknown, offset, offset_is_insn_count, skip_prologue,
+ internal, hardware);
}
}
@@ -811,6 +814,17 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByName(
const SBFileSpecList &comp_unit_list) {
LLDB_INSTRUMENT_VA(this, symbol_name, name_type_mask, symbol_language,
module_list, comp_unit_list);
+ return BreakpointCreateByName(symbol_name, name_type_mask, symbol_language, 0,
+ false, module_list, comp_unit_list);
+}
+
+lldb::SBBreakpoint SBTarget::BreakpointCreateByName(
+ const char *symbol_name, uint32_t name_type_mask,
+ LanguageType symbol_language, lldb::addr_t offset,
+ bool offset_is_insn_count, const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list) {
+ LLDB_INSTRUMENT_VA(this, symbol_name, name_type_mask, symbol_language, offset,
+ offset_is_insn_count, module_list, comp_unit_list);
SBBreakpoint sb_bp;
if (TargetSP target_sp = GetSP();
@@ -821,7 +835,8 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByName(
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
FunctionNameType mask = static_cast<FunctionNameType>(name_type_mask);
sb_bp = target_sp->CreateBreakpoint(module_list.get(), comp_unit_list.get(),
- symbol_name, mask, symbol_language, 0,
+ symbol_name, mask, symbol_language,
+ offset, offset_is_insn_count,
skip_prologue, internal, hardware);
}
@@ -1555,6 +1570,18 @@ SBModule SBTarget::FindModule(const SBFileSpec &sb_file_spec) {
return sb_module;
}
+SBModule SBTarget::FindModule(const SBModuleSpec &sb_module_spec) {
+ LLDB_INSTRUMENT_VA(this, sb_module_spec);
+
+ SBModule sb_module;
+ if (TargetSP target_sp = GetSP(); target_sp && sb_module_spec.IsValid()) {
+ // The module list is thread safe, no need to lock.
+ sb_module.SetSP(
+ target_sp->GetImages().FindFirstModule(*sb_module_spec.m_opaque_up));
+ }
+ return sb_module;
+}
+
SBSymbolContextList SBTarget::FindCompileUnits(const SBFileSpec &sb_file_spec) {
LLDB_INSTRUMENT_VA(this, sb_file_spec);
@@ -1955,29 +1982,10 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr,
if (TargetSP target_sp = GetSP()) {
if (Address *addr_ptr = base_addr.get()) {
- DataBufferHeap data(
- target_sp->GetArchitecture().GetMaximumOpcodeByteSize() * count, 0);
- bool force_live_memory = true;
- lldb_private::Status error;
- lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
- const size_t bytes_read =
- target_sp->ReadMemory(*addr_ptr, data.GetBytes(), data.GetByteSize(),
- error, force_live_memory, &load_addr);
-
- const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
- if (!flavor_string || flavor_string[0] == '\0') {
- // FIXME - we don't have the mechanism in place to do per-architecture
- // settings. But since we know that for now we only support flavors on
- // x86 & x86_64,
- const llvm::Triple::ArchType arch =
- target_sp->GetArchitecture().GetTriple().getArch();
- if (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64)
- flavor_string = target_sp->GetDisassemblyFlavor();
+ if (llvm::Expected<DisassemblerSP> disassembler =
+ target_sp->ReadInstructions(*addr_ptr, count, flavor_string)) {
+ sb_instructions.SetDisassembler(*disassembler);
}
- sb_instructions.SetDisassembler(Disassembler::DisassembleBytes(
- target_sp->GetArchitecture(), nullptr, flavor_string,
- target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(),
- *addr_ptr, data.GetBytes(), bytes_read, count, data_from_file));
}
}
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index 74bc66c..ec68b2a 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -90,16 +90,17 @@ lldb::SBQueue SBThread::GetQueue() const {
SBQueue sb_queue;
QueueSP queue_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- queue_sp = exe_ctx.GetThreadPtr()->GetQueue();
- if (queue_sp) {
- sb_queue.SetQueue(queue_sp);
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBQueue();
+ }
+
+ if (exe_ctx->HasThreadScope()) {
+ queue_sp = exe_ctx->GetThreadPtr()->GetQueue();
+ if (queue_sp) {
+ sb_queue.SetQueue(queue_sp);
}
}
@@ -112,19 +113,17 @@ bool SBThread::IsValid() const {
}
SBThread::operator bool() const {
LLDB_INSTRUMENT_VA(this);
+ if (!m_opaque_sp)
+ return false;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- Target *target = exe_ctx.GetTargetPtr();
- Process *process = exe_ctx.GetProcessPtr();
- if (target && process) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&process->GetRunLock()))
- return m_opaque_sp->GetThreadSP().get() != nullptr;
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
}
- // Without a valid target & process, this thread can't be valid.
- return false;
+
+ return m_opaque_sp->GetThreadSP().get() != nullptr;
}
void SBThread::Clear() {
@@ -137,29 +136,27 @@ StopReason SBThread::GetStopReason() {
LLDB_INSTRUMENT_VA(this);
StopReason reason = eStopReasonInvalid;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- return exe_ctx.GetThreadPtr()->GetStopReason();
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return reason;
}
+ if (exe_ctx->HasThreadScope())
+ return exe_ctx->GetThreadPtr()->GetStopReason();
+
return reason;
}
size_t SBThread::GetStopReasonDataCount() {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo();
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (exe_ctx) {
+ if (exe_ctx->HasThreadScope()) {
+ StopInfoSP stop_info_sp = exe_ctx->GetThreadPtr()->GetStopInfo();
if (stop_info_sp) {
StopReason reason = stop_info_sp->GetStopReason();
switch (reason) {
@@ -179,7 +176,7 @@ size_t SBThread::GetStopReasonDataCount() {
case eStopReasonBreakpoint: {
break_id_t site_id = stop_info_sp->GetValue();
lldb::BreakpointSiteSP bp_site_sp(
- exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID(
+ exe_ctx->GetProcessPtr()->GetBreakpointSiteList().FindByID(
site_id));
if (bp_site_sp)
return bp_site_sp->GetNumberOfConstituents() * 2;
@@ -207,6 +204,9 @@ size_t SBThread::GetStopReasonDataCount() {
}
}
}
+ } else {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return 0;
}
return 0;
}
@@ -214,13 +214,11 @@ size_t SBThread::GetStopReasonDataCount() {
uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
LLDB_INSTRUMENT_VA(this, idx);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- Thread *thread = exe_ctx.GetThreadPtr();
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (exe_ctx) {
+ if (exe_ctx->HasThreadScope()) {
+ Thread *thread = exe_ctx->GetThreadPtr();
StopInfoSP stop_info_sp = thread->GetStopInfo();
if (stop_info_sp) {
StopReason reason = stop_info_sp->GetStopReason();
@@ -241,7 +239,7 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
case eStopReasonBreakpoint: {
break_id_t site_id = stop_info_sp->GetValue();
lldb::BreakpointSiteSP bp_site_sp(
- exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID(
+ exe_ctx->GetProcessPtr()->GetBreakpointSiteList().FindByID(
site_id));
if (bp_site_sp) {
uint32_t bp_index = idx / 2;
@@ -280,6 +278,9 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
}
}
}
+ } else {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return 0;
}
return 0;
}
@@ -289,13 +290,17 @@ bool SBThread::GetStopReasonExtendedInfoAsJSON(lldb::SBStream &stream) {
Stream &strm = stream.ref();
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
+ }
- if (!exe_ctx.HasThreadScope())
+ if (!exe_ctx->HasThreadScope())
return false;
- StopInfoSP stop_info = exe_ctx.GetThreadPtr()->GetStopInfo();
+ StopInfoSP stop_info = exe_ctx->GetThreadPtr()->GetStopInfo();
StructuredData::ObjectSP info = stop_info->GetExtendedInfo();
if (!info)
return false;
@@ -311,15 +316,19 @@ SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) {
SBThreadCollection threads;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBThreadCollection();
+ }
- if (!exe_ctx.HasThreadScope())
+ if (!exe_ctx->HasThreadScope())
return SBThreadCollection();
- ProcessSP process_sp = exe_ctx.GetProcessSP();
+ ProcessSP process_sp = exe_ctx->GetProcessSP();
- StopInfoSP stop_info = exe_ctx.GetThreadPtr()->GetStopInfo();
+ StopInfoSP stop_info = exe_ctx->GetThreadPtr()->GetStopInfo();
StructuredData::ObjectSP info = stop_info->GetExtendedInfo();
if (!info)
return threads;
@@ -332,20 +341,20 @@ SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) {
size_t SBThread::GetStopDescription(char *dst, size_t dst_len) {
LLDB_INSTRUMENT_VA(this, dst, dst_len);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
if (dst)
*dst = 0;
- if (!exe_ctx.HasThreadScope())
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
return 0;
+ }
- Process::StopLocker stop_locker;
- if (!stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ if (!exe_ctx->HasThreadScope())
return 0;
- std::string thread_stop_desc = exe_ctx.GetThreadPtr()->GetStopDescription();
+ std::string thread_stop_desc = exe_ctx->GetThreadPtr()->GetStopDescription();
if (thread_stop_desc.empty())
return 0;
@@ -361,16 +370,17 @@ SBValue SBThread::GetStopReturnValue() {
LLDB_INSTRUMENT_VA(this);
ValueObjectSP return_valobj_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBValue();
+ }
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo();
- if (stop_info_sp) {
- return_valobj_sp = StopInfo::GetReturnValueObject(stop_info_sp);
- }
+ if (exe_ctx->HasThreadScope()) {
+ StopInfoSP stop_info_sp = exe_ctx->GetThreadPtr()->GetStopInfo();
+ if (stop_info_sp) {
+ return_valobj_sp = StopInfo::GetReturnValueObject(stop_info_sp);
}
}
@@ -402,47 +412,48 @@ uint32_t SBThread::GetIndexID() const {
const char *SBThread::GetName() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (!exe_ctx.HasThreadScope())
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
return nullptr;
+ }
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
- return ConstString(exe_ctx.GetThreadPtr()->GetName()).GetCString();
+ if (!exe_ctx->HasThreadScope())
+ return nullptr;
- return nullptr;
+ return ConstString(exe_ctx->GetThreadPtr()->GetName()).GetCString();
}
const char *SBThread::GetQueueName() const {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (!exe_ctx.HasThreadScope())
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
return nullptr;
+ }
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
- return ConstString(exe_ctx.GetThreadPtr()->GetQueueName()).GetCString();
+ if (!exe_ctx->HasThreadScope())
+ return nullptr;
- return nullptr;
+ return ConstString(exe_ctx->GetThreadPtr()->GetQueueName()).GetCString();
}
lldb::queue_id_t SBThread::GetQueueID() const {
LLDB_INSTRUMENT_VA(this);
queue_id_t id = LLDB_INVALID_QUEUE_ID;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return id;
+ }
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- id = exe_ctx.GetThreadPtr()->GetQueueID();
- }
+ if (exe_ctx->HasThreadScope()) {
+ id = exe_ctx->GetThreadPtr()->GetQueueID();
}
return id;
@@ -452,13 +463,11 @@ bool SBThread::GetInfoItemByPathAsString(const char *path, SBStream &strm) {
LLDB_INSTRUMENT_VA(this, path, strm);
bool success = false;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- Thread *thread = exe_ctx.GetThreadPtr();
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (exe_ctx) {
+ if (exe_ctx->HasThreadScope()) {
+ Thread *thread = exe_ctx->GetThreadPtr();
StructuredData::ObjectSP info_root_sp = thread->GetExtendedInfo();
if (info_root_sp) {
StructuredData::ObjectSP node =
@@ -490,16 +499,16 @@ bool SBThread::GetInfoItemByPathAsString(const char *path, SBStream &strm) {
}
}
}
+ } else {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return success;
}
return success;
}
-static Status ResumeNewPlan(ExecutionContext &exe_ctx, ThreadPlan *new_plan) {
- Process *process = exe_ctx.GetProcessPtr();
- if (!process)
- return Status::FromErrorString("No process in SBThread::ResumeNewPlan");
-
+static Status ResumeNewPlan(StoppedExecutionContext exe_ctx,
+ ThreadPlan *new_plan) {
Thread *thread = exe_ctx.GetThreadPtr();
if (!thread)
return Status::FromErrorString("No thread in SBThread::ResumeNewPlan");
@@ -512,8 +521,11 @@ static Status ResumeNewPlan(ExecutionContext &exe_ctx, ThreadPlan *new_plan) {
}
// Why do we need to set the current thread by ID here???
+ Process *process = exe_ctx.GetProcessPtr();
process->GetThreadList().SetSelectedThreadByID(thread->GetID());
+ // Release the run lock but keep the API lock.
+ std::unique_lock<std::recursive_mutex> api_lock = exe_ctx.AllowResume();
if (process->GetTarget().GetDebugger().GetAsyncExecution())
return process->Resume();
return process->ResumeSynchronous(nullptr);
@@ -529,15 +541,19 @@ void SBThread::StepOver(lldb::RunMode stop_other_threads) {
void SBThread::StepOver(lldb::RunMode stop_other_threads, SBError &error) {
LLDB_INSTRUMENT_VA(this, stop_other_threads, error);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ error = Status::FromError(exe_ctx.takeError());
+ return;
+ }
- if (!exe_ctx.HasThreadScope()) {
+ if (!exe_ctx->HasThreadScope()) {
error = Status::FromErrorString("this SBThread object is invalid");
return;
}
- Thread *thread = exe_ctx.GetThreadPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
bool abort_other_plans = false;
StackFrameSP frame_sp(thread->GetStackFrameAtIndex(0));
@@ -555,7 +571,7 @@ void SBThread::StepOver(lldb::RunMode stop_other_threads, SBError &error) {
true, abort_other_plans, stop_other_threads, new_plan_status);
}
}
- error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+ error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
}
void SBThread::StepInto(lldb::RunMode stop_other_threads) {
@@ -576,17 +592,21 @@ void SBThread::StepInto(const char *target_name, uint32_t end_line,
SBError &error, lldb::RunMode stop_other_threads) {
LLDB_INSTRUMENT_VA(this, target_name, end_line, error, stop_other_threads);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ error = Status::FromError(exe_ctx.takeError());
+ return;
+ }
- if (!exe_ctx.HasThreadScope()) {
+ if (!exe_ctx->HasThreadScope()) {
error = Status::FromErrorString("this SBThread object is invalid");
return;
}
bool abort_other_plans = false;
- Thread *thread = exe_ctx.GetThreadPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
StackFrameSP frame_sp(thread->GetStackFrameAtIndex(0));
ThreadPlanSP new_plan_sp;
Status new_plan_status;
@@ -618,7 +638,7 @@ void SBThread::StepInto(const char *target_name, uint32_t end_line,
}
if (new_plan_status.Success())
- error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+ error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
else
error = Status::FromErrorString(new_plan_status.AsCString());
}
@@ -633,10 +653,14 @@ void SBThread::StepOut() {
void SBThread::StepOut(SBError &error) {
LLDB_INSTRUMENT_VA(this, error);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ error = Status::FromError(exe_ctx.takeError());
+ return;
+ }
- if (!exe_ctx.HasThreadScope()) {
+ if (!exe_ctx->HasThreadScope()) {
error = Status::FromErrorString("this SBThread object is invalid");
return;
}
@@ -644,7 +668,7 @@ void SBThread::StepOut(SBError &error) {
bool abort_other_plans = false;
bool stop_other_threads = false;
- Thread *thread = exe_ctx.GetThreadPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
const LazyBool avoid_no_debug = eLazyBoolCalculate;
Status new_plan_status;
@@ -653,7 +677,7 @@ void SBThread::StepOut(SBError &error) {
eVoteNoOpinion, 0, new_plan_status, avoid_no_debug));
if (new_plan_status.Success())
- error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+ error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
else
error = Status::FromErrorString(new_plan_status.AsCString());
}
@@ -668,8 +692,12 @@ void SBThread::StepOutOfFrame(SBFrame &sb_frame) {
void SBThread::StepOutOfFrame(SBFrame &sb_frame, SBError &error) {
LLDB_INSTRUMENT_VA(this, sb_frame, error);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ error = Status::FromError(exe_ctx.takeError());
+ return;
+ }
if (!sb_frame.IsValid()) {
error = Status::FromErrorString("passed invalid SBFrame object");
@@ -678,14 +706,14 @@ void SBThread::StepOutOfFrame(SBFrame &sb_frame, SBError &error) {
StackFrameSP frame_sp(sb_frame.GetFrameSP());
- if (!exe_ctx.HasThreadScope()) {
+ if (!exe_ctx->HasThreadScope()) {
error = Status::FromErrorString("this SBThread object is invalid");
return;
}
bool abort_other_plans = false;
bool stop_other_threads = false;
- Thread *thread = exe_ctx.GetThreadPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
if (sb_frame.GetThread().GetThreadID() != thread->GetID()) {
error = Status::FromErrorString("passed a frame from another thread");
return;
@@ -697,7 +725,7 @@ void SBThread::StepOutOfFrame(SBFrame &sb_frame, SBError &error) {
eVoteNoOpinion, frame_sp->GetFrameIndex(), new_plan_status));
if (new_plan_status.Success())
- error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+ error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
else
error = Status::FromErrorString(new_plan_status.AsCString());
}
@@ -712,21 +740,25 @@ void SBThread::StepInstruction(bool step_over) {
void SBThread::StepInstruction(bool step_over, SBError &error) {
LLDB_INSTRUMENT_VA(this, step_over, error);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ error = Status::FromError(exe_ctx.takeError());
+ return;
+ }
- if (!exe_ctx.HasThreadScope()) {
+ if (!exe_ctx->HasThreadScope()) {
error = Status::FromErrorString("this SBThread object is invalid");
return;
}
- Thread *thread = exe_ctx.GetThreadPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
Status new_plan_status;
ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction(
step_over, false, true, new_plan_status));
if (new_plan_status.Success())
- error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+ error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
else
error = Status::FromErrorString(new_plan_status.AsCString());
}
@@ -741,10 +773,14 @@ void SBThread::RunToAddress(lldb::addr_t addr) {
void SBThread::RunToAddress(lldb::addr_t addr, SBError &error) {
LLDB_INSTRUMENT_VA(this, addr, error);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ error = Status::FromError(exe_ctx.takeError());
+ return;
+ }
- if (!exe_ctx.HasThreadScope()) {
+ if (!exe_ctx->HasThreadScope()) {
error = Status::FromErrorString("this SBThread object is invalid");
return;
}
@@ -754,14 +790,14 @@ void SBThread::RunToAddress(lldb::addr_t addr, SBError &error) {
Address target_addr(addr);
- Thread *thread = exe_ctx.GetThreadPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
Status new_plan_status;
ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress(
abort_other_plans, target_addr, stop_other_threads, new_plan_status));
if (new_plan_status.Success())
- error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+ error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
else
error = Status::FromErrorString(new_plan_status.AsCString());
}
@@ -773,14 +809,16 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame,
SBError sb_error;
char path[PATH_MAX];
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx)
+ return Status::FromError(exe_ctx.takeError());
StackFrameSP frame_sp(sb_frame.GetFrameSP());
- if (exe_ctx.HasThreadScope()) {
- Target *target = exe_ctx.GetTargetPtr();
- Thread *thread = exe_ctx.GetThreadPtr();
+ if (exe_ctx->HasThreadScope()) {
+ Target *target = exe_ctx->GetTargetPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
if (line == 0) {
sb_error = Status::FromErrorString("invalid line argument");
@@ -875,7 +913,7 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame,
frame_sp->GetFrameIndex(), new_plan_status));
if (new_plan_status.Success())
- sb_error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+ sb_error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
else
sb_error = Status::FromErrorString(new_plan_status.AsCString());
}
@@ -907,15 +945,17 @@ SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name,
SBError error;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx)
+ return Status::FromError(exe_ctx.takeError());
- if (!exe_ctx.HasThreadScope()) {
+ if (!exe_ctx->HasThreadScope()) {
error = Status::FromErrorString("this SBThread object is invalid");
return error;
}
- Thread *thread = exe_ctx.GetThreadPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
Status new_plan_status;
StructuredData::ObjectSP obj_sp = args_data.m_impl_up->GetObjectSP();
@@ -931,7 +971,7 @@ SBError SBThread::StepUsingScriptedThreadPlan(const char *script_class_name,
return error;
if (new_plan_status.Success())
- error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
+ error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
else
error = Status::FromErrorString(new_plan_status.AsCString());
@@ -943,15 +983,17 @@ SBError SBThread::JumpToLine(lldb::SBFileSpec &file_spec, uint32_t line) {
SBError sb_error;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx)
+ return Status::FromError(exe_ctx.takeError());
- if (!exe_ctx.HasThreadScope()) {
+ if (!exe_ctx->HasThreadScope()) {
sb_error = Status::FromErrorString("this SBThread object is invalid");
return sb_error;
}
- Thread *thread = exe_ctx.GetThreadPtr();
+ Thread *thread = exe_ctx->GetThreadPtr();
Status err = thread->JumpToLine(file_spec.ref(), line, true);
sb_error.SetError(std::move(err));
@@ -963,11 +1005,13 @@ SBError SBThread::ReturnFromFrame(SBFrame &frame, SBValue &return_value) {
SBError sb_error;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx)
+ return Status::FromError(exe_ctx.takeError());
- if (exe_ctx.HasThreadScope()) {
- Thread *thread = exe_ctx.GetThreadPtr();
+ if (exe_ctx->HasThreadScope()) {
+ Thread *thread = exe_ctx->GetThreadPtr();
sb_error.SetError(
thread->ReturnFromFrame(frame.GetFrameSP(), return_value.GetSP()));
}
@@ -980,11 +1024,13 @@ SBError SBThread::UnwindInnermostExpression() {
SBError sb_error;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx)
+ return Status::FromError(exe_ctx.takeError());
- if (exe_ctx.HasThreadScope()) {
- Thread *thread = exe_ctx.GetThreadPtr();
+ if (exe_ctx->HasThreadScope()) {
+ Thread *thread = exe_ctx->GetThreadPtr();
sb_error.SetError(thread->UnwindInnermostExpression());
if (sb_error.Success())
thread->SetSelectedFrameByIndex(0, false);
@@ -1003,18 +1049,17 @@ bool SBThread::Suspend() {
bool SBThread::Suspend(SBError &error) {
LLDB_INSTRUMENT_VA(this, error);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ error = Status::FromError(exe_ctx.takeError());
+ return false;
+ }
bool result = false;
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- exe_ctx.GetThreadPtr()->SetResumeState(eStateSuspended);
- result = true;
- } else {
- error = Status::FromErrorString("process is running");
- }
+ if (exe_ctx->HasThreadScope()) {
+ exe_ctx->GetThreadPtr()->SetResumeState(eStateSuspended);
+ result = true;
} else
error = Status::FromErrorString("this SBThread object is invalid");
return result;
@@ -1030,19 +1075,19 @@ bool SBThread::Resume() {
bool SBThread::Resume(SBError &error) {
LLDB_INSTRUMENT_VA(this, error);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ error = Status::FromErrorString("process is running");
+ return false;
+ }
bool result = false;
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- const bool override_suspend = true;
- exe_ctx.GetThreadPtr()->SetResumeState(eStateRunning, override_suspend);
- result = true;
- } else {
- error = Status::FromErrorString("process is running");
- }
+ if (exe_ctx->HasThreadScope()) {
+ const bool override_suspend = true;
+ exe_ctx->GetThreadPtr()->SetResumeState(eStateRunning, override_suspend);
+ result = true;
} else
error = Status::FromErrorString("this SBThread object is invalid");
return result;
@@ -1051,22 +1096,30 @@ bool SBThread::Resume(SBError &error) {
bool SBThread::IsSuspended() {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
+ }
- if (exe_ctx.HasThreadScope())
- return exe_ctx.GetThreadPtr()->GetResumeState() == eStateSuspended;
+ if (exe_ctx->HasThreadScope())
+ return exe_ctx->GetThreadPtr()->GetResumeState() == eStateSuspended;
return false;
}
bool SBThread::IsStopped() {
LLDB_INSTRUMENT_VA(this);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
+ }
- if (exe_ctx.HasThreadScope())
- return StateIsStoppedState(exe_ctx.GetThreadPtr()->GetState(), true);
+ if (exe_ctx->HasThreadScope())
+ return StateIsStoppedState(exe_ctx->GetThreadPtr()->GetState(), true);
return false;
}
@@ -1074,13 +1127,17 @@ SBProcess SBThread::GetProcess() {
LLDB_INSTRUMENT_VA(this);
SBProcess sb_process;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBProcess();
+ }
- if (exe_ctx.HasThreadScope()) {
+ if (exe_ctx->HasThreadScope()) {
// Have to go up to the target so we can get a shared pointer to our
// process...
- sb_process.SetSP(exe_ctx.GetProcessSP());
+ sb_process.SetSP(exe_ctx->GetProcessSP());
}
return sb_process;
@@ -1089,34 +1146,33 @@ SBProcess SBThread::GetProcess() {
uint32_t SBThread::GetNumFrames() {
LLDB_INSTRUMENT_VA(this);
- uint32_t num_frames = 0;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- num_frames = exe_ctx.GetThreadPtr()->GetStackFrameCount();
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return 0;
}
- return num_frames;
+ if (exe_ctx->HasThreadScope())
+ return exe_ctx->GetThreadPtr()->GetStackFrameCount();
+
+ return 0;
}
SBFrame SBThread::GetFrameAtIndex(uint32_t idx) {
LLDB_INSTRUMENT_VA(this, idx);
SBFrame sb_frame;
- StackFrameSP frame_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBFrame();
+ }
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- frame_sp = exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(idx);
- sb_frame.SetFrameSP(frame_sp);
- }
+ if (exe_ctx->HasThreadScope()) {
+ StackFrameSP frame_sp = exe_ctx->GetThreadPtr()->GetStackFrameAtIndex(idx);
+ sb_frame.SetFrameSP(frame_sp);
}
return sb_frame;
@@ -1126,17 +1182,17 @@ lldb::SBFrame SBThread::GetSelectedFrame() {
LLDB_INSTRUMENT_VA(this);
SBFrame sb_frame;
- StackFrameSP frame_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- frame_sp =
- exe_ctx.GetThreadPtr()->GetSelectedFrame(SelectMostRelevantFrame);
- sb_frame.SetFrameSP(frame_sp);
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBFrame();
+ }
+
+ if (exe_ctx->HasThreadScope()) {
+ StackFrameSP frame_sp =
+ exe_ctx->GetThreadPtr()->GetSelectedFrame(SelectMostRelevantFrame);
+ sb_frame.SetFrameSP(frame_sp);
}
return sb_frame;
@@ -1147,18 +1203,19 @@ lldb::SBFrame SBThread::SetSelectedFrame(uint32_t idx) {
SBFrame sb_frame;
StackFrameSP frame_sp;
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
-
- if (exe_ctx.HasThreadScope()) {
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- Thread *thread = exe_ctx.GetThreadPtr();
- frame_sp = thread->GetStackFrameAtIndex(idx);
- if (frame_sp) {
- thread->SetSelectedFrame(frame_sp.get());
- sb_frame.SetFrameSP(frame_sp);
- }
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBFrame();
+ }
+
+ if (exe_ctx->HasThreadScope()) {
+ Thread *thread = exe_ctx->GetThreadPtr();
+ frame_sp = thread->GetStackFrameAtIndex(idx);
+ if (frame_sp) {
+ thread->SetSelectedFrame(frame_sp.get());
+ sb_frame.SetFrameSP(frame_sp);
}
}
@@ -1202,12 +1259,16 @@ bool SBThread::GetStatus(SBStream &status) const {
Stream &strm = status.ref();
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
+ }
- if (exe_ctx.HasThreadScope()) {
- exe_ctx.GetThreadPtr()->GetStatus(strm, 0, 1, 1, true,
- /*show_hidden=*/true);
+ if (exe_ctx->HasThreadScope()) {
+ exe_ctx->GetThreadPtr()->GetStatus(strm, 0, 1, 1, true,
+ /*show_hidden=*/true);
} else
strm.PutCString("No status");
@@ -1225,11 +1286,15 @@ bool SBThread::GetDescription(SBStream &description, bool stop_format) const {
Stream &strm = description.ref();
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
+ }
- if (exe_ctx.HasThreadScope()) {
- exe_ctx.GetThreadPtr()->DumpUsingSettingsFormat(
+ if (exe_ctx->HasThreadScope()) {
+ exe_ctx->GetThreadPtr()->DumpUsingSettingsFormat(
strm, LLDB_INVALID_THREAD_ID, stop_format);
} else
strm.PutCString("No value");
@@ -1247,11 +1312,15 @@ SBError SBThread::GetDescriptionWithFormat(const SBFormat &format,
return error;
}
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return error;
+ }
- if (exe_ctx.HasThreadScope()) {
- if (exe_ctx.GetThreadPtr()->DumpUsingFormat(
+ if (exe_ctx->HasThreadScope()) {
+ if (exe_ctx->GetThreadPtr()->DumpUsingFormat(
strm, LLDB_INVALID_THREAD_ID, format.GetFormatEntrySP().get())) {
return error;
}
@@ -1267,17 +1336,15 @@ SBError SBThread::GetDescriptionWithFormat(const SBFormat &format,
SBThread SBThread::GetExtendedBacktraceThread(const char *type) {
LLDB_INSTRUMENT_VA(this, type);
- std::unique_lock<std::recursive_mutex> lock;
- ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
SBThread sb_origin_thread;
-
- Process::StopLocker stop_locker;
- if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) {
- if (exe_ctx.HasThreadScope()) {
- ThreadSP real_thread(exe_ctx.GetThreadSP());
+ if (exe_ctx) {
+ if (exe_ctx->HasThreadScope()) {
+ ThreadSP real_thread(exe_ctx->GetThreadSP());
if (real_thread) {
ConstString type_const(type);
- Process *process = exe_ctx.GetProcessPtr();
+ Process *process = exe_ctx->GetProcessPtr();
if (process) {
SystemRuntime *runtime = process->GetSystemRuntime();
if (runtime) {
@@ -1293,6 +1360,8 @@ SBThread SBThread::GetExtendedBacktraceThread(const char *type) {
}
}
}
+ } else {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
}
return sb_origin_thread;
diff --git a/lldb/source/Breakpoint/BreakpointResolver.cpp b/lldb/source/Breakpoint/BreakpointResolver.cpp
index 91fdff4..4ac4050 100644
--- a/lldb/source/Breakpoint/BreakpointResolver.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolver.cpp
@@ -42,9 +42,9 @@ const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",
const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
BreakpointResolver::OptionNames::LastOptionName)] = {
- "AddressOffset", "Exact", "FileName", "Inlines", "Language",
- "LineNumber", "Column", "ModuleName", "NameMask", "Offset",
- "PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth",
+ "AddressOffset", "Exact", "FileName", "Inlines", "Language",
+ "LineNumber", "Column", "ModuleName", "NameMask", "Offset",
+ "PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth",
"SkipPrologue", "SymbolNames"};
const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
@@ -65,8 +65,10 @@ BreakpointResolver::NameToResolverTy(llvm::StringRef name) {
BreakpointResolver::BreakpointResolver(const BreakpointSP &bkpt,
const unsigned char resolverTy,
- lldb::addr_t offset)
- : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {}
+ lldb::addr_t offset,
+ bool offset_is_insn_count)
+ : m_breakpoint(bkpt), m_offset(offset),
+ m_offset_is_insn_count(offset_is_insn_count), SubclassID(resolverTy) {}
BreakpointResolver::~BreakpointResolver() = default;
@@ -364,7 +366,32 @@ void BreakpointResolver::AddLocation(SearchFilter &filter,
BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr,
bool *new_location) {
- loc_addr.Slide(m_offset);
+ if (m_offset_is_insn_count) {
+ Target &target = GetBreakpoint()->GetTarget();
+ llvm::Expected<DisassemblerSP> expected_instructions =
+ target.ReadInstructions(loc_addr, m_offset);
+ if (!expected_instructions) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Breakpoints),
+ expected_instructions.takeError(),
+ "error: Unable to read instructions at address 0x{0:x}",
+ loc_addr.GetLoadAddress(&target));
+ return BreakpointLocationSP();
+ }
+
+ const DisassemblerSP instructions = *expected_instructions;
+ if (!instructions ||
+ instructions->GetInstructionList().GetSize() != m_offset) {
+ LLDB_LOG(GetLog(LLDBLog::Breakpoints),
+ "error: Unable to read {0} instructions at address 0x{1:x}",
+ m_offset, loc_addr.GetLoadAddress(&target));
+ return BreakpointLocationSP();
+ }
+
+ loc_addr.Slide(instructions->GetInstructionList().GetTotalByteSize());
+ } else {
+ loc_addr.Slide(m_offset);
+ }
+
return GetBreakpoint()->AddLocation(loc_addr, new_location);
}
diff --git a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
index 828647c..70360d9 100644
--- a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -133,6 +133,11 @@ Searcher::CallbackReturn BreakpointResolverAddress::SearchCallback(
Address tmp_address;
if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address))
m_addr = tmp_address;
+ else
+ return Searcher::eCallbackReturnStop;
+ } else {
+ // If we didn't find the module, then we can't resolve the address.
+ return Searcher::eCallbackReturnStop;
}
}
diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp
index 21024a4..6372595 100644
--- a/lldb/source/Breakpoint/BreakpointResolverName.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp
@@ -24,11 +24,13 @@
using namespace lldb;
using namespace lldb_private;
-BreakpointResolverName::BreakpointResolverName(const BreakpointSP &bkpt,
- const char *name_cstr, FunctionNameType name_type_mask,
- LanguageType language, Breakpoint::MatchType type, lldb::addr_t offset,
+BreakpointResolverName::BreakpointResolverName(
+ const BreakpointSP &bkpt, const char *name_cstr,
+ FunctionNameType name_type_mask, LanguageType language,
+ Breakpoint::MatchType type, lldb::addr_t offset, bool offset_is_insn_count,
bool skip_prologue)
- : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
+ : BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset,
+ offset_is_insn_count),
m_match_type(type), m_language(language), m_skip_prologue(skip_prologue) {
if (m_match_type == Breakpoint::Regexp) {
m_regex = RegularExpression(name_cstr);
@@ -81,7 +83,7 @@ BreakpointResolverName::BreakpointResolverName(const BreakpointSP &bkpt,
BreakpointResolverName::BreakpointResolverName(
const BreakpointResolverName &rhs)
: BreakpointResolver(rhs.GetBreakpoint(), BreakpointResolver::NameResolver,
- rhs.GetOffset()),
+ rhs.GetOffset(), rhs.GetOffsetIsInsnCount()),
m_lookups(rhs.m_lookups), m_class_name(rhs.m_class_name),
m_regex(rhs.m_regex), m_match_type(rhs.m_match_type),
m_language(rhs.m_language), m_skip_prologue(rhs.m_skip_prologue) {}
@@ -177,7 +179,8 @@ BreakpointResolverSP BreakpointResolverName::CreateFromStructuredData(
std::shared_ptr<BreakpointResolverName> resolver_sp =
std::make_shared<BreakpointResolverName>(
nullptr, names[0].c_str(), name_masks[0], language,
- Breakpoint::MatchType::Exact, offset, skip_prologue);
+ Breakpoint::MatchType::Exact, offset,
+ /*offset_is_insn_count = */ false, skip_prologue);
for (size_t i = 1; i < num_elem; i++) {
resolver_sp->AddNameLookup(ConstString(names[i]), name_masks[i]);
}
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index d7589cc..0d9eb45 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -18,14 +18,11 @@
#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>
@@ -93,7 +90,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
dump_options.SetHideRootName(suppress_result)
.SetExpandPointerTypeFlags(lldb::eTypeIsObjC);
- bool is_po = m_varobj_options.use_objc;
+ bool is_po = m_varobj_options.use_object_desc;
StackFrame *frame = m_exe_ctx.GetFramePtr();
@@ -135,22 +132,27 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
};
// Dump `valobj` according to whether `po` was requested or not.
- auto dump_val_object = [&](ValueObject &valobj) -> Error {
+ auto dump_val_object = [&](ValueObject &valobj) {
if (is_po) {
StreamString temp_result_stream;
- if (Error err = valobj.Dump(temp_result_stream, dump_options))
- return err;
+ if (llvm::Error error = valobj.Dump(temp_result_stream, dump_options)) {
+ result.AppendError(toString(std::move(error)));
+ return;
+ }
llvm::StringRef output = temp_result_stream.GetString();
maybe_add_hint(output);
result.GetOutputStream() << output;
} else {
- if (Error err = valobj.Dump(result.GetOutputStream(), dump_options))
- return err;
+ llvm::Error error =
+ valobj.Dump(result.GetOutputStream(), dump_options);
+ if (error) {
+ result.AppendError(toString(std::move(error)));
+ return;
+ }
}
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
@@ -184,13 +186,8 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
expr);
}
- 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);
+ dump_val_object(*valobj_sp);
+ return;
}
}
@@ -199,14 +196,8 @@ 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()) {
- 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);
+ dump_val_object(*valobj_sp);
+ return;
}
// Third, and lastly, try `expr` as a source expression to evaluate.
@@ -257,12 +248,10 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
result.AppendNoteWithFormatv("ran `expression {0}{1}`", flags, expr);
}
- if (valobj_sp->GetError().GetError() != UserExpression::kNoResult) {
- if (Error err = dump_val_object(*valobj_sp))
- result.SetError(std::move(err));
- } else {
+ if (valobj_sp->GetError().GetError() != UserExpression::kNoResult)
+ dump_val_object(*valobj_sp);
+ else
result.SetStatus(eReturnStatusSuccessFinishNoResult);
- }
if (suppress_result)
if (auto result_var_sp =
diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp
index 70e687e..c0553d2 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -154,6 +154,10 @@ Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
}
} break;
+ case 'v':
+ enable_variable_annotations = true;
+ break;
+
case '\x01':
force = true;
break;
@@ -180,6 +184,7 @@ void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
end_addr = LLDB_INVALID_ADDRESS;
symbol_containing_addr = LLDB_INVALID_ADDRESS;
raw = false;
+ enable_variable_annotations = false;
plugin_name.clear();
Target *target =
@@ -503,8 +508,9 @@ void CommandObjectDisassemble::DoExecute(Args &command,
"\"disassemble\" arguments are specified as options.\n");
const int terminal_width =
GetCommandInterpreter().GetDebugger().GetTerminalWidth();
+ const bool use_color = GetCommandInterpreter().GetDebugger().GetUseColor();
GetOptions()->GenerateOptionUsage(result.GetErrorStream(), *this,
- terminal_width);
+ terminal_width, use_color);
return;
}
@@ -528,6 +534,9 @@ void CommandObjectDisassemble::DoExecute(Args &command,
if (m_options.raw)
options |= Disassembler::eOptionRawOuput;
+ if (m_options.enable_variable_annotations)
+ options |= Disassembler::eOptionVariableAnnotations;
+
llvm::Expected<std::vector<AddressRange>> ranges =
GetRangesForSelectedMode(result);
if (!ranges) {
diff --git a/lldb/source/Commands/CommandObjectDisassemble.h b/lldb/source/Commands/CommandObjectDisassemble.h
index 4fbcd72..eed44ad 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.h
+++ b/lldb/source/Commands/CommandObjectDisassemble.h
@@ -78,6 +78,7 @@ public:
// in SetOptionValue if anything the selects a location is set.
lldb::addr_t symbol_containing_addr = 0;
bool force = false;
+ bool enable_variable_annotations = false;
};
CommandObjectDisassemble(CommandInterpreter &interpreter);
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index c5b9167..197bffe9 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -202,7 +202,7 @@ EvaluateExpressionOptions
CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
const Target &target, const OptionGroupValueObjectDisplay &display_opts) {
EvaluateExpressionOptions options;
- options.SetCoerceToId(display_opts.use_objc);
+ options.SetCoerceToId(display_opts.use_object_desc);
options.SetUnwindOnError(unwind_on_error);
options.SetIgnoreBreakpoints(ignore_breakpoints);
options.SetKeepInMemory(true);
@@ -241,11 +241,11 @@ CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
bool CommandObjectExpression::CommandOptions::ShouldSuppressResult(
const OptionGroupValueObjectDisplay &display_opts) const {
// Explicitly disabling persistent results takes precedence over the
- // m_verbosity/use_objc logic.
+ // m_verbosity/use_object_desc logic.
if (suppress_persistent_result != eLazyBoolCalculate)
return suppress_persistent_result == eLazyBoolYes;
- return display_opts.use_objc &&
+ return display_opts.use_object_desc &&
m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact;
}
@@ -332,7 +332,7 @@ Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
void CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
EvaluateExpressionOptions options;
- options.SetCoerceToId(m_varobj_options.use_objc);
+ options.SetCoerceToId(m_varobj_options.use_object_desc);
options.SetLanguage(m_command_options.language);
options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
options.SetAutoApplyFixIts(false);
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 5692699..7e58a95 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -349,7 +349,8 @@ protected:
command[0].c_str());
m_options.GenerateOptionUsage(
result.GetErrorStream(), *this,
- GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
+ GetCommandInterpreter().GetDebugger().GetUseColor());
return;
}
diff --git a/lldb/source/Commands/CommandObjectProtocolServer.cpp b/lldb/source/Commands/CommandObjectProtocolServer.cpp
index f11e27f..c5ab9e9 100644
--- a/lldb/source/Commands/CommandObjectProtocolServer.cpp
+++ b/lldb/source/Commands/CommandObjectProtocolServer.cpp
@@ -15,6 +15,7 @@
#include "lldb/Utility/UriParser.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/FormatAdapters.h"
+#include <string>
using namespace llvm;
using namespace lldb;
@@ -28,7 +29,7 @@ public:
CommandObjectProtocolServerStart(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "protocol-server start",
"start protocol server",
- "protocol-server start <protocol> <connection>") {
+ "protocol-server start <protocol> [<connection>]") {
AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain);
}
@@ -51,15 +52,13 @@ protected:
return;
}
- if (args.GetArgumentCount() < 2) {
- result.AppendError("no connection specified");
- return;
- }
- llvm::StringRef connection_uri = args.GetArgumentAtIndex(1);
+ std::string connection_uri = "listen://[localhost]:0";
+ if (args.GetArgumentCount() >= 2)
+ connection_uri = args.GetArgumentAtIndex(1);
const char *connection_error =
- "unsupported connection specifier, expected 'accept:///path' or "
- "'listen://[host]:port', got '{0}'.";
+ "unsupported connection specifier, expected 'accept:///path' "
+ "or 'listen://[host]:port', got '{0}'.";
auto uri = lldb_private::URI::Parse(connection_uri);
if (!uri) {
result.AppendErrorWithFormatv(connection_error, connection_uri);
diff --git a/lldb/source/Commands/CommandObjectSettings.cpp b/lldb/source/Commands/CommandObjectSettings.cpp
index 7bbb0dd..126f57c 100644
--- a/lldb/source/Commands/CommandObjectSettings.cpp
+++ b/lldb/source/Commands/CommandObjectSettings.cpp
@@ -237,28 +237,62 @@ private:
};
// CommandObjectSettingsShow -- Show current values
+#define LLDB_OPTIONS_settings_show
+#include "CommandOptions.inc"
class CommandObjectSettingsShow : public CommandObjectParsed {
public:
CommandObjectSettingsShow(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "settings show",
"Show matching debugger settings and their current "
- "values. Defaults to showing all settings.",
- nullptr) {
+ "values. Defaults to showing all settings.") {
AddSimpleArgumentList(eArgTypeSettingVariableName, eArgRepeatOptional);
}
~CommandObjectSettingsShow() override = default;
+ Options *GetOptions() override { return &m_options; }
+
+ class CommandOptions : public Options {
+ public:
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ const int short_option = m_getopt_table[option_idx].val;
+ switch (short_option) {
+ case 'd':
+ m_include_defaults = true;
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+ return {};
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_include_defaults = false;
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return g_settings_show_options;
+ }
+
+ bool m_include_defaults = false;
+ };
+
protected:
void DoExecute(Args &args, CommandReturnObject &result) override {
result.SetStatus(eReturnStatusSuccessFinishResult);
+ uint32_t dump_mask = OptionValue::eDumpGroupValue;
+ if (m_options.m_include_defaults)
+ dump_mask |= OptionValue::eDumpOptionDefaultValue;
+
if (!args.empty()) {
for (const auto &arg : args) {
Status error(GetDebugger().DumpPropertyValue(
- &m_exe_ctx, result.GetOutputStream(), arg.ref(),
- OptionValue::eDumpGroupValue));
+ &m_exe_ctx, result.GetOutputStream(), arg.ref(), dump_mask));
if (error.Success()) {
result.GetOutputStream().EOL();
} else {
@@ -267,9 +301,12 @@ protected:
}
} else {
GetDebugger().DumpAllPropertyValues(&m_exe_ctx, result.GetOutputStream(),
- OptionValue::eDumpGroupValue);
+ dump_mask);
}
}
+
+private:
+ CommandOptions m_options;
};
// CommandObjectSettingsWrite -- Write settings to file
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index dbebbbd..3ae08de 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -4075,7 +4075,8 @@ public:
default:
m_options.GenerateOptionUsage(
result.GetErrorStream(), *this,
- GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
+ GetCommandInterpreter().GetDebugger().GetUseColor());
syntax_error = true;
break;
}
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index acb7410..4a70e55 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -56,6 +56,11 @@ let Command = "settings clear" in {
Desc<"Clear all settings.">;
}
+let Command = "settings show" in {
+ def setshow_defaults : Option<"defaults", "d">,
+ Desc<"Include default values if defined.">;
+}
+
let Command = "breakpoint list" in {
// FIXME: We need to add an "internal" command, and then add this sort of
// thing to it. But I need to see it for now, and don't want to wait.
@@ -79,7 +84,7 @@ let Command = "breakpoint modify" in {
Desc<"Set the number of times this breakpoint is skipped before stopping.">;
def breakpoint_modify_one_shot : Option<"one-shot", "o">, Group<1>,
Arg<"Boolean">,
- Desc<"The breakpoint is deleted the first time it stop causes a stop.">;
+ Desc<"The breakpoint is deleted the first time it causes a stop.">;
def breakpoint_modify_thread_index : Option<"thread-index", "x">, Group<1>,
Arg<"ThreadIndex">, Desc<"The breakpoint stops only for the thread whose "
"index matches this argument.">;
@@ -205,7 +210,7 @@ let Command = "breakpoint set" in {
"identifiers). If not set the target.language setting is used.">;
def breakpoint_set_skip_prologue : Option<"skip-prologue", "K">,
Arg<"Boolean">, Groups<[1,3,4,5,6,7,8,12]>,
- Desc<"sKip the prologue if the breakpoint is at the beginning of a "
+ Desc<"Skip the prologue if the breakpoint is at the beginning of a "
"function. If not set the target.skip-prologue setting is used.">;
def breakpoint_set_breakpoint_name : Option<"breakpoint-name", "N">,
Arg<"BreakpointName">,
@@ -245,9 +250,12 @@ let Command = "breakpoint delete" in {
def breakpoint_delete_dummy_breakpoints : Option<"dummy-breakpoints", "D">,
Group<1>, Desc<"Delete Dummy breakpoints - i.e. breakpoints set before a "
"file is provided, which prime new targets.">;
- def breakpoint_delete_disabled : Option<"disabled", "d">, Group<1>,
- Desc<"Delete all breakpoints which are currently disabled. When using the disabled option "
- "any breakpoints listed on the command line are EXCLUDED from deletion.">;
+ def breakpoint_delete_disabled
+ : Option<"disabled", "d">,
+ Group<1>,
+ Desc<"Delete all breakpoints which are currently disabled. When using "
+ "the disabled option any breakpoints listed on the command line "
+ "are EXCLUDED from deletion.">;
}
let Command = "breakpoint name" in {
@@ -337,8 +345,10 @@ let Command = "disassemble" in {
Desc<"Override the CPU for disassembling.">;
def disassemble_options_features : Option<"features", "Y">, Arg<"CPUFeatures">,
Desc<"Specify additional CPU features for disassembling.">;
- def disassemble_options_arch : Option<"arch", "A">, Arg<"Architecture">,
- Desc<"Specify the architecture to use from cross disassembly.">;
+ def disassemble_options_arch
+ : Option<"arch", "A">,
+ Arg<"Architecture">,
+ Desc<"Specify the architecture to use for cross disassembly.">;
def disassemble_options_start_address : Option<"start-address", "s">,
Groups<[1,2]>, Arg<"AddressOrExpression">, Required,
Desc<"Address at which to start disassembling.">;
@@ -361,6 +371,8 @@ let Command = "disassemble" in {
Desc<"Disassemble function containing this address.">;
def disassemble_options_force : Option<"force", "\\x01">, Groups<[2,3,4,5,7]>,
Desc<"Force disassembly of large functions.">;
+ def disassemble_options_variable : Option<"variable", "v">,
+ Desc<"Enable variable disassembly annotations for this invocation.">;
}
let Command = "diagnostics dump" in {
@@ -441,13 +453,17 @@ let Command = "frame recognizer add" in {
Desc<"Give the name of a Python class to use for this frame recognizer.">;
def frame_recognizer_regex : Option<"regex", "x">,
Desc<"Function name and module name are actually regular expressions.">;
- def frame_recognizer_first_instruction_only : Option<"first-instruction-only", "f">, Arg<"Boolean">,
- Desc<"If true, only apply this recognizer to frames whose PC currently points to the "
- "first instruction of the specified function. If false, the recognizer "
- "will always be applied, regardless of the current position within the specified function. The "
- "implementer should keep in mind that some features, e.g. accessing function argument "
- "values via $arg<N>, are not guaranteed to work reliably in this case, so extra care must "
- "be taken to make the recognizer operate correctly. Defaults to true.">;
+ def frame_recognizer_first_instruction_only
+ : Option<"first-instruction-only", "f">,
+ Arg<"Boolean">,
+ Desc<"If true, only apply this recognizer to frames whose PC currently "
+ "points to the first instruction of the specified function. If "
+ "false, the recognizer will always be applied, regardless of the "
+ "current position within the specified function. The implementer "
+ "should keep in mind that some features, e.g., accessing function "
+ "argument values via $arg<N>, are not guaranteed to work reliably "
+ "in this case, so extra care must be taken to make the recognizer "
+ "operate correctly. Defaults to true.">;
}
let Command = "history" in {
@@ -665,9 +681,10 @@ let Command = "platform process list" in {
def platform_process_list_show_args : Option<"show-args", "A">,
GroupRange<1, 6>,
Desc<"Show process arguments instead of the process executable basename.">;
- def platform_process_list_all_users: Option<"all-users", "x">,
- GroupRange<1,6>,
- Desc<"Show processes matching all user IDs.">;
+ def platform_process_list_all_users
+ : Option<"all-users", "x">,
+ GroupRange<1, 6>,
+ Desc<"Show processes matching all user IDs.">;
def platform_process_list_verbose : Option<"verbose", "v">, GroupRange<1, 6>,
Desc<"Enable verbose output.">;
}
@@ -737,17 +754,31 @@ let Command = "process launch" in {
let Command = "process attach" in {
def process_attach_continue : Option<"continue", "c">,
- Desc<"Immediately continue the process once attached.">;
- def process_attach_plugin : Option<"plugin", "P">, Arg<"Plugin">,
- Desc<"Name of the process plugin you want to use.">;
- def process_attach_pid : Option<"pid", "p">, Group<1>, Arg<"Pid">,
- Desc<"The process ID of an existing process to attach to.">;
- def process_attach_name : Option<"name", "n">, Group<2>, Arg<"ProcessName">,
- Desc<"The name of the process to attach to.">;
- def process_attach_include_existing : Option<"include-existing", "i">,
- Group<2>, Desc<"Include existing processes when doing attach -w.">;
- def process_attach_waitfor : Option<"waitfor", "w">, Group<2>,
- Desc<"Wait for the process with <process-name> to launch.">;
+ Desc<"Immediately ${c}ontinue the process "
+ "once attached.">;
+ def process_attach_plugin : Option<"plugin", "P">,
+ Arg<"Plugin">,
+ Desc<"Name of the process ${p}lugin you "
+ "want to use.">;
+ def process_attach_pid : Option<"pid", "p">,
+ Group<1>,
+ Arg<"Pid">,
+ Desc<"The ${p}rocess ID "
+ "of an existing process to attach to.">;
+ def process_attach_name : Option<"name", "n">,
+ Group<2>,
+ Arg<"ProcessName">,
+ Desc<"The ${n}ame of "
+ "the process to attach to.">;
+ def process_attach_include_existing
+ : Option<"include-existing", "i">,
+ Group<2>,
+ Desc<"${I}nclude existing processes when "
+ "doing attach -w.">;
+ def process_attach_waitfor : Option<"waitfor", "w">,
+ Group<2>,
+ Desc<"${W}ait for the process with "
+ "<process-name> to launch.">;
}
let Command = "process continue" in {
@@ -905,8 +936,11 @@ let Command = "source list" in {
"indicate valid places to set source level breakpoints.">;
def source_list_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
Completion<"SourceFile">, Desc<"The file from which to display source.">;
- def source_list_line : Option<"line", "l">, Group<1>, Arg<"LineNum">,
- Desc<"The line number at which to start the display source.">;
+ def source_list_line
+ : Option<"line", "l">,
+ Group<1>,
+ Arg<"LineNum">,
+ Desc<"The line number at which to start displaying source.">;
def source_list_name : Option<"name", "n">, Group<2>, Arg<"Symbol">,
Completion<"Symbol">,
Desc<"The name of a function whose source to display.">;
@@ -1068,12 +1102,14 @@ let Command = "target stop hook add" in {
def target_stop_hook_add_auto_continue : Option<"auto-continue", "G">,
Arg<"Boolean">, Desc<"The stop-hook will auto-continue after running its"
" commands.">;
- def target_stop_hook_add_at_initial_stop : Option<"at-initial-stop", "I">,
- Arg<"Boolean">, Desc<"Whether the stop-hook will trigger when lldb "
- "initially gains control of the process. For a process launch, this "
- "initial stop may happen very early on - before the loader has run. You "
- "can use this option if you do not want some stop-hooks to run then. "
- "Defaults to true.">;
+ def target_stop_hook_add_at_initial_stop
+ : Option<"at-initial-stop", "I">,
+ Arg<"Boolean">,
+ Desc<"Whether the stop-hook will trigger when lldb "
+ "initially gains control of the process. For a process launch, "
+ "this initial stop may happen very early on - before the loader "
+ "has run. You can use this option if you do not want some "
+ "stop-hooks to run then. Defaults to true.">;
}
let Command = "thread backtrace" in {
@@ -1099,12 +1135,16 @@ let Command = "thread step scope" in {
def thread_step_scope_count : Option<"count", "c">, Group<1>, Arg<"Count">,
Desc<"How many times to perform the stepping operation - currently only "
"supported for step-inst and next-inst.">;
- def thread_step_scope_end_linenumber : Option<"end-linenumber", "e">,
- Group<1>, Arg<"LineNum">, Desc<"The line at which to stop stepping - "
- "defaults to the next line and only supported for step-in and step-over."
- " You can also pass the string 'block' to step to the end of the current"
- " block. This is particularly use in conjunction with --step-target to"
- " step through a complex calling sequence.">;
+ def thread_step_scope_end_linenumber
+ : Option<"end-linenumber", "e">,
+ Group<1>,
+ Arg<"LineNum">,
+ Desc<"The line at which to stop stepping - "
+ "defaults to the next line and only supported for step-in and "
+ "step-over. You can also pass the string 'block' to step to the "
+ "end of the current block. This is particularly useful in "
+ "conjunction with --step-target to step through a complex calling "
+ "sequence.">;
def thread_step_scope_run_mode : Option<"run-mode", "m">, Group<1>,
EnumArg<"RunMode">, Desc<"Determine how to run other "
"threads while stepping the current thread.">;
@@ -1149,9 +1189,13 @@ let Command = "thread jump" in {
Completion<"SourceFile">, Desc<"Specifies the source file to jump to.">;
def thread_jump_line : Option<"line", "l">, Group<1>, Arg<"LineNum">,
Required, Desc<"Specifies the line number to jump to.">;
- def thread_jump_by : Option<"by", "b">, Group<2>, Arg<"Offset">, Required,
- Desc<"Jumps by a relative line offset from the current line,"
- "can be a positive or negative offset">;
+ def thread_jump_by
+ : Option<"by", "b">,
+ Group<2>,
+ Arg<"Offset">,
+ Required,
+ Desc<"Jumps by a relative line offset from the current line, "
+ "can be a positive or negative offset.">;
def thread_jump_address : Option<"address", "a">, Group<3>,
Arg<"AddressOrExpression">, Required, Desc<"Jumps to a specific address.">;
def thread_jump_force : Option<"force", "r">, Groups<[1,2,3]>,
@@ -1373,8 +1417,10 @@ let Command = "type category enable" in {
}
let Command = "type category disable" in {
- def type_category_disable_language : Option<"language", "l">, Arg<"Language">,
- Desc<"Enable the category for this language.">;
+ def type_category_disable_language
+ : Option<"language", "l">,
+ Arg<"Language">,
+ Desc<"Disable the category for this language.">;
}
let Command = "type filter add" in {
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
index 925de2a..f2ed1f7 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -26,7 +26,11 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
@@ -41,6 +45,8 @@
#include "lldb/lldb-private-enumerations.h"
#include "lldb/lldb-private-interfaces.h"
#include "lldb/lldb-private-types.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/TargetParser/Triple.h"
@@ -280,6 +286,127 @@ bool Disassembler::ElideMixedSourceAndDisassemblyLine(
return false;
}
+// For each instruction, this block attempts to resolve in-scope variables
+// and determine if the current PC falls within their
+// DWARF location entry. If so, it prints a simplified annotation using the
+// variable name and its resolved location (e.g., "var = reg; " ).
+//
+// Annotations are only included if the variable has a valid DWARF location
+// entry, and the location string is non-empty after filtering. Decoding
+// errors and DWARF opcodes are intentionally omitted to keep the output
+// concise and user-friendly.
+//
+// The goal is to give users helpful live variable hints alongside the
+// disassembled instruction stream, similar to how debug information
+// enhances source-level debugging.
+std::vector<std::string>
+VariableAnnotator::annotate(Instruction &inst, Target &target,
+ const lldb::ModuleSP &module_sp) {
+ std::vector<std::string> events;
+
+ // If we lost module context, everything becomes <undef>.
+ if (!module_sp) {
+ for (const auto &KV : Live_)
+ events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
+ Live_.clear();
+ return events;
+ }
+
+ // Resolve function/block at this *file* address.
+ SymbolContext sc;
+ const Address &iaddr = inst.GetAddress();
+ const auto mask = eSymbolContextFunction | eSymbolContextBlock;
+ if (!module_sp->ResolveSymbolContextForAddress(iaddr, mask, sc) ||
+ !sc.function) {
+ // No function context: everything dies here.
+ for (const auto &KV : Live_)
+ events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
+ Live_.clear();
+ return events;
+ }
+
+ // Collect in-scope variables for this instruction into Current.
+ VariableList var_list;
+ // Innermost block containing iaddr.
+ if (Block *B = sc.block) {
+ auto filter = [](Variable *v) -> bool { return v && !v->IsArtificial(); };
+ B->AppendVariables(/*can_create*/ true,
+ /*get_parent_variables*/ true,
+ /*stop_if_block_is_inlined_function*/ false,
+ /*filter*/ filter,
+ /*variable_list*/ &var_list);
+ }
+
+ const lldb::addr_t pc_file = iaddr.GetFileAddress();
+ const lldb::addr_t func_file = sc.function->GetAddress().GetFileAddress();
+
+ // ABI from Target (pretty reg names if plugin exists). Safe to be null.
+ lldb::ABISP abi_sp = ABI::FindPlugin(nullptr, target.GetArchitecture());
+ ABI *abi = abi_sp.get();
+
+ llvm::DIDumpOptions opts;
+ opts.ShowAddresses = false;
+ // Prefer "register-only" output when we have an ABI.
+ opts.PrintRegisterOnly = static_cast<bool>(abi_sp);
+
+ llvm::DenseMap<lldb::user_id_t, VarState> Current;
+
+ for (size_t i = 0, e = var_list.GetSize(); i != e; ++i) {
+ lldb::VariableSP v = var_list.GetVariableAtIndex(i);
+ if (!v || v->IsArtificial())
+ continue;
+
+ const char *nm = v->GetName().AsCString();
+ llvm::StringRef name = nm ? nm : "<anon>";
+
+ DWARFExpressionList &exprs = v->LocationExpressionList();
+ if (!exprs.IsValid())
+ continue;
+
+ auto entry_or_err = exprs.GetExpressionEntryAtAddress(func_file, pc_file);
+ if (!entry_or_err)
+ continue;
+
+ auto entry = *entry_or_err;
+
+ StreamString loc_ss;
+ entry.expr->DumpLocation(&loc_ss, eDescriptionLevelBrief, abi, opts);
+
+ llvm::StringRef loc = llvm::StringRef(loc_ss.GetString()).trim();
+ if (loc.empty())
+ continue;
+
+ Current.try_emplace(v->GetID(),
+ VarState{std::string(name), std::string(loc)});
+ }
+
+ // Diff Live_ → Current.
+
+ // 1) Starts/changes: iterate Current and compare with Live_.
+ for (const auto &KV : Current) {
+ auto it = Live_.find(KV.first);
+ if (it == Live_.end()) {
+ // Newly live.
+ events.emplace_back(
+ llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());
+ } else if (it->second.last_loc != KV.second.last_loc) {
+ // Location changed.
+ events.emplace_back(
+ llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());
+ }
+ }
+
+ // 2) Ends: anything that was live but is not in Current becomes <undef>.
+ for (const auto &KV : Live_) {
+ if (!Current.count(KV.first))
+ events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
+ }
+
+ // Commit new state.
+ Live_ = std::move(Current);
+ return events;
+}
+
void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
const ExecutionContext &exe_ctx,
bool mixed_source_and_assembly,
@@ -376,6 +503,7 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
}
}
+ VariableAnnotator annot;
previous_symbol = nullptr;
SourceLine previous_line;
for (size_t i = 0; i < num_instructions_found; ++i) {
@@ -540,10 +668,26 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
const bool show_bytes = (options & eOptionShowBytes) != 0;
const bool show_control_flow_kind =
(options & eOptionShowControlFlowKind) != 0;
- inst->Dump(&strm, max_opcode_byte_size, true, show_bytes,
+
+ StreamString inst_line;
+
+ inst->Dump(&inst_line, max_opcode_byte_size, true, show_bytes,
show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
address_text_size);
+
+ if ((options & eOptionVariableAnnotations) && target_sp) {
+ auto annotations = annot.annotate(*inst, *target_sp, module_sp);
+ if (!annotations.empty()) {
+ const size_t annotation_column = 100;
+ inst_line.FillLastLineToColumn(annotation_column, ' ');
+ inst_line.PutCString("; ");
+ inst_line.PutCString(llvm::join(annotations, ", "));
+ }
+ }
+
+ strm.PutCString(inst_line.GetString());
strm.EOL();
+
} else {
break;
}
@@ -724,9 +868,7 @@ bool Instruction::DumpEmulation(const ArchSpec &arch) {
return false;
}
-bool Instruction::CanSetBreakpoint () {
- return !HasDelaySlot();
-}
+bool Instruction::CanSetBreakpoint() { return !HasDelaySlot(); }
bool Instruction::HasDelaySlot() {
// Default is false.
@@ -1016,6 +1158,16 @@ uint32_t InstructionList::GetMaxOpcocdeByteSize() const {
return max_inst_size;
}
+size_t InstructionList::GetTotalByteSize() const {
+ size_t total_byte_size = 0;
+ collection::const_iterator pos, end;
+ for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end;
+ ++pos) {
+ total_byte_size += (*pos)->GetOpcode().GetByteSize();
+ }
+ return total_byte_size;
+}
+
InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const {
InstructionSP inst_sp;
if (idx < m_instructions.size())
@@ -1063,10 +1215,8 @@ void InstructionList::Append(lldb::InstructionSP &inst_sp) {
m_instructions.push_back(inst_sp);
}
-uint32_t
-InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
- bool ignore_calls,
- bool *found_calls) const {
+uint32_t InstructionList::GetIndexOfNextBranchInstruction(
+ uint32_t start, bool ignore_calls, bool *found_calls) const {
size_t num_instructions = m_instructions.size();
uint32_t next_branch = UINT32_MAX;
diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp
index 4be9f3e..7580b15 100644
--- a/lldb/source/Core/DynamicLoader.cpp
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -211,7 +211,7 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress(
if (uuid.IsValid())
prog_str << uuid.GetAsString();
if (value_is_offset == 0 && value != LLDB_INVALID_ADDRESS) {
- prog_str << "at 0x";
+ prog_str << " at 0x";
prog_str.PutHex64(value);
}
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index ce4db4e..91b9c00 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -556,3 +556,18 @@ void Mangled::Encode(DataEncoder &file, ConstStringTable &strtab) const {
break;
}
}
+
+ConstString Mangled::GetBaseName() const {
+ const auto &demangled_info = GetDemangledInfo();
+ if (!demangled_info.has_value())
+ return {};
+
+ ConstString demangled_name = GetDemangledName();
+ if (!demangled_name)
+ return {};
+
+ const char *name_str = demangled_name.AsCString();
+ const auto &range = demangled_info->BasenameRange;
+ return ConstString(
+ llvm::StringRef(name_str + range.first, range.second - range.first));
+}
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index d5ddc2b..bc63a41 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -755,6 +755,230 @@ size_t ModuleList::GetIndexForModule(const Module *module) const {
}
namespace {
+/// A wrapper around ModuleList for shared modules. Provides fast lookups for
+/// file-based ModuleSpec queries.
+class SharedModuleList {
+public:
+ /// Finds all the modules matching the module_spec, and adds them to \p
+ /// matching_module_list.
+ void FindModules(const ModuleSpec &module_spec,
+ ModuleList &matching_module_list) const {
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ // Try map first for performance - if found, skip expensive full list
+ // search.
+ FindModulesInMap(module_spec, matching_module_list);
+ if (!matching_module_list.IsEmpty())
+ return;
+ m_list.FindModules(module_spec, matching_module_list);
+ // Assert that modules were found in the list but not the map, it's
+ // because the module_spec has no filename or the found module has a
+ // different filename. For example, when searching by UUID and finding a
+ // module with an alias.
+ assert((matching_module_list.IsEmpty() ||
+ module_spec.GetFileSpec().GetFilename().IsEmpty() ||
+ module_spec.GetFileSpec().GetFilename() !=
+ matching_module_list.GetModuleAtIndex(0)
+ ->GetFileSpec()
+ .GetFilename()) &&
+ "Search by name not found in SharedModuleList's map");
+ }
+
+ ModuleSP FindModule(const Module &module) {
+
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ if (ModuleSP result = FindModuleInMap(module))
+ return result;
+ return m_list.FindModule(&module);
+ }
+
+ // UUID searches bypass map since UUIDs aren't indexed by filename.
+ ModuleSP FindModule(const UUID &uuid) const {
+ return m_list.FindModule(uuid);
+ }
+
+ void Append(const ModuleSP &module_sp, bool use_notifier) {
+ if (!module_sp)
+ return;
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ m_list.Append(module_sp, use_notifier);
+ AddToMap(module_sp);
+ }
+
+ size_t RemoveOrphans(bool mandatory) {
+ std::unique_lock<std::recursive_mutex> lock(GetMutex(), std::defer_lock);
+ if (mandatory) {
+ lock.lock();
+ } else {
+ if (!lock.try_lock())
+ return 0;
+ }
+ size_t total_count = 0;
+ size_t run_count;
+ do {
+ // Remove indexed orphans first, then remove non-indexed orphans. This
+ // order is important because the shared count will be different if a
+ // module is indexed or not.
+ run_count = RemoveOrphansFromMapAndList();
+ run_count += m_list.RemoveOrphans(mandatory);
+ total_count += run_count;
+ // Because removing orphans might make new orphans, remove from both
+ // containers until a fixed-point is reached.
+ } while (run_count != 0);
+
+ return total_count;
+ }
+
+ bool Remove(const ModuleSP &module_sp, bool use_notifier = true) {
+ if (!module_sp)
+ return false;
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ RemoveFromMap(*module_sp.get());
+ return m_list.Remove(module_sp, use_notifier);
+ }
+
+ void ReplaceEquivalent(const ModuleSP &module_sp,
+ llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules) {
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ m_list.ReplaceEquivalent(module_sp, old_modules);
+ ReplaceEquivalentInMap(module_sp);
+ }
+
+ bool RemoveIfOrphaned(const Module *module_ptr) {
+ std::lock_guard<std::recursive_mutex> guard(GetMutex());
+ RemoveFromMap(*module_ptr, /*if_orphaned=*/true);
+ return m_list.RemoveIfOrphaned(module_ptr);
+ }
+
+ std::recursive_mutex &GetMutex() const { return m_list.GetMutex(); }
+
+private:
+ ModuleSP FindModuleInMap(const Module &module) const {
+ if (!module.GetFileSpec().GetFilename())
+ return ModuleSP();
+ ConstString name = module.GetFileSpec().GetFilename();
+ auto it = m_name_to_modules.find(name);
+ if (it == m_name_to_modules.end())
+ return ModuleSP();
+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second;
+ for (const ModuleSP &module_sp : vector) {
+ if (module_sp.get() == &module)
+ return module_sp;
+ }
+ return ModuleSP();
+ }
+
+ void FindModulesInMap(const ModuleSpec &module_spec,
+ ModuleList &matching_module_list) const {
+ auto it = m_name_to_modules.find(module_spec.GetFileSpec().GetFilename());
+ if (it == m_name_to_modules.end())
+ return;
+ const llvm::SmallVectorImpl<ModuleSP> &vector = it->second;
+ for (const ModuleSP &module_sp : vector) {
+ if (module_sp->MatchesModuleSpec(module_spec))
+ matching_module_list.Append(module_sp);
+ }
+ }
+
+ void AddToMap(const ModuleSP &module_sp) {
+ ConstString name = module_sp->GetFileSpec().GetFilename();
+ if (name.IsEmpty())
+ return;
+ m_name_to_modules[name].push_back(module_sp);
+ }
+
+ void RemoveFromMap(const Module &module, bool if_orphaned = false) {
+ ConstString name = module.GetFileSpec().GetFilename();
+ if (!m_name_to_modules.contains(name))
+ return;
+ llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
+ for (auto *it = vec.begin(); it != vec.end(); ++it) {
+ if (it->get() == &module) {
+ if (!if_orphaned || it->use_count() == kUseCountOrphaned) {
+ vec.erase(it);
+ break;
+ }
+ }
+ }
+ }
+
+ void ReplaceEquivalentInMap(const ModuleSP &module_sp) {
+ RemoveEquivalentModulesFromMap(module_sp);
+ AddToMap(module_sp);
+ }
+
+ void RemoveEquivalentModulesFromMap(const ModuleSP &module_sp) {
+ ConstString name = module_sp->GetFileSpec().GetFilename();
+ if (name.IsEmpty())
+ return;
+
+ auto it = m_name_to_modules.find(name);
+ if (it == m_name_to_modules.end())
+ return;
+
+ // First remove any equivalent modules. Equivalent modules are modules
+ // whose path, platform path and architecture match.
+ ModuleSpec equivalent_module_spec(module_sp->GetFileSpec(),
+ module_sp->GetArchitecture());
+ equivalent_module_spec.GetPlatformFileSpec() =
+ module_sp->GetPlatformFileSpec();
+
+ llvm::SmallVectorImpl<ModuleSP> &vec = it->second;
+ llvm::erase_if(vec, [&equivalent_module_spec](ModuleSP &element) {
+ return element->MatchesModuleSpec(equivalent_module_spec);
+ });
+ }
+
+ /// Remove orphans from the vector and return the removed modules.
+ ModuleList RemoveOrphansFromVector(llvm::SmallVectorImpl<ModuleSP> &vec) {
+ // remove_if moves the elements that match the condition to the end of the
+ // container, and returns an iterator to the first element that was moved.
+ auto *to_remove_start = llvm::remove_if(vec, [](const ModuleSP &module) {
+ return module.use_count() == kUseCountOrphaned;
+ });
+
+ ModuleList to_remove;
+ for (ModuleSP *it = to_remove_start; it != vec.end(); ++it)
+ to_remove.Append(*it);
+
+ vec.erase(to_remove_start, vec.end());
+ return to_remove;
+ }
+
+ /// Remove orphans that exist in both the map and list. This does not remove
+ /// any orphans that exist exclusively on the list.
+ ///
+ /// The mutex must be locked by the caller.
+ int RemoveOrphansFromMapAndList() {
+ // Modules might hold shared pointers to other modules, so removing one
+ // module might orphan other modules. Keep removing modules until
+ // there are no further modules that can be removed.
+ int remove_count = 0;
+ int previous_remove_count;
+ do {
+ previous_remove_count = remove_count;
+ for (auto &[name, vec] : m_name_to_modules) {
+ if (vec.empty())
+ continue;
+ ModuleList to_remove = RemoveOrphansFromVector(vec);
+ remove_count += to_remove.GetSize();
+ m_list.Remove(to_remove);
+ }
+ // Break when fixed-point is reached.
+ } while (previous_remove_count != remove_count);
+
+ return remove_count;
+ }
+
+ ModuleList m_list;
+
+ /// A hash map from a module's filename to all the modules that share that
+ /// filename, for fast module lookups by name.
+ llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1>> m_name_to_modules;
+
+ /// The use count of a module held only by m_list and m_name_to_modules.
+ static constexpr long kUseCountOrphaned = 2;
+};
+
struct SharedModuleListInfo {
ModuleList module_list;
ModuleListProperties module_list_properties;
diff --git a/lldb/source/Core/ProtocolServer.cpp b/lldb/source/Core/ProtocolServer.cpp
index 41636cd..38668f3 100644
--- a/lldb/source/Core/ProtocolServer.cpp
+++ b/lldb/source/Core/ProtocolServer.cpp
@@ -8,24 +8,29 @@
#include "lldb/Core/ProtocolServer.h"
#include "lldb/Core/PluginManager.h"
+#include "llvm/Support/Error.h"
using namespace lldb_private;
using namespace lldb;
-ProtocolServer *ProtocolServer::GetOrCreate(llvm::StringRef name) {
- static std::mutex g_mutex;
+static std::pair<llvm::StringMap<ProtocolServerUP> &, std::mutex &> Servers() {
static llvm::StringMap<ProtocolServerUP> g_protocol_server_instances;
+ static std::mutex g_mutex;
+ return {g_protocol_server_instances, g_mutex};
+}
+
+ProtocolServer *ProtocolServer::GetOrCreate(llvm::StringRef name) {
+ auto [protocol_server_instances, mutex] = Servers();
- std::lock_guard<std::mutex> guard(g_mutex);
+ std::lock_guard<std::mutex> guard(mutex);
- auto it = g_protocol_server_instances.find(name);
- if (it != g_protocol_server_instances.end())
+ auto it = protocol_server_instances.find(name);
+ if (it != protocol_server_instances.end())
return it->second.get();
if (ProtocolServerCreateInstance create_callback =
PluginManager::GetProtocolCreateCallbackForPluginName(name)) {
- auto pair =
- g_protocol_server_instances.try_emplace(name, create_callback());
+ auto pair = protocol_server_instances.try_emplace(name, create_callback());
return pair.first->second.get();
}
@@ -45,3 +50,18 @@ std::vector<llvm::StringRef> ProtocolServer::GetSupportedProtocols() {
return supported_protocols;
}
+
+llvm::Error ProtocolServer::Terminate() {
+ llvm::Error error = llvm::Error::success();
+
+ auto [protocol_server_instances, mutex] = Servers();
+ std::lock_guard<std::mutex> guard(mutex);
+ for (auto &instance : protocol_server_instances) {
+ if (llvm::Error instance_error = instance.second->Stop())
+ error = llvm::joinErrors(std::move(error), std::move(instance_error));
+ }
+
+ protocol_server_instances.clear();
+
+ return error;
+}
diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp
index 27dcf98..02d9d86 100644
--- a/lldb/source/Core/Section.cpp
+++ b/lldb/source/Core/Section.cpp
@@ -153,6 +153,8 @@ const char *Section::GetTypeAsCString() const {
return "lldb-formatters";
case eSectionTypeSwiftModules:
return "swift-modules";
+ case eSectionTypeWasmName:
+ return "wasm-name";
case eSectionTypeOther:
return "regular";
}
@@ -415,6 +417,7 @@ bool Section::ContainsOnlyDebugInfo() const {
case eSectionTypeCompactUnwind:
case eSectionTypeGoSymtab:
case eSectionTypeAbsoluteAddress:
+ case eSectionTypeWasmName:
case eSectionTypeOther:
// Used for "__dof_cache" in mach-o or ".debug" for COFF which isn't debug
// information that we parse at all. This was causing system files with no
diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
index 028f058..f9e65d3 100644
--- a/lldb/source/Core/Value.cpp
+++ b/lldb/source/Core/Value.cpp
@@ -347,6 +347,9 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
else
data.SetAddressByteSize(sizeof(void *));
+ if (!type_size)
+ return Status::FromErrorString("type does not have a size");
+
uint32_t result_byte_size = *type_size;
if (m_value.GetData(data, result_byte_size))
return error; // Success;
@@ -488,9 +491,11 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
address_type = eAddressTypeHost;
if (exe_ctx) {
- Target *target = exe_ctx->GetTargetPtr();
- if (target) {
- data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ if (Target *target = exe_ctx->GetTargetPtr()) {
+ // Registers are always stored in host endian.
+ data.SetByteOrder(m_context_type == ContextType::RegisterInfo
+ ? endian::InlHostByteOrder()
+ : target->GetArchitecture().GetByteOrder());
data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
break;
}
diff --git a/lldb/source/DataFormatters/DumpValueObjectOptions.cpp b/lldb/source/DataFormatters/DumpValueObjectOptions.cpp
index c343e60..e1df952 100644
--- a/lldb/source/DataFormatters/DumpValueObjectOptions.cpp
+++ b/lldb/source/DataFormatters/DumpValueObjectOptions.cpp
@@ -17,7 +17,7 @@ DumpValueObjectOptions::DumpValueObjectOptions()
: m_summary_sp(), m_root_valobj_name(), m_decl_printing_helper(),
m_child_printing_decider(), m_pointer_as_array(), m_use_synthetic(true),
m_scope_already_checked(false), m_flat_output(false), m_ignore_cap(false),
- m_show_types(false), m_show_location(false), m_use_objc(false),
+ m_show_types(false), m_show_location(false), m_use_object_desc(false),
m_hide_root_type(false), m_hide_root_name(false), m_hide_name(false),
m_hide_value(false), m_run_validator(false),
m_use_type_display_name(true), m_allow_oneliner_mode(true),
@@ -65,8 +65,19 @@ DumpValueObjectOptions &DumpValueObjectOptions::SetShowLocation(bool show) {
return *this;
}
-DumpValueObjectOptions &DumpValueObjectOptions::SetUseObjectiveC(bool use) {
- m_use_objc = use;
+DumpValueObjectOptions &DumpValueObjectOptions::DisableObjectDescription() {
+ // Reset these options to their default values.
+ SetUseObjectDescription(false);
+ SetHideRootType(false);
+ SetHideName(false);
+ SetHideValue(false);
+ SetShowSummary(true);
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetUseObjectDescription(bool use) {
+ m_use_object_desc = use;
return *this;
}
diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
index c2f8bb3..e200511 100644
--- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
@@ -14,9 +14,11 @@
#include "lldb/Target/Target.h"
#include "lldb/Utility/Stream.h"
#include "lldb/ValueObject/ValueObject.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include <cstdint>
#include <memory>
+#include <optional>
using namespace lldb;
using namespace lldb_private;
@@ -69,6 +71,18 @@ void ValueObjectPrinter::Init(
SetupMostSpecializedValue();
}
+static const char *maybeNewline(const std::string &s) {
+ // If the string already ends with a \n don't add another one.
+ if (s.empty() || s.back() != '\n')
+ return "\n";
+ return "";
+}
+
+bool ValueObjectPrinter::ShouldPrintObjectDescription() {
+ return ShouldPrintValueObject() && m_options.m_use_object_desc && !IsNil() &&
+ !IsUninitialized() && !m_options.m_pointer_as_array;
+}
+
llvm::Error ValueObjectPrinter::PrintValueObject() {
// If the incoming ValueObject is in an error state, the best we're going to
// get out of it is its type. But if we don't even have that, just print
@@ -77,6 +91,25 @@ llvm::Error ValueObjectPrinter::PrintValueObject() {
!m_orig_valobj.GetCompilerType().IsValid())
return m_orig_valobj.GetError().ToError();
+ std::optional<std::string> object_desc;
+ if (ShouldPrintObjectDescription()) {
+ // The object description is invoked now, but not printed until after
+ // value/summary. Calling GetObjectDescription at the outset of printing
+ // allows for early discovery of errors. In the case of an error, the value
+ // object is printed normally.
+ llvm::Expected<std::string> object_desc_or_err =
+ GetMostSpecializedValue().GetObjectDescription();
+ if (!object_desc_or_err) {
+ auto error_msg = toString(object_desc_or_err.takeError());
+ *m_stream << "error: " << error_msg << maybeNewline(error_msg);
+
+ // Print the value object directly.
+ m_options.DisableObjectDescription();
+ } else {
+ object_desc = *object_desc_or_err;
+ }
+ }
+
if (ShouldPrintValueObject()) {
PrintLocationIfNeeded();
m_stream->Indent();
@@ -90,8 +123,10 @@ llvm::Error ValueObjectPrinter::PrintValueObject() {
m_val_summary_ok =
PrintValueAndSummaryIfNeeded(value_printed, summary_printed);
- if (m_val_summary_ok)
+ if (m_val_summary_ok) {
+ PrintObjectDescriptionIfNeeded(object_desc);
return PrintChildrenIfNeeded(value_printed, summary_printed);
+ }
m_stream->EOL();
return llvm::Error::success();
@@ -144,24 +179,6 @@ void ValueObjectPrinter::SetupMostSpecializedValue() {
"SetupMostSpecialized value must compute a valid ValueObject");
}
-llvm::Expected<std::string> ValueObjectPrinter::GetDescriptionForDisplay() {
- ValueObject &valobj = GetMostSpecializedValue();
- llvm::Expected<std::string> maybe_str = valobj.GetObjectDescription();
- if (maybe_str)
- return maybe_str;
-
- const char *str = nullptr;
- if (!str)
- str = valobj.GetSummaryAsCString();
- if (!str)
- str = valobj.GetValueAsCString();
-
- if (!str)
- return maybe_str;
- llvm::consumeError(maybe_str.takeError());
- return str;
-}
-
const char *ValueObjectPrinter::GetRootNameForDisplay() {
const char *root_valobj_name =
m_options.m_root_valobj_name.empty()
@@ -468,38 +485,14 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,
return !error_printed;
}
-llvm::Error
-ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
- bool summary_printed) {
- if (ShouldPrintValueObject()) {
- // let's avoid the overly verbose no description error for a nil thing
- if (m_options.m_use_objc && !IsNil() && !IsUninitialized() &&
- (!m_options.m_pointer_as_array)) {
- if (!m_options.m_hide_value || ShouldShowName())
- *m_stream << ' ';
- llvm::Expected<std::string> object_desc =
- (value_printed || summary_printed)
- ? GetMostSpecializedValue().GetObjectDescription()
- : GetDescriptionForDisplay();
- if (!object_desc) {
- // If no value or summary was printed, surface the error.
- if (!value_printed && !summary_printed)
- return object_desc.takeError();
- // Otherwise gently nudge the user that they should have used
- // `p` instead of `po`. Unfortunately we cannot be more direct
- // about this, because we don't actually know what the user did.
- *m_stream << "warning: no object description available\n";
- llvm::consumeError(object_desc.takeError());
- } else {
- *m_stream << *object_desc;
- // If the description already ends with a \n don't add another one.
- if (object_desc->empty() || object_desc->back() != '\n')
- *m_stream << '\n';
- }
- return llvm::Error::success();
- }
- }
- return llvm::Error::success();
+void ValueObjectPrinter::PrintObjectDescriptionIfNeeded(
+ std::optional<std::string> object_desc) {
+ if (!object_desc)
+ return;
+
+ if (!m_options.m_hide_value || ShouldShowName())
+ *m_stream << ' ';
+ *m_stream << *object_desc << maybeNewline(*object_desc);
}
bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {
@@ -524,7 +517,7 @@ bool ValueObjectPrinter::ShouldPrintChildren(
if (m_options.m_pointer_as_array)
return true;
- if (m_options.m_use_objc)
+ if (m_options.m_use_object_desc)
return false;
bool print_children = true;
@@ -819,9 +812,6 @@ bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
bool summary_printed) {
- auto error = PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
- if (error)
- return error;
ValueObject &valobj = GetMostSpecializedValue();
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index ed4e4e4..df56bcf 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -67,7 +67,8 @@ void DWARFExpression::UpdateValue(uint64_t const_value,
}
void DWARFExpression::DumpLocation(Stream *s, lldb::DescriptionLevel level,
- ABI *abi) const {
+ ABI *abi,
+ llvm::DIDumpOptions options) const {
auto *MCRegInfo = abi ? &abi->GetMCRegisterInfo() : nullptr;
auto GetRegName = [&MCRegInfo](uint64_t DwarfRegNum,
bool IsEH) -> llvm::StringRef {
@@ -79,10 +80,9 @@ void DWARFExpression::DumpLocation(Stream *s, lldb::DescriptionLevel level,
return llvm::StringRef(RegName);
return {};
};
- llvm::DIDumpOptions DumpOpts;
- DumpOpts.GetNameForDWARFReg = GetRegName;
+ options.GetNameForDWARFReg = GetRegName;
llvm::DWARFExpression E(m_data.GetAsLLVM(), m_data.GetAddressByteSize());
- llvm::printDwarfExpression(&E, s->AsRawOstream(), DumpOpts, nullptr);
+ llvm::printDwarfExpression(&E, s->AsRawOstream(), options, nullptr);
}
RegisterKind DWARFExpression::GetRegisterKind() const { return m_reg_kind; }
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index e7a26d3..d557084 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -799,7 +799,7 @@ ResolveFunctionCallLabel(const FunctionCallLabel &label,
auto sc_or_err = symbol_file->ResolveFunctionCallLabel(label);
if (!sc_or_err)
return llvm::joinErrors(
- llvm::createStringError("failed to resolve function by UID"),
+ llvm::createStringError("failed to resolve function by UID:"),
sc_or_err.takeError());
SymbolContextList sc_list;
diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp
index 329768d..771a9ab 100644
--- a/lldb/source/Expression/Materializer.cpp
+++ b/lldb/source/Expression/Materializer.cpp
@@ -1377,29 +1377,26 @@ public:
return;
}
- DataExtractor register_data;
-
- if (!reg_value.GetData(register_data)) {
- err = Status::FromErrorStringWithFormat(
- "couldn't get the data for register %s", m_register_info.name);
- return;
- }
-
- if (register_data.GetByteSize() != m_register_info.byte_size) {
+ if (reg_value.GetByteSize() != m_register_info.byte_size) {
err = Status::FromErrorStringWithFormat(
"data for register %s had size %llu but we expected %llu",
- m_register_info.name, (unsigned long long)register_data.GetByteSize(),
+ m_register_info.name, (unsigned long long)reg_value.GetByteSize(),
(unsigned long long)m_register_info.byte_size);
return;
}
- m_register_contents = std::make_shared<DataBufferHeap>(
- register_data.GetDataStart(), register_data.GetByteSize());
+ lldb_private::DataBufferHeap buf(reg_value.GetByteSize(), 0);
+ reg_value.GetAsMemoryData(m_register_info, buf.GetBytes(),
+ buf.GetByteSize(), map.GetByteOrder(), err);
+ if (!err.Success())
+ return;
+
+ m_register_contents = std::make_shared<DataBufferHeap>(buf);
Status write_error;
- map.WriteMemory(load_addr, register_data.GetDataStart(),
- register_data.GetByteSize(), write_error);
+ map.WriteMemory(load_addr, buf.GetBytes(), reg_value.GetByteSize(),
+ write_error);
if (!write_error.Success()) {
err = Status::FromErrorStringWithFormat(
diff --git a/lldb/source/Expression/REPL.cpp b/lldb/source/Expression/REPL.cpp
index e5377d3..92017d2 100644
--- a/lldb/source/Expression/REPL.cpp
+++ b/lldb/source/Expression/REPL.cpp
@@ -321,7 +321,7 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
EvaluateExpressionOptions expr_options = m_expr_options;
- expr_options.SetCoerceToId(m_varobj_options.use_objc);
+ expr_options.SetCoerceToId(m_varobj_options.use_object_desc);
expr_options.SetKeepInMemory(true);
expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
expr_options.SetGenerateDebugInfo(true);
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index b15d72e..c9e8afe 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -7,7 +7,7 @@ if (APPLE AND LLVM_ENABLE_LOCAL_SUBMODULE_VISIBILITY)
endif()
endif()
-if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+if (UNIX AND "${CMAKE_SYSTEM_NAME}" MATCHES "AIX")
add_definitions("-D_ALL_SOURCE")
endif()
diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index 5ed30fb..1fc86c8a 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -10,10 +10,8 @@
#include <iomanip>
#include <optional>
-#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Editline.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/StreamFile.h"
#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/CompletionRequest.h"
@@ -219,20 +217,19 @@ private:
const char *GetHistoryFilePath() {
// Compute the history path lazily.
if (m_path.empty() && m_history && !m_prefix.empty()) {
- llvm::SmallString<128> lldb_history_file;
- FileSystem::Instance().GetHomeDirectory(lldb_history_file);
- llvm::sys::path::append(lldb_history_file, ".lldb");
+ FileSpec lldb_dir = HostInfo::GetUserLLDBDir();
// LLDB stores its history in ~/.lldb/. If for some reason this directory
// isn't writable or cannot be created, history won't be available.
- if (!llvm::sys::fs::create_directory(lldb_history_file)) {
+ if (!llvm::sys::fs::create_directory(lldb_dir.GetPath())) {
#if LLDB_EDITLINE_USE_WCHAR
std::string filename = m_prefix + "-widehistory";
#else
std::string filename = m_prefix + "-history";
#endif
- llvm::sys::path::append(lldb_history_file, filename);
- m_path = std::string(lldb_history_file.str());
+ FileSpec lldb_history_file =
+ lldb_dir.CopyByAppendingPathComponent(filename);
+ m_path = lldb_history_file.GetPath();
}
}
diff --git a/lldb/source/Host/common/HostInfoBase.cpp b/lldb/source/Host/common/HostInfoBase.cpp
index 89dfe4a..a02ac77 100644
--- a/lldb/source/Host/common/HostInfoBase.cpp
+++ b/lldb/source/Host/common/HostInfoBase.cpp
@@ -61,6 +61,10 @@ struct HostInfoBaseFields {
FileSpec m_lldb_clang_resource_dir;
llvm::once_flag m_lldb_system_plugin_dir_once;
FileSpec m_lldb_system_plugin_dir;
+ llvm::once_flag m_lldb_user_home_dir_once;
+ FileSpec m_lldb_user_home_dir;
+ llvm::once_flag m_lldb_user_lldb_dir_once;
+ FileSpec m_lldb_user_lldb_dir;
llvm::once_flag m_lldb_user_plugin_dir_once;
FileSpec m_lldb_user_plugin_dir;
llvm::once_flag m_lldb_process_tmp_dir_once;
@@ -161,6 +165,26 @@ FileSpec HostInfoBase::GetSystemPluginDir() {
return g_fields->m_lldb_system_plugin_dir;
}
+FileSpec HostInfoBase::GetUserHomeDir() {
+ llvm::call_once(g_fields->m_lldb_user_home_dir_once, []() {
+ if (!HostInfo::ComputeUserHomeDirectory(g_fields->m_lldb_user_home_dir))
+ g_fields->m_lldb_user_home_dir = FileSpec();
+ LLDB_LOG(GetLog(LLDBLog::Host), "user home dir -> `{0}`",
+ g_fields->m_lldb_user_home_dir);
+ });
+ return g_fields->m_lldb_user_home_dir;
+}
+
+FileSpec HostInfoBase::GetUserLLDBDir() {
+ llvm::call_once(g_fields->m_lldb_user_lldb_dir_once, []() {
+ if (!HostInfo::ComputeUserLLDBHomeDirectory(g_fields->m_lldb_user_lldb_dir))
+ g_fields->m_lldb_user_lldb_dir = FileSpec();
+ LLDB_LOG(GetLog(LLDBLog::Host), "user lldb home dir -> `{0}`",
+ g_fields->m_lldb_user_lldb_dir);
+ });
+ return g_fields->m_lldb_user_lldb_dir;
+}
+
FileSpec HostInfoBase::GetUserPluginDir() {
llvm::call_once(g_fields->m_lldb_user_plugin_dir_once, []() {
if (!HostInfo::ComputeUserPluginsDirectory(
@@ -316,6 +340,20 @@ bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
return false;
}
+bool HostInfoBase::ComputeUserHomeDirectory(FileSpec &file_spec) {
+ FileSpec temp_file("~");
+ FileSystem::Instance().Resolve(temp_file);
+ file_spec.SetDirectory(temp_file.GetPathAsConstString());
+ return true;
+}
+
+bool HostInfoBase::ComputeUserLLDBHomeDirectory(FileSpec &file_spec) {
+ FileSpec home_dir_spec = GetUserHomeDir();
+ home_dir_spec.AppendPathComponent(".lldb");
+ file_spec.SetDirectory(home_dir_spec.GetPathAsConstString());
+ return true;
+}
+
bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
// TODO(zturner): Figure out how to compute the user plugins directory for
// all platforms.
diff --git a/lldb/source/Host/common/JSONTransport.cpp b/lldb/source/Host/common/JSONTransport.cpp
index 546c12c..c4b42ea 100644
--- a/lldb/source/Host/common/JSONTransport.cpp
+++ b/lldb/source/Host/common/JSONTransport.cpp
@@ -7,171 +7,26 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/JSONTransport.h"
-#include "lldb/Utility/IOObject.h"
-#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
-#include "lldb/Utility/SelectHelper.h"
#include "lldb/Utility/Status.h"
-#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
#include "llvm/Support/raw_ostream.h"
-#include <optional>
#include <string>
-#include <utility>
using namespace llvm;
using namespace lldb;
using namespace lldb_private;
-/// ReadFull attempts to read the specified number of bytes. If EOF is
-/// encountered, an empty string is returned.
-static Expected<std::string>
-ReadFull(IOObject &descriptor, size_t length,
- std::optional<std::chrono::microseconds> timeout = std::nullopt) {
- if (!descriptor.IsValid())
- return llvm::make_error<TransportInvalidError>();
+char TransportUnhandledContentsError::ID;
- bool timeout_supported = true;
- // FIXME: SelectHelper does not work with NativeFile on Win32.
-#if _WIN32
- timeout_supported = descriptor.GetFdType() == IOObject::eFDTypeSocket;
-#endif
+TransportUnhandledContentsError::TransportUnhandledContentsError(
+ std::string unhandled_contents)
+ : m_unhandled_contents(unhandled_contents) {}
- if (timeout && timeout_supported) {
- SelectHelper sh;
- sh.SetTimeout(*timeout);
- sh.FDSetRead(
- reinterpret_cast<lldb::socket_t>(descriptor.GetWaitableHandle()));
- Status status = sh.Select();
- if (status.Fail()) {
- // Convert timeouts into a specific error.
- if (status.GetType() == lldb::eErrorTypePOSIX &&
- status.GetError() == ETIMEDOUT)
- return make_error<TransportTimeoutError>();
- return status.takeError();
- }
- }
-
- std::string data;
- data.resize(length);
- Status status = descriptor.Read(data.data(), length);
- if (status.Fail())
- return status.takeError();
-
- // Read returns '' on EOF.
- if (length == 0)
- return make_error<TransportEOFError>();
-
- // Return the actual number of bytes read.
- return data.substr(0, length);
-}
-
-static Expected<std::string>
-ReadUntil(IOObject &descriptor, StringRef delimiter,
- std::optional<std::chrono::microseconds> timeout = std::nullopt) {
- std::string buffer;
- buffer.reserve(delimiter.size() + 1);
- while (!llvm::StringRef(buffer).ends_with(delimiter)) {
- Expected<std::string> next =
- ReadFull(descriptor, buffer.empty() ? delimiter.size() : 1, timeout);
- if (auto Err = next.takeError())
- return std::move(Err);
- buffer += *next;
- }
- return buffer.substr(0, buffer.size() - delimiter.size());
-}
-
-JSONTransport::JSONTransport(IOObjectSP input, IOObjectSP output)
- : m_input(std::move(input)), m_output(std::move(output)) {}
-
-void JSONTransport::Log(llvm::StringRef message) {
- LLDB_LOG(GetLog(LLDBLog::Host), "{0}", message);
+void TransportUnhandledContentsError::log(llvm::raw_ostream &OS) const {
+ OS << "transport EOF with unhandled contents: '" << m_unhandled_contents
+ << "'";
}
-
-Expected<std::string>
-HTTPDelimitedJSONTransport::ReadImpl(const std::chrono::microseconds &timeout) {
- if (!m_input || !m_input->IsValid())
- return llvm::make_error<TransportInvalidError>();
-
- IOObject *input = m_input.get();
- Expected<std::string> message_header =
- ReadFull(*input, kHeaderContentLength.size(), timeout);
- if (!message_header)
- return message_header.takeError();
- if (*message_header != kHeaderContentLength)
- return createStringError(formatv("expected '{0}' and got '{1}'",
- kHeaderContentLength, *message_header)
- .str());
-
- Expected<std::string> raw_length = ReadUntil(*input, kHeaderSeparator);
- if (!raw_length)
- return handleErrors(raw_length.takeError(),
- [&](const TransportEOFError &E) -> llvm::Error {
- return createStringError(
- "unexpected EOF while reading header separator");
- });
-
- size_t length;
- if (!to_integer(*raw_length, length))
- return createStringError(
- formatv("invalid content length {0}", *raw_length).str());
-
- Expected<std::string> raw_json = ReadFull(*input, length);
- if (!raw_json)
- return handleErrors(
- raw_json.takeError(), [&](const TransportEOFError &E) -> llvm::Error {
- return createStringError("unexpected EOF while reading JSON");
- });
-
- Log(llvm::formatv("--> {0}", *raw_json).str());
-
- return raw_json;
+std::error_code TransportUnhandledContentsError::convertToErrorCode() const {
+ return std::make_error_code(std::errc::bad_message);
}
-
-Error HTTPDelimitedJSONTransport::WriteImpl(const std::string &message) {
- if (!m_output || !m_output->IsValid())
- return llvm::make_error<TransportInvalidError>();
-
- Log(llvm::formatv("<-- {0}", message).str());
-
- std::string Output;
- raw_string_ostream OS(Output);
- OS << kHeaderContentLength << message.length() << kHeaderSeparator << message;
- size_t num_bytes = Output.size();
- return m_output->Write(Output.data(), num_bytes).takeError();
-}
-
-Expected<std::string>
-JSONRPCTransport::ReadImpl(const std::chrono::microseconds &timeout) {
- if (!m_input || !m_input->IsValid())
- return make_error<TransportInvalidError>();
-
- IOObject *input = m_input.get();
- Expected<std::string> raw_json =
- ReadUntil(*input, kMessageSeparator, timeout);
- if (!raw_json)
- return raw_json.takeError();
-
- Log(llvm::formatv("--> {0}", *raw_json).str());
-
- return *raw_json;
-}
-
-Error JSONRPCTransport::WriteImpl(const std::string &message) {
- if (!m_output || !m_output->IsValid())
- return llvm::make_error<TransportInvalidError>();
-
- Log(llvm::formatv("<-- {0}", message).str());
-
- std::string Output;
- llvm::raw_string_ostream OS(Output);
- OS << message << kMessageSeparator;
- size_t num_bytes = Output.size();
- return m_output->Write(Output.data(), num_bytes).takeError();
-}
-
-char TransportEOFError::ID;
-char TransportTimeoutError::ID;
-char TransportInvalidError::ID;
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index 61f9419..79e1322 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -39,7 +39,7 @@
#include <Foundation/Foundation.h>
#include <mach-o/dyld.h>
#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
- MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_0
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_0
#if __has_include(<mach-o/dyld_introspection.h>)
#include <mach-o/dyld_introspection.h>
#define SDK_HAS_NEW_DYLD_INTROSPECTION_SPIS
@@ -78,8 +78,8 @@ std::optional<std::string> HostInfoMacOSX::GetOSBuildString() {
static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) {
@autoreleasepool {
NSDictionary *version_info =
- [NSDictionary dictionaryWithContentsOfFile:
- @"/System/Library/CoreServices/SystemVersion.plist"];
+ [NSDictionary dictionaryWithContentsOfFile:
+ @"/System/Library/CoreServices/SystemVersion.plist"];
NSString *version_value = [version_info objectForKey: Key];
const char *version_str = [version_value UTF8String];
version.tryParse(version_str);
@@ -225,9 +225,9 @@ bool HostInfoMacOSX::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
}
bool HostInfoMacOSX::ComputeUserPluginsDirectory(FileSpec &file_spec) {
- FileSpec temp_file("~/Library/Application Support/LLDB/PlugIns");
- FileSystem::Instance().Resolve(temp_file);
- file_spec.SetDirectory(temp_file.GetPathAsConstString());
+ FileSpec home_dir_spec = GetUserHomeDir();
+ home_dir_spec.AppendPathComponent("Library/Application Support/LLDB/PlugIns");
+ file_spec.SetDirectory(home_dir_spec.GetPathAsConstString());
return true;
}
diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp
index 4e747f7..4277b8e 100644
--- a/lldb/source/Host/windows/Host.cpp
+++ b/lldb/source/Host/windows/Host.cpp
@@ -22,6 +22,7 @@
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ManagedStatic.h"
@@ -32,6 +33,8 @@
using namespace lldb;
using namespace lldb_private;
+using llvm::sys::windows::UTF8ToUTF16;
+
static bool GetTripleForProcess(const FileSpec &executable,
llvm::Triple &triple) {
// Open the PE File as a binary file, and parse just enough information to
@@ -325,31 +328,18 @@ private:
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) {
+ if (message.empty())
+ return;
+
HANDLE h = event_log->GetHandle();
if (!h)
return;
- std::wstring wide_message = AnsiToUtf16(message.str());
- if (wide_message.empty())
+ llvm::SmallVector<wchar_t, 1> argsUTF16;
+ if (UTF8ToUTF16(message.str(), argsUTF16))
return;
- LPCWSTR msg_ptr = wide_message.c_str();
-
WORD event_type;
switch (severity) {
case lldb::eSeverityWarning:
@@ -363,5 +353,7 @@ void Host::SystemLog(Severity severity, llvm::StringRef message) {
event_type = EVENTLOG_INFORMATION_TYPE;
}
- ReportEventW(h, event_type, 0, 0, nullptr, 1, 0, &msg_ptr, nullptr);
+ LPCWSTR messages[1] = {argsUTF16.data()};
+ ReportEventW(h, event_type, 0, 0, nullptr, std::size(messages), 0, messages,
+ nullptr);
}
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index a0080cf..d06e8c3 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -52,6 +52,7 @@
#include "lldb/Core/Telemetry.h"
#include "lldb/Host/StreamFile.h"
#include "lldb/Utility/ErrorMessages.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/State.h"
@@ -335,7 +336,7 @@ void CommandInterpreter::Initialize() {
AddAlias("ni", cmd_obj_sp);
}
- cmd_obj_sp = GetCommandSPExact("thread step-in");
+ cmd_obj_sp = GetCommandSPExact("_regexp-step");
if (cmd_obj_sp) {
AddAlias("s", cmd_obj_sp);
AddAlias("step", cmd_obj_sp);
@@ -946,6 +947,27 @@ void CommandInterpreter::LoadCommandDictionary() {
jump_regex_cmd_sp;
}
}
+
+ std::shared_ptr<CommandObjectRegexCommand> step_regex_cmd_sp(
+ new CommandObjectRegexCommand(
+ *this, "_regexp-step",
+ "Single step, optionally to a specific function.",
+ "\n"
+ "_regexp-step // Single step\n"
+ "_regexp-step <function-name> // Step into the named function\n",
+ 0, false));
+ if (step_regex_cmd_sp) {
+ if (step_regex_cmd_sp->AddRegexCommand("^[[:space:]]*$",
+ "thread step-in") &&
+ step_regex_cmd_sp->AddRegexCommand("^[[:space:]]*(-.+)$",
+ "thread step-in %1") &&
+ step_regex_cmd_sp->AddRegexCommand(
+ "^[[:space:]]*(.+)[[:space:]]*$",
+ "thread step-in --end-linenumber block --step-in-target %1")) {
+ m_command_dict[std::string(step_regex_cmd_sp->GetCommandName())] =
+ step_regex_cmd_sp;
+ }
+ }
}
int CommandInterpreter::GetCommandNamesMatchingPartialString(
@@ -2481,22 +2503,18 @@ int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
return position;
}
-static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
- llvm::StringRef suffix = {}) {
+static void GetHomeInitFile(FileSpec &init_file, llvm::StringRef suffix = {}) {
std::string init_file_name = ".lldbinit";
if (!suffix.empty()) {
init_file_name.append("-");
init_file_name.append(suffix.str());
}
- FileSystem::Instance().GetHomeDirectory(init_file);
- llvm::sys::path::append(init_file, init_file_name);
-
- FileSystem::Instance().Resolve(init_file);
+ init_file =
+ HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(init_file_name);
}
-static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
- LanguageType language) {
+static void GetHomeREPLInitFile(FileSpec &init_file, LanguageType language) {
if (language == eLanguageTypeUnknown) {
LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
if (auto main_repl_language = repl_languages.GetSingularLanguage())
@@ -2510,9 +2528,9 @@ static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
llvm::Twine(Language::GetNameForLanguageType(language)) +
llvm::Twine("-repl"))
.str();
- FileSystem::Instance().GetHomeDirectory(init_file);
- llvm::sys::path::append(init_file, init_file_name);
- FileSystem::Instance().Resolve(init_file);
+
+ init_file =
+ HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(init_file_name);
}
static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
@@ -2567,10 +2585,10 @@ void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
SourceInitFile(FileSpec(init_file.str()), result);
break;
case eLoadCWDlldbinitWarn: {
- llvm::SmallString<128> home_init_file;
+ FileSpec home_init_file;
GetHomeInitFile(home_init_file);
if (llvm::sys::path::parent_path(init_file) ==
- llvm::sys::path::parent_path(home_init_file)) {
+ llvm::sys::path::parent_path(home_init_file.GetPath())) {
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else {
result.AppendError(InitFileWarning);
@@ -2590,24 +2608,24 @@ void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result,
return;
}
- llvm::SmallString<128> init_file;
+ FileSpec init_file;
if (is_repl)
GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
- if (init_file.empty())
+ if (init_file.GetPath().empty())
GetHomeInitFile(init_file);
if (!m_skip_app_init_files) {
llvm::StringRef program_name =
HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
- llvm::SmallString<128> program_init_file;
+ FileSpec program_init_file;
GetHomeInitFile(program_init_file, program_name);
if (FileSystem::Instance().Exists(program_init_file))
init_file = program_init_file;
}
- SourceInitFile(FileSpec(init_file.str()), result);
+ SourceInitFile(init_file, result);
}
void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) {
diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp
index 129646e..43e19b3 100644
--- a/lldb/source/Interpreter/CommandObject.cpp
+++ b/lldb/source/Interpreter/CommandObject.cpp
@@ -359,7 +359,8 @@ bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word,
StreamString usage_help;
GetOptions()->GenerateOptionUsage(
usage_help, *this,
- GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
+ GetCommandInterpreter().GetDebugger().GetUseColor());
if (!usage_help.Empty()) {
llvm::StringRef usage_text = usage_help.GetString();
if (usage_text.contains_insensitive(search_word))
@@ -672,7 +673,8 @@ void CommandObject::GenerateHelpText(Stream &output_strm) {
if (options != nullptr) {
options->GenerateOptionUsage(
output_strm, *this,
- GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
+ GetCommandInterpreter().GetDebugger().GetUseColor());
}
llvm::StringRef long_help = GetHelpLong();
if (!long_help.empty()) {
diff --git a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
index d633c46..1939d79 100644
--- a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
+++ b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp
@@ -90,7 +90,7 @@ Status OptionGroupValueObjectDisplay::SetOptionValue(
flat_output = true;
break;
case 'O':
- use_objc = true;
+ use_object_desc = true;
break;
case 'R':
be_raw = true;
@@ -163,7 +163,7 @@ void OptionGroupValueObjectDisplay::OptionParsingStarting(
no_summary_depth = 0;
show_location = false;
flat_output = false;
- use_objc = false;
+ use_object_desc = false;
max_depth = UINT32_MAX;
max_depth_is_default = true;
ptr_depth = 0;
@@ -191,14 +191,14 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
lldb::Format format, lldb::TypeSummaryImplSP summary_sp) {
DumpValueObjectOptions options;
options.SetMaximumPointerDepth(ptr_depth);
- if (use_objc)
+ if (use_object_desc)
options.SetShowSummary(false);
else
options.SetOmitSummaryDepth(no_summary_depth);
options.SetMaximumDepth(max_depth, max_depth_is_default)
.SetShowTypes(show_types)
.SetShowLocation(show_location)
- .SetUseObjectiveC(use_objc)
+ .SetUseObjectDescription(use_object_desc)
.SetUseDynamicType(use_dynamic)
.SetUseSyntheticValue(use_synth)
.SetFlatOutput(flat_output)
@@ -208,8 +208,9 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions(
if (lang_descr_verbosity ==
eLanguageRuntimeDescriptionDisplayVerbosityCompact)
- options.SetHideRootType(use_objc).SetHideName(use_objc).SetHideValue(
- use_objc);
+ options.SetHideRootType(use_object_desc)
+ .SetHideName(use_object_desc)
+ .SetHideValue(use_object_desc);
if (be_raw)
options.SetRawDisplay();
diff --git a/lldb/source/Interpreter/OptionValueArch.cpp b/lldb/source/Interpreter/OptionValueArch.cpp
index ea15cca..a960e39 100644
--- a/lldb/source/Interpreter/OptionValueArch.cpp
+++ b/lldb/source/Interpreter/OptionValueArch.cpp
@@ -11,6 +11,7 @@
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/State.h"
@@ -30,6 +31,12 @@ void OptionValueArch::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
if (arch_name)
strm.PutCString(arch_name);
}
+
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value && m_default_value.IsValid()) {
+ DefaultValueFormat label(strm);
+ strm.PutCString(m_default_value.GetArchitectureName());
+ }
}
}
diff --git a/lldb/source/Interpreter/OptionValueArray.cpp b/lldb/source/Interpreter/OptionValueArray.cpp
index f6c14de..5600333 100644
--- a/lldb/source/Interpreter/OptionValueArray.cpp
+++ b/lldb/source/Interpreter/OptionValueArray.cpp
@@ -8,6 +8,7 @@
#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/Stream.h"
@@ -27,8 +28,15 @@ void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
if (dump_mask & eDumpOptionValue) {
const bool one_line = dump_mask & eDumpOptionCommand;
const uint32_t size = m_values.size();
- if (dump_mask & eDumpOptionType)
- strm.Printf(" =%s", (m_values.size() > 0 && !one_line) ? "\n" : "");
+ if (dump_mask & (eDumpOptionType | eDumpOptionDefaultValue)) {
+ strm.PutCString(" =");
+ if (dump_mask & eDumpOptionDefaultValue && !m_values.empty()) {
+ DefaultValueFormat label(strm);
+ strm.PutCString("empty");
+ }
+ if (!m_values.empty() && !one_line)
+ strm.PutCString("\n");
+ }
if (!one_line)
strm.IndentMore();
for (uint32_t i = 0; i < size; ++i) {
diff --git a/lldb/source/Interpreter/OptionValueBoolean.cpp b/lldb/source/Interpreter/OptionValueBoolean.cpp
index d4fda76..023c243 100644
--- a/lldb/source/Interpreter/OptionValueBoolean.cpp
+++ b/lldb/source/Interpreter/OptionValueBoolean.cpp
@@ -10,6 +10,7 @@
#include "lldb/Host/PosixApi.h"
#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StringList.h"
#include "llvm/ADT/STLExtras.h"
@@ -27,6 +28,11 @@ void OptionValueBoolean::DumpValue(const ExecutionContext *exe_ctx,
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
strm.PutCString(m_current_value ? "true" : "false");
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value) {
+ DefaultValueFormat label(strm);
+ strm.PutCString(m_default_value ? "true" : "false");
+ }
}
}
diff --git a/lldb/source/Interpreter/OptionValueChar.cpp b/lldb/source/Interpreter/OptionValueChar.cpp
index 2aadcff..595dcba 100644
--- a/lldb/source/Interpreter/OptionValueChar.cpp
+++ b/lldb/source/Interpreter/OptionValueChar.cpp
@@ -9,6 +9,7 @@
#include "lldb/Interpreter/OptionValueChar.h"
#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StringList.h"
#include "llvm/ADT/STLExtras.h"
@@ -16,6 +17,13 @@
using namespace lldb;
using namespace lldb_private;
+static void DumpChar(Stream &strm, char value) {
+ if (value != '\0')
+ strm.PutChar(value);
+ else
+ strm.PutCString("(null)");
+}
+
void OptionValueChar::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) {
if (dump_mask & eDumpOptionType)
@@ -24,10 +32,12 @@ void OptionValueChar::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
if (dump_mask & eDumpOptionValue) {
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
- if (m_current_value != '\0')
- strm.PutChar(m_current_value);
- else
- strm.PutCString("(null)");
+ DumpChar(strm, m_current_value);
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value) {
+ DefaultValueFormat label(strm);
+ DumpChar(strm, m_default_value);
+ }
}
}
diff --git a/lldb/source/Interpreter/OptionValueDictionary.cpp b/lldb/source/Interpreter/OptionValueDictionary.cpp
index 19e21dd..0efc76b 100644
--- a/lldb/source/Interpreter/OptionValueDictionary.cpp
+++ b/lldb/source/Interpreter/OptionValueDictionary.cpp
@@ -9,6 +9,7 @@
#include "lldb/Interpreter/OptionValueDictionary.h"
#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Interpreter/OptionValueEnumeration.h"
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Utility/Args.h"
@@ -30,8 +31,13 @@ void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
}
if (dump_mask & eDumpOptionValue) {
const bool one_line = dump_mask & eDumpOptionCommand;
- if (dump_mask & eDumpOptionType)
+ if (dump_mask & (eDumpOptionType | eDumpOptionDefaultValue)) {
strm.PutCString(" =");
+ if (dump_mask & eDumpOptionDefaultValue && !m_values.empty()) {
+ DefaultValueFormat label(strm);
+ strm.PutCString("empty");
+ }
+ }
if (!one_line)
strm.IndentMore();
diff --git a/lldb/source/Interpreter/OptionValueEnumeration.cpp b/lldb/source/Interpreter/OptionValueEnumeration.cpp
index cf64623..eb31bde 100644
--- a/lldb/source/Interpreter/OptionValueEnumeration.cpp
+++ b/lldb/source/Interpreter/OptionValueEnumeration.cpp
@@ -8,6 +8,7 @@
#include "lldb/Interpreter/OptionValueEnumeration.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/StringList.h"
using namespace lldb;
@@ -19,6 +20,17 @@ OptionValueEnumeration::OptionValueEnumeration(
SetEnumerations(enumerators);
}
+void OptionValueEnumeration::DumpEnum(Stream &strm, enum_type value) {
+ const size_t count = m_enumerations.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ if (m_enumerations.GetValueAtIndexUnchecked(i).value == value) {
+ strm.PutCString(m_enumerations.GetCStringAtIndex(i));
+ return;
+ }
+
+ strm.Printf("%" PRIu64, (uint64_t)value);
+}
+
void OptionValueEnumeration::DumpValue(const ExecutionContext *exe_ctx,
Stream &strm, uint32_t dump_mask) {
if (dump_mask & eDumpOptionType)
@@ -26,14 +38,12 @@ void OptionValueEnumeration::DumpValue(const ExecutionContext *exe_ctx,
if (dump_mask & eDumpOptionValue) {
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
- const size_t count = m_enumerations.GetSize();
- for (size_t i = 0; i < count; ++i) {
- if (m_enumerations.GetValueAtIndexUnchecked(i).value == m_current_value) {
- strm.PutCString(m_enumerations.GetCStringAtIndex(i).GetStringRef());
- return;
- }
+ DumpEnum(strm, m_current_value);
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value) {
+ DefaultValueFormat label(strm);
+ DumpEnum(strm, m_default_value);
}
- strm.Printf("%" PRIu64, (uint64_t)m_current_value);
}
}
diff --git a/lldb/source/Interpreter/OptionValueFileSpec.cpp b/lldb/source/Interpreter/OptionValueFileSpec.cpp
index 6fa6af4..8d4966d 100644
--- a/lldb/source/Interpreter/OptionValueFileSpec.cpp
+++ b/lldb/source/Interpreter/OptionValueFileSpec.cpp
@@ -12,6 +12,7 @@
#include "lldb/Host/FileSystem.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/State.h"
@@ -41,7 +42,12 @@ void OptionValueFileSpec::DumpValue(const ExecutionContext *exe_ctx,
strm.PutCString(" = ");
if (m_current_value) {
- strm << '"' << m_current_value.GetPath().c_str() << '"';
+ strm << '"' << m_current_value.GetPath() << '"';
+ }
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value && m_default_value) {
+ DefaultValueFormat label(strm);
+ strm << '"' << m_default_value.GetPath() << '"';
}
}
}
diff --git a/lldb/source/Interpreter/OptionValueFileSpecList.cpp b/lldb/source/Interpreter/OptionValueFileSpecList.cpp
index f252dc4..f331c5d 100644
--- a/lldb/source/Interpreter/OptionValueFileSpecList.cpp
+++ b/lldb/source/Interpreter/OptionValueFileSpecList.cpp
@@ -8,6 +8,7 @@
#include "lldb/Interpreter/OptionValueFileSpecList.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/Stream.h"
@@ -22,9 +23,15 @@ void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx,
if (dump_mask & eDumpOptionValue) {
const bool one_line = dump_mask & eDumpOptionCommand;
const uint32_t size = m_current_value.GetSize();
- if (dump_mask & eDumpOptionType)
- strm.Printf(" =%s",
- (m_current_value.GetSize() > 0 && !one_line) ? "\n" : "");
+ if (dump_mask & (eDumpOptionType | eDumpOptionDefaultValue)) {
+ strm.Printf(" =");
+ if (dump_mask & eDumpOptionDefaultValue && !m_current_value.IsEmpty()) {
+ DefaultValueFormat label(strm);
+ strm.PutCString("empty");
+ }
+ if (!m_current_value.IsEmpty() && !one_line)
+ strm.PutCString("\n");
+ }
if (!one_line)
strm.IndentMore();
for (uint32_t i = 0; i < size; ++i) {
diff --git a/lldb/source/Interpreter/OptionValueFormat.cpp b/lldb/source/Interpreter/OptionValueFormat.cpp
index bc4e779..05990fb 100644
--- a/lldb/source/Interpreter/OptionValueFormat.cpp
+++ b/lldb/source/Interpreter/OptionValueFormat.cpp
@@ -10,6 +10,7 @@
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
@@ -23,6 +24,11 @@ void OptionValueFormat::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
strm.PutCString(FormatManager::GetFormatAsCString(m_current_value));
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value) {
+ DefaultValueFormat label(strm);
+ strm.PutCString(FormatManager::GetFormatAsCString(m_default_value));
+ }
}
}
diff --git a/lldb/source/Interpreter/OptionValueFormatEntity.cpp b/lldb/source/Interpreter/OptionValueFormatEntity.cpp
index d8b8301..b31dd4e 100644
--- a/lldb/source/Interpreter/OptionValueFormatEntity.cpp
+++ b/lldb/source/Interpreter/OptionValueFormatEntity.cpp
@@ -10,6 +10,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StringList.h"
using namespace lldb;
@@ -33,10 +34,9 @@ void OptionValueFormatEntity::Clear() {
m_value_was_set = false;
}
-static void EscapeBackticks(llvm::StringRef str, std::string &dst) {
- dst.clear();
+static std::string EscapeBackticks(llvm::StringRef str) {
+ std::string dst;
dst.reserve(str.size());
-
for (size_t i = 0, e = str.size(); i != e; ++i) {
char c = str[i];
if (c == '`') {
@@ -45,6 +45,7 @@ static void EscapeBackticks(llvm::StringRef str, std::string &dst) {
}
dst += c;
}
+ return dst;
}
void OptionValueFormatEntity::DumpValue(const ExecutionContext *exe_ctx,
@@ -54,17 +55,18 @@ void OptionValueFormatEntity::DumpValue(const ExecutionContext *exe_ctx,
if (dump_mask & eDumpOptionValue) {
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
- std::string escaped;
- EscapeBackticks(m_current_format, escaped);
- strm << '"' << escaped << '"';
+ strm << '"' << EscapeBackticks(m_current_format) << '"';
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_format != m_default_format) {
+ DefaultValueFormat label(strm);
+ strm << '"' << EscapeBackticks(m_default_format) << '"';
+ }
}
}
llvm::json::Value
OptionValueFormatEntity::ToJSON(const ExecutionContext *exe_ctx) const {
- std::string escaped;
- EscapeBackticks(m_current_format, escaped);
- return escaped;
+ return EscapeBackticks(m_current_format);
}
Status OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str,
diff --git a/lldb/source/Interpreter/OptionValueLanguage.cpp b/lldb/source/Interpreter/OptionValueLanguage.cpp
index 0fdaacb..bb28dc8 100644
--- a/lldb/source/Interpreter/OptionValueLanguage.cpp
+++ b/lldb/source/Interpreter/OptionValueLanguage.cpp
@@ -9,8 +9,9 @@
#include "lldb/Interpreter/OptionValueLanguage.h"
#include "lldb/DataFormatters/FormatManager.h"
-#include "lldb/Target/Language.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Target/Language.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/Stream.h"
@@ -26,6 +27,12 @@ void OptionValueLanguage::DumpValue(const ExecutionContext *exe_ctx,
strm.PutCString(" = ");
if (m_current_value != eLanguageTypeUnknown)
strm.PutCString(Language::GetNameForLanguageType(m_current_value));
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value &&
+ m_default_value != eLanguageTypeUnknown) {
+ DefaultValueFormat label(strm);
+ strm.PutCString(Language::GetNameForLanguageType(m_default_value));
+ }
}
}
diff --git a/lldb/source/Interpreter/OptionValuePathMappings.cpp b/lldb/source/Interpreter/OptionValuePathMappings.cpp
index 95b8e64..abf4d42 100644
--- a/lldb/source/Interpreter/OptionValuePathMappings.cpp
+++ b/lldb/source/Interpreter/OptionValuePathMappings.cpp
@@ -9,6 +9,7 @@
#include "lldb/Interpreter/OptionValuePathMappings.h"
#include "lldb/Host/FileSystem.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Stream.h"
@@ -28,8 +29,15 @@ void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
if (dump_mask & eDumpOptionType)
strm.Printf("(%s)", GetTypeAsCString());
if (dump_mask & eDumpOptionValue) {
- if (dump_mask & eDumpOptionType)
- strm.Printf(" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
+ if (dump_mask & (eDumpOptionType | eDumpOptionDefaultValue)) {
+ strm.Printf(" =");
+ if (dump_mask & eDumpOptionDefaultValue && !m_path_mappings.IsEmpty()) {
+ DefaultValueFormat label(strm);
+ strm.PutCString("empty");
+ }
+ if (!m_path_mappings.IsEmpty())
+ strm.PutCString("\n");
+ }
m_path_mappings.Dump(&strm);
}
}
diff --git a/lldb/source/Interpreter/OptionValueRegex.cpp b/lldb/source/Interpreter/OptionValueRegex.cpp
index 91ec41d..30e307a 100644
--- a/lldb/source/Interpreter/OptionValueRegex.cpp
+++ b/lldb/source/Interpreter/OptionValueRegex.cpp
@@ -8,6 +8,7 @@
#include "lldb/Interpreter/OptionValueRegex.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
@@ -24,6 +25,12 @@ void OptionValueRegex::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
llvm::StringRef regex_text = m_regex.GetText();
strm.Printf("%s", regex_text.str().c_str());
}
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_regex.GetText() != m_default_regex_str &&
+ !m_default_regex_str.empty()) {
+ DefaultValueFormat label(strm);
+ strm.PutCString(m_default_regex_str);
+ }
}
}
diff --git a/lldb/source/Interpreter/OptionValueSInt64.cpp b/lldb/source/Interpreter/OptionValueSInt64.cpp
index df7aee9..00f1cc3 100644
--- a/lldb/source/Interpreter/OptionValueSInt64.cpp
+++ b/lldb/source/Interpreter/OptionValueSInt64.cpp
@@ -8,6 +8,7 @@
#include "lldb/Interpreter/OptionValueSInt64.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
@@ -26,6 +27,11 @@ void OptionValueSInt64::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
strm.Printf("%" PRIi64, m_current_value);
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value) {
+ DefaultValueFormat label(strm);
+ strm.Printf("%" PRIi64, m_default_value);
+ }
}
}
diff --git a/lldb/source/Interpreter/OptionValueString.cpp b/lldb/source/Interpreter/OptionValueString.cpp
index ae30661a..022a27d 100644
--- a/lldb/source/Interpreter/OptionValueString.cpp
+++ b/lldb/source/Interpreter/OptionValueString.cpp
@@ -9,12 +9,28 @@
#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Host/OptionParser.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
+static void DumpString(Stream &strm, const std::string &str, bool escape,
+ bool raw) {
+ if (escape) {
+ std::string escaped_str;
+ Args::ExpandEscapedCharacters(str.c_str(), escaped_str);
+ DumpString(strm, escaped_str, false, raw);
+ return;
+ }
+
+ if (raw)
+ strm.PutCString(str);
+ else
+ strm.QuotedCString(str.c_str());
+}
+
void OptionValueString::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
uint32_t dump_mask) {
if (dump_mask & eDumpOptionType)
@@ -22,21 +38,15 @@ void OptionValueString::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
if (dump_mask & eDumpOptionValue) {
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
- if (!m_current_value.empty() || m_value_was_set) {
- if (m_options.Test(eOptionEncodeCharacterEscapeSequences)) {
- std::string expanded_escape_value;
- Args::ExpandEscapedCharacters(m_current_value.c_str(),
- expanded_escape_value);
- if (dump_mask & eDumpOptionRaw)
- strm.Printf("%s", expanded_escape_value.c_str());
- else
- strm.Printf("\"%s\"", expanded_escape_value.c_str());
- } else {
- if (dump_mask & eDumpOptionRaw)
- strm.Printf("%s", m_current_value.c_str());
- else
- strm.Printf("\"%s\"", m_current_value.c_str());
- }
+ const bool escape = m_options.Test(eOptionEncodeCharacterEscapeSequences);
+ const bool raw = dump_mask & eDumpOptionRaw;
+ if (!m_current_value.empty() || m_value_was_set)
+ DumpString(strm, m_current_value, escape, raw);
+
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value && !m_default_value.empty()) {
+ DefaultValueFormat label(strm);
+ DumpString(strm, m_default_value, escape, raw);
}
}
}
diff --git a/lldb/source/Interpreter/OptionValueUInt64.cpp b/lldb/source/Interpreter/OptionValueUInt64.cpp
index aa5e9a2..63f83cb 100644
--- a/lldb/source/Interpreter/OptionValueUInt64.cpp
+++ b/lldb/source/Interpreter/OptionValueUInt64.cpp
@@ -8,6 +8,7 @@
#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
@@ -30,6 +31,11 @@ void OptionValueUInt64::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
if (dump_mask & eDumpOptionType)
strm.PutCString(" = ");
strm.Printf("%" PRIu64, m_current_value);
+ if (dump_mask & eDumpOptionDefaultValue &&
+ m_current_value != m_default_value) {
+ DefaultValueFormat label(strm);
+ strm.Printf("%" PRIu64, m_default_value);
+ }
}
}
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index 4cf68db..ec72542 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -19,6 +19,7 @@
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/DiagnosticsRendering.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/STLExtras.h"
@@ -261,7 +262,8 @@ Option *Options::GetLongOptions() {
void Options::OutputFormattedUsageText(Stream &strm,
const OptionDefinition &option_def,
- uint32_t output_max_columns) {
+ uint32_t output_max_columns,
+ bool use_color) {
std::string actual_text;
if (option_def.validator) {
const char *condition = option_def.validator->ShortConditionString();
@@ -278,7 +280,7 @@ void Options::OutputFormattedUsageText(Stream &strm,
if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) <
output_max_columns) {
// Output it as a single line.
- strm.Indent(actual_text);
+ strm.Indent(ansi::FormatAnsiTerminalCodes(actual_text, use_color));
strm.EOL();
} else {
// We need to break it up into multiple lines.
@@ -312,7 +314,8 @@ void Options::OutputFormattedUsageText(Stream &strm,
strm.Indent();
assert(start < final_end);
assert(start + sub_len <= final_end);
- strm.Write(actual_text.c_str() + start, sub_len);
+ strm.PutCString(ansi::FormatAnsiTerminalCodes(
+ llvm::StringRef(actual_text.c_str() + start, sub_len), use_color));
start = end + 1;
}
strm.EOL();
@@ -385,7 +388,7 @@ static bool PrintOption(const OptionDefinition &opt_def,
}
void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,
- uint32_t screen_width) {
+ uint32_t screen_width, bool use_color) {
auto opt_defs = GetDefinitions();
const uint32_t save_indent_level = strm.GetIndentLevel();
llvm::StringRef name = cmd.GetCommandName();
@@ -527,7 +530,7 @@ void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,
strm.IndentMore(5);
if (opt_def.usage_text)
- OutputFormattedUsageText(strm, opt_def, screen_width);
+ OutputFormattedUsageText(strm, opt_def, screen_width, use_color);
if (!opt_def.enum_values.empty()) {
strm.Indent();
strm.Printf("Values: ");
diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index fe9f5d0..1d210ea 100644
--- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -1561,7 +1561,8 @@ void DynamicLoaderDarwinKernel::SetNotificationBreakpointIfNeeded() {
.CreateBreakpoint(&module_spec_list, nullptr,
"OSKextLoadedKextSummariesUpdated",
eFunctionNameTypeFull, eLanguageTypeUnknown, 0,
- skip_prologue, internal_bp, hardware)
+ /*offset_is_insn_count = */ false, skip_prologue,
+ internal_bp, hardware)
.get();
bp->SetCallback(DynamicLoaderDarwinKernel::BreakpointHitCallback, this,
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
index 08bef49..efb9ccc 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
@@ -530,7 +530,7 @@ bool DynamicLoaderMacOS::SetNotificationBreakpoint() {
m_process->GetTarget()
.CreateBreakpoint(&dyld_filelist, source_files,
"lldb_image_notifier", eFunctionNameTypeFull,
- eLanguageTypeUnknown, 0, skip_prologue,
+ eLanguageTypeUnknown, 0, false, skip_prologue,
internal, hardware)
.get();
breakpoint->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this,
@@ -546,8 +546,9 @@ bool DynamicLoaderMacOS::SetNotificationBreakpoint() {
m_process->GetTarget()
.CreateBreakpoint(&dyld_filelist, source_files,
"gdb_image_notifier", eFunctionNameTypeFull,
- eLanguageTypeUnknown, 0, skip_prologue,
- internal, hardware)
+ eLanguageTypeUnknown, 0,
+ /*offset_is_insn_count = */ false,
+ skip_prologue, internal, hardware)
.get();
breakpoint->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this,
true);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 2529e78..92094c0 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -123,6 +123,12 @@ private:
decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl());
decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl());
+ // Changing the DeclContext might change the linkage. For example, if the
+ // entity was previously declared inside a function, it will not be
+ // external, but changing the declaration context to the TU will make it
+ // external. Make sure this will recompute the linkage if it was computed
+ // before.
+ decl->invalidateCachedLinkage();
}
bool ChainPassesThrough(
@@ -229,6 +235,35 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
clang::ASTContext *m_src_ctx;
ClangASTImporter &importer;
+ void CompleteDecl(
+ Decl *decl,
+ lldb_private::ClangASTImporter::ASTContextMetadata const &to_context_md) {
+ // The decl that should be completed has to be imported into the target
+ // context from some other context.
+ assert(to_context_md.hasOrigin(decl));
+ // We should only complete decls coming from the source context.
+ assert(to_context_md.getOrigin(decl).ctx == m_src_ctx);
+
+ Decl *original_decl = to_context_md.getOrigin(decl).decl;
+
+ // Complete the decl now.
+ TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
+ if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
+ if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
+ if (original_tag_decl->isCompleteDefinition()) {
+ m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
+ tag_decl->setCompleteDefinition(true);
+ }
+ }
+
+ tag_decl->setHasExternalLexicalStorage(false);
+ tag_decl->setHasExternalVisibleStorage(false);
+ } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
+ container_decl->setHasExternalLexicalStorage(false);
+ container_decl->setHasExternalVisibleStorage(false);
+ }
+ }
+
public:
/// Constructs a CompleteTagDeclsScope.
/// \param importer The ClangASTImporter that we should observe.
@@ -251,30 +286,7 @@ public:
NamedDecl *decl = m_decls_to_complete.pop_back_val();
m_decls_already_completed.insert(decl);
- // The decl that should be completed has to be imported into the target
- // context from some other context.
- assert(to_context_md->hasOrigin(decl));
- // We should only complete decls coming from the source context.
- assert(to_context_md->getOrigin(decl).ctx == m_src_ctx);
-
- Decl *original_decl = to_context_md->getOrigin(decl).decl;
-
- // Complete the decl now.
- TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
- if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
- if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
- if (original_tag_decl->isCompleteDefinition()) {
- m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
- tag_decl->setCompleteDefinition(true);
- }
- }
-
- tag_decl->setHasExternalLexicalStorage(false);
- tag_decl->setHasExternalVisibleStorage(false);
- } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
- container_decl->setHasExternalLexicalStorage(false);
- container_decl->setHasExternalVisibleStorage(false);
- }
+ CompleteDecl(decl, *to_context_md);
to_context_md->removeOrigin(decl);
}
@@ -320,7 +332,8 @@ CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst,
DeclContextOverride decl_context_override;
if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>())
- decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl());
+ decl_context_override.OverrideAllDeclsFromContainingFunction(
+ t->getOriginalDecl());
CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(),
&src_ctxt->getASTContext());
@@ -358,6 +371,16 @@ clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx,
return result;
}
+bool ClangASTImporter::CanImport(const Decl *d) {
+ if (!d)
+ return false;
+ if (isa<TagDecl>(d))
+ return GetDeclOrigin(d).Valid();
+ if (isa<ObjCInterfaceDecl>(d))
+ return GetDeclOrigin(d).Valid();
+ return false;
+}
+
bool ClangASTImporter::CanImport(const CompilerType &type) {
if (!ClangUtil::IsClangType(type))
return false;
@@ -367,24 +390,10 @@ bool ClangASTImporter::CanImport(const CompilerType &type) {
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
switch (type_class) {
- case clang::Type::Record: {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- if (GetDeclOrigin(cxx_record_decl).Valid())
- return true;
- }
- } break;
-
- case clang::Type::Enum: {
- clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getDecl();
- if (enum_decl) {
- if (GetDeclOrigin(enum_decl).Valid())
- return true;
- }
- } break;
-
+ case clang::Type::Record:
+ return CanImport(qual_type->getAsCXXRecordDecl());
+ case clang::Type::Enum:
+ return CanImport(llvm::cast<clang::EnumType>(qual_type)->getOriginalDecl());
case clang::Type::ObjCObject:
case clang::Type::ObjCInterface: {
const clang::ObjCObjectType *objc_class_type =
@@ -394,10 +403,7 @@ bool ClangASTImporter::CanImport(const CompilerType &type) {
objc_class_type->getInterface();
// We currently can't complete objective C types through the newly added
// ASTContext because it only supports TagDecl objects right now...
- if (class_interface_decl) {
- if (GetDeclOrigin(class_interface_decl).Valid())
- return true;
- }
+ return CanImport(class_interface_decl);
}
} break;
@@ -414,12 +420,6 @@ bool ClangASTImporter::CanImport(const CompilerType &type) {
->getDeducedType()
.getAsOpaquePtr()));
- case clang::Type::Elaborated:
- return CanImport(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::ElaboratedType>(qual_type)
- ->getNamedType()
- .getAsOpaquePtr()));
-
case clang::Type::Paren:
return CanImport(CompilerType(
type.GetTypeSystem(),
@@ -452,7 +452,7 @@ bool ClangASTImporter::Import(const CompilerType &type) {
case clang::Type::Enum: {
clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ llvm::cast<clang::EnumType>(qual_type)->getOriginalDecl();
if (enum_decl) {
if (GetDeclOrigin(enum_decl).Valid())
return CompleteAndFetchChildren(qual_type);
@@ -488,12 +488,6 @@ bool ClangASTImporter::Import(const CompilerType &type) {
->getDeducedType()
.getAsOpaquePtr()));
- case clang::Type::Elaborated:
- return Import(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::ElaboratedType>(qual_type)
- ->getNamedType()
- .getAsOpaquePtr()));
-
case clang::Type::Paren:
return Import(CompilerType(
type.GetTypeSystem(),
@@ -597,7 +591,7 @@ bool ExtractBaseOffsets(const ASTRecordLayout &record_layout,
return false;
DeclFromUser<RecordDecl> origin_base_record(
- origin_base_record_type->getDecl());
+ origin_base_record_type->getOriginalDecl());
if (origin_base_record.IsInvalid())
return false;
@@ -728,7 +722,8 @@ bool ClangASTImporter::importRecordLayoutFromOrigin(
QualType base_type = bi->getType();
const RecordType *base_record_type = base_type->getAs<RecordType>();
- DeclFromParser<RecordDecl> base_record(base_record_type->getDecl());
+ DeclFromParser<RecordDecl> base_record(
+ base_record_type->getOriginalDecl());
DeclFromParser<CXXRecordDecl> base_cxx_record =
DynCast<CXXRecordDecl>(base_record);
@@ -860,7 +855,7 @@ bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) {
Log *log = GetLog(LLDBLog::Expressions);
if (const TagType *tag_type = type->getAs<TagType>()) {
- TagDecl *tag_decl = tag_type->getDecl();
+ TagDecl *tag_decl = tag_type->getOriginalDecl();
DeclOrigin decl_origin = GetDeclOrigin(tag_decl);
@@ -928,9 +923,9 @@ bool ClangASTImporter::RequireCompleteType(clang::QualType type) {
return false;
if (const TagType *tag_type = type->getAs<TagType>()) {
- TagDecl *tag_decl = tag_type->getDecl();
+ TagDecl *tag_decl = tag_type->getOriginalDecl();
- if (tag_decl->getDefinition() || tag_decl->isBeingDefined())
+ if (tag_decl->getDefinition())
return true;
return CompleteTagDecl(tag_decl);
@@ -1053,6 +1048,16 @@ ClangASTImporter::MapCompleter::~MapCompleter() = default;
llvm::Expected<Decl *>
ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
+ // FIXME: The Minimal import mode of clang::ASTImporter does not correctly
+ // import Lambda definitions. Work around this for now by not importing
+ // lambdas at all. This is most likely encountered when importing decls from
+ // the `std` module (not from debug-info), where lambdas can be defined in
+ // inline function bodies. Those will be imported by LLDB.
+ if (const auto *CXX = llvm::dyn_cast<clang::CXXRecordDecl>(From))
+ if (CXX->isLambda())
+ return llvm::make_error<ASTImportError>(
+ ASTImportError::UnsupportedConstruct);
+
if (m_std_handler) {
std::optional<Decl *> D = m_std_handler->Import(From);
if (D) {
@@ -1375,6 +1380,18 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
from, m_source_ctx, &to->getASTContext());
}
+ if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) {
+ m_main.BuildNamespaceMap(to_namespace_decl);
+ to_namespace_decl->setHasExternalVisibleStorage();
+ }
+
+ MarkDeclImported(from, to);
+}
+
+void ClangASTImporter::ASTImporterDelegate::MarkDeclImported(Decl *from,
+ Decl *to) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) {
to_tag_decl->setHasExternalLexicalStorage();
to_tag_decl->getPrimaryContext()->setMustBuildLookupTable();
@@ -1389,11 +1406,6 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
(to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
}
- if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) {
- m_main.BuildNamespaceMap(to_namespace_decl);
- to_namespace_decl->setHasExternalVisibleStorage();
- }
-
if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) {
to_container_decl->setHasExternalLexicalStorage();
to_container_decl->setHasExternalVisibleStorage();
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
index 47b137a..03d2556 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
@@ -157,6 +157,8 @@ public:
/// \see ClangASTImporter::Import
bool CanImport(const CompilerType &type);
+ bool CanImport(const clang::Decl *d);
+
/// If the given type was copied from another TypeSystemClang then copy over
/// all missing information (e.g., the definition of a 'class' type).
///
@@ -346,6 +348,8 @@ public:
llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override;
private:
+ void MarkDeclImported(clang::Decl *from, clang::Decl *to);
+
/// Decls we should ignore when mapping decls back to their original
/// ASTContext. Used by the CxxModuleHandler to mark declarations that
/// were created from the 'std' C++ module to prevent that the Importer
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 4b52f6a..21a9307 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -223,7 +223,7 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
continue;
TagDecl *candidate_tag_decl =
- const_cast<TagDecl *>(tag_type->getDecl());
+ tag_type->getOriginalDecl()->getDefinitionOrSelf();
if (TypeSystemClang::GetCompleteDecl(
&candidate_tag_decl->getASTContext(), candidate_tag_decl))
@@ -250,7 +250,8 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
if (!tag_type)
continue;
- TagDecl *candidate_tag_decl = const_cast<TagDecl *>(tag_type->getDecl());
+ TagDecl *candidate_tag_decl =
+ tag_type->getOriginalDecl()->getDefinitionOrSelf();
if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(),
candidate_tag_decl))
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 214e260..8a68282 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -839,7 +839,7 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {
clang::CXXRecordDecl *class_decl = method_decl->getParent();
- QualType class_qual_type(class_decl->getTypeForDecl(), 0);
+ QualType class_qual_type = m_ast_context->getCanonicalTagType(class_decl);
TypeFromUser class_user_type(
class_qual_type.getAsOpaquePtr(),
@@ -1561,7 +1561,7 @@ ClangExpressionDeclMap::AddExpressionVariable(NameSearchContext &context,
if (const clang::Type *parser_type = parser_opaque_type.getTypePtr()) {
if (const TagType *tag_type = dyn_cast<TagType>(parser_type))
- CompleteType(tag_type->getDecl());
+ CompleteType(tag_type->getOriginalDecl()->getDefinitionOrSelf());
if (const ObjCObjectPointerType *objc_object_ptr_type =
dyn_cast<ObjCObjectPointerType>(parser_type))
CompleteType(objc_object_ptr_type->getInterfaceDecl());
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
index aa0e6e3..319ff3fe8 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
@@ -79,9 +79,11 @@ ClangPersistentVariables::GetCompilerTypeFromPersistentDecl(
if (p.m_decl == nullptr)
return std::nullopt;
+ auto ctx = std::static_pointer_cast<TypeSystemClang>(p.m_context.lock());
if (clang::TypeDecl *tdecl = llvm::dyn_cast<clang::TypeDecl>(p.m_decl)) {
- opaque_compiler_type_t t = static_cast<opaque_compiler_type_t>(
- const_cast<clang::Type *>(tdecl->getTypeForDecl()));
+ opaque_compiler_type_t t =
+ static_cast<opaque_compiler_type_t>(const_cast<clang::Type *>(
+ ctx->getASTContext().getTypeDeclType(tdecl).getTypePtr()));
return CompilerType(p.m_context, t);
}
return std::nullopt;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
index 45ad4f1..6f57c18 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
@@ -153,7 +153,7 @@ NameSearchContext::AddTypeDecl(const CompilerType &clang_type) {
return (NamedDecl *)typedef_name_decl;
} else if (const TagType *tag_type = qual_type->getAs<TagType>()) {
- TagDecl *tag_decl = tag_type->getDecl();
+ TagDecl *tag_decl = tag_type->getOriginalDecl()->getDefinitionOrSelf();
m_decls.push_back(tag_decl);
diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp
index e67e60b..b89a6aa 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp
@@ -266,9 +266,9 @@ InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo(
// We gather symbolication addresses above, so no need for HistoryThread to
// try to infer the call addresses.
- bool pcs_are_call_addresses = true;
- ThreadSP new_thread_sp = std::make_shared<HistoryThread>(
- *process_sp, tid, PCs, pcs_are_call_addresses);
+ auto pc_type = HistoryPCType::Calls;
+ ThreadSP new_thread_sp =
+ std::make_shared<HistoryThread>(*process_sp, tid, PCs, pc_type);
// Save this in the Process' ExtendedThreadList so a strong pointer retains
// the object
diff --git a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
index c2db354..565fd35 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp
@@ -324,9 +324,9 @@ InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo(
// We gather symbolication addresses above, so no need for HistoryThread to
// try to infer the call addresses.
- bool pcs_are_call_addresses = true;
- ThreadSP new_thread_sp = std::make_shared<HistoryThread>(
- *process_sp, tid, PCs, pcs_are_call_addresses);
+ auto pc_type = HistoryPCType::Calls;
+ ThreadSP new_thread_sp =
+ std::make_shared<HistoryThread>(*process_sp, tid, PCs, pc_type);
std::string stop_reason_description = GetStopReasonDescription(info);
new_thread_sp->SetName(stop_reason_description.c_str());
diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
index 9648924..38c334b 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
@@ -83,7 +83,7 @@ ReportRetriever::RetrieveReportData(const ProcessSP process_sp) {
options.SetAutoApplyFixIts(false);
options.SetLanguage(eLanguageTypeObjC_plus_plus);
- if (auto m = GetPreferredAsanModule(process_sp->GetTarget())) {
+ if (auto [m, _] = GetPreferredAsanModule(process_sp->GetTarget()); m) {
SymbolContextList sc_list;
sc_list.Append(SymbolContext(std::move(m)));
options.SetPreferredSymbolContexts(std::move(sc_list));
diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp
index a5cee5d..09c6988 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp
@@ -13,10 +13,12 @@
namespace lldb_private {
-lldb::ModuleSP GetPreferredAsanModule(const Target &target) {
- // Currently only supported on Darwin.
+std::tuple<lldb::ModuleSP, HistoryPCType>
+GetPreferredAsanModule(const Target &target) {
+ // Currently only Darwin provides ASan runtime support as part of the OS
+ // (libsanitizers).
if (!target.GetArchitecture().GetTriple().isOSDarwin())
- return nullptr;
+ return {nullptr, HistoryPCType::Calls};
lldb::ModuleSP module;
llvm::Regex pattern(R"(libclang_rt\.asan_.*_dynamic\.dylib)");
@@ -29,7 +31,16 @@ lldb::ModuleSP GetPreferredAsanModule(const Target &target) {
return IterationAction::Continue;
});
- return module;
+ // `Calls` - The ASan compiler-rt runtime already massages the return
+ // addresses into call addresses, so we don't want LLDB's unwinder to try to
+ // locate the previous instruction again as this might lead to us reporting
+ // a different line.
+ // `ReturnsNoZerothFrame` - Darwin, but not ASan compiler-rt implies
+ // libsanitizers which collects return addresses. It also discards a few
+ // non-user frames at the top of the stack.
+ auto pc_type =
+ (module ? HistoryPCType::Calls : HistoryPCType::ReturnsNoZerothFrame);
+ return {module, pc_type};
}
} // namespace lldb_private
diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h
index 425f0a2..e26d2bc 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h
@@ -9,18 +9,20 @@
#ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_UTILITY_H
#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_UTILITY_H
+#include <tuple>
+
#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private-enumerations.h"
namespace lldb_private {
-class Target;
-
/// On Darwin, if LLDB loaded libclang_rt, it's coming from a locally built
/// compiler-rt, and we should prefer it in favour of the system sanitizers
/// when running InstrumentationRuntime utility expressions that use symbols
/// from the sanitizer libraries. This helper searches the target for such a
/// dylib. Returns nullptr if no such dylib was found.
-lldb::ModuleSP GetPreferredAsanModule(const Target &target);
+std::tuple<lldb::ModuleSP, HistoryPCType>
+GetPreferredAsanModule(const Target &target);
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 3118ff1..c39b529 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -105,7 +105,9 @@ CPlusPlusLanguage::GetFunctionNameInfo(ConstString name) const {
bool CPlusPlusLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
const char *mangled_name = mangled.GetMangledName().GetCString();
- return mangled_name && Mangled::IsMangledName(mangled_name);
+ auto mangling_scheme = Mangled::GetManglingScheme(mangled_name);
+ return mangled_name && (mangling_scheme == Mangled::eManglingSchemeItanium ||
+ mangling_scheme == Mangled::eManglingSchemeMSVC);
}
ConstString CPlusPlusLanguage::GetDemangledFunctionNameWithoutArguments(
@@ -602,126 +604,6 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier(
return false;
}
-namespace {
-class NodeAllocator {
- llvm::BumpPtrAllocator Alloc;
-
-public:
- void reset() { Alloc.Reset(); }
-
- template <typename T, typename... Args> T *makeNode(Args &&...args) {
- return new (Alloc.Allocate(sizeof(T), alignof(T)))
- T(std::forward<Args>(args)...);
- }
-
- void *allocateNodeArray(size_t sz) {
- return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
- alignof(llvm::itanium_demangle::Node *));
- }
-};
-
-template <typename Derived>
-class ManglingSubstitutor
- : public llvm::itanium_demangle::AbstractManglingParser<Derived,
- NodeAllocator> {
- using Base =
- llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
-
-public:
- ManglingSubstitutor() : Base(nullptr, nullptr) {}
-
- template <typename... Ts>
- ConstString substitute(llvm::StringRef Mangled, Ts &&...Vals) {
- this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
- return substituteImpl(Mangled);
- }
-
-protected:
- void reset(llvm::StringRef Mangled) {
- Base::reset(Mangled.begin(), Mangled.end());
- Written = Mangled.begin();
- Result.clear();
- Substituted = false;
- }
-
- ConstString substituteImpl(llvm::StringRef Mangled) {
- Log *log = GetLog(LLDBLog::Language);
- if (this->parse() == nullptr) {
- LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
- return ConstString();
- }
- if (!Substituted)
- return ConstString();
-
- // Append any trailing unmodified input.
- appendUnchangedInput();
- LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
- return ConstString(Result);
- }
-
- void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
- if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
- return;
-
- // We found a match. Append unmodified input up to this point.
- appendUnchangedInput();
-
- // And then perform the replacement.
- Result += To;
- Written += From.size();
- Substituted = true;
- }
-
-private:
- /// Input character until which we have constructed the respective output
- /// already.
- const char *Written = "";
-
- llvm::SmallString<128> Result;
-
- /// Whether we have performed any substitutions.
- bool Substituted = false;
-
- const char *currentParserPos() const { return this->First; }
-
- void appendUnchangedInput() {
- Result +=
- llvm::StringRef(Written, std::distance(Written, currentParserPos()));
- Written = currentParserPos();
- }
-};
-
-/// Given a mangled function `Mangled`, replace all the primitive function type
-/// arguments of `Search` with type `Replace`.
-class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
- llvm::StringRef Search;
- llvm::StringRef Replace;
-
-public:
- void reset(llvm::StringRef Mangled, llvm::StringRef Search,
- llvm::StringRef Replace) {
- ManglingSubstitutor::reset(Mangled);
- this->Search = Search;
- this->Replace = Replace;
- }
-
- llvm::itanium_demangle::Node *parseType() {
- trySubstitute(Search, Replace);
- return ManglingSubstitutor::parseType();
- }
-};
-
-class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
-public:
- llvm::itanium_demangle::Node *
- parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
- trySubstitute("C1", "C2");
- trySubstitute("D1", "D2");
- return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
- }
-};
-} // namespace
-
std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
const ConstString mangled_name) const {
std::vector<ConstString> alternates;
@@ -749,29 +631,49 @@ std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
alternates.push_back(ConstString(fixed_scratch));
}
- TypeSubstitutor TS;
+ auto *log = GetLog(LLDBLog::Language);
+
// `char` is implementation defined as either `signed` or `unsigned`. As a
// result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
// char, 'h'-unsigned char. If we're looking for symbols with a signed char
// parameter, try finding matches which have the general case 'c'.
- if (ConstString char_fixup =
- TS.substitute(mangled_name.GetStringRef(), "a", "c"))
- alternates.push_back(char_fixup);
+ if (auto char_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "a", "c")) {
+ // LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
+ if (*char_fixup_or_err)
+ alternates.push_back(*char_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(log, char_fixup_or_err.takeError(),
+ "Failed to substitute 'char' type mangling: {0}");
// long long parameter mangling 'x', may actually just be a long 'l' argument
- if (ConstString long_fixup =
- TS.substitute(mangled_name.GetStringRef(), "x", "l"))
- alternates.push_back(long_fixup);
+ if (auto long_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "x", "l")) {
+ if (*long_fixup_or_err)
+ alternates.push_back(*long_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(log, long_fixup_or_err.takeError(),
+ "Failed to substitute 'long long' type mangling: {0}");
// unsigned long long parameter mangling 'y', may actually just be unsigned
// long 'm' argument
- if (ConstString ulong_fixup =
- TS.substitute(mangled_name.GetStringRef(), "y", "m"))
- alternates.push_back(ulong_fixup);
-
- if (ConstString ctor_fixup =
- CtorDtorSubstitutor().substitute(mangled_name.GetStringRef()))
- alternates.push_back(ctor_fixup);
+ if (auto ulong_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "y", "m")) {
+ if (*ulong_fixup_or_err)
+ alternates.push_back(*ulong_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(
+ log, ulong_fixup_or_err.takeError(),
+ "Failed to substitute 'unsigned long long' type mangling: {0}");
+
+ if (auto ctor_fixup_or_err = SubstituteStructorAliases_ItaniumMangle(
+ mangled_name.GetStringRef())) {
+ if (*ctor_fixup_or_err) {
+ alternates.push_back(*ctor_fixup_or_err);
+ }
+ } else
+ LLDB_LOG_ERROR(log, ctor_fixup_or_err.takeError(),
+ "Failed to substitute structor alias manglings: {0}");
return alternates;
}
@@ -2440,6 +2342,160 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
}
}
+namespace {
+class NodeAllocator {
+ llvm::BumpPtrAllocator Alloc;
+
+public:
+ void reset() { Alloc.Reset(); }
+
+ template <typename T, typename... Args> T *makeNode(Args &&...args) {
+ return new (Alloc.Allocate(sizeof(T), alignof(T)))
+ T(std::forward<Args>(args)...);
+ }
+
+ void *allocateNodeArray(size_t sz) {
+ return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
+ alignof(llvm::itanium_demangle::Node *));
+ }
+};
+
+template <typename Derived>
+class ManglingSubstitutor
+ : public llvm::itanium_demangle::AbstractManglingParser<Derived,
+ NodeAllocator> {
+ using Base =
+ llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
+
+public:
+ ManglingSubstitutor() : Base(nullptr, nullptr) {}
+
+ template <typename... Ts>
+ llvm::Expected<ConstString> substitute(llvm::StringRef Mangled,
+ Ts &&...Vals) {
+ this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
+ return substituteImpl(Mangled);
+ }
+
+protected:
+ void reset(llvm::StringRef Mangled) {
+ Base::reset(Mangled.begin(), Mangled.end());
+ Written = Mangled.begin();
+ Result.clear();
+ Substituted = false;
+ }
+
+ llvm::Expected<ConstString> substituteImpl(llvm::StringRef Mangled) {
+ if (this->parse() == nullptr)
+ return llvm::createStringError(
+ llvm::formatv("Failed to substitute mangling in '{0}'", Mangled));
+
+ if (!Substituted)
+ return ConstString();
+
+ // Append any trailing unmodified input.
+ appendUnchangedInput();
+ return ConstString(Result);
+ }
+
+ void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
+ if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
+ return;
+
+ // We found a match. Append unmodified input up to this point.
+ appendUnchangedInput();
+
+ // And then perform the replacement.
+ Result += To;
+ Written += From.size();
+ Substituted = true;
+ }
+
+private:
+ /// Input character until which we have constructed the respective output
+ /// already.
+ const char *Written = "";
+
+ llvm::SmallString<128> Result;
+
+ /// Whether we have performed any substitutions.
+ bool Substituted = false;
+
+ const char *currentParserPos() const { return this->First; }
+
+ void appendUnchangedInput() {
+ Result +=
+ llvm::StringRef(Written, std::distance(Written, currentParserPos()));
+ Written = currentParserPos();
+ }
+};
+
+/// Given a mangled function `Mangled`, replace all the primitive function type
+/// arguments of `Search` with type `Replace`.
+class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
+ llvm::StringRef Search;
+ llvm::StringRef Replace;
+
+public:
+ void reset(llvm::StringRef Mangled, llvm::StringRef Search,
+ llvm::StringRef Replace) {
+ ManglingSubstitutor::reset(Mangled);
+ this->Search = Search;
+ this->Replace = Replace;
+ }
+
+ llvm::itanium_demangle::Node *parseType() {
+ trySubstitute(Search, Replace);
+ return ManglingSubstitutor::parseType();
+ }
+};
+
+class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
+ llvm::StringRef Search;
+ llvm::StringRef Replace;
+
+public:
+ void reset(llvm::StringRef Mangled, llvm::StringRef Search,
+ llvm::StringRef Replace) {
+ ManglingSubstitutor::reset(Mangled);
+ this->Search = Search;
+ this->Replace = Replace;
+ }
+
+ void reset(llvm::StringRef Mangled) { ManglingSubstitutor::reset(Mangled); }
+
+ llvm::itanium_demangle::Node *
+ parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
+ if (!Search.empty() && !Replace.empty()) {
+ trySubstitute(Search, Replace);
+ } else {
+ trySubstitute("D1", "D2");
+ trySubstitute("C1", "C2");
+ }
+ return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
+ }
+};
+} // namespace
+
+llvm::Expected<ConstString>
+CPlusPlusLanguage::SubstituteType_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to) {
+ return TypeSubstitutor().substitute(mangled_name, subst_from, subst_to);
+}
+
+llvm::Expected<ConstString> CPlusPlusLanguage::SubstituteStructor_ItaniumMangle(
+ llvm::StringRef mangled_name, llvm::StringRef subst_from,
+ llvm::StringRef subst_to) {
+ return CtorDtorSubstitutor().substitute(mangled_name, subst_from, subst_to);
+}
+
+llvm::Expected<ConstString>
+CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(
+ llvm::StringRef mangled_name) {
+ return CtorDtorSubstitutor().substitute(mangled_name);
+}
+
#define LLDB_PROPERTIES_language_cplusplus
#include "LanguageCPlusPlusProperties.inc"
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 4a30299..9a528ca 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -164,6 +164,76 @@ public:
ConstString FindBestAlternateFunctionMangledName(
const Mangled mangled, const SymbolContext &sym_ctx) const override;
+ /// Substitutes Itanium type encoding substrings given by \c subst_from
+ /// in \c mangled_name with \c subst_to.
+ ///
+ /// This function will only replace Itanium type encodings (i.e., <type>
+ /// productions in the Itanium ABI mangling grammar). However, no verifiction
+ /// is done on whether \c subst_from or \c subst_to is a valid type encoding.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \param[in] subst_from The substring to substitute.
+ ///
+ /// \param[in] subst_to The substring to insert.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteType_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to);
+
+ /// Substitutes Itanium structor encoding substrings given by \c subst_from
+ /// in \c mangled_name with \c subst_to.
+ ///
+ /// This function will only replace Itanium structor encodings (i.e.,
+ /// <ctor-dtor-name> productions in the Itanium ABI mangling grammar).
+ /// However, no verifiction is done on whether \c subst_from or \c subst_to is
+ /// a valid structor encoding.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \param[in] subst_from The substring to substitute.
+ ///
+ /// \param[in] subst_to The substring to insert.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteStructor_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to);
+
+ /// Tries replacing Itanium structor encoding substrings in \c mangled_name
+ /// with potential aliases.j
+ ///
+ /// This function will only replace Itanium structor encodings (i.e.,
+ /// <ctor-dtor-name> productions in the Itanium ABI mangling grammar).
+ ///
+ /// E.g., on some platforms, the C1/D1 variants are aliased to the C2/D2
+ /// variants. This function will try to replace occurrences of C1/D1 with
+ /// C2/D2.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteStructorAliases_ItaniumMangle(llvm::StringRef mangled_name);
+
llvm::StringRef GetInstanceVariableName() override { return "this"; }
FormatEntity::Entry GetFunctionNameFormat() const override;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index ea1edbf..5289027 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -339,11 +339,18 @@ lldb::ChildCacheState LibCxxForwardListFrontEnd::Update() {
if (err.Fail() || !backend_addr)
return lldb::ChildCacheState::eRefetch;
- ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
+ auto list_base_sp = m_backend.GetChildAtIndex(0);
+ if (!list_base_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Anonymous strucutre index is in base class at index 0.
+ auto [impl_sp, is_compressed_pair] =
+ GetValueOrOldCompressedPair(*list_base_sp, /*anon_struct_idx=*/0,
+ "__before_begin_", "__before_begin_");
if (!impl_sp)
return ChildCacheState::eRefetch;
- if (isOldCompressedPairLayout(*impl_sp))
+ if (is_compressed_pair)
impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
if (!impl_sp)
@@ -366,17 +373,10 @@ llvm::Expected<uint32_t> LibCxxListFrontEnd::CalculateNumChildren() {
if (!m_head || !m_tail || m_node_address == 0)
return 0;
- ValueObjectSP size_node_sp(m_backend.GetChildMemberWithName("__size_"));
- if (!size_node_sp) {
- size_node_sp = m_backend.GetChildMemberWithName(
- "__size_alloc_"); // pre-compressed_pair rework
-
- if (!isOldCompressedPairLayout(*size_node_sp))
- return llvm::createStringError("Unexpected std::list layout: expected "
- "old __compressed_pair layout.");
-
+ auto [size_node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ m_backend, /*anon_struct_idx=*/1, "__size_", "__size_alloc_");
+ if (is_compressed_pair)
size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp);
- }
if (size_node_sp)
m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index a787404..6053d04 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -49,11 +49,6 @@ static void consumeInlineNamespace(llvm::StringRef &name) {
}
}
-bool lldb_private::formatters::isOldCompressedPairLayout(
- ValueObject &pair_obj) {
- return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
-}
-
bool lldb_private::formatters::isStdTemplate(ConstString type_name,
llvm::StringRef type) {
llvm::StringRef name = type_name.GetStringRef();
@@ -105,6 +100,44 @@ lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
return value;
}
+std::pair<lldb::ValueObjectSP, bool>
+lldb_private::formatters::GetValueOrOldCompressedPair(
+ ValueObject &obj, size_t anon_struct_idx, llvm::StringRef child_name,
+ llvm::StringRef compressed_pair_name) {
+ auto is_old_compressed_pair = [](ValueObject &pair_obj) -> bool {
+ return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
+ };
+
+ // Try searching the child member in an anonymous structure first.
+ if (auto unwrapped = obj.GetChildAtIndex(anon_struct_idx)) {
+ ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));
+ if (node_sp)
+ return {node_sp, is_old_compressed_pair(*node_sp)};
+ }
+
+ // Older versions of libc++ don't wrap the children in anonymous structures.
+ // Try that instead.
+ ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));
+ if (node_sp)
+ return {node_sp, is_old_compressed_pair(*node_sp)};
+
+ // Try the even older __compressed_pair layout.
+
+ assert(!compressed_pair_name.empty());
+
+ node_sp = obj.GetChildMemberWithName(compressed_pair_name);
+
+ // Unrecognized layout (possibly older than LLDB supports).
+ if (!node_sp)
+ return {nullptr, false};
+
+ // Expected old compressed_pair layout, but got something else.
+ if (!is_old_compressed_pair(*node_sp))
+ return {nullptr, false};
+
+ return {node_sp, true};
+}
+
bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
@@ -205,11 +238,12 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
if (!valobj_sp)
return false;
- ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
if (!ptr_sp)
return false;
- if (isOldCompressedPairLayout(*ptr_sp))
+ if (is_compressed_pair)
ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
if (!ptr_sp)
@@ -379,13 +413,14 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
if (!valobj_sp)
return lldb::ChildCacheState::eRefetch;
- ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
if (!ptr_sp)
return lldb::ChildCacheState::eRefetch;
// Retrieve the actual pointer and the deleter, and clone them to give them
// user-friendly names.
- if (isOldCompressedPairLayout(*ptr_sp)) {
+ if (is_compressed_pair) {
if (ValueObjectSP value_pointer_sp =
GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
@@ -424,17 +459,15 @@ enum class StringLayout { CSD, DSC };
}
static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
- if (auto rep_sp = valobj.GetChildMemberWithName("__rep_"))
- return rep_sp;
-
- ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
- if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
+ auto [valobj_r_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ valobj, /*anon_struct_idx=*/0, "__rep_", "__r_");
+ if (!valobj_r_sp)
return nullptr;
- if (!isOldCompressedPairLayout(*valobj_r_sp))
- return nullptr;
+ if (is_compressed_pair)
+ return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
- return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
+ return valobj_r_sp;
}
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index d88a6ec..819f8a9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -25,7 +25,22 @@ GetChildMemberWithName(ValueObject &obj,
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair);
lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair);
-bool isOldCompressedPairLayout(ValueObject &pair_obj);
+
+/// Returns the ValueObjectSP of the child of \c obj. If \c obj has no
+/// child named \c child_name, returns the __compressed_pair child instead
+/// with \c compressed_pair_name, if one exists.
+///
+/// Latest libc++ wrap the compressed children in an anonymous structure.
+/// The \c anon_struct_idx indicates the location of this struct.
+///
+/// The returned boolean is \c true if the returned child was has an old-style
+/// libc++ __compressed_pair layout.
+///
+/// If no child was found returns a nullptr.
+std::pair<lldb::ValueObjectSP, bool>
+GetValueOrOldCompressedPair(ValueObject &obj, size_t anon_struct_idx,
+ llvm::StringRef child_name,
+ llvm::StringRef compressed_pair_name);
bool isStdTemplate(ConstString type_name, llvm::StringRef type);
bool LibcxxStringSummaryProviderASCII(
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index 41441df..8576696 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -200,7 +200,8 @@ public:
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
private:
- llvm::Expected<uint32_t> CalculateNumChildrenForOldCompressedPairLayout();
+ llvm::Expected<uint32_t>
+ CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair);
/// Returns the ValueObject for the __tree_node type that
/// holds the key/value pair of the node at index \ref idx.
@@ -254,16 +255,8 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
llvm::Expected<uint32_t>
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
- CalculateNumChildrenForOldCompressedPairLayout() {
- ValueObjectSP node_sp(m_tree->GetChildMemberWithName("__pair3_"));
- if (!node_sp)
- return 0;
-
- if (!isOldCompressedPairLayout(*node_sp))
- return llvm::createStringError("Unexpected std::map layout: expected "
- "old __compressed_pair layout.");
-
- node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
+ CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair) {
+ auto node_sp = GetFirstValueOfLibCXXCompressedPair(pair);
if (!node_sp)
return 0;
@@ -281,12 +274,16 @@ llvm::Expected<uint32_t> lldb_private::formatters::
if (m_tree == nullptr)
return 0;
- if (auto node_sp = m_tree->GetChildMemberWithName("__size_")) {
- m_count = node_sp->GetValueAsUnsigned(0);
- return m_count;
- }
+ auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *m_tree, /*anon_struct_idx=*/2, "__size_", "__pair3_");
+ if (!size_sp)
+ return llvm::createStringError("Unexpected std::map layout");
- return CalculateNumChildrenForOldCompressedPairLayout();
+ if (is_compressed_pair)
+ return CalculateNumChildrenForOldCompressedPairLayout(*size_sp);
+
+ m_count = size_sp->GetValueAsUnsigned(0);
+ return m_count;
}
ValueObjectSP
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 501fd09..f88a531 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -130,22 +130,17 @@ CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
GetNodeType() {
- auto node_sp = m_backend.GetChildAtNamePath({"__table_", "__first_node_"});
-
- if (!node_sp) {
- auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
- if (!p1_sp)
- return {};
+ auto table_sp = m_backend.GetChildMemberWithName("__table_");
+ if (!table_sp)
+ return {};
- if (!isOldCompressedPairLayout(*p1_sp))
- return {};
+ auto [node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *table_sp, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
+ if (is_compressed_pair)
+ node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
- node_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
- if (!node_sp)
- return {};
- }
-
- assert(node_sp);
+ if (!node_sp)
+ return {};
return node_sp->GetCompilerType().GetTypeTemplateArgument(0).GetPointeeType();
}
@@ -223,19 +218,15 @@ lldb::ValueObjectSP lldb_private::formatters::
llvm::Expected<size_t>
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
CalculateNumChildrenImpl(ValueObject &table) {
- if (auto size_sp = table.GetChildMemberWithName("__size_"))
+ auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ table, /*anon_struct_idx=*/2, "__size_", "__p2_");
+ if (!is_compressed_pair && size_sp)
return size_sp->GetValueAsUnsigned(0);
- ValueObjectSP p2_sp = table.GetChildMemberWithName("__p2_");
- if (!p2_sp)
- return llvm::createStringError(
- "Unexpected std::unordered_map layout: __p2_ member not found.");
+ if (!is_compressed_pair)
+ return llvm::createStringError("Unsupported std::unordered_map layout.");
- if (!isOldCompressedPairLayout(*p2_sp))
- return llvm::createStringError("Unexpected std::unordered_map layout: old "
- "__compressed_pair layout not found.");
-
- ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
+ ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*size_sp);
if (!num_elements_sp)
return llvm::createStringError(
@@ -246,19 +237,13 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
}
static ValueObjectSP GetTreePointer(ValueObject &table) {
- ValueObjectSP tree_sp = table.GetChildMemberWithName("__first_node_");
- if (!tree_sp) {
- ValueObjectSP p1_sp = table.GetChildMemberWithName("__p1_");
- if (!p1_sp)
- return nullptr;
-
- if (!isOldCompressedPairLayout(*p1_sp))
- return nullptr;
-
- tree_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
- if (!tree_sp)
- return nullptr;
- }
+ auto [tree_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ table, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
+ if (is_compressed_pair)
+ tree_sp = GetFirstValueOfLibCXXCompressedPair(*tree_sp);
+
+ if (!tree_sp)
+ return nullptr;
return tree_sp->GetChildMemberWithName("__next_");
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 4bcdf01..60913e5 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -126,17 +126,15 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
}
static ValueObjectSP GetDataPointer(ValueObject &root) {
- if (auto cap_sp = root.GetChildMemberWithName("__cap_"))
- return cap_sp;
-
- ValueObjectSP cap_sp = root.GetChildMemberWithName("__end_cap_");
+ auto [cap_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ root, /*anon_struct_idx=*/2, "__cap_", "__end_cap_");
if (!cap_sp)
return nullptr;
- if (!isOldCompressedPairLayout(*cap_sp))
- return nullptr;
+ if (is_compressed_pair)
+ return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
- return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
+ return cap_sp;
}
lldb::ChildCacheState
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index 595e835..f4a695e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -241,10 +241,11 @@ VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
bool lldb_private::formatters::LibStdcppStringSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});
- if (!ptr)
- return false;
+ if (!ptr || !ptr->GetError().Success())
+ stream << "Summary Unavailable";
+ else
+ stream << ptr->GetSummaryAsCString();
- stream << ptr->GetSummaryAsCString();
return true;
}
diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
index ef1c2c8..24e8489 100644
--- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -73,7 +73,8 @@ static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
static constexpr llvm::StringLiteral g_lldb_autogen_nspair("__lldb_autogen_nspair");
- compiler_type = scratch_ts_sp->GetTypeForIdentifier<clang::CXXRecordDecl>(g_lldb_autogen_nspair);
+ compiler_type = scratch_ts_sp->GetTypeForIdentifier<clang::CXXRecordDecl>(
+ scratch_ts_sp->getASTContext(), g_lldb_autogen_nspair);
if (!compiler_type) {
compiler_type = scratch_ts_sp->CreateRecordType(
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
index 24a7371..b1f2a66 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -102,7 +102,7 @@ AppleObjCRuntimeV1::CreateExceptionResolver(const BreakpointSP &bkpt,
resolver_sp = std::make_shared<BreakpointResolverName>(
bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
- eLazyBoolNo);
+ /*offset_is_insn_count = */ false, eLazyBoolNo);
// FIXME: don't do catch yet.
return resolver_sp;
}
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index cca721e..9beb133 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -1163,7 +1163,7 @@ AppleObjCRuntimeV2::CreateExceptionResolver(const BreakpointSP &bkpt,
resolver_sp = std::make_shared<BreakpointResolverName>(
bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
- eLazyBoolNo);
+ /*offset_is_insn_count = */ false, eLazyBoolNo);
// FIXME: We don't do catch breakpoints for ObjC yet.
// Should there be some way for the runtime to specify what it can do in this
// regard?
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
index a4b3e26..8dc5f51 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
@@ -169,7 +169,8 @@ GNUstepObjCRuntime::CreateExceptionResolver(const BreakpointSP &bkpt,
if (throw_bp)
resolver_sp = std::make_shared<BreakpointResolverName>(
bkpt, "objc_exception_throw", eFunctionNameTypeBase,
- eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo);
+ eLanguageTypeUnknown, Breakpoint::Exact, 0,
+ /*offset_is_insn_count = */ false, eLazyBoolNo);
return resolver_sp;
}
diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
index afaaa57..206a471 100644
--- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
+++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
@@ -91,11 +91,9 @@ const char *memory_history_asan_command_format =
t;
)";
-static void CreateHistoryThreadFromValueObject(ProcessSP process_sp,
- ValueObjectSP return_value_sp,
- const char *type,
- const char *thread_name,
- HistoryThreads &result) {
+static void CreateHistoryThreadFromValueObject(
+ ProcessSP process_sp, ValueObjectSP return_value_sp, HistoryPCType pc_type,
+ const char *type, const char *thread_name, HistoryThreads &result) {
std::string count_path = "." + std::string(type) + "_count";
std::string tid_path = "." + std::string(type) + "_tid";
std::string trace_path = "." + std::string(type) + "_trace";
@@ -128,12 +126,8 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp,
pcs.push_back(pc);
}
- // The ASAN runtime already massages the return addresses into call
- // addresses, we don't want LLDB's unwinder to try to locate the previous
- // instruction again as this might lead to us reporting a different line.
- bool pcs_are_call_addresses = true;
HistoryThread *history_thread =
- new HistoryThread(*process_sp, tid, pcs, pcs_are_call_addresses);
+ new HistoryThread(*process_sp, tid, pcs, pc_type);
ThreadSP new_thread_sp(history_thread);
std::ostringstream thread_name_with_number;
thread_name_with_number << thread_name << " Thread " << tid;
@@ -176,7 +170,8 @@ HistoryThreads MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address) {
options.SetAutoApplyFixIts(false);
options.SetLanguage(eLanguageTypeObjC_plus_plus);
- if (auto m = GetPreferredAsanModule(process_sp->GetTarget())) {
+ auto [m, pc_type] = GetPreferredAsanModule(process_sp->GetTarget());
+ if (m) {
SymbolContextList sc_list;
sc_list.Append(SymbolContext(std::move(m)));
options.SetPreferredSymbolContexts(std::move(sc_list));
@@ -197,10 +192,10 @@ HistoryThreads MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address) {
if (!return_value_sp)
return result;
- CreateHistoryThreadFromValueObject(process_sp, return_value_sp, "free",
- "Memory deallocated by", result);
- CreateHistoryThreadFromValueObject(process_sp, return_value_sp, "alloc",
- "Memory allocated by", result);
+ CreateHistoryThreadFromValueObject(process_sp, return_value_sp, pc_type,
+ "free", "Memory deallocated by", result);
+ CreateHistoryThreadFromValueObject(process_sp, return_value_sp, pc_type,
+ "alloc", "Memory allocated by", result);
return result;
}
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index f69358d..931baf5 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -2037,6 +2037,19 @@ static char FindArmAarch64MappingSymbol(const char *symbol_name) {
return '\0';
}
+static char FindRISCVMappingSymbol(const char *symbol_name) {
+ if (!symbol_name)
+ return '\0';
+
+ if (strcmp(symbol_name, "$d") == 0) {
+ return 'd';
+ }
+ if (strcmp(symbol_name, "$x") == 0) {
+ return 'x';
+ }
+ return '\0';
+}
+
#define STO_MIPS_ISA (3 << 6)
#define STO_MICROMIPS (2 << 6)
#define IS_MICROMIPS(ST_OTHER) (((ST_OTHER)&STO_MIPS_ISA) == STO_MICROMIPS)
@@ -2102,6 +2115,12 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
if (!symbol_name)
symbol_name = "";
+ // Skip local symbols starting with ".L" because these are compiler
+ // generated local labels used for internal purposes (e.g. debugging,
+ // optimization) and are not relevant for symbol resolution or external
+ // linkage.
+ if (llvm::StringRef(symbol_name).starts_with(".L"))
+ continue;
// No need to add non-section symbols that have no names
if (symbol.getType() != STT_SECTION &&
(symbol_name == nullptr || symbol_name[0] == '\0'))
@@ -2190,7 +2209,6 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
int64_t symbol_value_offset = 0;
uint32_t additional_flags = 0;
-
if (arch.IsValid()) {
if (arch.GetMachine() == llvm::Triple::arm) {
if (symbol.getBinding() == STB_LOCAL) {
@@ -2235,6 +2253,27 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
if (mapping_symbol)
continue;
}
+ } else if (arch.GetTriple().isRISCV()) {
+ if (symbol.getBinding() == STB_LOCAL) {
+ char mapping_symbol = FindRISCVMappingSymbol(symbol_name);
+ if (symbol_type == eSymbolTypeCode) {
+ // Only handle $d and $x mapping symbols.
+ // Other mapping symbols are ignored as they don't affect address
+ // classification.
+ switch (mapping_symbol) {
+ case 'x':
+ // $x - marks a RISCV instruction sequence
+ address_class_map[symbol.st_value] = AddressClass::eCode;
+ break;
+ case 'd':
+ // $d - marks a RISCV data item sequence
+ address_class_map[symbol.st_value] = AddressClass::eData;
+ break;
+ }
+ }
+ if (mapping_symbol)
+ continue;
+ }
}
if (arch.GetMachine() == llvm::Triple::arm) {
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 13df6e2..924e340 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -1156,6 +1156,7 @@ AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) {
case eSectionTypeDataObjCMessageRefs:
case eSectionTypeDataObjCCFStrings:
case eSectionTypeGoSymtab:
+ case eSectionTypeWasmName:
return AddressClass::eData;
case eSectionTypeDebug:
@@ -2784,7 +2785,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
const char *symbol_name_non_abi_mangled = NULL;
SectionSP symbol_section;
- uint32_t symbol_byte_size = 0;
bool add_nlist = true;
bool is_debug = ((nlist.n_type & N_STAB) != 0);
bool demangled_is_synthesized = false;
@@ -3436,61 +3436,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
if (symbol_section) {
const addr_t section_file_addr =
symbol_section->GetFileAddress();
- if (symbol_byte_size == 0 &&
- function_starts_count > 0) {
- addr_t symbol_lookup_file_addr = nlist.n_value;
- // Do an exact address match for non-ARM addresses,
- // else get the closest since the symbol might be a
- // thumb symbol which has an address with bit zero
- // set
- FunctionStarts::Entry *func_start_entry =
- function_starts.FindEntry(symbol_lookup_file_addr,
- !is_arm);
- if (is_arm && func_start_entry) {
- // Verify that the function start address is the
- // symbol address (ARM) or the symbol address + 1
- // (thumb)
- if (func_start_entry->addr !=
- symbol_lookup_file_addr &&
- func_start_entry->addr !=
- (symbol_lookup_file_addr + 1)) {
- // Not the right entry, NULL it out...
- func_start_entry = NULL;
- }
- }
- if (func_start_entry) {
- func_start_entry->data = true;
-
- addr_t symbol_file_addr = func_start_entry->addr;
- uint32_t symbol_flags = 0;
- if (is_arm) {
- if (symbol_file_addr & 1)
- symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- }
-
- const FunctionStarts::Entry *next_func_start_entry =
- function_starts.FindNextEntry(func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr +
- symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr =
- next_func_start_entry->addr;
- // Be sure the clear the Thumb address bit when
- // we calculate the size from the current and
- // next address
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size =
- section_end_file_addr - symbol_file_addr;
- }
- }
- }
symbol_value -= section_file_addr;
}
@@ -3619,9 +3564,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
}
sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc);
- if (symbol_byte_size > 0)
- sym[sym_idx].SetByteSize(symbol_byte_size);
-
if (demangled_is_synthesized)
sym[sym_idx].SetDemangledNameIsSynthesized(true);
++sym_idx;
@@ -3710,7 +3652,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
SymbolType type = eSymbolTypeInvalid;
SectionSP symbol_section;
- lldb::addr_t symbol_byte_size = 0;
bool add_nlist = true;
bool is_gsym = false;
bool demangled_is_synthesized = false;
@@ -4296,47 +4237,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
if (symbol_section) {
const addr_t section_file_addr = symbol_section->GetFileAddress();
- if (symbol_byte_size == 0 && function_starts_count > 0) {
- addr_t symbol_lookup_file_addr = nlist.n_value;
- // Do an exact address match for non-ARM addresses, else get the
- // closest since the symbol might be a thumb symbol which has an
- // address with bit zero set.
- FunctionStarts::Entry *func_start_entry =
- function_starts.FindEntry(symbol_lookup_file_addr, !is_arm);
- if (is_arm && func_start_entry) {
- // Verify that the function start address is the symbol address
- // (ARM) or the symbol address + 1 (thumb).
- if (func_start_entry->addr != symbol_lookup_file_addr &&
- func_start_entry->addr != (symbol_lookup_file_addr + 1)) {
- // Not the right entry, NULL it out...
- func_start_entry = nullptr;
- }
- }
- if (func_start_entry) {
- func_start_entry->data = true;
-
- addr_t symbol_file_addr = func_start_entry->addr;
- if (is_arm)
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
-
- const FunctionStarts::Entry *next_func_start_entry =
- function_starts.FindNextEntry(func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- // Be sure the clear the Thumb address bit when we calculate the
- // size from the current and next address
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
- }
- }
symbol_value -= section_file_addr;
}
@@ -4443,9 +4343,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
if (nlist.n_desc & N_WEAK_REF)
sym[sym_idx].SetIsWeak(true);
- if (symbol_byte_size > 0)
- sym[sym_idx].SetByteSize(symbol_byte_size);
-
if (demangled_is_synthesized)
sym[sym_idx].SetDemangledNameIsSynthesized(true);
@@ -4564,23 +4461,7 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
Address symbol_addr;
if (module_sp->ResolveFileAddress(symbol_file_addr, symbol_addr)) {
SectionSP symbol_section(symbol_addr.GetSection());
- uint32_t symbol_byte_size = 0;
if (symbol_section) {
- const addr_t section_file_addr = symbol_section->GetFileAddress();
- const FunctionStarts::Entry *next_func_start_entry =
- function_starts.FindNextEntry(func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
sym[sym_idx].SetID(synthetic_sym_id++);
// Don't set the name for any synthetic symbols, the Symbol
// object will generate one if needed when the name is accessed
@@ -4592,8 +4473,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
add_symbol_addr(symbol_addr.GetFileAddress());
if (symbol_flags)
sym[sym_idx].SetFlags(symbol_flags);
- if (symbol_byte_size)
- sym[sym_idx].SetByteSize(symbol_byte_size);
++sym_idx;
}
}
diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
index 25e9888..c361087 100644
--- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
+++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp
@@ -308,40 +308,49 @@ Status MinidumpFileBuilder::AddModuleList() {
// the llvm::minidump::Module's structures into helper data
size_t size_before = GetCurrentDataEndOffset();
- // This is the size of the main part of the ModuleList stream.
- // It consists of a module number and corresponding number of
- // structs describing individual modules
- size_t module_stream_size =
- sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
-
- // Adding directory describing this stream.
- error = AddDirectory(StreamType::ModuleList, module_stream_size);
- if (error.Fail())
- return error;
-
- m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
-
// Temporary storage for the helper data (of variable length)
// as these cannot be dumped to m_data before dumping entire
// array of module structures.
DataBufferHeap helper_data;
+ // Vector to store modules that pass validation.
+ std::vector<std::pair<ModuleSP, uint64_t>> valid_modules;
+
for (size_t i = 0; i < modules_count; ++i) {
ModuleSP mod = modules.GetModuleAtIndex(i);
std::string module_name = mod->GetSpecificationDescription();
auto maybe_mod_size = getModuleFileSize(target, mod);
if (!maybe_mod_size) {
llvm::Error mod_size_err = maybe_mod_size.takeError();
- llvm::handleAllErrors(std::move(mod_size_err),
- [&](const llvm::ErrorInfoBase &E) {
- error = Status::FromErrorStringWithFormat(
- "Unable to get the size of module %s: %s.",
- module_name.c_str(), E.message().c_str());
- });
- return error;
+ Log *log = GetLog(LLDBLog::Object);
+ llvm::handleAllErrors(
+ std::move(mod_size_err), [&](const llvm::ErrorInfoBase &E) {
+ if (log) {
+ LLDB_LOGF(log, "Unable to get the size of module %s: %s",
+ module_name.c_str(), E.message().c_str());
+ }
+ });
+ continue;
}
+ valid_modules.emplace_back(mod, *maybe_mod_size);
+ }
+
+ size_t module_stream_size = sizeof(llvm::support::ulittle32_t) +
+ valid_modules.size() * minidump_module_size;
+
+ error = AddDirectory(StreamType::ModuleList, module_stream_size);
+ if (error.Fail())
+ return error;
- uint64_t mod_size = std::move(*maybe_mod_size);
+ // Setting the header with the number of modules.
+ llvm::support::ulittle32_t count =
+ static_cast<llvm::support::ulittle32_t>(valid_modules.size());
+ m_data.AppendData(&count, sizeof(llvm::support::ulittle32_t));
+
+ for (const auto &valid_module : valid_modules) {
+ ModuleSP mod = valid_module.first;
+ uint64_t module_size = valid_module.second;
+ std::string module_name = mod->GetSpecificationDescription();
llvm::support::ulittle32_t signature =
static_cast<llvm::support::ulittle32_t>(
@@ -381,7 +390,7 @@ Status MinidumpFileBuilder::AddModuleList() {
llvm::minidump::Module m{};
m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
- m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);
+ m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(module_size);
m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
m.TimeDateStamp =
static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index b1efd25..492b441 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/Support/CheckedArithmetic.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Format.h"
#include <optional>
@@ -35,6 +36,82 @@ LLDB_PLUGIN_DEFINE(ObjectFileWasm)
static const uint32_t kWasmHeaderSize =
sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion);
+/// Helper to read a 32-bit ULEB using LLDB's DataExtractor.
+static inline llvm::Expected<uint32_t> GetULEB32(DataExtractor &data,
+ lldb::offset_t &offset) {
+ const uint64_t value = data.GetULEB128(&offset);
+ if (value > std::numeric_limits<uint32_t>::max())
+ return llvm::createStringError("ULEB exceeds 32 bits");
+ return value;
+}
+
+/// Helper to read a 32-bit ULEB using LLVM's DataExtractor.
+static inline llvm::Expected<uint32_t>
+GetULEB32(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
+ const uint64_t value = data.getULEB128(c);
+ if (!c)
+ return c.takeError();
+ if (value > std::numeric_limits<uint32_t>::max())
+ return llvm::createStringError("ULEB exceeds 32 bits");
+ return value;
+}
+
+/// Helper to read a Wasm string, whcih is encoded as a vector of UTF-8 codes.
+static inline llvm::Expected<std::string>
+GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
+ llvm::Expected<uint32_t> len = GetULEB32(data, c);
+ if (!len)
+ return len.takeError();
+
+ llvm::SmallVector<uint8_t, 32> str_storage;
+ data.getU8(c, str_storage, *len);
+ if (!c)
+ return c.takeError();
+
+ return std::string(toStringRef(llvm::ArrayRef(str_storage)));
+}
+
+/// An "init expr" refers to a constant expression used to determine the initial
+/// value of certain elements within a module during instantiation. These
+/// expressions are restricted to operations that can be evaluated at module
+/// instantiation time. Currently we only support simple constant opcodes.
+static lldb::offset_t GetWasmOffsetFromInitExpr(DataExtractor &data,
+ lldb::offset_t &offset) {
+ lldb::offset_t init_expr_offset = LLDB_INVALID_OFFSET;
+
+ uint8_t opcode = data.GetU8(&offset);
+ switch (opcode) {
+ case llvm::wasm::WASM_OPCODE_I32_CONST:
+ case llvm::wasm::WASM_OPCODE_I64_CONST:
+ init_expr_offset = data.GetSLEB128(&offset);
+ break;
+ case llvm::wasm::WASM_OPCODE_GLOBAL_GET:
+ init_expr_offset = data.GetULEB128(&offset);
+ break;
+ case llvm::wasm::WASM_OPCODE_F32_CONST:
+ case llvm::wasm::WASM_OPCODE_F64_CONST:
+ // Not a meaningful offset.
+ data.GetFloat(&offset);
+ break;
+ case llvm::wasm::WASM_OPCODE_REF_NULL:
+ // Not a meaningful offset.
+ data.GetULEB128(&offset);
+ break;
+ }
+
+ // Make sure the opcodes we read aren't part of an extended init expr.
+ opcode = data.GetU8(&offset);
+ if (opcode == llvm::wasm::WASM_OPCODE_END)
+ return init_expr_offset;
+
+ // Extended init expressions are not supported, but we still have to parse
+ // them to skip over them and read the next segment.
+ do {
+ opcode = data.GetU8(&offset);
+ } while (opcode != llvm::wasm::WASM_OPCODE_END);
+ return LLDB_INVALID_OFFSET;
+}
+
/// Checks whether the data buffer starts with a valid Wasm module header.
static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize)
@@ -50,32 +127,6 @@ static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
return version == llvm::wasm::WasmVersion;
}
-static std::optional<ConstString>
-GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
- // A Wasm string is encoded as a vector of UTF-8 codes.
- // Vectors are encoded with their u32 length followed by the element
- // sequence.
- uint64_t len = data.getULEB128(c);
- if (!c) {
- consumeError(c.takeError());
- return std::nullopt;
- }
-
- if (len >= (uint64_t(1) << 32)) {
- return std::nullopt;
- }
-
- llvm::SmallVector<uint8_t, 32> str_storage;
- data.getU8(c, str_storage, len);
- if (!c) {
- consumeError(c.takeError());
- return std::nullopt;
- }
-
- llvm::StringRef str = toStringRef(llvm::ArrayRef(str_storage));
- return ConstString(str);
-}
-
char ObjectFileWasm::ID;
void ObjectFileWasm::Initialize() {
@@ -174,7 +225,7 @@ bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
if (!c)
return !llvm::errorToBool(c.takeError());
- if (payload_len >= (uint64_t(1) << 32))
+ if (payload_len > std::numeric_limits<uint32_t>::max())
return false;
if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
@@ -182,16 +233,19 @@ bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
// identifying the custom section, followed by an uninterpreted sequence
// of bytes.
lldb::offset_t prev_offset = c.tell();
- std::optional<ConstString> sect_name = GetWasmString(data, c);
- if (!sect_name)
+ llvm::Expected<std::string> sect_name = GetWasmString(data, c);
+ if (!sect_name) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Object), sect_name.takeError(),
+ "failed to parse section name: {0}");
return false;
+ }
if (payload_len < c.tell() - prev_offset)
return false;
uint32_t section_length = payload_len - (c.tell() - prev_offset);
m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length,
- section_id, *sect_name});
+ section_id, ConstString(*sect_name)});
*offset_ptr += (c.tell() + section_length);
} else if (section_id <= llvm::wasm::WASM_SEC_LAST_KNOWN) {
m_sect_infos.push_back(section_info{*offset_ptr + c.tell(),
@@ -248,16 +302,221 @@ bool ObjectFileWasm::ParseHeader() {
return true;
}
-void ObjectFileWasm::ParseSymtab(Symtab &symtab) {}
+struct WasmFunction {
+ lldb::offset_t section_offset = LLDB_INVALID_OFFSET;
+ uint32_t size = 0;
+};
+
+static llvm::Expected<std::vector<WasmFunction>>
+ParseFunctions(DataExtractor &data) {
+ lldb::offset_t offset = 0;
+
+ llvm::Expected<uint32_t> function_count = GetULEB32(data, offset);
+ if (!function_count)
+ return function_count.takeError();
+
+ std::vector<WasmFunction> functions;
+ functions.reserve(*function_count);
+
+ for (uint32_t i = 0; i < *function_count; ++i) {
+ llvm::Expected<uint32_t> function_size = GetULEB32(data, offset);
+ if (!function_size)
+ return function_size.takeError();
+ // llvm-objdump considers the ULEB with the function size to be part of the
+ // function. We can't do that here because that would break symbolic
+ // breakpoints, as that address is never executed.
+ functions.push_back({offset, *function_size});
+
+ std::optional<lldb::offset_t> next_offset =
+ llvm::checkedAddUnsigned<lldb::offset_t>(offset, *function_size);
+ if (!next_offset)
+ return llvm::createStringError("function offset overflows 64 bits");
+ offset = *next_offset;
+ }
+
+ return functions;
+}
+
+struct WasmSegment {
+ enum SegmentType {
+ Active,
+ Passive,
+ };
+
+ std::string name;
+ SegmentType type = Passive;
+ lldb::offset_t section_offset = LLDB_INVALID_OFFSET;
+ uint32_t size = 0;
+ uint32_t memory_index = 0;
+ lldb::offset_t init_expr_offset = 0;
+
+ lldb::offset_t GetFileOffset() const { return section_offset & 0xffffffff; }
+};
+
+static llvm::Expected<std::vector<WasmSegment>> ParseData(DataExtractor &data) {
+ lldb::offset_t offset = 0;
+
+ llvm::Expected<uint32_t> segment_count = GetULEB32(data, offset);
+ if (!segment_count)
+ return segment_count.takeError();
+
+ std::vector<WasmSegment> segments;
+ segments.reserve(*segment_count);
+
+ for (uint32_t i = 0; i < *segment_count; ++i) {
+ llvm::Expected<uint32_t> flags = GetULEB32(data, offset);
+ if (!flags)
+ return flags.takeError();
+
+ WasmSegment segment;
+
+ // Data segments have a mode that identifies them as either passive or
+ // active. An active data segment copies its contents into a memory during
+ // instantiation, as specified by a memory index and a constant expression
+ // defining an offset into that memory.
+ segment.type = (*flags & llvm::wasm::WASM_DATA_SEGMENT_IS_PASSIVE)
+ ? WasmSegment::Passive
+ : WasmSegment::Active;
+
+ if (*flags & llvm::wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX) {
+ assert(segment.type == WasmSegment::Active);
+ llvm::Expected<uint32_t> memidx = GetULEB32(data, offset);
+ if (!memidx)
+ return memidx.takeError();
+ segment.memory_index = *memidx;
+ }
+
+ if (segment.type == WasmSegment::Active)
+ segment.init_expr_offset = GetWasmOffsetFromInitExpr(data, offset);
+
+ llvm::Expected<uint32_t> segment_size = GetULEB32(data, offset);
+ if (!segment_size)
+ return segment_size.takeError();
+
+ segment.section_offset = offset;
+ segment.size = *segment_size;
+ segments.push_back(segment);
+
+ std::optional<lldb::offset_t> next_offset =
+ llvm::checkedAddUnsigned<lldb::offset_t>(offset, *segment_size);
+ if (!next_offset)
+ return llvm::createStringError("segment offset overflows 64 bits");
+ offset = *next_offset;
+ }
+
+ return segments;
+}
+
+static llvm::Expected<std::vector<Symbol>>
+ParseNames(SectionSP code_section_sp, DataExtractor &name_data,
+ const std::vector<WasmFunction> &functions,
+ std::vector<WasmSegment> &segments) {
+
+ llvm::DataExtractor data = name_data.GetAsLLVM();
+ llvm::DataExtractor::Cursor c(0);
+ std::vector<Symbol> symbols;
+ while (c && c.tell() < data.size()) {
+ const uint8_t type = data.getU8(c);
+ llvm::Expected<uint32_t> size = GetULEB32(data, c);
+ if (!size)
+ return size.takeError();
+
+ switch (type) {
+ case llvm::wasm::WASM_NAMES_FUNCTION: {
+ const uint64_t count = data.getULEB128(c);
+ if (count > std::numeric_limits<uint32_t>::max())
+ return llvm::createStringError("function count overflows uint32_t");
+
+ for (uint64_t i = 0; c && i < count; ++i) {
+ llvm::Expected<uint32_t> idx = GetULEB32(data, c);
+ if (!idx)
+ return idx.takeError();
+ llvm::Expected<std::string> name = GetWasmString(data, c);
+ if (!name)
+ return name.takeError();
+ if (*idx >= functions.size())
+ continue;
+ symbols.emplace_back(
+ symbols.size(), *name, lldb::eSymbolTypeCode,
+ /*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false,
+ /*is_artificial=*/false, code_section_sp,
+ functions[i].section_offset, functions[i].size,
+ /*size_is_valid=*/true, /*contains_linker_annotations=*/false,
+ /*flags=*/0);
+ }
+ } break;
+ case llvm::wasm::WASM_NAMES_DATA_SEGMENT: {
+ llvm::Expected<uint32_t> count = GetULEB32(data, c);
+ if (!count)
+ return count.takeError();
+ for (uint32_t i = 0; c && i < *count; ++i) {
+ llvm::Expected<uint32_t> idx = GetULEB32(data, c);
+ if (!idx)
+ return idx.takeError();
+ llvm::Expected<std::string> name = GetWasmString(data, c);
+ if (!name)
+ return name.takeError();
+ if (*idx >= segments.size())
+ continue;
+ // Update the segment name.
+ segments[i].name = *name;
+ }
+
+ } break;
+ case llvm::wasm::WASM_NAMES_GLOBAL:
+ case llvm::wasm::WASM_NAMES_LOCAL:
+ default:
+ std::optional<lldb::offset_t> offset =
+ llvm::checkedAddUnsigned<lldb::offset_t>(c.tell(), *size);
+ if (!offset)
+ return llvm::createStringError("offset overflows 64 bits");
+ c.seek(*offset);
+ }
+ }
+
+ if (!c)
+ return c.takeError();
+
+ return symbols;
+}
+
+void ObjectFileWasm::ParseSymtab(Symtab &symtab) {
+ for (const Symbol &symbol : m_symbols)
+ symtab.AddSymbol(symbol);
+
+ symtab.Finalize();
+ m_symbols.clear();
+}
static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
- if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {
+ if (Name == "name")
+ return lldb::eSectionTypeWasmName;
+ if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_"))
return ObjectFile::GetDWARFSectionTypeFromName(Name);
- }
return eSectionTypeOther;
}
+std::optional<ObjectFileWasm::section_info>
+ObjectFileWasm::GetSectionInfo(uint32_t section_id) {
+ for (const section_info &sect_info : m_sect_infos) {
+ if (sect_info.id == section_id)
+ return sect_info;
+ }
+ return std::nullopt;
+}
+
+std::optional<ObjectFileWasm::section_info>
+ObjectFileWasm::GetSectionInfo(llvm::StringRef section_name) {
+ for (const section_info &sect_info : m_sect_infos) {
+ if (sect_info.name == section_name)
+ return sect_info;
+ }
+ return std::nullopt;
+}
+
void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
+ Log *log = GetLog(LLDBLog::Object);
+
if (m_sections_up)
return;
@@ -271,7 +530,7 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
SectionType section_type = eSectionTypeOther;
ConstString section_name;
offset_t file_offset = sect_info.offset & 0xffffffff;
- addr_t vm_addr = file_offset;
+ addr_t vm_addr = sect_info.offset;
size_t vm_size = sect_info.size;
if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
@@ -294,23 +553,107 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
}
}
- SectionSP section_sp(
- new Section(GetModule(), // Module to which this section belongs.
- this, // ObjectFile to which this section belongs and
- // should read section data from.
- section_type, // Section ID.
- section_name, // Section name.
- section_type, // Section type.
- vm_addr, // VM address.
- vm_size, // VM size in bytes of this section.
- file_offset, // Offset of this section in the file.
- sect_info.size, // Size of the section as found in the file.
- 0, // Alignment of the section
- 0, // Flags for this section.
- 1)); // Number of host bytes per target byte
+ SectionSP section_sp = std::make_shared<Section>(
+ GetModule(), // Module to which this section belongs.
+ this, // ObjectFile to which this section belongs and
+ // should read section data from.
+ section_type, // Section ID.
+ section_name, // Section name.
+ section_type, // Section type.
+ vm_addr, // VM address.
+ vm_size, // VM size in bytes of this section.
+ file_offset, // Offset of this section in the file.
+ sect_info.size, // Size of the section as found in the file.
+ 0, // Alignment of the section
+ 0, // Flags for this section.
+ 1); // Number of host bytes per target byte
m_sections_up->AddSection(section_sp);
unified_section_list.AddSection(section_sp);
}
+
+ // The name section contains names and indexes. First parse the data from the
+ // relevant sections so we can access it by its index.
+ std::vector<WasmFunction> functions;
+ std::vector<WasmSegment> segments;
+
+ // Parse the code section.
+ if (std::optional<section_info> info =
+ GetSectionInfo(llvm::wasm::WASM_SEC_CODE)) {
+ DataExtractor code_data = ReadImageData(info->offset, info->size);
+ llvm::Expected<std::vector<WasmFunction>> maybe_functions =
+ ParseFunctions(code_data);
+ if (!maybe_functions) {
+ LLDB_LOG_ERROR(log, maybe_functions.takeError(),
+ "Failed to parse Wasm code section: {0}");
+ } else {
+ functions = *maybe_functions;
+ }
+ }
+
+ // Parse the data section.
+ std::optional<section_info> data_info =
+ GetSectionInfo(llvm::wasm::WASM_SEC_DATA);
+ if (data_info) {
+ DataExtractor data_data = ReadImageData(data_info->offset, data_info->size);
+ llvm::Expected<std::vector<WasmSegment>> maybe_segments =
+ ParseData(data_data);
+ if (!maybe_segments) {
+ LLDB_LOG_ERROR(log, maybe_segments.takeError(),
+ "Failed to parse Wasm data section: {0}");
+ } else {
+ segments = *maybe_segments;
+ }
+ }
+
+ if (std::optional<section_info> info = GetSectionInfo("name")) {
+ DataExtractor names_data = ReadImageData(info->offset, info->size);
+ llvm::Expected<std::vector<Symbol>> symbols = ParseNames(
+ m_sections_up->FindSectionByType(lldb::eSectionTypeCode, false),
+ names_data, functions, segments);
+ if (!symbols) {
+ LLDB_LOG_ERROR(log, symbols.takeError(),
+ "Failed to parse Wasm names: {0}");
+ } else {
+ m_symbols = *symbols;
+ }
+ }
+
+ lldb::user_id_t segment_id = 0;
+ for (const WasmSegment &segment : segments) {
+ if (segment.type == WasmSegment::Active) {
+ // FIXME: Support segments with a memory index.
+ if (segment.memory_index != 0) {
+ LLDB_LOG(log, "Skipping segment {0}: non-zero memory index is "
+ "currently unsupported");
+ continue;
+ }
+
+ if (segment.init_expr_offset == LLDB_INVALID_OFFSET) {
+ LLDB_LOG(log, "Skipping segment {0}: unsupported init expression");
+ continue;
+ }
+ }
+
+ const lldb::addr_t file_vm_addr =
+ segment.type == WasmSegment::Active
+ ? segment.init_expr_offset
+ : data_info->offset + segment.section_offset;
+ const lldb::offset_t file_offset =
+ data_info->GetFileOffset() + segment.GetFileOffset();
+ SectionSP segment_sp = std::make_shared<Section>(
+ GetModule(),
+ /*obj_file=*/this,
+ ++segment_id << 8, // 1-based segment index, shifted by 8 bits to avoid
+ // collision with section IDs.
+ ConstString(segment.name), eSectionTypeData,
+ /*file_vm_addr=*/file_vm_addr,
+ /*vm_size=*/segment.size,
+ /*file_offset=*/file_offset,
+ /*file_size=*/segment.size,
+ /*log2align=*/0, /*flags=*/0);
+ m_sections_up->AddSection(segment_sp);
+ GetModule()->GetSectionList()->AddSection(segment_sp);
+ }
}
bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
@@ -395,11 +738,15 @@ std::optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() {
const uint32_t kBufferSize = 1024;
DataExtractor section_header_data =
ReadImageData(sect_info.offset, kBufferSize);
+
llvm::DataExtractor data = section_header_data.GetAsLLVM();
llvm::DataExtractor::Cursor c(0);
- std::optional<ConstString> symbols_url = GetWasmString(data, c);
- if (symbols_url)
- return FileSpec(symbols_url->GetStringRef());
+ llvm::Expected<std::string> symbols_url = GetWasmString(data, c);
+ if (!symbols_url) {
+ llvm::consumeError(symbols_url.takeError());
+ return std::nullopt;
+ }
+ return FileSpec(*symbols_url);
}
}
return std::nullopt;
@@ -431,7 +778,7 @@ void ObjectFileWasm::Dump(Stream *s) {
}
void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
- const section_info_t &sh) {
+ const section_info &sh) {
ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
<< llvm::format_hex(sh.offset, 10) << " "
<< llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
index 531b5f0..86ecbf2 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
@@ -128,20 +128,25 @@ private:
/// Read a range of bytes from the Wasm module.
DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size);
- typedef struct section_info {
+ struct section_info {
lldb::offset_t offset;
uint32_t size;
uint32_t id;
ConstString name;
- } section_info_t;
+ lldb::offset_t GetFileOffset() const { return offset & 0xffffffff; }
+ };
+
+ std::optional<section_info> GetSectionInfo(uint32_t section_id);
+ std::optional<section_info> GetSectionInfo(llvm::StringRef section_name);
/// Wasm section header dump routines.
/// \{
- void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info_t &sh);
+ void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info &sh);
void DumpSectionHeaders(llvm::raw_ostream &ostream);
/// \}
- std::vector<section_info_t> m_sect_infos;
+ std::vector<section_info> m_sect_infos;
+ std::vector<Symbol> m_symbols;
ArchSpec m_arch;
UUID m_uuid;
};
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index 1db7bc7..cd72454 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -1039,7 +1039,12 @@ ResolveSDKPathFromDebugInfo(lldb_private::Target *target) {
SymbolFile *sym_file = exe_module_sp->GetSymbolFile();
if (!sym_file)
- return llvm::createStringError("Failed to get symbol file from module");
+ return llvm::createStringError("Failed to get symbol file from executable");
+
+ if (sym_file->GetNumCompileUnits() == 0)
+ return llvm::createStringError(
+ "Failed to resolve SDK for target: executable's symbol file has no "
+ "compile units");
XcodeSDK merged_sdk;
for (unsigned i = 0; i < sym_file->GetNumCompileUnits(); ++i) {
@@ -1397,6 +1402,12 @@ PlatformDarwin::GetSDKPathFromDebugInfo(Module &module) {
llvm::formatv("No symbol file available for module '{0}'",
module.GetFileSpec().GetFilename().AsCString("")));
+ if (sym_file->GetNumCompileUnits() == 0)
+ return llvm::createStringError(
+ llvm::formatv("Could not resolve SDK for module '{0}'. Symbol file has "
+ "no compile units.",
+ module.GetFileSpec()));
+
bool found_public_sdk = false;
bool found_internal_sdk = false;
XcodeSDK merged_sdk;
diff --git a/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
index b0d1370..c35b4de 100644
--- a/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/FreeBSDKernel/CMakeLists.txt
@@ -2,7 +2,7 @@ set(FBSDKERNEL_LIBS)
if(FBSDVMCore_FOUND)
list(APPEND FBSDKERNEL_LIBS fbsdvmcore)
endif()
-if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
list(APPEND FBSDKERNEL_LIBS kvm)
endif()
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
index fdafacf..c1bc6a3 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -76,7 +76,7 @@ NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
::memset(&m_fpr, 0, sizeof(m_fpr));
::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
- ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
+ ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
// 16 is just a maximum value, query hardware for actual watchpoint count
m_max_hwp_supported = 16;
@@ -283,522 +283,43 @@ bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
return false;
}
-uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- Status error;
-
- // Read hardware breakpoint and watchpoint information.
- error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return 0;
-
- LLDB_LOG(log, "{0}", m_max_hbp_supported);
- return m_max_hbp_supported;
-}
-
-uint32_t
-NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
- size_t size) {
- Log *log = GetLog(POSIXLog::Breakpoints);
- LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return LLDB_INVALID_INDEX32;
-
- uint32_t control_value = 0, bp_index = 0;
-
- // Setup address and control values.
- // Use size to get a hint of arm vs thumb modes.
- switch (size) {
- case 2:
- control_value = (0x3 << 5) | 7;
- addr &= ~1;
- break;
- case 4:
- control_value = (0xfu << 5) | 7;
- addr &= ~3;
- break;
- default:
- return LLDB_INVALID_INDEX32;
- }
-
- // Iterate over stored breakpoints and find a free bp_index
- bp_index = LLDB_INVALID_INDEX32;
- for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
- if ((m_hbr_regs[i].control & 1) == 0) {
- bp_index = i; // Mark last free slot
- } else if (m_hbr_regs[i].address == addr) {
- return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
- }
- }
-
- if (bp_index == LLDB_INVALID_INDEX32)
- return LLDB_INVALID_INDEX32;
-
- // Update breakpoint in local cache
- m_hbr_regs[bp_index].real_addr = addr;
- m_hbr_regs[bp_index].address = addr;
- m_hbr_regs[bp_index].control = control_value;
-
- // PTRACE call to set corresponding hardware breakpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
- bp_index);
-
- if (error.Fail()) {
- m_hbr_regs[bp_index].address = 0;
- m_hbr_regs[bp_index].control &= ~1;
-
- return LLDB_INVALID_INDEX32;
- }
-
- return bp_index;
-}
-
-bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
- Log *log = GetLog(POSIXLog::Breakpoints);
- LLDB_LOG(log, "hw_idx: {0}", hw_idx);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return false;
-
- if (hw_idx >= m_max_hbp_supported)
- return false;
-
- // Create a backup we can revert to in case of failure.
- lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
- uint32_t tempControl = m_hbr_regs[hw_idx].control;
-
- m_hbr_regs[hw_idx].control &= ~1;
- m_hbr_regs[hw_idx].address = 0;
-
- // PTRACE call to clear corresponding hardware breakpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
- hw_idx);
-
- if (error.Fail()) {
- m_hbr_regs[hw_idx].control = tempControl;
- m_hbr_regs[hw_idx].address = tempAddr;
-
- return false;
- }
-
- return true;
-}
-
-Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
- uint32_t &bp_index, lldb::addr_t trap_addr) {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- lldb::addr_t break_addr;
-
- for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
- break_addr = m_hbr_regs[bp_index].address;
-
- if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
- m_hbr_regs[bp_index].hit_addr = trap_addr;
- return Status();
- }
- }
-
- bp_index = LLDB_INVALID_INDEX32;
- return Status();
-}
-
-Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- Status error;
-
- // Read hardware breakpoint and watchpoint information.
- error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return error;
-
- lldb::addr_t tempAddr = 0;
- uint32_t tempControl = 0;
-
- for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
- if (m_hbr_regs[i].control & 0x01) {
- // Create a backup we can revert to in case of failure.
- tempAddr = m_hbr_regs[i].address;
- tempControl = m_hbr_regs[i].control;
-
- // Clear breakpoints in local cache
- m_hbr_regs[i].control &= ~1;
- m_hbr_regs[i].address = 0;
-
- // Ptrace call to update hardware debug registers
- error =
- WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, i);
-
- if (error.Fail()) {
- m_hbr_regs[i].control = tempControl;
- m_hbr_regs[i].address = tempAddr;
-
- return error;
- }
- }
- }
-
- return Status();
-}
-
-uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
- Log *log = GetLog(POSIXLog::Watchpoints);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return 0;
-
- LLDB_LOG(log, "{0}", m_max_hwp_supported);
- return m_max_hwp_supported;
-}
-
-uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
- lldb::addr_t addr, size_t size, uint32_t watch_flags) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
- watch_flags);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return LLDB_INVALID_INDEX32;
-
- uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
- lldb::addr_t real_addr = addr;
-
- // Check if we are setting watchpoint other than read/write/access Also
- // update watchpoint flag to match Arm write-read bit configuration.
- switch (watch_flags) {
- case 1:
- watch_flags = 2;
- break;
- case 2:
- watch_flags = 1;
- break;
- case 3:
- break;
- default:
- return LLDB_INVALID_INDEX32;
- }
-
- // Can't watch zero bytes
- // Can't watch more than 4 bytes per WVR/WCR pair
-
- if (size == 0 || size > 4)
- return LLDB_INVALID_INDEX32;
-
- // Check 4-byte alignment for hardware watchpoint target address. Below is a
- // hack to recalculate address and size in order to make sure we can watch
- // non 4-byte aligned addresses as well.
- if (addr & 0x03) {
- uint8_t watch_mask = (addr & 0x03) + size;
-
- if (watch_mask > 0x04)
- return LLDB_INVALID_INDEX32;
- else if (watch_mask <= 0x02)
- size = 2;
- else
- size = 4;
-
- addr = addr & (~0x03);
- }
-
- // We can only watch up to four bytes that follow a 4 byte aligned address
- // per watchpoint register pair, so make sure we can properly encode this.
- addr_word_offset = addr % 4;
- byte_mask = ((1u << size) - 1u) << addr_word_offset;
-
- // Check if we need multiple watchpoint register
- if (byte_mask > 0xfu)
- return LLDB_INVALID_INDEX32;
-
- // Setup control value
- // Make the byte_mask into a valid Byte Address Select mask
- control_value = byte_mask << 5;
-
- // Turn on appropriate watchpoint flags read or write
- control_value |= (watch_flags << 3);
-
- // Enable this watchpoint and make it stop in privileged or user mode;
- control_value |= 7;
-
- // Make sure bits 1:0 are clear in our address
- addr &= ~((lldb::addr_t)3);
-
- // Iterate over stored watchpoints and find a free wp_index
- wp_index = LLDB_INVALID_INDEX32;
- for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
- if ((m_hwp_regs[i].control & 1) == 0) {
- wp_index = i; // Mark last free slot
- } else if (m_hwp_regs[i].address == addr) {
- return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
- }
- }
-
- if (wp_index == LLDB_INVALID_INDEX32)
- return LLDB_INVALID_INDEX32;
-
- // Update watchpoint in local cache
- m_hwp_regs[wp_index].real_addr = real_addr;
- m_hwp_regs[wp_index].address = addr;
- m_hwp_regs[wp_index].control = control_value;
-
- // PTRACE call to set corresponding watchpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
- wp_index);
-
- if (error.Fail()) {
- m_hwp_regs[wp_index].address = 0;
- m_hwp_regs[wp_index].control &= ~1;
-
- return LLDB_INVALID_INDEX32;
- }
-
- return wp_index;
-}
-
-bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
- uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return false;
-
- if (wp_index >= m_max_hwp_supported)
- return false;
-
- // Create a backup we can revert to in case of failure.
- lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
- uint32_t tempControl = m_hwp_regs[wp_index].control;
-
- // Update watchpoint in local cache
- m_hwp_regs[wp_index].control &= ~1;
- m_hwp_regs[wp_index].address = 0;
-
- // Ptrace call to update hardware debug registers
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
- wp_index);
-
- if (error.Fail()) {
- m_hwp_regs[wp_index].control = tempControl;
- m_hwp_regs[wp_index].address = tempAddr;
-
- return false;
- }
-
- return true;
-}
-
-Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return error;
-
- lldb::addr_t tempAddr = 0;
- uint32_t tempControl = 0;
-
- for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
- if (m_hwp_regs[i].control & 0x01) {
- // Create a backup we can revert to in case of failure.
- tempAddr = m_hwp_regs[i].address;
- tempControl = m_hwp_regs[i].control;
-
- // Clear watchpoints in local cache
- m_hwp_regs[i].control &= ~1;
- m_hwp_regs[i].address = 0;
-
- // Ptrace call to update hardware debug registers
- error =
- WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, i);
-
- if (error.Fail()) {
- m_hwp_regs[i].control = tempControl;
- m_hwp_regs[i].address = tempAddr;
-
- return error;
- }
- }
- }
-
- return Status();
-}
-
-uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
- case 0x01:
- return 1;
- case 0x03:
- return 2;
- case 0x07:
- return 3;
- case 0x0f:
- return 4;
- default:
- return 0;
- }
-}
-bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
- return true;
- else
- return false;
-}
-
-Status
-NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
-
- uint32_t watch_size;
- lldb::addr_t watch_addr;
-
- for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
- watch_size = GetWatchpointSize(wp_index);
- watch_addr = m_hwp_regs[wp_index].address;
-
- if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
- trap_addr < watch_addr + watch_size) {
- m_hwp_regs[wp_index].hit_addr = trap_addr;
- return Status();
- }
- }
-
- wp_index = LLDB_INVALID_INDEX32;
- return Status();
-}
-
-lldb::addr_t
-NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if (wp_index >= m_max_hwp_supported)
- return LLDB_INVALID_ADDRESS;
-
- if (WatchpointIsEnabled(wp_index))
- return m_hwp_regs[wp_index].real_addr;
- else
- return LLDB_INVALID_ADDRESS;
-}
-
-lldb::addr_t
-NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if (wp_index >= m_max_hwp_supported)
- return LLDB_INVALID_ADDRESS;
-
- if (WatchpointIsEnabled(wp_index))
- return m_hwp_regs[wp_index].hit_addr;
- else
- return LLDB_INVALID_ADDRESS;
-}
-
-Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
- Status error;
-
- if (!m_refresh_hwdebug_info) {
- return Status();
- }
+llvm::Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
+ if (!m_refresh_hwdebug_info)
+ return llvm::Error::success();
#ifdef __arm__
unsigned int cap_val;
-
- error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
- nullptr, &cap_val,
- sizeof(unsigned int));
+ Status error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val,
+ sizeof(unsigned int));
if (error.Fail())
- return error;
+ return error.ToError();
m_max_hwp_supported = (cap_val >> 8) & 0xff;
m_max_hbp_supported = cap_val & 0xff;
m_refresh_hwdebug_info = false;
- return error;
+ return error.ToError();
#else // __aarch64__
return arm64::ReadHardwareDebugInfo(m_thread.GetID(), m_max_hwp_supported,
- m_max_hbp_supported);
+ m_max_hbp_supported)
+ .ToError();
#endif // ifdef __arm__
}
-Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
- NativeRegisterContextDBReg::DREGType hwbType, int hwb_index) {
- Status error;
-
+llvm::Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType) {
#ifdef __arm__
- lldb::addr_t *addr_buf;
- uint32_t *ctrl_buf;
-
- if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) {
- addr_buf = &m_hwp_regs[hwb_index].address;
- ctrl_buf = &m_hwp_regs[hwb_index].control;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
- sizeof(unsigned int));
-
- if (error.Fail())
- return error;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
- sizeof(unsigned int));
- } else {
- addr_buf = &m_hbr_regs[hwb_index].address;
- ctrl_buf = &m_hbr_regs[hwb_index].control;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
- sizeof(unsigned int));
+ uint32_t max_index = m_max_hbp_supported;
+ if (hwbType == eDREGTypeWATCH)
+ max_index = m_max_hwp_supported;
- if (error.Fail())
+ for (uint32_t idx = 0; idx < max_index; ++idx)
+ if (auto error = WriteHardwareDebugReg(hwbType, idx))
return error;
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
- sizeof(unsigned int));
- }
-
- return error;
+ return llvm::Error::success();
#else // __aarch64__
uint32_t max_supported =
(hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
@@ -806,12 +327,48 @@ Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
: m_max_hbp_supported;
auto &regs = (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
? m_hwp_regs
- : m_hbr_regs;
+ : m_hbp_regs;
return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported,
- regs);
+ regs)
+ .ToError();
#endif // ifdef __arm__
}
+#ifdef __arm__
+llvm::Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugReg(DREGType hwbType,
+ int hwb_index) {
+ Status error;
+ lldb::addr_t *addr_buf;
+ uint32_t *ctrl_buf;
+ int addr_idx = (hwb_index << 1) + 1;
+ int ctrl_idx = addr_idx + 1;
+
+ if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) {
+ addr_idx *= -1;
+ addr_buf = &m_hwp_regs[hwb_index].address;
+ ctrl_idx *= -1;
+ ctrl_buf = &m_hwp_regs[hwb_index].control;
+ } else {
+ addr_buf = &m_hbp_regs[hwb_index].address;
+ ctrl_buf = &m_hbp_regs[hwb_index].control;
+ }
+
+ error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)addr_idx,
+ addr_buf, sizeof(unsigned int));
+
+ if (error.Fail())
+ return error.ToError();
+
+ error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)ctrl_idx,
+ ctrl_buf, sizeof(unsigned int));
+
+ return error.ToError();
+}
+#endif // ifdef __arm__
+
uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
const RegisterInfo *reg_info) const {
return reg_info->byte_offset - GetGPRSize();
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
index 3a31d68..cf36859 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
@@ -12,7 +12,7 @@
#define lldb_NativeRegisterContextLinux_arm_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
-#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
@@ -21,7 +21,8 @@ namespace process_linux {
class NativeProcessLinux;
-class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
+class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux,
+ public NativeRegisterContextDBReg_arm {
public:
NativeRegisterContextLinux_arm(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
@@ -42,39 +43,6 @@ public:
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
- // Hardware breakpoints/watchpoint management functions
-
- uint32_t NumSupportedHardwareBreakpoints() override;
-
- uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
-
- bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
-
- Status ClearAllHardwareBreakpoints() override;
-
- Status GetHardwareBreakHitIndex(uint32_t &bp_index,
- lldb::addr_t trap_addr) override;
-
- uint32_t NumSupportedHardwareWatchpoints() override;
-
- uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
- uint32_t watch_flags) override;
-
- bool ClearHardwareWatchpoint(uint32_t hw_index) override;
-
- Status ClearAllHardwareWatchpoints() override;
-
- Status GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr) override;
-
- lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
-
- lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
-
- uint32_t GetWatchpointSize(uint32_t wp_index);
-
- bool WatchpointIsEnabled(uint32_t wp_index);
-
protected:
Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
uint32_t size, RegisterValue &value) override;
@@ -100,23 +68,18 @@ private:
uint32_t m_gpr_arm[k_num_gpr_registers_arm];
RegisterInfoPOSIX_arm::FPU m_fpr;
- std::array<NativeRegisterContextDBReg::DREG, 16>
- m_hbr_regs; // Arm native linux hardware breakpoints
- std::array<NativeRegisterContextDBReg::DREG, 16>
- m_hwp_regs; // Arm native linux hardware watchpoints
-
- uint32_t m_max_hwp_supported;
- uint32_t m_max_hbp_supported;
bool m_refresh_hwdebug_info;
bool IsGPR(unsigned reg) const;
bool IsFPR(unsigned reg) const;
- Status ReadHardwareDebugInfo();
+ llvm::Error ReadHardwareDebugInfo() override;
- Status WriteHardwareDebugRegs(NativeRegisterContextDBReg::DREGType hwbType,
- int hwb_index);
+ llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
+#ifdef __arm__
+ llvm::Error WriteHardwareDebugReg(DREGType hwbType, int hwb_index);
+#endif
uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 5d99c22..b1e326e 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lldb_library(lldbPluginProcessUtility
MemoryTagManagerAArch64MTE.cpp
NativeProcessSoftwareSingleStep.cpp
NativeRegisterContextDBReg.cpp
+ NativeRegisterContextDBReg_arm.cpp
NativeRegisterContextDBReg_arm64.cpp
NativeRegisterContextDBReg_loongarch.cpp
NativeRegisterContextDBReg_x86.cpp
diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
index bc06757..93efa2a 100644
--- a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
+++ b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
@@ -27,13 +27,12 @@ using namespace lldb_private;
HistoryThread::HistoryThread(lldb_private::Process &process, lldb::tid_t tid,
std::vector<lldb::addr_t> pcs,
- bool pcs_are_call_addresses)
+ HistoryPCType pc_type)
: Thread(process, tid, true), m_framelist_mutex(), m_framelist(),
m_pcs(pcs), m_extended_unwind_token(LLDB_INVALID_ADDRESS), m_queue_name(),
m_thread_name(), m_originating_unique_thread_id(tid),
m_queue_id(LLDB_INVALID_QUEUE_ID) {
- m_unwinder_up =
- std::make_unique<HistoryUnwind>(*this, pcs, pcs_are_call_addresses);
+ m_unwinder_up = std::make_unique<HistoryUnwind>(*this, pcs, pc_type);
Log *log = GetLog(LLDBLog::Object);
LLDB_LOGF(log, "%p HistoryThread::HistoryThread", static_cast<void *>(this));
}
diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.h b/lldb/source/Plugins/Process/Utility/HistoryThread.h
index a66e0f2..cdc3b09 100644
--- a/lldb/source/Plugins/Process/Utility/HistoryThread.h
+++ b/lldb/source/Plugins/Process/Utility/HistoryThread.h
@@ -27,14 +27,14 @@ namespace lldb_private {
/// process execution
///
/// This subclass of Thread is used to provide a backtrace from earlier in
-/// process execution. It is given a backtrace list of pc addresses and it
-/// will create stack frames for them.
+/// process execution. It is given a backtrace list of pcs (return or call
+/// addresses) and it will create stack frames for them.
class HistoryThread : public lldb_private::Thread {
public:
HistoryThread(lldb_private::Process &process, lldb::tid_t tid,
std::vector<lldb::addr_t> pcs,
- bool pcs_are_call_addresses = false);
+ HistoryPCType pc_type = HistoryPCType::Returns);
~HistoryThread() override;
diff --git a/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp b/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp
index 7749dc6..3b0618f 100644
--- a/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp
+++ b/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp
@@ -24,9 +24,8 @@ using namespace lldb_private;
// Constructor
HistoryUnwind::HistoryUnwind(Thread &thread, std::vector<lldb::addr_t> pcs,
- bool pcs_are_call_addresses)
- : Unwind(thread), m_pcs(pcs),
- m_pcs_are_call_addresses(pcs_are_call_addresses) {}
+ HistoryPCType pc_type)
+ : Unwind(thread), m_pcs(pcs), m_pc_type(pc_type) {}
// Destructor
@@ -52,6 +51,17 @@ HistoryUnwind::DoCreateRegisterContextForFrame(StackFrame *frame) {
return rctx;
}
+static bool BehavesLikeZerothFrame(HistoryPCType pc_type, uint32_t frame_idx) {
+ switch (pc_type) {
+ case HistoryPCType::Returns:
+ return (frame_idx == 0);
+ case HistoryPCType::ReturnsNoZerothFrame:
+ return false;
+ case HistoryPCType::Calls:
+ return true;
+ }
+}
+
bool HistoryUnwind::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
lldb::addr_t &pc,
bool &behaves_like_zeroth_frame) {
@@ -61,10 +71,7 @@ bool HistoryUnwind::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
if (frame_idx < m_pcs.size()) {
cfa = frame_idx;
pc = m_pcs[frame_idx];
- if (m_pcs_are_call_addresses)
- behaves_like_zeroth_frame = true;
- else
- behaves_like_zeroth_frame = (frame_idx == 0);
+ behaves_like_zeroth_frame = BehavesLikeZerothFrame(m_pc_type, frame_idx);
return true;
}
return false;
diff --git a/lldb/source/Plugins/Process/Utility/HistoryUnwind.h b/lldb/source/Plugins/Process/Utility/HistoryUnwind.h
index cb72b5d..3cf70a4 100644
--- a/lldb/source/Plugins/Process/Utility/HistoryUnwind.h
+++ b/lldb/source/Plugins/Process/Utility/HistoryUnwind.h
@@ -19,7 +19,7 @@ namespace lldb_private {
class HistoryUnwind : public lldb_private::Unwind {
public:
HistoryUnwind(Thread &thread, std::vector<lldb::addr_t> pcs,
- bool pcs_are_call_addresses = false);
+ HistoryPCType pc_type = HistoryPCType::Returns);
~HistoryUnwind() override;
@@ -36,9 +36,7 @@ protected:
private:
std::vector<lldb::addr_t> m_pcs;
- /// This boolean indicates that the PCs in the non-0 frames are call
- /// addresses and not return addresses.
- bool m_pcs_are_call_addresses;
+ HistoryPCType m_pc_type;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
index 19601b7..f35027e 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
@@ -44,15 +44,16 @@ uint32_t NativeRegisterContextDBReg::SetHardwareBreakpoint(lldb::addr_t addr,
return LLDB_INVALID_INDEX32;
}
- uint32_t control_value = 0, bp_index = 0;
-
if (!ValidateBreakpoint(size, addr))
return LLDB_INVALID_INDEX32;
- control_value = MakeBreakControlValue(size);
+ uint32_t control_value = MakeBreakControlValue(size);
+ auto details = AdjustBreakpoint({size, addr});
+ size = details.size;
+ addr = details.addr;
// Iterate over stored breakpoints and find a free bp_index
- bp_index = LLDB_INVALID_INDEX32;
+ uint32_t bp_index = LLDB_INVALID_INDEX32;
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
if (!BreakpointIsEnabled(i))
bp_index = i; // Mark last free slot
@@ -222,7 +223,7 @@ uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(
addr = adjusted->addr;
// Check if we are setting watchpoint other than read/write/access Also
- // update watchpoint flag to match AArch64/LoongArch write-read bit
+ // update watchpoint flag to match ARM/AArch64/LoongArch write-read bit
// configuration.
switch (watch_flags) {
case lldb::eWatchpointKindWrite:
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
index 9b6ecd3..2dd11dc 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
@@ -12,6 +12,7 @@
#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
#include <array>
+#include <optional>
// Common utilities for hardware breakpoints and hardware watchpoints on AArch64
// and LoongArch.
@@ -76,19 +77,25 @@ protected:
// On AArch64 and Loongarch the hardware breakpoint length size is 4, and the
// target address must 4-byte alignment.
- bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
+ virtual bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
return (size == 4) && !(addr & 0x3);
}
+
struct WatchpointDetails {
size_t size;
lldb::addr_t addr;
};
virtual std::optional<WatchpointDetails>
AdjustWatchpoint(const WatchpointDetails &details) = 0;
+
+ using BreakpointDetails = WatchpointDetails;
+ virtual BreakpointDetails AdjustBreakpoint(const BreakpointDetails &details) {
+ return details;
+ }
+
virtual uint32_t MakeBreakControlValue(size_t size) = 0;
virtual uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) = 0;
virtual uint32_t GetWatchpointSize(uint32_t wp_index) = 0;
-
virtual llvm::Error ReadHardwareDebugInfo() = 0;
virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0;
virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) {
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
new file mode 100644
index 0000000..803fed5
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
@@ -0,0 +1,117 @@
+//===-- NativeRegisterContextDBReg_arm.cpp --------------------------------===//
+//
+// 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 "NativeRegisterContextDBReg_arm.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+uint32_t NativeRegisterContextDBReg_arm::GetWatchpointSize(uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
+ case 0x01:
+ return 1;
+ case 0x03:
+ return 2;
+ case 0x07:
+ return 3;
+ case 0x0f:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+std::optional<NativeRegisterContextDBReg::WatchpointDetails>
+NativeRegisterContextDBReg_arm::AdjustWatchpoint(
+ const WatchpointDetails &details) {
+ auto [size, addr] = details;
+
+ if (size == 0 || size > 4)
+ return {};
+
+ // Check 4-byte alignment for hardware watchpoint target address. Below is a
+ // hack to recalculate address and size in order to make sure we can watch
+ // non 4-byte aligned addresses as well.
+ if (addr & 0x03) {
+ uint8_t watch_mask = (addr & 0x03) + size;
+ if (watch_mask > 0x04)
+ return {};
+ else if (watch_mask <= 0x02)
+ size = 2;
+ else
+ size = 4;
+
+ addr = addr & (~0x03);
+ }
+
+ return WatchpointDetails{size, addr};
+}
+
+NativeRegisterContextDBReg::BreakpointDetails
+NativeRegisterContextDBReg_arm::AdjustBreakpoint(
+ const BreakpointDetails &details) {
+ BreakpointDetails bd = details;
+ // Use size to get a hint of arm vs thumb modes.
+ // LLDB usually aligns this client side, but other clients may not.
+ switch (bd.size) {
+ case 2:
+ bd.addr &= ~1;
+ break;
+ case 4:
+ bd.addr &= ~3;
+ break;
+ default:
+ // We assume that ValidateBreakpoint would have caught this earlier.
+ llvm_unreachable("Invalid breakpoint size!");
+ }
+
+ return bd;
+}
+
+uint32_t NativeRegisterContextDBReg_arm::MakeBreakControlValue(size_t size) {
+ switch (size) {
+ case 2:
+ return (0x3 << 5) | 7;
+ case 4:
+ return (0xfu << 5) | 7;
+ default:
+ // ValidateBreakpoint would have rejected this earlier.
+ llvm_unreachable("Invalid breakpoint size.");
+ }
+}
+
+uint32_t
+NativeRegisterContextDBReg_arm::MakeWatchControlValue(size_t size,
+ uint32_t watch_flags) {
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair, so make sure we can properly encode this.
+ // We assume that the address was 4 byte aligned by AdjustWatchpoint.
+ uint32_t byte_mask = (1u << size) - 1u;
+
+ // Check if we need multiple watchpoint register
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Setup control value
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t control_value = byte_mask << 5;
+
+ // Turn on appropriate watchpoint flags read or write
+ control_value |= (watch_flags << 3);
+
+ // Enable this watchpoint and make it stop in privileged or user mode;
+ control_value |= 7;
+
+ return control_value;
+}
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
new file mode 100644
index 0000000..253ae96
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
@@ -0,0 +1,42 @@
+//===-- NativeRegisterContextDBReg_arm.h ------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextDBReg_arm_h
+#define lldb_NativeRegisterContextDBReg_arm_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+
+namespace lldb_private {
+
+class NativeRegisterContextDBReg_arm : public NativeRegisterContextDBReg {
+public:
+ NativeRegisterContextDBReg_arm()
+ : NativeRegisterContextDBReg(/*enable_bit=*/0x1U) {}
+
+private:
+ uint32_t GetWatchpointSize(uint32_t wp_index) override;
+
+ std::optional<WatchpointDetails>
+ AdjustWatchpoint(const WatchpointDetails &details) override;
+
+ BreakpointDetails AdjustBreakpoint(const BreakpointDetails &details) override;
+
+ uint32_t MakeBreakControlValue(size_t size) override;
+
+ uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) override;
+
+ bool ValidateBreakpoint(size_t size,
+ [[maybe_unused]] lldb::addr_t addr) override {
+ // Break on 4 or 2 byte instructions.
+ return size == 4 || size == 2;
+ }
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextDBReg_arm_h
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 85e141d..91f3a6c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5773,7 +5773,7 @@ public:
CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter)
: CommandObjectRaw(interpreter, "process plugin packet monitor",
"Send a qRcmd packet through the GDB remote protocol "
- "and print the response."
+ "and print the response. "
"The argument passed to this command will be hex "
"encoded into a valid 'qRcmd' packet, sent and the "
"response will be printed.") {}
diff --git a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
index c359663..12cb257 100644
--- a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
@@ -10,14 +10,15 @@
#include "Resource.h"
#include "Tool.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Protocol/MCP/MCPError.h"
-#include "lldb/Protocol/MCP/Tool.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Protocol/MCP/Server.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/Threading.h"
#include <thread>
-#include <variant>
using namespace lldb_private;
using namespace lldb_private::mcp;
@@ -26,24 +27,10 @@ using namespace llvm;
LLDB_PLUGIN_DEFINE(ProtocolServerMCP)
-static constexpr size_t kChunkSize = 1024;
static constexpr llvm::StringLiteral kName = "lldb-mcp";
static constexpr llvm::StringLiteral kVersion = "0.1.0";
-ProtocolServerMCP::ProtocolServerMCP()
- : ProtocolServer(),
- lldb_protocol::mcp::Server(std::string(kName), std::string(kVersion)) {
- AddNotificationHandler("notifications/initialized",
- [](const lldb_protocol::mcp::Notification &) {
- LLDB_LOG(GetLog(LLDBLog::Host),
- "MCP initialization complete");
- });
-
- AddTool(
- std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
-
- AddResourceProvider(std::make_unique<DebuggerResourceProvider>());
-}
+ProtocolServerMCP::ProtocolServerMCP() : ProtocolServer() {}
ProtocolServerMCP::~ProtocolServerMCP() { llvm::consumeError(Stop()); }
@@ -53,6 +40,8 @@ void ProtocolServerMCP::Initialize() {
}
void ProtocolServerMCP::Terminate() {
+ if (llvm::Error error = ProtocolServer::Terminate())
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(error), "{0}");
PluginManager::UnregisterPlugin(CreateInstance);
}
@@ -64,57 +53,37 @@ llvm::StringRef ProtocolServerMCP::GetPluginDescriptionStatic() {
return "MCP Server.";
}
+void ProtocolServerMCP::Extend(lldb_protocol::mcp::Server &server) const {
+ server.AddNotificationHandler("notifications/initialized",
+ [](const lldb_protocol::mcp::Notification &) {
+ LLDB_LOG(GetLog(LLDBLog::Host),
+ "MCP initialization complete");
+ });
+ server.AddTool(
+ std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
+ server.AddResourceProvider(std::make_unique<DebuggerResourceProvider>());
+}
+
void ProtocolServerMCP::AcceptCallback(std::unique_ptr<Socket> socket) {
- LLDB_LOG(GetLog(LLDBLog::Host), "New MCP client ({0}) connected",
- m_clients.size() + 1);
+ Log *log = GetLog(LLDBLog::Host);
+ std::string client_name = llvm::formatv("client_{0}", m_instances.size() + 1);
+ LLDB_LOG(log, "New MCP client connected: {0}", client_name);
lldb::IOObjectSP io_sp = std::move(socket);
- auto client_up = std::make_unique<Client>();
- client_up->io_sp = io_sp;
- Client *client = client_up.get();
-
- Status status;
- auto read_handle_up = m_loop.RegisterReadObject(
- io_sp,
- [this, client](MainLoopBase &loop) {
- if (llvm::Error error = ReadCallback(*client)) {
- LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(error), "{0}");
- client->read_handle_up.reset();
- }
- },
- status);
- if (status.Fail())
+ auto transport_up = std::make_unique<lldb_protocol::mcp::MCPTransport>(
+ io_sp, io_sp, std::move(client_name), [&](llvm::StringRef message) {
+ LLDB_LOG(GetLog(LLDBLog::Host), "{0}", message);
+ });
+ auto instance_up = std::make_unique<lldb_protocol::mcp::Server>(
+ std::string(kName), std::string(kVersion), std::move(transport_up),
+ m_loop);
+ Extend(*instance_up);
+ llvm::Error error = instance_up->Run();
+ if (error) {
+ LLDB_LOG_ERROR(log, std::move(error), "Failed to run MCP server: {0}");
return;
-
- client_up->read_handle_up = std::move(read_handle_up);
- m_clients.emplace_back(std::move(client_up));
-}
-
-llvm::Error ProtocolServerMCP::ReadCallback(Client &client) {
- char chunk[kChunkSize];
- size_t bytes_read = sizeof(chunk);
- if (Status status = client.io_sp->Read(chunk, bytes_read); status.Fail())
- return status.takeError();
- client.buffer.append(chunk, bytes_read);
-
- for (std::string::size_type pos;
- (pos = client.buffer.find('\n')) != std::string::npos;) {
- llvm::Expected<std::optional<lldb_protocol::mcp::Message>> message =
- HandleData(StringRef(client.buffer.data(), pos));
- client.buffer = client.buffer.erase(0, pos + 1);
- if (!message)
- return message.takeError();
-
- if (*message) {
- std::string Output;
- llvm::raw_string_ostream OS(Output);
- OS << llvm::formatv("{0}", toJSON(**message)) << '\n';
- size_t num_bytes = Output.size();
- return client.io_sp->Write(Output.data(), num_bytes).takeError();
- }
}
-
- return llvm::Error::success();
+ m_instances.push_back(std::move(instance_up));
}
llvm::Error ProtocolServerMCP::Start(ProtocolServer::Connection connection) {
@@ -138,6 +107,39 @@ llvm::Error ProtocolServerMCP::Start(ProtocolServer::Connection connection) {
if (llvm::Error error = handles.takeError())
return error;
+ auto listening_uris = m_listener->GetListeningConnectionURI();
+ if (listening_uris.empty())
+ return createStringError("failed to get listening connections");
+ std::string address =
+ llvm::join(m_listener->GetListeningConnectionURI(), ", ");
+
+ FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir();
+
+ Status error(llvm::sys::fs::create_directory(user_lldb_dir.GetPath()));
+ if (error.Fail())
+ return error.takeError();
+
+ m_mcp_registry_entry_path = user_lldb_dir.CopyByAppendingPathComponent(
+ formatv("lldb-mcp-{0}.json", getpid()).str());
+
+ ServerInfo info;
+ info.connection_uri = listening_uris[0];
+ info.pid = getpid();
+
+ std::string buf = formatv("{0}", toJSON(info)).str();
+ size_t num_bytes = buf.size();
+
+ const File::OpenOptions flags = File::eOpenOptionWriteOnly |
+ File::eOpenOptionCanCreate |
+ File::eOpenOptionTruncate;
+ llvm::Expected<lldb::FileUP> file =
+ FileSystem::Instance().Open(m_mcp_registry_entry_path, flags,
+ lldb::eFilePermissionsFileDefault, false);
+ if (!file)
+ return file.takeError();
+ if (llvm::Error error = (*file)->Write(buf.data(), num_bytes).takeError())
+ return error;
+
m_running = true;
m_listen_handlers = std::move(*handles);
m_loop_thread = std::thread([=] {
@@ -156,29 +158,17 @@ llvm::Error ProtocolServerMCP::Stop() {
m_running = false;
}
+ if (!m_mcp_registry_entry_path.GetPath().empty())
+ FileSystem::Instance().RemoveFile(m_mcp_registry_entry_path);
+ m_mcp_registry_entry_path.Clear();
+
// Stop the main loop.
m_loop.AddPendingCallback(
- [](MainLoopBase &loop) { loop.RequestTermination(); });
+ [](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
// Wait for the main loop to exit.
if (m_loop_thread.joinable())
m_loop_thread.join();
- {
- std::lock_guard<std::mutex> guard(m_mutex);
- m_listener.reset();
- m_listen_handlers.clear();
- m_clients.clear();
- }
-
return llvm::Error::success();
}
-
-lldb_protocol::mcp::Capabilities ProtocolServerMCP::GetCapabilities() {
- lldb_protocol::mcp::Capabilities capabilities;
- capabilities.tools.listChanged = true;
- // FIXME: Support sending notifications when a debugger/target are
- // added/removed.
- capabilities.resources.listChanged = false;
- return capabilities;
-}
diff --git a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
index 7fe909a..004fa3c 100644
--- a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
+++ b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
@@ -18,8 +18,7 @@
namespace lldb_private::mcp {
-class ProtocolServerMCP : public ProtocolServer,
- public lldb_protocol::mcp::Server {
+class ProtocolServerMCP : public ProtocolServer {
public:
ProtocolServerMCP();
virtual ~ProtocolServerMCP() override;
@@ -39,26 +38,25 @@ public:
Socket *GetSocket() const override { return m_listener.get(); }
+protected:
+ // This adds tools and resource providers that
+ // are specific to this server. Overridable by the unit tests.
+ virtual void Extend(lldb_protocol::mcp::Server &server) const;
+
private:
void AcceptCallback(std::unique_ptr<Socket> socket);
- lldb_protocol::mcp::Capabilities GetCapabilities() override;
-
bool m_running = false;
- MainLoop m_loop;
+ FileSpec m_mcp_registry_entry_path;
+ lldb_private::MainLoop m_loop;
std::thread m_loop_thread;
+ std::mutex m_mutex;
std::unique_ptr<Socket> m_listener;
- std::vector<MainLoopBase::ReadHandleUP> m_listen_handlers;
- struct Client {
- lldb::IOObjectSP io_sp;
- MainLoopBase::ReadHandleUP read_handle_up;
- std::string buffer;
- };
- llvm::Error ReadCallback(Client &client);
- std::vector<std::unique_ptr<Client>> m_clients;
+ std::vector<MainLoopBase::ReadHandleUP> m_listen_handlers;
+ std::vector<std::unique_ptr<lldb_protocol::mcp::Server>> m_instances;
};
} // namespace lldb_private::mcp
diff --git a/lldb/source/Plugins/Protocol/MCP/Resource.cpp b/lldb/source/Plugins/Protocol/MCP/Resource.cpp
index e94d2cd..5814245 100644
--- a/lldb/source/Plugins/Protocol/MCP/Resource.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/Resource.cpp
@@ -8,7 +8,6 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Protocol/MCP/MCPError.h"
-#include "lldb/Target/Platform.h"
using namespace lldb_private;
using namespace lldb_private::mcp;
@@ -124,7 +123,7 @@ DebuggerResourceProvider::GetResources() const {
return resources;
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
auto [protocol, path] = uri.split("://");
@@ -161,7 +160,7 @@ DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
return ReadDebuggerResource(uri, debugger_idx);
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
lldb::user_id_t debugger_id) {
lldb::DebuggerSP debugger_sp = Debugger::FindDebuggerWithID(debugger_id);
@@ -173,17 +172,17 @@ DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
debugger_resource.name = debugger_sp->GetInstanceName();
debugger_resource.num_targets = debugger_sp->GetTargetList().GetNumTargets();
- lldb_protocol::mcp::ResourceContents contents;
+ lldb_protocol::mcp::TextResourceContents contents;
contents.uri = uri;
contents.mimeType = kMimeTypeJSON;
contents.text = llvm::formatv("{0}", toJSON(debugger_resource));
- lldb_protocol::mcp::ResourceResult result;
+ lldb_protocol::mcp::ReadResourceResult result;
result.contents.push_back(contents);
return result;
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
lldb::user_id_t debugger_id,
size_t target_idx) {
@@ -209,12 +208,12 @@ DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
if (lldb::PlatformSP platform_sp = target_sp->GetPlatform())
target_resource.platform = platform_sp->GetName();
- lldb_protocol::mcp::ResourceContents contents;
+ lldb_protocol::mcp::TextResourceContents contents;
contents.uri = uri;
contents.mimeType = kMimeTypeJSON;
contents.text = llvm::formatv("{0}", toJSON(target_resource));
- lldb_protocol::mcp::ResourceResult result;
+ lldb_protocol::mcp::ReadResourceResult result;
result.contents.push_back(contents);
return result;
}
diff --git a/lldb/source/Plugins/Protocol/MCP/Resource.h b/lldb/source/Plugins/Protocol/MCP/Resource.h
index e2382a7..0c65766 100644
--- a/lldb/source/Plugins/Protocol/MCP/Resource.h
+++ b/lldb/source/Plugins/Protocol/MCP/Resource.h
@@ -11,7 +11,11 @@
#include "lldb/Protocol/MCP/Protocol.h"
#include "lldb/Protocol/MCP/Resource.h"
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
#include <vector>
namespace lldb_private::mcp {
@@ -21,9 +25,8 @@ public:
using ResourceProvider::ResourceProvider;
virtual ~DebuggerResourceProvider() = default;
- virtual std::vector<lldb_protocol::mcp::Resource>
- GetResources() const override;
- virtual llvm::Expected<lldb_protocol::mcp::ResourceResult>
+ std::vector<lldb_protocol::mcp::Resource> GetResources() const override;
+ llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
ReadResource(llvm::StringRef uri) const override;
private:
@@ -31,9 +34,9 @@ private:
static lldb_protocol::mcp::Resource GetTargetResource(size_t target_idx,
Target &target);
- static llvm::Expected<lldb_protocol::mcp::ResourceResult>
+ static llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
ReadDebuggerResource(llvm::StringRef uri, lldb::user_id_t debugger_id);
- static llvm::Expected<lldb_protocol::mcp::ResourceResult>
+ static llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
ReadTargetResource(llvm::StringRef uri, lldb::user_id_t debugger_id,
size_t target_idx);
};
diff --git a/lldb/source/Plugins/Protocol/MCP/Tool.cpp b/lldb/source/Plugins/Protocol/MCP/Tool.cpp
index 14347070..2f451bf 100644
--- a/lldb/source/Plugins/Protocol/MCP/Tool.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/Tool.cpp
@@ -7,9 +7,9 @@
//===----------------------------------------------------------------------===//
#include "Tool.h"
-#include "lldb/Core/Module.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Protocol/MCP/Protocol.h"
using namespace lldb_private;
using namespace lldb_protocol;
@@ -29,10 +29,10 @@ bool fromJSON(const llvm::json::Value &V, CommandToolArguments &A,
O.mapOptional("arguments", A.arguments);
}
-/// Helper function to create a TextResult from a string output.
-static lldb_protocol::mcp::TextResult createTextResult(std::string output,
- bool is_error = false) {
- lldb_protocol::mcp::TextResult text_result;
+/// Helper function to create a CallToolResult from a string output.
+static lldb_protocol::mcp::CallToolResult
+createTextResult(std::string output, bool is_error = false) {
+ lldb_protocol::mcp::CallToolResult text_result;
text_result.content.emplace_back(
lldb_protocol::mcp::TextContent{{std::move(output)}});
text_result.isError = is_error;
@@ -41,7 +41,7 @@ static lldb_protocol::mcp::TextResult createTextResult(std::string output,
} // namespace
-llvm::Expected<lldb_protocol::mcp::TextResult>
+llvm::Expected<lldb_protocol::mcp::CallToolResult>
CommandTool::Call(const lldb_protocol::mcp::ToolArguments &args) {
if (!std::holds_alternative<json::Value>(args))
return createStringError("CommandTool requires arguments");
diff --git a/lldb/source/Plugins/Protocol/MCP/Tool.h b/lldb/source/Plugins/Protocol/MCP/Tool.h
index b7b1756..1886525 100644
--- a/lldb/source/Plugins/Protocol/MCP/Tool.h
+++ b/lldb/source/Plugins/Protocol/MCP/Tool.h
@@ -9,11 +9,11 @@
#ifndef LLDB_PLUGINS_PROTOCOL_MCP_TOOL_H
#define LLDB_PLUGINS_PROTOCOL_MCP_TOOL_H
-#include "lldb/Core/Debugger.h"
#include "lldb/Protocol/MCP/Protocol.h"
#include "lldb/Protocol/MCP/Tool.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
-#include <string>
+#include <optional>
namespace lldb_private::mcp {
@@ -22,10 +22,10 @@ public:
using lldb_protocol::mcp::Tool::Tool;
~CommandTool() = default;
- virtual llvm::Expected<lldb_protocol::mcp::TextResult>
+ llvm::Expected<lldb_protocol::mcp::CallToolResult>
Call(const lldb_protocol::mcp::ToolArguments &args) override;
- virtual std::optional<llvm::json::Value> GetSchema() const override;
+ std::optional<llvm::json::Value> GetSchema() const override;
};
} // namespace lldb_private::mcp
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index f19dc8b..eb9e013 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -47,7 +47,7 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
// See if we have made this type before and can reuse it.
CompilerType fields_type =
type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
- register_type_name);
+ type_system->getASTContext(), register_type_name);
if (!fields_type) {
// In most ABI, a change of field type means a change in storage unit.
@@ -83,7 +83,7 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
// may have built this one already.
CompilerType field_enum_type =
type_system->GetTypeForIdentifier<clang::EnumDecl>(
- enum_type_name);
+ type_system->getASTContext(), enum_type_name);
if (field_enum_type)
field_type = field_enum_type;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index 27ac5432..a2a287a 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -405,15 +405,33 @@ Expected<llvm::StringRef> PythonString::AsUTF8() const {
if (!IsValid())
return nullDeref();
- Py_ssize_t size;
- const char *data;
+ // PyUnicode_AsUTF8AndSize caches the UTF-8 representation of the string in
+ // the Unicode object, which makes it more efficient and ties the lifetime of
+ // the data to the Python string. However, it was only added to the Stable API
+ // in Python 3.10. Older versions that want to use the Stable API must use
+ // PyUnicode_AsUTF8String in combination with ConstString.
+#if defined(Py_LIMITED_API) && (Py_LIMITED_API < 0x030a0000)
+ PyObject *py_bytes = PyUnicode_AsUTF8String(m_py_obj);
+ if (!py_bytes)
+ return exception();
+ auto release_py_str =
+ llvm::make_scope_exit([py_bytes] { Py_DECREF(py_bytes); });
+ Py_ssize_t size = PyBytes_Size(py_bytes);
+ const char *str = PyBytes_AsString(py_bytes);
+
+ if (!str)
+ return exception();
- data = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
+ return ConstString(str, size).GetStringRef();
+#else
+ Py_ssize_t size;
+ const char *str = PyUnicode_AsUTF8AndSize(m_py_obj, &size);
- if (!data)
+ if (!str)
return exception();
- return llvm::StringRef(data, size);
+ return llvm::StringRef(str, size);
+#endif
}
size_t PythonString::GetSize() const {
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 24d604f..9330a63 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -92,10 +92,23 @@ namespace {
struct InitializePythonRAII {
public:
InitializePythonRAII() {
+ // The table of built-in modules can only be extended before Python is
+ // initialized.
+ if (!Py_IsInitialized()) {
+#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
+ // Python's readline is incompatible with libedit being linked into lldb.
+ // Provide a patched version local to the embedded interpreter.
+ PyImport_AppendInittab("readline", initlldb_readline);
+#endif
+
+ // Register _lldb as a built-in module.
+ PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
+ }
+
+#if LLDB_EMBED_PYTHON_HOME
PyConfig config;
PyConfig_InitPythonConfig(&config);
-#if LLDB_EMBED_PYTHON_HOME
static std::string g_python_home = []() -> std::string {
if (llvm::sys::path::is_absolute(LLDB_PYTHON_HOME))
return LLDB_PYTHON_HOME;
@@ -109,34 +122,13 @@ public:
if (!g_python_home.empty()) {
PyConfig_SetBytesString(&config, &config.home, g_python_home.c_str());
}
-#endif
-
- // The table of built-in modules can only be extended before Python is
- // initialized.
- if (!Py_IsInitialized()) {
-#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
- // Python's readline is incompatible with libedit being linked into lldb.
- // Provide a patched version local to the embedded interpreter.
- bool ReadlinePatched = false;
- for (auto *p = PyImport_Inittab; p->name != nullptr; p++) {
- if (strcmp(p->name, "readline") == 0) {
- p->initfunc = initlldb_readline;
- break;
- }
- }
- if (!ReadlinePatched) {
- PyImport_AppendInittab("readline", initlldb_readline);
- ReadlinePatched = true;
- }
-#endif
-
- // Register _lldb as a built-in module.
- PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
- }
config.install_signal_handlers = 0;
Py_InitializeFromConfig(&config);
PyConfig_Clear(&config);
+#else
+ Py_InitializeEx(/*install_sigs=*/0);
+#endif
// The only case we should go further and acquire the GIL: it is unlocked.
PyGILState_STATE gil_state = PyGILState_Ensure();
@@ -907,11 +899,11 @@ bool ScriptInterpreterPythonImpl::Interrupt() {
Log *log = GetLog(LLDBLog::Script);
if (IsExecutingPython()) {
- PyThreadState *state = PyThreadState_GET();
+ PyThreadState *state = PyThreadState_Get();
if (!state)
state = GetThreadState();
if (state) {
- long tid = state->thread_id;
+ long tid = PyThread_get_thread_ident();
PyThreadState_Swap(state);
int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt);
LLDB_LOGF(log,
diff --git a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
index 867f6a6..70093c9 100644
--- a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
+++ b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
@@ -1601,6 +1601,7 @@ void StructuredDataDarwinLog::AddInitCompletionHook(Process &process) {
const char *func_name = "_libtrace_init";
const lldb::addr_t offset = 0;
+ const bool offset_is_insn_count = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
// This is an internal breakpoint - the user shouldn't see it.
const bool internal = true;
@@ -1608,7 +1609,8 @@ void StructuredDataDarwinLog::AddInitCompletionHook(Process &process) {
auto breakpoint_sp = target.CreateBreakpoint(
&module_spec_list, source_spec_list, func_name, eFunctionNameTypeFull,
- eLanguageTypeC, offset, skip_prologue, internal, hardware);
+ eLanguageTypeC, offset, offset_is_insn_count, skip_prologue, internal,
+ hardware);
if (!breakpoint_sp) {
// Huh? Bail here.
LLDB_LOGF(log,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
index a9345c7..1bfa17f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
@@ -44,7 +44,7 @@ class ElaboratingDIEIterator
// Container sizes are optimized for the case of following DW_AT_specification
// and DW_AT_abstract_origin just once.
llvm::SmallVector<DWARFDIE, 2> m_worklist;
- llvm::SmallSet<DWARFDebugInfoEntry *, 3> m_seen;
+ llvm::SmallPtrSet<DWARFDebugInfoEntry *, 3> m_seen;
void Next() {
assert(!m_worklist.empty() && "Incrementing end iterator?");
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index f968eee..849f573 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -284,9 +284,10 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges(
/// Adds all attributes of the DIE at the top of the \c worklist to the
/// \c attributes list. Specifcations and abstract origins are added
/// to the \c worklist if the referenced DIE has not been seen before.
-static bool GetAttributes(llvm::SmallVectorImpl<DWARFDIE> &worklist,
- llvm::SmallSet<DWARFDebugInfoEntry const *, 3> &seen,
- DWARFAttributes &attributes) {
+static bool
+GetAttributes(llvm::SmallVectorImpl<DWARFDIE> &worklist,
+ llvm::SmallPtrSet<DWARFDebugInfoEntry const *, 3> &seen,
+ DWARFAttributes &attributes) {
assert(!worklist.empty() && "Need at least one DIE to visit.");
assert(seen.size() >= 1 &&
"Need to have seen at least the currently visited entry.");
@@ -366,7 +367,7 @@ DWARFAttributes DWARFDebugInfoEntry::GetAttributes(const DWARFUnit *cu,
// Keep track if DIEs already seen to prevent infinite recursion.
// Value of '3' was picked for the same reason that
// DWARFDie::findRecursively does.
- llvm::SmallSet<DWARFDebugInfoEntry const *, 3> seen;
+ llvm::SmallPtrSet<DWARFDebugInfoEntry const *, 3> seen;
seen.insert(this);
do {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 84b3da3..b15e0c1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -8,6 +8,7 @@
#include "SymbolFileDWARF.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/Support/Casting.h"
@@ -998,12 +999,12 @@ XcodeSDK SymbolFileDWARF::ParseXcodeSDK(CompileUnit &comp_unit) {
const char *sdk = cu_die.GetAttributeValueAsString(DW_AT_APPLE_sdk, nullptr);
if (!sdk)
return {};
- std::string sysroot =
+ llvm::StringRef sysroot =
cu_die.GetAttributeValueAsString(DW_AT_LLVM_sysroot, "");
// RegisterXcodeSDK calls into xcrun which is not aware of CLT, which is
// expensive.
- if (sysroot.find("/Library/Developer/CommandLineTools/SDKs") != 0) {
+ if (!sysroot.starts_with("/Library/Developer/CommandLineTools/SDKs")) {
// Register the sysroot path remapping with the module belonging to
// the CU as well as the one belonging to the symbol file. The two
// would be different if this is an OSO object and module is the
@@ -1017,7 +1018,7 @@ XcodeSDK SymbolFileDWARF::ParseXcodeSDK(CompileUnit &comp_unit) {
local_module_sp->RegisterXcodeSDK(sdk, sysroot);
}
- return {sdk, FileSpec{std::move(sysroot)}};
+ return {sdk, FileSpec(sysroot)};
}
size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) {
@@ -2483,6 +2484,30 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
return false;
}
+DWARFDIE
+SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label) {
+ DWARFDIE definition;
+ Module::LookupInfo info(ConstString(label.lookup_name),
+ lldb::eFunctionNameTypeFull,
+ lldb::eLanguageTypeUnknown);
+
+ m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+ if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+ return IterationAction::Continue;
+
+ // We don't check whether the specification DIE for this function
+ // corresponds to the declaration DIE because the declaration might be in
+ // a type-unit but the definition in the compile-unit (and it's
+ // specifcation would point to the declaration in the compile-unit). We
+ // rely on the mangled name within the module to be enough to find us the
+ // unique definition.
+ definition = entry;
+ return IterationAction::Stop;
+ });
+
+ return definition;
+}
+
llvm::Expected<SymbolContext>
SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
@@ -2495,37 +2520,19 @@ SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
// Label was created using a declaration DIE. Need to fetch the definition
// to resolve the function call.
if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) {
- Module::LookupInfo info(ConstString(label.lookup_name),
- lldb::eFunctionNameTypeFull,
- lldb::eLanguageTypeUnknown);
-
- m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
- if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
- return IterationAction::Continue;
-
- // We don't check whether the specification DIE for this function
- // corresponds to the declaration DIE because the declaration might be in
- // a type-unit but the definition in the compile-unit (and it's
- // specifcation would point to the declaration in the compile-unit). We
- // rely on the mangled name within the module to be enough to find us the
- // unique definition.
- die = entry;
- return IterationAction::Stop;
- });
+ auto definition = FindFunctionDefinition(label);
+ if (!definition)
+ return llvm::createStringError("failed to find definition DIE");
- if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
- return llvm::createStringError(
- llvm::formatv("failed to find definition DIE for {0}", label));
+ die = std::move(definition);
}
SymbolContextList sc_list;
if (!ResolveFunction(die, /*include_inlines=*/false, sc_list))
- return llvm::createStringError(
- llvm::formatv("failed to resolve function for {0}", label));
+ return llvm::createStringError("failed to resolve function");
if (sc_list.IsEmpty())
- return llvm::createStringError(
- llvm::formatv("failed to find function for {0}", label));
+ return llvm::createStringError("failed to find function");
assert(sc_list.GetSize() == 1);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 5042d91..d7db8a3 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -373,6 +373,13 @@ public:
/// Returns the DWARFIndex for this symbol, if it exists.
DWARFIndex *getIndex() { return m_index.get(); }
+private:
+ /// Find the definition DIE for the specified \c label in this
+ /// SymbolFile.
+ ///
+ /// \returns A valid definition DIE on success.
+ DWARFDIE FindFunctionDefinition(const FunctionCallLabel &label);
+
protected:
SymbolFileDWARF(const SymbolFileDWARF &) = delete;
const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index f01fba3..709281c 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -449,7 +449,7 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) {
->GetIndex();
lldbassert(IsTagRecord(type_id, index.tpi()));
- clang::QualType tag_qt = m_clang.getASTContext().getTypeDeclType(&tag);
+ clang::QualType tag_qt = m_clang.getASTContext().getCanonicalTagType(&tag);
TypeSystemClang::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false);
TypeIndex tag_ti = type_id.index;
@@ -562,7 +562,8 @@ clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) {
m_clang.getASTContext(), spelling));
}
return m_clang.getASTContext().getMemberPointerType(
- pointee_type, /*Qualifier=*/nullptr, class_type->getAsCXXRecordDecl());
+ pointee_type, /*Qualifier=*/std::nullopt,
+ class_type->getAsCXXRecordDecl());
}
clang::QualType pointer_type;
@@ -862,9 +863,9 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
m_clang.GetSymbolFile()->GetBackingSymbolFile());
PdbIndex &index = pdb->GetIndex();
- clang::QualType parent_qt = llvm::cast<clang::TypeDecl>(parent)
- ->getTypeForDecl()
- ->getCanonicalTypeInternal();
+ clang::CanQualType parent_qt =
+ m_clang.getASTContext().getCanonicalTypeDeclType(
+ llvm::cast<clang::TypeDecl>(parent));
lldb::opaque_compiler_type_t parent_opaque_ty =
ToCompilerType(parent_qt).GetOpaqueQualType();
// FIXME: Remove this workaround.
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index dcea33d..112eb06 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -39,6 +39,7 @@
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDB.h"
@@ -643,8 +644,14 @@ SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id,
std::string uname = GetUnqualifiedTypeName(record);
- // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE.
+ llvm::Expected<Declaration> maybeDecl = ResolveUdtDeclaration(type_id);
Declaration decl;
+ if (maybeDecl)
+ decl = std::move(*maybeDecl);
+ else
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), maybeDecl.takeError(),
+ "Failed to resolve declaration for '{1}': {0}", uname);
+
return MakeType(toOpaqueUid(type_id), ConstString(uname), size, nullptr,
LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
Type::ResolveState::Forward);
@@ -667,7 +674,14 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
CompilerType ct) {
std::string uname = GetUnqualifiedTypeName(er);
+ llvm::Expected<Declaration> maybeDecl = ResolveUdtDeclaration(type_id);
Declaration decl;
+ if (maybeDecl)
+ decl = std::move(*maybeDecl);
+ else
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), maybeDecl.takeError(),
+ "Failed to resolve declaration for '{1}': {0}", uname);
+
TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);
return MakeType(
@@ -1641,6 +1655,94 @@ void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
clang->GetNativePDBParser()->Dump(s, filter);
}
+void SymbolFileNativePDB::CacheFunctionNames() {
+ if (!m_func_full_names.IsEmpty())
+ return;
+
+ // (segment, code offset) -> gid
+ std::map<std::pair<uint16_t, uint32_t>, uint32_t> addr_ids;
+
+ // First, find all function references in the globals table.
+ for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
+ CVSymbol ref_sym = m_index->symrecords().readRecord(gid);
+ auto kind = ref_sym.kind();
+ if (kind != S_PROCREF && kind != S_LPROCREF)
+ continue;
+
+ ProcRefSym ref =
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(ref_sym));
+ if (ref.Name.empty())
+ continue;
+
+ // Find the function this is referencing.
+ CompilandIndexItem &cci =
+ m_index->compilands().GetOrCreateCompiland(ref.modi());
+ auto iter = cci.m_debug_stream.getSymbolArray().at(ref.SymOffset);
+ if (iter == cci.m_debug_stream.getSymbolArray().end())
+ continue;
+ kind = iter->kind();
+ if (kind != S_GPROC32 && kind != S_LPROC32)
+ continue;
+
+ ProcSym proc =
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*iter));
+ if ((proc.Flags & ProcSymFlags::IsUnreachable) != ProcSymFlags::None)
+ continue;
+ if (proc.Name.empty() || proc.FunctionType.isSimple())
+ continue;
+
+ // The function/procedure symbol only contains the demangled name.
+ // The mangled names are in the publics table. Save the address of this
+ // function to lookup the mangled name later.
+ addr_ids.emplace(std::make_pair(proc.Segment, proc.CodeOffset), gid);
+
+ llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(proc.Name);
+ if (basename.empty())
+ basename = proc.Name;
+
+ m_func_base_names.Append(ConstString(basename), gid);
+ m_func_full_names.Append(ConstString(proc.Name), gid);
+
+ // To see if this is a member function, check the type.
+ auto type = m_index->tpi().getType(proc.FunctionType);
+ if (type.kind() == LF_MFUNCTION) {
+ MemberFunctionRecord mfr;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<MemberFunctionRecord>(type, mfr));
+ if (!mfr.getThisType().isNoneType())
+ m_func_method_names.Append(ConstString(basename), gid);
+ }
+ }
+
+ // The publics stream contains all mangled function names and their address.
+ for (auto pid : m_index->publics().getPublicsTable()) {
+ PdbGlobalSymId global{pid, true};
+ CVSymbol sym = m_index->ReadSymbolRecord(global);
+ auto kind = sym.kind();
+ if (kind != S_PUB32)
+ continue;
+ PublicSym32 pub =
+ llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym));
+ // We only care about mangled names - if the name isn't mangled, it's
+ // already in the full name map.
+ if (!Mangled::IsMangledName(pub.Name))
+ continue;
+
+ // Check if this symbol is for one of our functions.
+ auto it = addr_ids.find({pub.Segment, pub.Offset});
+ if (it != addr_ids.end())
+ m_func_full_names.Append(ConstString(pub.Name), it->second);
+ }
+
+ // Sort them before value searching is working properly.
+ m_func_full_names.Sort();
+ m_func_full_names.SizeToFit();
+ m_func_method_names.Sort();
+ m_func_method_names.SizeToFit();
+ m_func_base_names.Sort();
+ m_func_base_names.SizeToFit();
+}
+
void SymbolFileNativePDB::FindGlobalVariables(
ConstString name, const CompilerDeclContext &parent_decl_ctx,
uint32_t max_matches, VariableList &variables) {
@@ -1677,34 +1779,60 @@ void SymbolFileNativePDB::FindFunctions(
if (name_type_mask & eFunctionNameTypeFull)
name = lookup_info.GetName();
- // For now we only support lookup by method name or full name.
if (!(name_type_mask & eFunctionNameTypeFull ||
+ name_type_mask & eFunctionNameTypeBase ||
name_type_mask & eFunctionNameTypeMethod))
return;
+ CacheFunctionNames();
- using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
+ std::set<uint32_t> resolved_ids; // avoid duplicate lookups
+ auto resolve_from = [&](UniqueCStringMap<uint32_t> &Names) {
+ std::vector<uint32_t> ids;
+ if (!Names.GetValues(name, ids))
+ return;
- std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName(
- name.GetStringRef(), m_index->symrecords());
- for (const SymbolAndOffset &match : matches) {
- if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF)
- continue;
- ProcRefSym proc(match.second.kind());
- cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc));
+ for (uint32_t id : ids) {
+ if (!resolved_ids.insert(id).second)
+ continue;
- if (!IsValidRecord(proc))
- continue;
+ PdbGlobalSymId global{id, false};
+ if (parent_decl_ctx.IsValid() &&
+ GetDeclContextContainingUID(toOpaqueUid(global)) != parent_decl_ctx)
+ continue;
- CompilandIndexItem &cci =
- m_index->compilands().GetOrCreateCompiland(proc.modi());
- SymbolContext sc;
+ CVSymbol sym = m_index->ReadSymbolRecord(global);
+ auto kind = sym.kind();
+ lldbassert(kind == S_PROCREF || kind == S_LPROCREF);
- sc.comp_unit = GetOrCreateCompileUnit(cci).get();
- PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
- sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
+ ProcRefSym proc =
+ cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(sym));
- sc_list.Append(sc);
- }
+ if (!IsValidRecord(proc))
+ continue;
+
+ CompilandIndexItem &cci =
+ m_index->compilands().GetOrCreateCompiland(proc.modi());
+ SymbolContext sc;
+
+ sc.comp_unit = GetOrCreateCompileUnit(cci).get();
+ if (!sc.comp_unit)
+ continue;
+
+ PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
+ sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
+ if (!sc.function)
+ continue;
+
+ sc_list.Append(sc);
+ }
+ };
+
+ if (name_type_mask & eFunctionNameTypeFull)
+ resolve_from(m_func_full_names);
+ if (name_type_mask & eFunctionNameTypeBase)
+ resolve_from(m_func_base_names);
+ if (name_type_mask & eFunctionNameTypeMethod)
+ resolve_from(m_func_method_names);
}
void SymbolFileNativePDB::FindFunctions(const RegularExpression &regex,
@@ -2441,3 +2569,70 @@ SymbolFileNativePDB::GetContextForType(TypeIndex ti) {
}
return ctx;
}
+
+void SymbolFileNativePDB::CacheUdtDeclarations() {
+ for (CVType cvt : m_index->ipi().typeArray()) {
+ switch (cvt.kind()) {
+ case LF_UDT_SRC_LINE: {
+ UdtSourceLineRecord udt_src;
+ llvm::cantFail(TypeDeserializer::deserializeAs(cvt, udt_src));
+ m_udt_declarations.try_emplace(
+ udt_src.UDT, UdtDeclaration{/*FileNameIndex=*/udt_src.SourceFile,
+ /*IsIpiIndex=*/true,
+ /*Line=*/udt_src.LineNumber});
+ } break;
+ case LF_UDT_MOD_SRC_LINE: {
+ UdtModSourceLineRecord udt_mod_src;
+ llvm::cantFail(TypeDeserializer::deserializeAs(cvt, udt_mod_src));
+ // Some types might be contributed by multiple modules. We assume that
+ // they all point to the same file and line because we can only provide
+ // one location.
+ m_udt_declarations.try_emplace(
+ udt_mod_src.UDT,
+ UdtDeclaration{/*FileNameIndex=*/udt_mod_src.SourceFile,
+ /*IsIpiIndex=*/false,
+ /*Line=*/udt_mod_src.LineNumber});
+ } break;
+ default:
+ break;
+ }
+ }
+}
+
+llvm::Expected<Declaration>
+SymbolFileNativePDB::ResolveUdtDeclaration(PdbTypeSymId type_id) {
+ std::call_once(m_cached_udt_declarations, [this] { CacheUdtDeclarations(); });
+
+ auto it = m_udt_declarations.find(type_id.index);
+ if (it == m_udt_declarations.end())
+ return llvm::createStringError("No UDT declaration found");
+
+ llvm::StringRef file_name;
+ if (it->second.IsIpiIndex) {
+ CVType cvt = m_index->ipi().getType(it->second.FileNameIndex);
+ if (cvt.kind() != LF_STRING_ID)
+ return llvm::createStringError("File name was not a LF_STRING_ID");
+
+ StringIdRecord sid;
+ llvm::cantFail(TypeDeserializer::deserializeAs(cvt, sid));
+ file_name = sid.String;
+ } else {
+ // The file name index is an index into the string table
+ auto string_table = m_index->pdb().getStringTable();
+ if (!string_table)
+ return string_table.takeError();
+
+ llvm::Expected<llvm::StringRef> string =
+ string_table->getStringTable().getString(
+ it->second.FileNameIndex.getIndex());
+ if (!string)
+ return string.takeError();
+ file_name = *string;
+ }
+
+ // rustc sets the filename to "<unknown>" for some files
+ if (file_name == "\\<unknown>")
+ return Declaration();
+
+ return Declaration(FileSpec(file_name), it->second.Line);
+}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index eda375d..cfa0041 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -260,6 +260,11 @@ private:
std::vector<CompilerContext> GetContextForType(llvm::codeview::TypeIndex ti);
+ void CacheFunctionNames();
+
+ void CacheUdtDeclarations();
+ llvm::Expected<Declaration> ResolveUdtDeclaration(PdbTypeSymId type_id);
+
llvm::BumpPtrAllocator m_allocator;
lldb::addr_t m_obj_load_address = 0;
@@ -281,7 +286,26 @@ private:
llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
m_parent_types;
+ struct UdtDeclaration {
+ /// This could either be an index into the `/names` section (string table,
+ /// LF_UDT_MOD_SRC_LINE) or, this could be an index into the IPI stream to a
+ /// LF_STRING_ID record (LF_UDT_SRC_LINE).
+ llvm::codeview::TypeIndex FileNameIndex;
+ bool IsIpiIndex;
+
+ uint32_t Line;
+ };
+ llvm::DenseMap<llvm::codeview::TypeIndex, UdtDeclaration> m_udt_declarations;
+ std::once_flag m_cached_udt_declarations;
+
lldb_private::UniqueCStringMap<uint32_t> m_type_base_names;
+
+ /// mangled name/full function name -> Global ID(s)
+ lldb_private::UniqueCStringMap<uint32_t> m_func_full_names;
+ /// basename -> Global ID(s)
+ lldb_private::UniqueCStringMap<uint32_t> m_func_base_names;
+ /// method basename -> Global ID(s)
+ lldb_private::UniqueCStringMap<uint32_t> m_func_method_names;
};
} // namespace npdb
diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
index 8b8eac6e..3a95588 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
@@ -407,8 +407,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
// symbols in PDB for types with const or volatile modifiers, but we need
// to create only one declaration for them all.
Type::ResolveState type_resolve_state;
- CompilerType clang_type =
- m_ast.GetTypeForIdentifier<clang::CXXRecordDecl>(name, decl_context);
+ CompilerType clang_type = m_ast.GetTypeForIdentifier<clang::CXXRecordDecl>(
+ m_ast.getASTContext(), name, decl_context);
if (!clang_type.IsValid()) {
auto access = GetAccessibilityForUdt(*udt);
@@ -479,8 +479,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
uint64_t bytes = enum_type->getLength();
// Check if such an enum already exists in the current context
- CompilerType ast_enum =
- m_ast.GetTypeForIdentifier<clang::EnumDecl>(name, decl_context);
+ CompilerType ast_enum = m_ast.GetTypeForIdentifier<clang::EnumDecl>(
+ m_ast.getASTContext(), name, decl_context);
if (!ast_enum.IsValid()) {
auto underlying_type_up = enum_type->getUnderlyingType();
if (!underlying_type_up)
@@ -557,7 +557,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
// Check if such a typedef already exists in the current context
CompilerType ast_typedef =
- m_ast.GetTypeForIdentifier<clang::TypedefNameDecl>(name, decl_ctx);
+ m_ast.GetTypeForIdentifier<clang::TypedefNameDecl>(
+ m_ast.getASTContext(), name, decl_ctx);
if (!ast_typedef.IsValid()) {
CompilerType target_ast_type = target_type->GetFullCompilerType();
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
index b23f642..04a25e4 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
@@ -544,9 +544,9 @@ ThreadSP SystemRuntimeMacOSX::GetExtendedBacktraceThread(ThreadSP real_thread,
if (!thread_extended_info->ForEach(extract_frame_pc))
return {};
- originating_thread_sp =
- std::make_shared<HistoryThread>(*m_process, real_thread->GetIndexID(),
- app_specific_backtrace_pcs, true);
+ originating_thread_sp = std::make_shared<HistoryThread>(
+ *m_process, real_thread->GetIndexID(), app_specific_backtrace_pcs,
+ HistoryPCType::Calls);
originating_thread_sp->SetQueueName(type.AsCString());
}
return originating_thread_sp;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 6addf4f..39aacdb 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -27,6 +27,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/QualTypeNames.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/AST/VTableBuilder.h"
@@ -161,8 +162,7 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) {
auto find_overridden_methods =
[&decls, decl](const clang::CXXBaseSpecifier *specifier,
clang::CXXBasePath &path) {
- if (auto *base_record = llvm::dyn_cast<clang::CXXRecordDecl>(
- specifier->getType()->castAs<clang::RecordType>()->getDecl())) {
+ if (auto *base_record = specifier->getType()->getAsCXXRecordDecl()) {
clang::DeclarationName name = decl->getDeclName();
@@ -1179,7 +1179,7 @@ CompilerType TypeSystemClang::GetTypeForDecl(clang::NamedDecl *decl) {
}
CompilerType TypeSystemClang::GetTypeForDecl(TagDecl *decl) {
- return GetType(getASTContext().getTagDeclType(decl));
+ return GetType(getASTContext().getCanonicalTagType(decl));
}
CompilerType TypeSystemClang::GetTypeForDecl(ObjCInterfaceDecl *decl) {
@@ -1306,7 +1306,7 @@ CompilerType TypeSystemClang::CreateRecordType(
if (decl_ctx)
decl_ctx->addDecl(decl);
- return GetType(ast.getTagDeclType(decl));
+ return GetType(ast.getCanonicalTagType(decl));
}
namespace {
@@ -1674,7 +1674,6 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
class_template_specialization_decl->setInstantiationOf(class_template_decl);
class_template_specialization_decl->setTemplateArgs(
TemplateArgumentList::CreateCopy(ast, args));
- ast.getTypeDeclType(class_template_specialization_decl, nullptr);
class_template_specialization_decl->setDeclName(
class_template_decl->getDeclName());
@@ -1696,7 +1695,7 @@ CompilerType TypeSystemClang::CreateClassTemplateSpecializationType(
ClassTemplateSpecializationDecl *class_template_specialization_decl) {
if (class_template_specialization_decl) {
ASTContext &ast = getASTContext();
- return GetType(ast.getTagDeclType(class_template_specialization_decl));
+ return GetType(ast.getCanonicalTagType(class_template_specialization_decl));
}
return CompilerType();
}
@@ -1792,9 +1791,7 @@ bool TypeSystemClang::RecordHasFields(const RecordDecl *record_decl) {
for (base_class = cxx_record_decl->bases_begin(),
base_class_end = cxx_record_decl->bases_end();
base_class != base_class_end; ++base_class) {
- const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(
- base_class->getType()->getAs<RecordType>()->getDecl());
- if (RecordHasFields(base_class_decl))
+ if (RecordHasFields(base_class->getType()->getAsCXXRecordDecl()))
return true;
}
}
@@ -2290,9 +2287,9 @@ CompilerType TypeSystemClang::CreateStructForIdentifier(
&type_fields,
bool packed) {
CompilerType type;
- if (!type_name.empty() &&
- (type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name))
- .IsValid()) {
+ if (!type_name.empty() && (type = GetTypeForIdentifier<clang::CXXRecordDecl>(
+ getASTContext(), type_name))
+ .IsValid()) {
lldbassert(0 && "Trying to create a type for an existing name");
return type;
}
@@ -2316,7 +2313,9 @@ CompilerType TypeSystemClang::GetOrCreateStructForIdentifier(
&type_fields,
bool packed) {
CompilerType type;
- if ((type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)).IsValid())
+ if ((type = GetTypeForIdentifier<clang::CXXRecordDecl>(getASTContext(),
+ type_name))
+ .IsValid())
return type;
return CreateStructForIdentifier(type_name, type_fields, packed);
@@ -2355,7 +2354,7 @@ CompilerType TypeSystemClang::CreateEnumerationType(
enum_decl->setAccess(AS_public); // TODO respect what's in the debug info
- return GetType(ast.getTagDeclType(enum_decl));
+ return GetType(ast.getCanonicalTagType(enum_decl));
}
CompilerType TypeSystemClang::GetIntTypeFromBitSize(size_t bit_size,
@@ -2471,7 +2470,7 @@ bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast,
ast_source->CompleteType(tag_decl);
- return !tag_decl->getTypeForDecl()->isIncompleteType();
+ return !ast->getCanonicalTagType(tag_decl)->isIncompleteType();
} else if (clang::ObjCInterfaceDecl *objc_interface_decl =
llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl)) {
if (objc_interface_decl->getDefinition())
@@ -2575,7 +2574,6 @@ RemoveWrappingTypes(QualType type, ArrayRef<clang::Type::TypeClass> mask = {}) {
break;
case clang::Type::Auto:
case clang::Type::Decltype:
- case clang::Type::Elaborated:
case clang::Type::Paren:
case clang::Type::SubstTemplateTypeParm:
case clang::Type::TemplateSpecialization:
@@ -2607,10 +2605,11 @@ TypeSystemClang::GetDeclContextForType(clang::QualType type) {
return GetDeclContextForType(
llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
->getPointeeType());
- case clang::Type::Record:
- return llvm::cast<clang::RecordType>(qual_type)->getDecl();
case clang::Type::Enum:
- return llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ case clang::Type::Record:
+ return llvm::cast<clang::TagType>(qual_type)
+ ->getOriginalDecl()
+ ->getDefinitionOrSelf();
default:
break;
}
@@ -2790,7 +2789,7 @@ static bool GetCompleteQualType(clang::ASTContext *ast,
if (ast->getTargetInfo().getCXXABI().isMicrosoft()) {
auto *MPT = qual_type.getTypePtr()->castAs<clang::MemberPointerType>();
if (auto *RD = MPT->getMostRecentCXXRecordDecl())
- GetCompleteRecordType(ast, QualType(RD->getTypeForDecl(), 0),
+ GetCompleteRecordType(ast, ast->getCanonicalTagType(RD),
allow_completion);
return !qual_type.getTypePtr()->isIncompleteType();
@@ -2859,7 +2858,8 @@ bool TypeSystemClang::IsAnonymousType(lldb::opaque_compiler_type_t type) {
if (const clang::RecordType *record_type =
llvm::dyn_cast_or_null<clang::RecordType>(
qual_type.getTypePtrOrNull())) {
- if (const clang::RecordDecl *record_decl = record_type->getDecl()) {
+ if (const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()) {
return record_decl->isAnonymousStructOrUnion();
}
}
@@ -3099,8 +3099,8 @@ TypeSystemClang::IsHomogeneousAggregate(lldb::opaque_compiler_type_t type,
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
if (record_type) {
- const clang::RecordDecl *record_decl = record_type->getDecl();
- if (record_decl) {
+ if (const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinition()) {
// We are looking for a structure that contains only floating point
// types
clang::RecordDecl::field_iterator field_pos,
@@ -3280,7 +3280,10 @@ bool TypeSystemClang::IsEnumerationType(lldb::opaque_compiler_type_t type,
GetCanonicalQualType(type)->getCanonicalTypeInternal());
if (enum_type) {
- IsIntegerType(enum_type->getDecl()->getIntegerType().getAsOpaquePtr(),
+ IsIntegerType(enum_type->getOriginalDecl()
+ ->getDefinitionOrSelf()
+ ->getIntegerType()
+ .getAsOpaquePtr(),
is_signed);
return true;
}
@@ -3505,8 +3508,7 @@ bool TypeSystemClang::IsDefined(lldb::opaque_compiler_type_t type) {
const clang::TagType *tag_type =
llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
- if (tag_decl)
+ if (clang::TagDecl *tag_decl = tag_type->getOriginalDecl()->getDefinition())
return tag_decl->isCompleteDefinition();
return false;
} else {
@@ -3565,21 +3567,14 @@ bool TypeSystemClang::IsPolymorphicClass(lldb::opaque_compiler_type_t type) {
switch (type_class) {
case clang::Type::Record:
if (GetCompleteType(type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- if (record_decl) {
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl) {
- // We can't just call is isPolymorphic() here because that just
- // means the current class has virtual functions, it doesn't check
- // if any inherited classes have virtual functions. The doc string
- // in SBType::IsPolymorphicClass() says it is looking for both
- // if the class has virtual methods or if any bases do, so this
- // should be more correct.
- return cxx_record_decl->isDynamicClass();
- }
+ if (const auto *cxx_record_decl = qual_type->getAsCXXRecordDecl()) {
+ // We can't just call is isPolymorphic() here because that just
+ // means the current class has virtual functions, it doesn't check
+ // if any inherited classes have virtual functions. The doc string
+ // in SBType::IsPolymorphicClass() says it is looking for both
+ // if the class has virtual methods or if any bases do, so this
+ // should be more correct.
+ return cxx_record_decl->isDynamicClass();
}
}
break;
@@ -3766,7 +3761,7 @@ bool TypeSystemClang::IsBeingDefined(lldb::opaque_compiler_type_t type) {
clang::QualType qual_type(GetCanonicalQualType(type));
const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type);
if (tag_type)
- return tag_type->isBeingDefined();
+ return tag_type->getOriginalDecl()->isEntityBeingDefined();
return false;
}
@@ -3974,7 +3969,8 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type,
if (pointee_or_element_clang_type)
pointee_or_element_clang_type->SetCompilerType(
weak_from_this(), llvm::cast<clang::EnumType>(qual_type)
- ->getDecl()
+ ->getOriginalDecl()
+ ->getDefinitionOrSelf()
->getIntegerType()
.getAsOpaquePtr());
return eTypeIsEnumeration | eTypeHasValue;
@@ -4154,7 +4150,6 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) {
case clang::Type::Auto:
case clang::Type::CountAttributed:
case clang::Type::Decltype:
- case clang::Type::Elaborated:
case clang::Type::Paren:
case clang::Type::TypeOf:
case clang::Type::TypeOfExpr:
@@ -4214,7 +4209,7 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) {
case clang::Type::Record: {
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordDecl *record_decl = record_type->getOriginalDecl();
if (record_decl->isUnion())
return lldb::eTypeClassUnion;
else if (record_decl->isStruct())
@@ -4280,6 +4275,8 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) {
break;
case clang::Type::HLSLInlineSpirv:
break;
+ case clang::Type::SubstBuiltinTemplatePack:
+ break;
}
// We don't know hot to display this type...
return lldb::eTypeClassOther;
@@ -4412,17 +4409,10 @@ TypeSystemClang::GetNumMemberFunctions(lldb::opaque_compiler_type_t type) {
clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
switch (qual_type->getTypeClass()) {
case clang::Type::Record:
- if (GetCompleteQualType(&getASTContext(), qual_type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl)
+ if (GetCompleteQualType(&getASTContext(), qual_type))
+ if (const auto *cxx_record_decl = qual_type->getAsCXXRecordDecl())
num_functions = std::distance(cxx_record_decl->method_begin(),
cxx_record_decl->method_end());
- }
break;
case clang::Type::ObjCObjectPointer: {
@@ -4477,13 +4467,7 @@ TypeSystemClang::GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type,
switch (qual_type->getTypeClass()) {
case clang::Type::Record:
if (GetCompleteQualType(&getASTContext(), qual_type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl) {
+ if (const auto *cxx_record_decl = qual_type->getAsCXXRecordDecl()) {
auto method_iter = cxx_record_decl->method_begin();
auto method_end = cxx_record_decl->method_end();
if (idx <
@@ -4703,9 +4687,9 @@ CompilerType TypeSystemClang::CreateTypedef(
clang::TagDecl *tdecl = nullptr;
if (!qual_type.isNull()) {
if (const clang::RecordType *rt = qual_type->getAs<clang::RecordType>())
- tdecl = rt->getDecl();
+ tdecl = rt->getOriginalDecl();
if (const clang::EnumType *et = qual_type->getAs<clang::EnumType>())
- tdecl = et->getDecl();
+ tdecl = et->getOriginalDecl();
}
// Check whether this declaration is an anonymous struct, union, or enum,
@@ -4717,7 +4701,10 @@ CompilerType TypeSystemClang::CreateTypedef(
decl->setAccess(clang::AS_public); // TODO respect proper access specifier
// Get a uniqued clang::QualType for the typedef decl type
- return GetType(clang_ast.getTypedefType(decl));
+ NestedNameSpecifier Qualifier =
+ clang::TypeName::getFullyQualifiedDeclaredContext(clang_ast, decl);
+ return GetType(
+ clang_ast.getTypedefType(ElaboratedTypeKeyword::None, Qualifier, decl));
}
return CompilerType();
}
@@ -4869,7 +4856,6 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
case clang::Type::Auto:
case clang::Type::CountAttributed:
case clang::Type::Decltype:
- case clang::Type::Elaborated:
case clang::Type::Paren:
case clang::Type::Typedef:
case clang::Type::TypeOf:
@@ -5155,6 +5141,8 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
break;
case clang::Type::HLSLInlineSpirv:
break;
+ case clang::Type::SubstBuiltinTemplatePack:
+ break;
}
count = 0;
return lldb::eEncodingInvalid;
@@ -5171,7 +5159,6 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) {
case clang::Type::Auto:
case clang::Type::CountAttributed:
case clang::Type::Decltype:
- case clang::Type::Elaborated:
case clang::Type::Paren:
case clang::Type::Typedef:
case clang::Type::TypeOf:
@@ -5324,6 +5311,8 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) {
break;
case clang::Type::HLSLInlineSpirv:
break;
+ case clang::Type::SubstBuiltinTemplatePack:
+ break;
}
// We don't know hot to display this type...
return lldb::eFormatBytes;
@@ -5380,8 +5369,8 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
if (GetCompleteQualType(&getASTContext(), qual_type)) {
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
+ const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinitionOrSelf();
const clang::CXXRecordDecl *cxx_record_decl =
llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
@@ -5577,7 +5566,8 @@ void TypeSystemClang::ForEachEnumerator(
const clang::EnumType *enum_type =
llvm::dyn_cast<clang::EnumType>(GetCanonicalQualType(type));
if (enum_type) {
- const clang::EnumDecl *enum_decl = enum_type->getDecl();
+ const clang::EnumDecl *enum_decl =
+ enum_type->getOriginalDecl()->getDefinitionOrSelf();
if (enum_decl) {
CompilerType integer_type = GetType(enum_decl->getIntegerType());
@@ -5608,7 +5598,8 @@ uint32_t TypeSystemClang::GetNumFields(lldb::opaque_compiler_type_t type) {
const clang::RecordType *record_type =
llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr());
if (record_type) {
- clang::RecordDecl *record_decl = record_type->getDecl();
+ clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinition();
if (record_decl) {
count = std::distance(record_decl->field_begin(),
record_decl->field_end());
@@ -5722,7 +5713,8 @@ CompilerType TypeSystemClang::GetFieldAtIndex(lldb::opaque_compiler_type_t type,
if (GetCompleteType(type)) {
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinitionOrSelf();
uint32_t field_idx = 0;
clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(),
@@ -5908,7 +5900,7 @@ CompilerType TypeSystemClang::GetDirectBaseClassAtIndex(
llvm::cast<clang::CXXRecordDecl>(
base_class->getType()
->castAs<clang::RecordType>()
- ->getDecl());
+ ->getOriginalDecl());
if (base_class->isVirtual())
*bit_offset_ptr =
record_layout.getVBaseClassOffset(base_class_decl)
@@ -6003,7 +5995,7 @@ CompilerType TypeSystemClang::GetVirtualBaseClassAtIndex(
llvm::cast<clang::CXXRecordDecl>(
base_class->getType()
->castAs<clang::RecordType>()
- ->getDecl());
+ ->getOriginalDecl());
*bit_offset_ptr =
record_layout.getVBaseClassOffset(base_class_decl)
.getQuantity() *
@@ -6033,7 +6025,8 @@ TypeSystemClang::GetStaticFieldWithName(lldb::opaque_compiler_type_t type,
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinitionOrSelf();
clang::DeclarationName decl_name(&getASTContext().Idents.get(name));
for (NamedDecl *decl : record_decl->lookup(decl_name)) {
@@ -6263,8 +6256,8 @@ llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex(
if (idx_is_valid && GetCompleteType(type)) {
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(parent_qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
+ const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinitionOrSelf();
const clang::ASTRecordLayout &record_layout =
getASTContext().getASTRecordLayout(record_decl);
uint32_t child_idx = 0;
@@ -6283,7 +6276,10 @@ llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex(
// Skip empty base classes
if (omit_empty_base_classes) {
base_class_decl = llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()->getAs<clang::RecordType>()->getDecl());
+ base_class->getType()
+ ->getAs<clang::RecordType>()
+ ->getOriginalDecl())
+ ->getDefinitionOrSelf();
if (!TypeSystemClang::RecordHasFields(base_class_decl))
continue;
}
@@ -6291,7 +6287,10 @@ llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex(
if (idx == child_idx) {
if (base_class_decl == nullptr)
base_class_decl = llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()->getAs<clang::RecordType>()->getDecl());
+ base_class->getType()
+ ->getAs<clang::RecordType>()
+ ->getOriginalDecl())
+ ->getDefinitionOrSelf();
if (base_class->isVirtual()) {
bool handled = false;
@@ -6752,7 +6751,8 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
if (GetCompleteType(type)) {
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinitionOrSelf();
assert(record_decl);
uint32_t child_idx = 0;
@@ -6817,10 +6817,10 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
return 0;
} else {
child_indexes.push_back(child_idx);
- parent_record_decl = llvm::cast<clang::RecordDecl>(
- elem.Base->getType()
- ->castAs<clang::RecordType>()
- ->getDecl());
+ parent_record_decl = elem.Base->getType()
+ ->castAs<clang::RecordType>()
+ ->getOriginalDecl()
+ ->getDefinitionOrSelf();
}
}
for (clang::DeclContext::lookup_iterator I = path->Decls, E;
@@ -6954,7 +6954,8 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
if (GetCompleteType(type)) {
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinitionOrSelf();
assert(record_decl);
uint32_t child_idx = 0;
@@ -6973,7 +6974,8 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
llvm::cast<clang::CXXRecordDecl>(
base_class->getType()
->castAs<clang::RecordType>()
- ->getDecl());
+ ->getOriginalDecl())
+ ->getDefinitionOrSelf();
if (omit_empty_base_classes &&
!TypeSystemClang::RecordHasFields(base_class_decl))
continue;
@@ -7092,14 +7094,17 @@ TypeSystemClang::GetDirectNestedTypeWithName(lldb::opaque_compiler_type_t type,
return CompilerType();
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinitionOrSelf();
clang::DeclarationName decl_name(&getASTContext().Idents.get(name));
for (NamedDecl *decl : record_decl->lookup(decl_name)) {
if (auto *tag_decl = dyn_cast<clang::TagDecl>(decl))
- return GetType(getASTContext().getTagDeclType(tag_decl));
+ return GetType(getASTContext().getCanonicalTagType(tag_decl));
if (auto *typedef_decl = dyn_cast<clang::TypedefNameDecl>(decl))
- return GetType(getASTContext().getTypedefType(typedef_decl));
+ return GetType(getASTContext().getTypedefType(
+ ElaboratedTypeKeyword::None, /*Qualifier=*/std::nullopt,
+ typedef_decl));
}
break;
}
@@ -7116,7 +7121,7 @@ bool TypeSystemClang::IsTemplateType(lldb::opaque_compiler_type_t type) {
const clang::Type *clang_type = ClangUtil::GetQualType(ct).getTypePtr();
if (auto *cxx_record_decl = dyn_cast<clang::TagType>(clang_type))
return isa<clang::ClassTemplateSpecializationDecl>(
- cxx_record_decl->getDecl());
+ cxx_record_decl->getOriginalDecl());
return false;
}
@@ -7319,7 +7324,7 @@ clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) {
const clang::EnumType *enutype =
llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type));
if (enutype)
- return enutype->getDecl();
+ return enutype->getOriginalDecl()->getDefinitionOrSelf();
return nullptr;
}
@@ -7327,7 +7332,7 @@ clang::RecordDecl *TypeSystemClang::GetAsRecordDecl(const CompilerType &type) {
const clang::RecordType *record_type =
llvm::dyn_cast<clang::RecordType>(ClangUtil::GetCanonicalQualType(type));
if (record_type)
- return record_type->getDecl();
+ return record_type->getOriginalDecl()->getDefinitionOrSelf();
return nullptr;
}
@@ -7409,7 +7414,7 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType(
if (const clang::TagType *TagT =
field->getType()->getAs<clang::TagType>()) {
if (clang::RecordDecl *Rec =
- llvm::dyn_cast<clang::RecordDecl>(TagT->getDecl()))
+ llvm::dyn_cast<clang::RecordDecl>(TagT->getOriginalDecl()))
if (!Rec->getDeclName()) {
Rec->setAnonymousStructOrUnion(true);
field->setImplicit();
@@ -7494,7 +7499,8 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) {
if (!field_record_type)
continue;
- clang::RecordDecl *field_record_decl = field_record_type->getDecl();
+ clang::RecordDecl *field_record_decl =
+ field_record_type->getOriginalDecl()->getDefinition();
if (!field_record_decl)
continue;
@@ -7636,7 +7642,8 @@ void TypeSystemClang::SetIntegerInitializerForVariable(
// If the variable is an enum type, take the underlying integer type as
// the type of the integer literal.
if (const EnumType *enum_type = qt->getAs<EnumType>()) {
- const EnumDecl *enum_decl = enum_type->getDecl();
+ const EnumDecl *enum_decl =
+ enum_type->getOriginalDecl()->getDefinitionOrSelf();
qt = enum_decl->getIntegerType();
}
// Bools are handled separately because the clang AST printer handles bools
@@ -8296,7 +8303,7 @@ bool TypeSystemClang::SetHasExternalStorage(lldb::opaque_compiler_type_t type,
case clang::Type::Enum: {
clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ llvm::cast<clang::EnumType>(qual_type)->getOriginalDecl();
if (enum_decl) {
enum_decl->setHasExternalLexicalStorage(has_extern);
enum_decl->setHasExternalVisibleStorage(has_extern);
@@ -8334,7 +8341,7 @@ bool TypeSystemClang::StartTagDeclarationDefinition(const CompilerType &type) {
if (!qual_type.isNull()) {
const clang::TagType *tag_type = qual_type->getAs<clang::TagType>();
if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
+ clang::TagDecl *tag_decl = tag_type->getOriginalDecl();
if (tag_decl) {
tag_decl->startDefinition();
return true;
@@ -8369,7 +8376,8 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition(
// the definition.
const clang::TagType *tag_type = qual_type->getAs<clang::TagType>();
if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
+ clang::TagDecl *tag_decl =
+ tag_type->getOriginalDecl()->getDefinitionOrSelf();
if (auto *cxx_record_decl = llvm::dyn_cast<CXXRecordDecl>(tag_decl)) {
// If we have a move constructor declared but no copy constructor we
@@ -8404,7 +8412,8 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition(
if (!enutype)
return false;
- clang::EnumDecl *enum_decl = enutype->getDecl();
+ clang::EnumDecl *enum_decl =
+ enutype->getOriginalDecl()->getDefinitionOrSelf();
if (enum_decl->isCompleteDefinition())
return true;
@@ -8462,17 +8471,19 @@ clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType(
clang::EnumConstantDecl *enumerator_decl =
clang::EnumConstantDecl::CreateDeserialized(getASTContext(),
GlobalDeclID());
- enumerator_decl->setDeclContext(enutype->getDecl());
+ clang::EnumDecl *enum_decl =
+ enutype->getOriginalDecl()->getDefinitionOrSelf();
+ enumerator_decl->setDeclContext(enum_decl);
if (name && name[0])
enumerator_decl->setDeclName(&getASTContext().Idents.get(name));
enumerator_decl->setType(clang::QualType(enutype, 0));
enumerator_decl->setInitVal(getASTContext(), value);
- SetMemberOwningModule(enumerator_decl, enutype->getDecl());
+ SetMemberOwningModule(enumerator_decl, enum_decl);
if (!enumerator_decl)
return nullptr;
- enutype->getDecl()->addDecl(enumerator_decl);
+ enum_decl->addDecl(enumerator_decl);
VerifyDecl(enumerator_decl);
return enumerator_decl;
@@ -8496,7 +8507,8 @@ CompilerType TypeSystemClang::GetEnumerationIntegerType(CompilerType type) {
if (!enum_type)
return CompilerType();
- return GetType(enum_type->getDecl()->getIntegerType());
+ return GetType(
+ enum_type->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType());
}
CompilerType
@@ -8509,7 +8521,7 @@ TypeSystemClang::CreateMemberPointerType(const CompilerType &type,
return CompilerType();
return ast->GetType(ast->getASTContext().getMemberPointerType(
ClangUtil::GetQualType(pointee_type),
- /*Qualifier=*/nullptr,
+ /*Qualifier=*/std::nullopt,
ClangUtil::GetQualType(type)->getAsCXXRecordDecl()));
}
return CompilerType();
@@ -8587,8 +8599,8 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
uint32_t bitfield_bit_size) {
const clang::EnumType *enutype =
llvm::cast<clang::EnumType>(qual_type.getTypePtr());
- const clang::EnumDecl *enum_decl = enutype->getDecl();
- assert(enum_decl);
+ const clang::EnumDecl *enum_decl =
+ enutype->getOriginalDecl()->getDefinitionOrSelf();
lldb::offset_t offset = byte_offset;
bool qual_type_is_signed = qual_type->isSignedIntegerOrEnumerationType();
const uint64_t enum_svalue =
@@ -8694,15 +8706,7 @@ bool TypeSystemClang::DumpTypeValue(
} else {
clang::QualType qual_type(GetQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
-
- if (type_class == clang::Type::Elaborated) {
- qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
- return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data, byte_offset, byte_size,
- bitfield_bit_size, bitfield_bit_offset, exe_scope);
- }
-
- switch (type_class) {
+ switch (qual_type->getTypeClass()) {
case clang::Type::Typedef: {
clang::QualType typedef_qual_type =
llvm::cast<clang::TypedefType>(qual_type)
@@ -8872,7 +8876,7 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
GetCompleteType(type);
auto *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::RecordDecl *record_decl = record_type->getOriginalDecl();
if (level == eDescriptionLevelVerbose)
record_decl->dump(llvm_ostrm);
else {
@@ -8884,7 +8888,7 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
default: {
if (auto *tag_type =
llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr())) {
- if (clang::TagDecl *tag_decl = tag_type->getDecl()) {
+ if (clang::TagDecl *tag_decl = tag_type->getOriginalDecl()) {
if (level == eDescriptionLevelVerbose)
tag_decl->dump(llvm_ostrm);
else
@@ -8924,7 +8928,7 @@ void TypeSystemClang::DumpTypeName(const CompilerType &type) {
case clang::Type::Enum: {
clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ llvm::cast<clang::EnumType>(qual_type)->getOriginalDecl();
if (enum_decl) {
printf("enum %s", enum_decl->getName().str().c_str());
}
@@ -8960,13 +8964,6 @@ void TypeSystemClang::DumpTypeName(const CompilerType &type) {
->getDeducedType()
.getAsOpaquePtr()));
- case clang::Type::Elaborated:
- printf("elaborated ");
- return DumpTypeName(CompilerType(
- type.GetTypeSystem(), llvm::cast<clang::ElaboratedType>(qual_type)
- ->getNamedType()
- .getAsOpaquePtr()));
-
case clang::Type::Paren:
printf("paren ");
return DumpTypeName(CompilerType(
@@ -9796,8 +9793,8 @@ bool TypeSystemClang::IsForcefullyCompleted(lldb::opaque_compiler_type_t type) {
const clang::RecordType *record_type =
llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr());
if (record_type) {
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
+ const clang::RecordDecl *record_decl =
+ record_type->getOriginalDecl()->getDefinitionOrSelf();
if (std::optional<ClangASTMetadata> metadata = GetMetadata(record_decl))
return metadata->IsForcefullyCompleted();
}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 70d613d..709f8959 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -260,7 +260,7 @@ public:
template <typename RecordDeclType>
CompilerType
- GetTypeForIdentifier(llvm::StringRef type_name,
+ GetTypeForIdentifier(const clang::ASTContext &Ctx, llvm::StringRef type_name,
clang::DeclContext *decl_context = nullptr) {
CompilerType compiler_type;
if (type_name.empty())
@@ -278,11 +278,10 @@ public:
return compiler_type;
clang::NamedDecl *named_decl = *result.begin();
- if (const RecordDeclType *record_decl =
- llvm::dyn_cast<RecordDeclType>(named_decl))
+ if (const auto *type_decl = llvm::dyn_cast<clang::TypeDecl>(named_decl);
+ llvm::isa_and_nonnull<RecordDeclType>(type_decl))
compiler_type = CompilerType(
- weak_from_this(),
- clang::QualType(record_decl->getTypeForDecl(), 0).getAsOpaquePtr());
+ weak_from_this(), Ctx.getTypeDeclType(type_decl).getAsOpaquePtr());
return compiler_type;
}
diff --git a/lldb/source/Protocol/MCP/CMakeLists.txt b/lldb/source/Protocol/MCP/CMakeLists.txt
index a73e7e6..a4f270a 100644
--- a/lldb/source/Protocol/MCP/CMakeLists.txt
+++ b/lldb/source/Protocol/MCP/CMakeLists.txt
@@ -7,6 +7,7 @@ add_lldb_library(lldbProtocolMCP NO_PLUGIN_DEPENDENCIES
LINK_COMPONENTS
Support
LINK_LIBS
+ lldbHost
lldbUtility
)
diff --git a/lldb/source/Protocol/MCP/MCPError.cpp b/lldb/source/Protocol/MCP/MCPError.cpp
index c610e88..e140d11 100644
--- a/lldb/source/Protocol/MCP/MCPError.cpp
+++ b/lldb/source/Protocol/MCP/MCPError.cpp
@@ -25,10 +25,10 @@ std::error_code MCPError::convertToErrorCode() const {
return llvm::inconvertibleErrorCode();
}
-lldb_protocol::mcp::Error MCPError::toProtcolError() const {
+lldb_protocol::mcp::Error MCPError::toProtocolError() const {
lldb_protocol::mcp::Error error;
- error.error.code = m_error_code;
- error.error.message = m_message;
+ error.code = m_error_code;
+ error.message = m_message;
return error;
}
diff --git a/lldb/source/Protocol/MCP/Protocol.cpp b/lldb/source/Protocol/MCP/Protocol.cpp
index d579b88..0988f45 100644
--- a/lldb/source/Protocol/MCP/Protocol.cpp
+++ b/lldb/source/Protocol/MCP/Protocol.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Protocol/MCP/Protocol.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/JSON.h"
using namespace llvm;
@@ -26,8 +27,45 @@ static bool mapRaw(const json::Value &Params, StringLiteral Prop,
return true;
}
+static llvm::json::Value toJSON(const Id &Id) {
+ if (const int64_t *I = std::get_if<int64_t>(&Id))
+ return json::Value(*I);
+ if (const std::string *S = std::get_if<std::string>(&Id))
+ return json::Value(*S);
+ llvm_unreachable("unexpected type in protocol::Id");
+}
+
+static bool mapId(const llvm::json::Value &V, StringLiteral Prop, Id &Id,
+ llvm::json::Path P) {
+ const auto *O = V.getAsObject();
+ if (!O) {
+ P.report("expected object");
+ return false;
+ }
+
+ const auto *E = O->get(Prop);
+ if (!E) {
+ P.field(Prop).report("not found");
+ return false;
+ }
+
+ if (auto S = E->getAsString()) {
+ Id = S->str();
+ return true;
+ }
+
+ if (auto I = E->getAsInteger()) {
+ Id = *I;
+ return true;
+ }
+
+ P.report("expected string or number");
+ return false;
+}
+
llvm::json::Value toJSON(const Request &R) {
- json::Object Result{{"jsonrpc", "2.0"}, {"id", R.id}, {"method", R.method}};
+ json::Object Result{
+ {"jsonrpc", "2.0"}, {"id", toJSON(R.id)}, {"method", R.method}};
if (R.params)
Result.insert({"params", R.params});
return Result;
@@ -35,47 +73,75 @@ llvm::json::Value toJSON(const Request &R) {
bool fromJSON(const llvm::json::Value &V, Request &R, llvm::json::Path P) {
llvm::json::ObjectMapper O(V, P);
- if (!O || !O.map("id", R.id) || !O.map("method", R.method))
- return false;
- return mapRaw(V, "params", R.params, P);
+ return O && mapId(V, "id", R.id, P) && O.map("method", R.method) &&
+ mapRaw(V, "params", R.params, P);
}
-llvm::json::Value toJSON(const ErrorInfo &EI) {
- llvm::json::Object Result{{"code", EI.code}, {"message", EI.message}};
- if (!EI.data.empty())
- Result.insert({"data", EI.data});
- return Result;
-}
-
-bool fromJSON(const llvm::json::Value &V, ErrorInfo &EI, llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("code", EI.code) && O.map("message", EI.message) &&
- O.mapOptional("data", EI.data);
+bool operator==(const Request &a, const Request &b) {
+ return a.id == b.id && a.method == b.method && a.params == b.params;
}
llvm::json::Value toJSON(const Error &E) {
- return json::Object{{"jsonrpc", "2.0"}, {"id", E.id}, {"error", E.error}};
+ llvm::json::Object Result{{"code", E.code}, {"message", E.message}};
+ if (E.data)
+ Result.insert({"data", *E.data});
+ return Result;
}
bool fromJSON(const llvm::json::Value &V, Error &E, llvm::json::Path P) {
llvm::json::ObjectMapper O(V, P);
- return O && O.map("id", E.id) && O.map("error", E.error);
+ return O && O.map("code", E.code) && O.map("message", E.message) &&
+ mapRaw(V, "data", E.data, P);
+}
+
+bool operator==(const Error &a, const Error &b) {
+ return a.code == b.code && a.message == b.message && a.data == b.data;
}
llvm::json::Value toJSON(const Response &R) {
- llvm::json::Object Result{{"jsonrpc", "2.0"}, {"id", R.id}};
- if (R.result)
- Result.insert({"result", R.result});
- if (R.error)
- Result.insert({"error", R.error});
+ llvm::json::Object Result{{"jsonrpc", "2.0"}, {"id", toJSON(R.id)}};
+
+ if (const Error *error = std::get_if<Error>(&R.result))
+ Result.insert({"error", *error});
+ if (const json::Value *result = std::get_if<json::Value>(&R.result))
+ Result.insert({"result", *result});
return Result;
}
bool fromJSON(const llvm::json::Value &V, Response &R, llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- if (!O || !O.map("id", R.id) || !O.map("error", R.error))
+ const json::Object *E = V.getAsObject();
+ if (!E) {
+ P.report("expected object");
+ return false;
+ }
+
+ const json::Value *result = E->get("result");
+ const json::Value *raw_error = E->get("error");
+
+ if (result && raw_error) {
+ P.report("'result' and 'error' fields are mutually exclusive");
return false;
- return mapRaw(V, "result", R.result, P);
+ }
+
+ if (!result && !raw_error) {
+ P.report("'result' or 'error' fields are required'");
+ return false;
+ }
+
+ if (result) {
+ R.result = std::move(*result);
+ } else {
+ Error error;
+ if (!fromJSON(*raw_error, error, P))
+ return false;
+ R.result = std::move(error);
+ }
+
+ return mapId(V, "id", R.id, P);
+}
+
+bool operator==(const Response &a, const Response &b) {
+ return a.id == b.id && a.result == b.result;
}
llvm::json::Value toJSON(const Notification &N) {
@@ -97,30 +163,8 @@ bool fromJSON(const llvm::json::Value &V, Notification &N, llvm::json::Path P) {
return true;
}
-llvm::json::Value toJSON(const ToolCapability &TC) {
- return llvm::json::Object{{"listChanged", TC.listChanged}};
-}
-
-bool fromJSON(const llvm::json::Value &V, ToolCapability &TC,
- llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("listChanged", TC.listChanged);
-}
-
-llvm::json::Value toJSON(const ResourceCapability &RC) {
- return llvm::json::Object{{"listChanged", RC.listChanged},
- {"subscribe", RC.subscribe}};
-}
-
-bool fromJSON(const llvm::json::Value &V, ResourceCapability &RC,
- llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("listChanged", RC.listChanged) &&
- O.map("subscribe", RC.subscribe);
-}
-
-llvm::json::Value toJSON(const Capabilities &C) {
- return llvm::json::Object{{"tools", C.tools}, {"resources", C.resources}};
+bool operator==(const Notification &a, const Notification &b) {
+ return a.method == b.method && a.params == b.params;
}
bool fromJSON(const llvm::json::Value &V, Resource &R, llvm::json::Path P) {
@@ -139,30 +183,25 @@ llvm::json::Value toJSON(const Resource &R) {
return Result;
}
-bool fromJSON(const llvm::json::Value &V, Capabilities &C, llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("tools", C.tools);
-}
-
-llvm::json::Value toJSON(const ResourceContents &RC) {
+llvm::json::Value toJSON(const TextResourceContents &RC) {
llvm::json::Object Result{{"uri", RC.uri}, {"text", RC.text}};
if (!RC.mimeType.empty())
Result.insert({"mimeType", RC.mimeType});
return Result;
}
-bool fromJSON(const llvm::json::Value &V, ResourceContents &RC,
+bool fromJSON(const llvm::json::Value &V, TextResourceContents &RC,
llvm::json::Path P) {
llvm::json::ObjectMapper O(V, P);
return O && O.map("uri", RC.uri) && O.map("text", RC.text) &&
O.mapOptional("mimeType", RC.mimeType);
}
-llvm::json::Value toJSON(const ResourceResult &RR) {
+llvm::json::Value toJSON(const ReadResourceResult &RR) {
return llvm::json::Object{{"contents", RR.contents}};
}
-bool fromJSON(const llvm::json::Value &V, ResourceResult &RR,
+bool fromJSON(const llvm::json::Value &V, ReadResourceResult &RR,
llvm::json::Path P) {
llvm::json::ObjectMapper O(V, P);
return O && O.map("contents", RR.contents);
@@ -177,15 +216,6 @@ bool fromJSON(const llvm::json::Value &V, TextContent &TC, llvm::json::Path P) {
return O && O.map("text", TC.text);
}
-llvm::json::Value toJSON(const TextResult &TR) {
- return llvm::json::Object{{"content", TR.content}, {"isError", TR.isError}};
-}
-
-bool fromJSON(const llvm::json::Value &V, TextResult &TR, llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("content", TR.content) && O.map("isError", TR.isError);
-}
-
llvm::json::Value toJSON(const ToolDefinition &TD) {
llvm::json::Object Result{{"name", TD.name}};
if (!TD.description.empty())
@@ -235,24 +265,16 @@ bool fromJSON(const llvm::json::Value &V, Message &M, llvm::json::Path P) {
return true;
}
- if (O->get("error")) {
- Error E;
- if (!fromJSON(V, E, P))
- return false;
- M = std::move(E);
- return true;
- }
-
- if (O->get("result")) {
- Response R;
+ if (O->get("method")) {
+ Request R;
if (!fromJSON(V, R, P))
return false;
M = std::move(R);
return true;
}
- if (O->get("method")) {
- Request R;
+ if (O->get("result") || O->get("error")) {
+ Response R;
if (!fromJSON(V, R, P))
return false;
M = std::move(R);
@@ -263,4 +285,159 @@ bool fromJSON(const llvm::json::Value &V, Message &M, llvm::json::Path P) {
return false;
}
+json::Value toJSON(const Implementation &I) {
+ json::Object result{{"name", I.name}, {"version", I.version}};
+
+ if (!I.title.empty())
+ result.insert({"title", I.title});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, Implementation &I, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("name", I.name) && O.mapOptional("title", I.title) &&
+ O.mapOptional("version", I.version);
+}
+
+json::Value toJSON(const ClientCapabilities &C) { return json::Object{}; }
+
+bool fromJSON(const json::Value &, ClientCapabilities &, json::Path) {
+ return true;
+}
+
+json::Value toJSON(const ServerCapabilities &C) {
+ json::Object result{};
+
+ if (C.supportsToolsList)
+ result.insert({"tools", json::Object{{"listChanged", true}}});
+
+ if (C.supportsResourcesList || C.supportsResourcesSubscribe) {
+ json::Object resources;
+ if (C.supportsResourcesList)
+ resources.insert({"listChanged", true});
+ if (C.supportsResourcesSubscribe)
+ resources.insert({"subscribe", true});
+ result.insert({"resources", std::move(resources)});
+ }
+
+ if (C.supportsCompletions)
+ result.insert({"completions", json::Object{}});
+
+ if (C.supportsLogging)
+ result.insert({"logging", json::Object{}});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, ServerCapabilities &C, json::Path P) {
+ const json::Object *O = V.getAsObject();
+ if (!O) {
+ P.report("expected object");
+ return false;
+ }
+
+ if (O->find("tools") != O->end())
+ C.supportsToolsList = true;
+
+ return true;
+}
+
+json::Value toJSON(const InitializeParams &P) {
+ return json::Object{
+ {"protocolVersion", P.protocolVersion},
+ {"capabilities", P.capabilities},
+ {"clientInfo", P.clientInfo},
+ };
+}
+
+bool fromJSON(const json::Value &V, InitializeParams &I, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("protocolVersion", I.protocolVersion) &&
+ O.map("capabilities", I.capabilities) &&
+ O.map("clientInfo", I.clientInfo);
+}
+
+json::Value toJSON(const InitializeResult &R) {
+ json::Object result{{"protocolVersion", R.protocolVersion},
+ {"capabilities", R.capabilities},
+ {"serverInfo", R.serverInfo}};
+
+ if (!R.instructions.empty())
+ result.insert({"instructions", R.instructions});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, InitializeResult &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("protocolVersion", R.protocolVersion) &&
+ O.map("capabilities", R.capabilities) &&
+ O.map("serverInfo", R.serverInfo) &&
+ O.mapOptional("instructions", R.instructions);
+}
+
+json::Value toJSON(const ListToolsResult &R) {
+ return json::Object{{"tools", R.tools}};
+}
+
+bool fromJSON(const json::Value &V, ListToolsResult &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("tools", R.tools);
+}
+
+json::Value toJSON(const CallToolResult &R) {
+ json::Object result{{"content", R.content}};
+
+ if (R.isError)
+ result.insert({"isError", R.isError});
+ if (R.structuredContent)
+ result.insert({"structuredContent", *R.structuredContent});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, CallToolResult &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("content", R.content) &&
+ O.mapOptional("isError", R.isError) &&
+ mapRaw(V, "structuredContent", R.structuredContent, P);
+}
+
+json::Value toJSON(const CallToolParams &R) {
+ json::Object result{{"name", R.name}};
+
+ if (R.arguments)
+ result.insert({"arguments", *R.arguments});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, CallToolParams &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("name", R.name) && mapRaw(V, "arguments", R.arguments, P);
+}
+
+json::Value toJSON(const ReadResourceParams &R) {
+ return json::Object{{"uri", R.uri}};
+}
+
+bool fromJSON(const json::Value &V, ReadResourceParams &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("uri", R.uri);
+}
+
+json::Value toJSON(const ListResourcesResult &R) {
+ return json::Object{{"resources", R.resources}};
+}
+
+bool fromJSON(const json::Value &V, ListResourcesResult &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("resources", R.resources);
+}
+
+json::Value toJSON(const Void &R) { return json::Object{}; }
+
+bool fromJSON(const json::Value &V, Void &R, json::Path P) { return true; }
+
} // namespace lldb_protocol::mcp
diff --git a/lldb/source/Protocol/MCP/Server.cpp b/lldb/source/Protocol/MCP/Server.cpp
index 4ec127fe..0381b7f 100644
--- a/lldb/source/Protocol/MCP/Server.cpp
+++ b/lldb/source/Protocol/MCP/Server.cpp
@@ -8,12 +8,29 @@
#include "lldb/Protocol/MCP/Server.h"
#include "lldb/Protocol/MCP/MCPError.h"
+#include "lldb/Protocol/MCP/Protocol.h"
+#include "llvm/Support/JSON.h"
using namespace lldb_protocol::mcp;
using namespace llvm;
-Server::Server(std::string name, std::string version)
- : m_name(std::move(name)), m_version(std::move(version)) {
+llvm::json::Value lldb_protocol::mcp::toJSON(const ServerInfo &SM) {
+ return llvm::json::Object{{"connection_uri", SM.connection_uri},
+ {"pid", SM.pid}};
+}
+
+bool lldb_protocol::mcp::fromJSON(const llvm::json::Value &V, ServerInfo &SM,
+ llvm::json::Path P) {
+ llvm::json::ObjectMapper O(V, P);
+ return O && O.map("connection_uri", SM.connection_uri) &&
+ O.map("pid", SM.pid);
+}
+
+Server::Server(std::string name, std::string version,
+ std::unique_ptr<MCPTransport> transport_up,
+ lldb_private::MainLoop &loop)
+ : m_name(std::move(name)), m_version(std::move(version)),
+ m_transport_up(std::move(transport_up)), m_loop(loop) {
AddRequestHandlers();
}
@@ -30,7 +47,7 @@ void Server::AddRequestHandlers() {
this, std::placeholders::_1));
}
-llvm::Expected<Response> Server::Handle(Request request) {
+llvm::Expected<Response> Server::Handle(const Request &request) {
auto it = m_request_handlers.find(request.method);
if (it != m_request_handlers.end()) {
llvm::Expected<Response> response = it->second(request);
@@ -44,7 +61,7 @@ llvm::Expected<Response> Server::Handle(Request request) {
llvm::formatv("no handler for request: {0}", request.method).str());
}
-void Server::Handle(Notification notification) {
+void Server::Handle(const Notification &notification) {
auto it = m_notification_handlers.find(notification.method);
if (it != m_notification_handlers.end()) {
it->second(notification);
@@ -52,50 +69,7 @@ void Server::Handle(Notification notification) {
}
}
-llvm::Expected<std::optional<Message>>
-Server::HandleData(llvm::StringRef data) {
- auto message = llvm::json::parse<Message>(/*JSON=*/data);
- if (!message)
- return message.takeError();
-
- if (const Request *request = std::get_if<Request>(&(*message))) {
- llvm::Expected<Response> response = Handle(*request);
-
- // Handle failures by converting them into an Error message.
- if (!response) {
- Error protocol_error;
- llvm::handleAllErrors(
- response.takeError(),
- [&](const MCPError &err) { protocol_error = err.toProtcolError(); },
- [&](const llvm::ErrorInfoBase &err) {
- protocol_error.error.code = MCPError::kInternalError;
- protocol_error.error.message = err.message();
- });
- protocol_error.id = request->id;
- return protocol_error;
- }
-
- return *response;
- }
-
- if (const Notification *notification =
- std::get_if<Notification>(&(*message))) {
- Handle(*notification);
- return std::nullopt;
- }
-
- if (std::get_if<Error>(&(*message)))
- return llvm::createStringError("unexpected MCP message: error");
-
- if (std::get_if<Response>(&(*message)))
- return llvm::createStringError("unexpected MCP message: response");
-
- llvm_unreachable("all message types handled");
-}
-
void Server::AddTool(std::unique_ptr<Tool> tool) {
- std::lock_guard<std::mutex> guard(m_mutex);
-
if (!tool)
return;
m_tools[tool->GetName()] = std::move(tool);
@@ -103,42 +77,39 @@ void Server::AddTool(std::unique_ptr<Tool> tool) {
void Server::AddResourceProvider(
std::unique_ptr<ResourceProvider> resource_provider) {
- std::lock_guard<std::mutex> guard(m_mutex);
-
if (!resource_provider)
return;
m_resource_providers.push_back(std::move(resource_provider));
}
void Server::AddRequestHandler(llvm::StringRef method, RequestHandler handler) {
- std::lock_guard<std::mutex> guard(m_mutex);
m_request_handlers[method] = std::move(handler);
}
void Server::AddNotificationHandler(llvm::StringRef method,
NotificationHandler handler) {
- std::lock_guard<std::mutex> guard(m_mutex);
m_notification_handlers[method] = std::move(handler);
}
llvm::Expected<Response> Server::InitializeHandler(const Request &request) {
Response response;
- response.result.emplace(llvm::json::Object{
- {"protocolVersion", mcp::kProtocolVersion},
- {"capabilities", GetCapabilities()},
- {"serverInfo",
- llvm::json::Object{{"name", m_name}, {"version", m_version}}}});
+ InitializeResult result;
+ result.protocolVersion = mcp::kProtocolVersion;
+ result.capabilities = GetCapabilities();
+ result.serverInfo.name = m_name;
+ result.serverInfo.version = m_version;
+ response.result = std::move(result);
return response;
}
llvm::Expected<Response> Server::ToolsListHandler(const Request &request) {
Response response;
- llvm::json::Array tools;
+ ListToolsResult result;
for (const auto &tool : m_tools)
- tools.emplace_back(toJSON(tool.second->GetDefinition()));
+ result.tools.emplace_back(tool.second->GetDefinition());
- response.result.emplace(llvm::json::Object{{"tools", std::move(tools)}});
+ response.result = std::move(result);
return response;
}
@@ -148,16 +119,12 @@ llvm::Expected<Response> Server::ToolsCallHandler(const Request &request) {
if (!request.params)
return llvm::createStringError("no tool parameters");
+ CallToolParams params;
+ json::Path::Root root("params");
+ if (!fromJSON(request.params, params, root))
+ return root.getError();
- const json::Object *param_obj = request.params->getAsObject();
- if (!param_obj)
- return llvm::createStringError("no tool parameters");
-
- const json::Value *name = param_obj->get("name");
- if (!name)
- return llvm::createStringError("no tool name");
-
- llvm::StringRef tool_name = name->getAsString().value_or("");
+ llvm::StringRef tool_name = params.name;
if (tool_name.empty())
return llvm::createStringError("no tool name");
@@ -166,14 +133,14 @@ llvm::Expected<Response> Server::ToolsCallHandler(const Request &request) {
return llvm::createStringError(llvm::formatv("no tool \"{0}\"", tool_name));
ToolArguments tool_args;
- if (const json::Value *args = param_obj->get("arguments"))
- tool_args = *args;
+ if (params.arguments)
+ tool_args = *params.arguments;
- llvm::Expected<TextResult> text_result = it->second->Call(tool_args);
+ llvm::Expected<CallToolResult> text_result = it->second->Call(tool_args);
if (!text_result)
return text_result.takeError();
- response.result.emplace(toJSON(*text_result));
+ response.result = toJSON(*text_result);
return response;
}
@@ -181,16 +148,13 @@ llvm::Expected<Response> Server::ToolsCallHandler(const Request &request) {
llvm::Expected<Response> Server::ResourcesListHandler(const Request &request) {
Response response;
- llvm::json::Array resources;
-
- std::lock_guard<std::mutex> guard(m_mutex);
+ ListResourcesResult result;
for (std::unique_ptr<ResourceProvider> &resource_provider_up :
- m_resource_providers) {
+ m_resource_providers)
for (const Resource &resource : resource_provider_up->GetResources())
- resources.push_back(resource);
- }
- response.result.emplace(
- llvm::json::Object{{"resources", std::move(resources)}});
+ result.resources.push_back(resource);
+
+ response.result = std::move(result);
return response;
}
@@ -201,22 +165,18 @@ llvm::Expected<Response> Server::ResourcesReadHandler(const Request &request) {
if (!request.params)
return llvm::createStringError("no resource parameters");
- const json::Object *param_obj = request.params->getAsObject();
- if (!param_obj)
- return llvm::createStringError("no resource parameters");
-
- const json::Value *uri = param_obj->get("uri");
- if (!uri)
- return llvm::createStringError("no resource uri");
+ ReadResourceParams params;
+ json::Path::Root root("params");
+ if (!fromJSON(request.params, params, root))
+ return root.getError();
- llvm::StringRef uri_str = uri->getAsString().value_or("");
+ llvm::StringRef uri_str = params.uri;
if (uri_str.empty())
return llvm::createStringError("no resource uri");
- std::lock_guard<std::mutex> guard(m_mutex);
for (std::unique_ptr<ResourceProvider> &resource_provider_up :
m_resource_providers) {
- llvm::Expected<ResourceResult> result =
+ llvm::Expected<ReadResourceResult> result =
resource_provider_up->ReadResource(uri_str);
if (result.errorIsA<UnsupportedURI>()) {
llvm::consumeError(result.takeError());
@@ -226,7 +186,7 @@ llvm::Expected<Response> Server::ResourcesReadHandler(const Request &request) {
return result.takeError();
Response response;
- response.result.emplace(std::move(*result));
+ response.result = std::move(*result);
return response;
}
@@ -234,3 +194,71 @@ llvm::Expected<Response> Server::ResourcesReadHandler(const Request &request) {
llvm::formatv("no resource handler for uri: {0}", uri_str).str(),
MCPError::kResourceNotFound);
}
+
+ServerCapabilities Server::GetCapabilities() {
+ lldb_protocol::mcp::ServerCapabilities capabilities;
+ capabilities.supportsToolsList = true;
+ // FIXME: Support sending notifications when a debugger/target are
+ // added/removed.
+ capabilities.supportsResourcesList = false;
+ return capabilities;
+}
+
+llvm::Error Server::Run() {
+ auto handle = m_transport_up->RegisterMessageHandler(m_loop, *this);
+ if (!handle)
+ return handle.takeError();
+
+ lldb_private::Status status = m_loop.Run();
+ if (status.Fail())
+ return status.takeError();
+
+ return llvm::Error::success();
+}
+
+void Server::Received(const Request &request) {
+ auto SendResponse = [this](const Response &response) {
+ if (llvm::Error error = m_transport_up->Send(response))
+ m_transport_up->Log(llvm::toString(std::move(error)));
+ };
+
+ llvm::Expected<Response> response = Handle(request);
+ if (response)
+ return SendResponse(*response);
+
+ lldb_protocol::mcp::Error protocol_error;
+ llvm::handleAllErrors(
+ response.takeError(),
+ [&](const MCPError &err) { protocol_error = err.toProtocolError(); },
+ [&](const llvm::ErrorInfoBase &err) {
+ protocol_error.code = MCPError::kInternalError;
+ protocol_error.message = err.message();
+ });
+ Response error_response;
+ error_response.id = request.id;
+ error_response.result = std::move(protocol_error);
+ SendResponse(error_response);
+}
+
+void Server::Received(const Response &response) {
+ m_transport_up->Log("unexpected MCP message: response");
+}
+
+void Server::Received(const Notification &notification) {
+ Handle(notification);
+}
+
+void Server::OnError(llvm::Error error) {
+ m_transport_up->Log(llvm::toString(std::move(error)));
+ TerminateLoop();
+}
+
+void Server::OnClosed() {
+ m_transport_up->Log("EOF");
+ TerminateLoop();
+}
+
+void Server::TerminateLoop() {
+ m_loop.AddPendingCallback(
+ [](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
+}
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
index 21daf74..7efce2a 100644
--- a/lldb/source/Symbol/ObjectFile.cpp
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -379,6 +379,7 @@ AddressClass ObjectFile::GetAddressClass(addr_t file_addr) {
case eSectionTypeELFDynamicSymbols:
case eSectionTypeELFRelocationEntries:
case eSectionTypeELFDynamicLinkInfo:
+ case eSectionTypeWasmName:
case eSectionTypeOther:
return AddressClass::eUnknown;
case eSectionTypeAbsoluteAddress:
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index d6689a6..40497db 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -392,45 +392,8 @@ bool Symbol::Compare(ConstString name, SymbolType type) const {
return false;
}
-#define ENUM_TO_CSTRING(x) \
- case eSymbolType##x: \
- return #x;
-
const char *Symbol::GetTypeAsString() const {
- switch (m_type) {
- ENUM_TO_CSTRING(Invalid);
- ENUM_TO_CSTRING(Absolute);
- ENUM_TO_CSTRING(Code);
- ENUM_TO_CSTRING(Resolver);
- ENUM_TO_CSTRING(Data);
- ENUM_TO_CSTRING(Trampoline);
- ENUM_TO_CSTRING(Runtime);
- ENUM_TO_CSTRING(Exception);
- ENUM_TO_CSTRING(SourceFile);
- ENUM_TO_CSTRING(HeaderFile);
- ENUM_TO_CSTRING(ObjectFile);
- ENUM_TO_CSTRING(CommonBlock);
- ENUM_TO_CSTRING(Block);
- ENUM_TO_CSTRING(Local);
- ENUM_TO_CSTRING(Param);
- ENUM_TO_CSTRING(Variable);
- ENUM_TO_CSTRING(VariableType);
- ENUM_TO_CSTRING(LineEntry);
- ENUM_TO_CSTRING(LineHeader);
- ENUM_TO_CSTRING(ScopeBegin);
- ENUM_TO_CSTRING(ScopeEnd);
- ENUM_TO_CSTRING(Additional);
- ENUM_TO_CSTRING(Compiler);
- ENUM_TO_CSTRING(Instrumentation);
- ENUM_TO_CSTRING(Undefined);
- ENUM_TO_CSTRING(ObjCClass);
- ENUM_TO_CSTRING(ObjCMetaClass);
- ENUM_TO_CSTRING(ObjCIVar);
- ENUM_TO_CSTRING(ReExported);
- default:
- break;
- }
- return "<unknown SymbolType>";
+ return GetTypeAsString(static_cast<lldb::SymbolType>(m_type));
}
void Symbol::CalculateSymbolContext(SymbolContext *sc) {
@@ -774,6 +737,79 @@ bool Symbol::operator==(const Symbol &rhs) const {
return true;
}
+#define ENUM_TO_CSTRING(x) \
+ case eSymbolType##x: \
+ return #x;
+
+const char *Symbol::GetTypeAsString(lldb::SymbolType symbol_type) {
+ switch (symbol_type) {
+ ENUM_TO_CSTRING(Invalid);
+ ENUM_TO_CSTRING(Absolute);
+ ENUM_TO_CSTRING(Code);
+ ENUM_TO_CSTRING(Resolver);
+ ENUM_TO_CSTRING(Data);
+ ENUM_TO_CSTRING(Trampoline);
+ ENUM_TO_CSTRING(Runtime);
+ ENUM_TO_CSTRING(Exception);
+ ENUM_TO_CSTRING(SourceFile);
+ ENUM_TO_CSTRING(HeaderFile);
+ ENUM_TO_CSTRING(ObjectFile);
+ ENUM_TO_CSTRING(CommonBlock);
+ ENUM_TO_CSTRING(Block);
+ ENUM_TO_CSTRING(Local);
+ ENUM_TO_CSTRING(Param);
+ ENUM_TO_CSTRING(Variable);
+ ENUM_TO_CSTRING(VariableType);
+ ENUM_TO_CSTRING(LineEntry);
+ ENUM_TO_CSTRING(LineHeader);
+ ENUM_TO_CSTRING(ScopeBegin);
+ ENUM_TO_CSTRING(ScopeEnd);
+ ENUM_TO_CSTRING(Additional);
+ ENUM_TO_CSTRING(Compiler);
+ ENUM_TO_CSTRING(Instrumentation);
+ ENUM_TO_CSTRING(Undefined);
+ ENUM_TO_CSTRING(ObjCClass);
+ ENUM_TO_CSTRING(ObjCMetaClass);
+ ENUM_TO_CSTRING(ObjCIVar);
+ ENUM_TO_CSTRING(ReExported);
+ }
+ return "<unknown SymbolType>";
+}
+
+lldb::SymbolType Symbol::GetTypeFromString(const char *str) {
+ std::string str_lower = llvm::StringRef(str).lower();
+ return llvm::StringSwitch<lldb::SymbolType>(str_lower)
+ .Case("absolute", eSymbolTypeAbsolute)
+ .Case("code", eSymbolTypeCode)
+ .Case("resolver", eSymbolTypeResolver)
+ .Case("data", eSymbolTypeData)
+ .Case("trampoline", eSymbolTypeTrampoline)
+ .Case("runtime", eSymbolTypeRuntime)
+ .Case("exception", eSymbolTypeException)
+ .Case("sourcefile", eSymbolTypeSourceFile)
+ .Case("headerfile", eSymbolTypeHeaderFile)
+ .Case("objectfile", eSymbolTypeObjectFile)
+ .Case("commonblock", eSymbolTypeCommonBlock)
+ .Case("block", eSymbolTypeBlock)
+ .Case("local", eSymbolTypeLocal)
+ .Case("param", eSymbolTypeParam)
+ .Case("variable", eSymbolTypeVariable)
+ .Case("variableType", eSymbolTypeVariableType)
+ .Case("lineentry", eSymbolTypeLineEntry)
+ .Case("lineheader", eSymbolTypeLineHeader)
+ .Case("scopebegin", eSymbolTypeScopeBegin)
+ .Case("scopeend", eSymbolTypeScopeEnd)
+ .Case("additional,", eSymbolTypeAdditional)
+ .Case("compiler", eSymbolTypeCompiler)
+ .Case("instrumentation", eSymbolTypeInstrumentation)
+ .Case("undefined", eSymbolTypeUndefined)
+ .Case("objcclass", eSymbolTypeObjCClass)
+ .Case("objcmetaclass", eSymbolTypeObjCMetaClass)
+ .Case("objcivar", eSymbolTypeObjCIVar)
+ .Case("reexported", eSymbolTypeReExported)
+ .Default(eSymbolTypeInvalid);
+}
+
namespace llvm {
namespace json {
@@ -804,36 +840,8 @@ bool fromJSON(const llvm::json::Value &value, lldb_private::JSONSymbol &symbol,
bool fromJSON(const llvm::json::Value &value, lldb::SymbolType &type,
llvm::json::Path path) {
if (auto str = value.getAsString()) {
- type = llvm::StringSwitch<lldb::SymbolType>(*str)
- .Case("absolute", eSymbolTypeAbsolute)
- .Case("code", eSymbolTypeCode)
- .Case("resolver", eSymbolTypeResolver)
- .Case("data", eSymbolTypeData)
- .Case("trampoline", eSymbolTypeTrampoline)
- .Case("runtime", eSymbolTypeRuntime)
- .Case("exception", eSymbolTypeException)
- .Case("sourcefile", eSymbolTypeSourceFile)
- .Case("headerfile", eSymbolTypeHeaderFile)
- .Case("objectfile", eSymbolTypeObjectFile)
- .Case("commonblock", eSymbolTypeCommonBlock)
- .Case("block", eSymbolTypeBlock)
- .Case("local", eSymbolTypeLocal)
- .Case("param", eSymbolTypeParam)
- .Case("variable", eSymbolTypeVariable)
- .Case("variableType", eSymbolTypeVariableType)
- .Case("lineentry", eSymbolTypeLineEntry)
- .Case("lineheader", eSymbolTypeLineHeader)
- .Case("scopebegin", eSymbolTypeScopeBegin)
- .Case("scopeend", eSymbolTypeScopeEnd)
- .Case("additional,", eSymbolTypeAdditional)
- .Case("compiler", eSymbolTypeCompiler)
- .Case("instrumentation", eSymbolTypeInstrumentation)
- .Case("undefined", eSymbolTypeUndefined)
- .Case("objcclass", eSymbolTypeObjCClass)
- .Case("objcmetaClass", eSymbolTypeObjCMetaClass)
- .Case("objcivar", eSymbolTypeObjCIVar)
- .Case("reexporte", eSymbolTypeReExported)
- .Default(eSymbolTypeInvalid);
+ llvm::StringRef str_ref = str.value_or("");
+ type = Symbol::GetTypeFromString(str_ref.data());
if (type == eSymbolTypeInvalid) {
path.report("invalid symbol type");
diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp
index 3f54ea5..9d232e4 100644
--- a/lldb/source/Target/ExecutionContext.cpp
+++ b/lldb/source/Target/ExecutionContext.cpp
@@ -12,7 +12,9 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/State.h"
+#include <mutex>
using namespace lldb_private;
@@ -125,19 +127,47 @@ ExecutionContext::ExecutionContext(const ExecutionContextRef *exe_ctx_ref_ptr,
}
}
-ExecutionContext::ExecutionContext(const ExecutionContextRef *exe_ctx_ref_ptr,
- std::unique_lock<std::recursive_mutex> &lock)
- : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() {
- if (exe_ctx_ref_ptr) {
- m_target_sp = exe_ctx_ref_ptr->GetTargetSP();
- if (m_target_sp) {
- lock = std::unique_lock<std::recursive_mutex>(m_target_sp->GetAPIMutex());
+llvm::Expected<StoppedExecutionContext>
+lldb_private::GetStoppedExecutionContext(
+ const lldb::ExecutionContextRefSP &exe_ctx_ref_ptr) {
+ return GetStoppedExecutionContext(exe_ctx_ref_ptr.get());
+}
- m_process_sp = exe_ctx_ref_ptr->GetProcessSP();
- m_thread_sp = exe_ctx_ref_ptr->GetThreadSP();
- m_frame_sp = exe_ctx_ref_ptr->GetFrameSP();
- }
- }
+llvm::Expected<StoppedExecutionContext>
+lldb_private::GetStoppedExecutionContext(
+ const ExecutionContextRef *exe_ctx_ref_ptr) {
+ if (!exe_ctx_ref_ptr)
+ return llvm::createStringError(
+ "StoppedExecutionContext created with an empty ExecutionContextRef");
+
+ lldb::TargetSP target_sp = exe_ctx_ref_ptr->GetTargetSP();
+ if (!target_sp)
+ return llvm::createStringError(
+ "StoppedExecutionContext created with a null target");
+
+ auto api_lock =
+ std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
+
+ auto process_sp = exe_ctx_ref_ptr->GetProcessSP();
+ if (!process_sp)
+ return llvm::createStringError(
+ "StoppedExecutionContext created with a null process");
+
+ ProcessRunLock::ProcessRunLocker stop_locker;
+ if (!stop_locker.TryLock(&process_sp->GetRunLock()))
+ return llvm::createStringError(
+ "attempted to create a StoppedExecutionContext with a running process");
+
+ auto thread_sp = exe_ctx_ref_ptr->GetThreadSP();
+ auto frame_sp = exe_ctx_ref_ptr->GetFrameSP();
+ return StoppedExecutionContext(target_sp, process_sp, thread_sp, frame_sp,
+ std::move(api_lock), std::move(stop_locker));
+}
+
+std::unique_lock<std::recursive_mutex> StoppedExecutionContext::AllowResume() {
+ Clear();
+ m_stop_locker = ProcessRunLock::ProcessRunLocker();
+ return std::move(m_api_lock);
}
ExecutionContext::ExecutionContext(ExecutionContextScope *exe_scope_ptr)
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 9e9e2d8..bcf1297 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -2026,7 +2026,6 @@ bool RegisterContextUnwind::ReadFrameAddress(
"Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64,
cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
cfa_reg_contents);
- cfa_reg_contents = LLDB_INVALID_ADDRESS;
return false;
}
address = cfa_reg_contents + fa.GetOffset();
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index d97a814..f27004c 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -61,8 +61,9 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
const SymbolContext *sc_ptr)
: m_thread_wp(thread_sp), m_frame_index(frame_idx),
m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(),
- m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(),
- m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
+ m_id(pc, cfa, nullptr, thread_sp->GetProcess().get()),
+ m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
+ m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
m_stack_frame_kind(kind),
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
m_variable_list_sp(), m_variable_list_value_objects(),
@@ -71,7 +72,7 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
// recursive functions properly aren't confused with one another on a history
// stack.
if (IsHistorical() && !m_cfa_is_valid) {
- m_id.SetCFA(m_frame_index);
+ m_id.SetCFA(m_frame_index, thread_sp->GetProcess().get());
}
if (sc_ptr != nullptr) {
@@ -87,7 +88,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
const SymbolContext *sc_ptr)
: m_thread_wp(thread_sp), m_frame_index(frame_idx),
m_concrete_frame_index(unwind_frame_index),
- m_reg_context_sp(reg_context_sp), m_id(pc, cfa, nullptr),
+ m_reg_context_sp(reg_context_sp),
+ m_id(pc, cfa, nullptr, thread_sp->GetProcess().get()),
m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
m_frame_base_error(), m_cfa_is_valid(true),
m_stack_frame_kind(StackFrame::Kind::Regular),
@@ -115,7 +117,7 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
m_concrete_frame_index(unwind_frame_index),
m_reg_context_sp(reg_context_sp),
m_id(pc_addr.GetLoadAddress(thread_sp->CalculateTarget().get()), cfa,
- nullptr),
+ nullptr, thread_sp->GetProcess().get()),
m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
m_frame_base_error(), m_cfa_is_valid(true),
m_stack_frame_kind(StackFrame::Kind::Regular),
@@ -264,6 +266,7 @@ bool StackFrame::ChangePC(addr_t pc) {
const char *StackFrame::Disassemble() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
if (!m_disassembly.Empty())
return m_disassembly.GetData();
@@ -438,10 +441,10 @@ VariableList *StackFrame::GetVariableList(bool get_file_globals,
const bool get_child_variables = true;
const bool can_create = true;
const bool stop_if_child_block_is_inlined_function = true;
- frame_block->AppendBlockVariables(can_create, get_child_variables,
- stop_if_child_block_is_inlined_function,
- [](Variable *v) { return true; },
- m_variable_list_sp.get());
+ frame_block->AppendBlockVariables(
+ can_create, get_child_variables,
+ stop_if_child_block_is_inlined_function,
+ [](Variable *v) { return true; }, m_variable_list_sp.get());
}
}
@@ -1225,10 +1228,12 @@ StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp,
VariableList *var_list = GetVariableList(true, nullptr);
if (var_list) {
// Make sure the variable is a frame variable
- const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get());
+ const uint32_t var_idx =
+ var_list->FindIndexForVariable(variable_sp.get());
const uint32_t num_variables = var_list->GetSize();
if (var_idx < num_variables) {
- valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
+ valobj_sp =
+ m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
if (!valobj_sp) {
if (m_variable_list_value_objects.GetSize() < num_variables)
m_variable_list_value_objects.Resize(num_variables);
@@ -1762,11 +1767,9 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
if (clobbered_reg_matcher(operands[0])) {
origin_operand = &operands[1];
- }
- else if (clobbered_reg_matcher(operands[1])) {
+ } else if (clobbered_reg_matcher(operands[1])) {
origin_operand = &operands[0];
- }
- else {
+ } else {
continue;
}
@@ -1792,8 +1795,7 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
if (!source_path) {
continue;
}
- source_path =
- GetValueForDereferincingOffset(frame, source_path, offset);
+ source_path = GetValueForDereferincingOffset(frame, source_path, offset);
}
if (source_path) {
@@ -1803,7 +1805,7 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
return ValueObjectSP();
}
-}
+} // namespace
lldb::ValueObjectSP StackFrame::GuessValueForRegisterAndOffset(ConstString reg,
int64_t offset) {
@@ -1995,7 +1997,9 @@ void StackFrame::UpdatePreviousFrameFromCurrentFrame(StackFrame &curr_frame) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
assert(GetStackID() ==
curr_frame.GetStackID()); // TODO: remove this after some testing
- m_id.SetPC(curr_frame.m_id.GetPC()); // Update the Stack ID PC value
+ m_id.SetPC(
+ curr_frame.m_id.GetPC(),
+ curr_frame.CalculateProcess().get()); // Update the Stack ID PC value
assert(GetThread() == curr_frame.GetThread());
m_frame_index = curr_frame.m_frame_index;
m_concrete_frame_index = curr_frame.m_concrete_frame_index;
diff --git a/lldb/source/Target/StackID.cpp b/lldb/source/Target/StackID.cpp
index 410d5b7..b179597 100644
--- a/lldb/source/Target/StackID.cpp
+++ b/lldb/source/Target/StackID.cpp
@@ -10,10 +10,28 @@
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Process.h"
#include "lldb/Utility/Stream.h"
using namespace lldb_private;
+StackID::StackID(lldb::addr_t pc, lldb::addr_t cfa,
+ SymbolContextScope *symbol_scope, Process *process)
+ : m_pc(pc), m_cfa(cfa), m_symbol_scope(symbol_scope) {
+ if (process) {
+ m_pc = process->FixCodeAddress(m_pc);
+ m_cfa = process->FixDataAddress(m_cfa);
+ }
+}
+
+void StackID::SetPC(lldb::addr_t pc, Process *process) {
+ m_pc = process ? process->FixCodeAddress(pc) : pc;
+}
+
+void StackID::SetCFA(lldb::addr_t cfa, Process *process) {
+ m_cfa = process ? process->FixDataAddress(cfa) : cfa;
+}
+
void StackID::Dump(Stream *s) {
s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64
", symbol_scope = %p",
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 4f39f60..fa98c24 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -558,10 +558,11 @@ BreakpointSP Target::CreateBreakpoint(lldb::addr_t addr, bool internal,
BreakpointSP Target::CreateBreakpoint(const Address &addr, bool internal,
bool hardware) {
- SearchFilterSP filter_sp(
- new SearchFilterForUnconstrainedSearches(shared_from_this()));
- BreakpointResolverSP resolver_sp(
- new BreakpointResolverAddress(nullptr, addr));
+ SearchFilterSP filter_sp =
+ std::make_shared<SearchFilterForUnconstrainedSearches>(
+ shared_from_this());
+ BreakpointResolverSP resolver_sp =
+ std::make_shared<BreakpointResolverAddress>(nullptr, addr);
return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, false);
}
@@ -569,10 +570,12 @@ lldb::BreakpointSP
Target::CreateAddressInModuleBreakpoint(lldb::addr_t file_addr, bool internal,
const FileSpec &file_spec,
bool request_hardware) {
- SearchFilterSP filter_sp(
- new SearchFilterForUnconstrainedSearches(shared_from_this()));
- BreakpointResolverSP resolver_sp(new BreakpointResolverAddress(
- nullptr, file_addr, file_spec));
+ SearchFilterSP filter_sp =
+ std::make_shared<SearchFilterForUnconstrainedSearches>(
+ shared_from_this());
+ BreakpointResolverSP resolver_sp =
+ std::make_shared<BreakpointResolverAddress>(nullptr, file_addr,
+ file_spec);
return CreateBreakpoint(filter_sp, resolver_sp, internal, request_hardware,
false);
}
@@ -581,7 +584,8 @@ BreakpointSP Target::CreateBreakpoint(
const FileSpecList *containingModules,
const FileSpecList *containingSourceFiles, const char *func_name,
FunctionNameType func_name_type_mask, LanguageType language,
- lldb::addr_t offset, LazyBool skip_prologue, bool internal, bool hardware) {
+ lldb::addr_t offset, bool offset_is_insn_count, LazyBool skip_prologue,
+ bool internal, bool hardware) {
BreakpointSP bp_sp;
if (func_name) {
SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList(
@@ -594,7 +598,7 @@ BreakpointSP Target::CreateBreakpoint(
BreakpointResolverSP resolver_sp(new BreakpointResolverName(
nullptr, func_name, func_name_type_mask, language, Breakpoint::Exact,
- offset, skip_prologue));
+ offset, offset_is_insn_count, skip_prologue));
bp_sp = CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true);
}
return bp_sp;
@@ -2996,6 +3000,38 @@ lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) {
return arch_plugin ? arch_plugin->GetBreakableLoadAddress(addr, *this) : addr;
}
+llvm::Expected<lldb::DisassemblerSP>
+Target::ReadInstructions(const Address &start_addr, uint32_t count,
+ const char *flavor_string) {
+ DataBufferHeap data(GetArchitecture().GetMaximumOpcodeByteSize() * count, 0);
+ bool force_live_memory = true;
+ lldb_private::Status error;
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ const size_t bytes_read =
+ ReadMemory(start_addr, data.GetBytes(), data.GetByteSize(), error,
+ force_live_memory, &load_addr);
+
+ if (error.Fail())
+ return llvm::createStringError(
+ error.AsCString("Target::ReadInstructions failed to read memory at %s"),
+ start_addr.GetLoadAddress(this));
+
+ const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
+ if (!flavor_string || flavor_string[0] == '\0') {
+ // FIXME - we don't have the mechanism in place to do per-architecture
+ // settings. But since we know that for now we only support flavors on
+ // x86 & x86_64,
+ const llvm::Triple::ArchType arch = GetArchitecture().GetTriple().getArch();
+ if (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64)
+ flavor_string = GetDisassemblyFlavor();
+ }
+
+ return Disassembler::DisassembleBytes(
+ GetArchitecture(), nullptr, flavor_string, GetDisassemblyCPU(),
+ GetDisassemblyFeatures(), start_addr, data.GetBytes(), bytes_read, count,
+ data_from_file);
+}
+
SourceManager &Target::GetSourceManager() {
if (!m_source_manager_up)
m_source_manager_up = std::make_unique<SourceManager>(shared_from_this());
diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp
index 7c71aaa..8f14cf6 100644
--- a/lldb/source/Utility/ArchSpec.cpp
+++ b/lldb/source/Utility/ArchSpec.cpp
@@ -1439,6 +1439,10 @@ bool lldb_private::operator==(const ArchSpec &lhs, const ArchSpec &rhs) {
return lhs.GetCore() == rhs.GetCore();
}
+bool lldb_private::operator!=(const ArchSpec &lhs, const ArchSpec &rhs) {
+ return !(lhs == rhs);
+}
+
bool ArchSpec::IsFullySpecifiedTriple() const {
if (!TripleOSWasSpecified())
return false;
diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp
index eb2047e..2040791 100644
--- a/lldb/source/Utility/XcodeSDK.cpp
+++ b/lldb/source/Utility/XcodeSDK.cpp
@@ -243,29 +243,6 @@ bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
return false;
}
-bool XcodeSDK::SupportsSwift() const {
- XcodeSDK::Info info = Parse();
- switch (info.type) {
- case Type::MacOSX:
- return info.version.empty() || info.version >= llvm::VersionTuple(10, 10);
- case Type::iPhoneOS:
- case Type::iPhoneSimulator:
- return info.version.empty() || info.version >= llvm::VersionTuple(8);
- case Type::AppleTVSimulator:
- case Type::AppleTVOS:
- return info.version.empty() || info.version >= llvm::VersionTuple(9);
- case Type::WatchSimulator:
- case Type::watchOS:
- return info.version.empty() || info.version >= llvm::VersionTuple(2);
- case Type::XROS:
- case Type::XRSimulator:
- case Type::Linux:
- return true;
- default:
- return false;
- }
-}
-
bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
const FileSpec &sdk_path) {
ConstString last_path_component = sdk_path.GetFilename();
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index b1cd824..7056466 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -37,4 +37,13 @@ BitFieldExtractionNode::Accept(Visitor *v) const {
return v->Visit(this);
}
+llvm::Expected<lldb::ValueObjectSP>
+IntegerLiteralNode::Accept(Visitor *v) const {
+ return v->Visit(this);
+}
+
+llvm::Expected<lldb::ValueObjectSP> FloatLiteralNode::Accept(Visitor *v) const {
+ return v->Visit(this);
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 6f28434..c6cf41e 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "lldb/ValueObject/DILEval.h"
+#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/ValueObject/DILAST.h"
@@ -330,40 +332,135 @@ Interpreter::Visit(const ArraySubscriptNode *node) {
return lhs_or_err;
lldb::ValueObjectSP base = *lhs_or_err;
- // Check to see if 'base' has a synthetic value; if so, try using that.
+ StreamString var_expr_path_strm;
uint64_t child_idx = node->GetIndex();
- if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue()) {
- llvm::Expected<uint32_t> num_children =
- synthetic->GetNumChildren(child_idx + 1);
- if (!num_children)
- return llvm::make_error<DILDiagnosticError>(
- m_expr, toString(num_children.takeError()), node->GetLocation());
- if (child_idx >= *num_children) {
- std::string message = llvm::formatv(
- "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ lldb::ValueObjectSP child_valobj_sp;
+
+ bool is_incomplete_array = false;
+ CompilerType base_type = base->GetCompilerType().GetNonReferenceType();
+ base->GetExpressionPath(var_expr_path_strm);
+
+ if (base_type.IsPointerType()) {
+ bool is_objc_pointer = true;
+
+ if (base->GetCompilerType().GetMinimumLanguage() != lldb::eLanguageTypeObjC)
+ is_objc_pointer = false;
+ else if (!base->GetCompilerType().IsPointerType())
+ is_objc_pointer = false;
+
+ if (!m_use_synthetic && is_objc_pointer) {
+ std::string err_msg = llvm::formatv(
+ "\"({0}) {1}\" is an Objective-C pointer, and cannot be subscripted",
base->GetTypeName().AsCString("<invalid type>"),
- base->GetName().AsCString());
- return llvm::make_error<DILDiagnosticError>(m_expr, message,
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
node->GetLocation());
}
- if (lldb::ValueObjectSP child_valobj_sp =
- synthetic->GetChildAtIndex(child_idx))
+ if (is_objc_pointer) {
+ lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
+ if (!synthetic || synthetic == base) {
+ std::string err_msg =
+ llvm::formatv("\"({0}) {1}\" is not an array type",
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ if (static_cast<uint32_t>(child_idx) >=
+ synthetic->GetNumChildrenIgnoringErrors()) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ if (m_use_dynamic != lldb::eNoDynamicValues) {
+ if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic))
+ child_valobj_sp = std::move(dynamic_sp);
+ }
return child_valobj_sp;
- }
+ }
- auto base_type = base->GetCompilerType().GetNonReferenceType();
- if (!base_type.IsPointerType() && !base_type.IsArrayType())
- return llvm::make_error<DILDiagnosticError>(
- m_expr, "subscripted value is not an array or pointer",
- node->GetLocation());
- if (base_type.IsPointerToVoid())
- return llvm::make_error<DILDiagnosticError>(
- m_expr, "subscript of pointer to incomplete type 'void'",
- node->GetLocation());
+ child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "failed to use pointer as array for index {0} for "
+ "\"({1}) {2}\"",
+ child_idx, base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ if (base_type.IsPointerToVoid())
+ err_msg = "subscript of pointer to incomplete type 'void'";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ } else if (base_type.IsArrayType(nullptr, nullptr, &is_incomplete_array)) {
+ child_valobj_sp = base->GetChildAtIndex(child_idx);
+ if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic))
+ child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ } else if (base_type.IsScalarType()) {
+ child_valobj_sp =
+ base->GetSyntheticBitFieldChild(child_idx, child_idx, true);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "bitfield range {0}-{1} is not valid for \"({2}) {3}\"", child_idx,
+ child_idx, base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation(), 1);
+ }
+ } else {
+ lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
+ if (!m_use_synthetic || !synthetic || synthetic == base) {
+ std::string err_msg =
+ llvm::formatv("\"{0}\" is not an array type",
+ base->GetTypeName().AsCString("<invalid type>"));
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation(), 1);
+ }
+ if (static_cast<uint32_t>(child_idx) >=
+ synthetic->GetNumChildrenIgnoringErrors(child_idx + 1)) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation(), 1);
+ }
+ child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation(), 1);
+ }
+ }
- if (base_type.IsArrayType()) {
- if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(child_idx))
- return child_valobj_sp;
+ if (child_valobj_sp) {
+ if (m_use_dynamic != lldb::eNoDynamicValues) {
+ if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic))
+ child_valobj_sp = std::move(dynamic_sp);
+ }
+ return child_valobj_sp;
}
int64_t signed_child_idx = node->GetIndex();
@@ -402,4 +499,107 @@ Interpreter::Visit(const BitFieldExtractionNode *node) {
return child_valobj_sp;
}
+static llvm::Expected<lldb::TypeSystemSP>
+GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
+ SymbolContext symbol_context =
+ ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
+ lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
+
+ symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule);
+ return symbol_context.module_sp->GetTypeSystemForLanguage(language);
+}
+
+static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
+ lldb::BasicType basic_type) {
+ if (type_system)
+ return type_system.get()->GetBasicTypeFromAST(basic_type);
+
+ return CompilerType();
+}
+
+llvm::Expected<CompilerType>
+Interpreter::PickIntegerType(lldb::TypeSystemSP type_system,
+ std::shared_ptr<ExecutionContextScope> ctx,
+ const IntegerLiteralNode *literal) {
+ // Binary, Octal, Hexadecimal and literals with a U suffix are allowed to be
+ // an unsigned integer.
+ bool unsigned_is_allowed = literal->IsUnsigned() || literal->GetRadix() != 10;
+ llvm::APInt apint = literal->GetValue();
+
+ llvm::SmallVector<std::pair<lldb::BasicType, lldb::BasicType>, 3> candidates;
+ if (literal->GetTypeSuffix() <= IntegerTypeSuffix::None)
+ candidates.emplace_back(lldb::eBasicTypeInt,
+ unsigned_is_allowed ? lldb::eBasicTypeUnsignedInt
+ : lldb::eBasicTypeInvalid);
+ if (literal->GetTypeSuffix() <= IntegerTypeSuffix::Long)
+ candidates.emplace_back(lldb::eBasicTypeLong,
+ unsigned_is_allowed ? lldb::eBasicTypeUnsignedLong
+ : lldb::eBasicTypeInvalid);
+ candidates.emplace_back(lldb::eBasicTypeLongLong,
+ lldb::eBasicTypeUnsignedLongLong);
+ for (auto [signed_, unsigned_] : candidates) {
+ CompilerType signed_type = type_system->GetBasicTypeFromAST(signed_);
+ if (!signed_type)
+ continue;
+ llvm::Expected<uint64_t> size = signed_type.GetBitSize(ctx.get());
+ if (!size)
+ return size.takeError();
+ if (!literal->IsUnsigned() && apint.isIntN(*size - 1))
+ return signed_type;
+ if (unsigned_ != lldb::eBasicTypeInvalid && apint.isIntN(*size))
+ return type_system->GetBasicTypeFromAST(unsigned_);
+ }
+
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr,
+ "integer literal is too large to be represented in any integer type",
+ literal->GetLocation());
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const IntegerLiteralNode *node) {
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_exe_ctx_scope);
+ if (!type_system)
+ return type_system.takeError();
+
+ llvm::Expected<CompilerType> type =
+ PickIntegerType(*type_system, m_exe_ctx_scope, node);
+ if (!type)
+ return type.takeError();
+
+ Scalar scalar = node->GetValue();
+ // APInt from StringRef::getAsInteger comes with just enough bitwidth to
+ // hold the value. This adjusts APInt bitwidth to match the compiler type.
+ llvm::Expected<uint64_t> type_bitsize =
+ type->GetBitSize(m_exe_ctx_scope.get());
+ if (!type_bitsize)
+ return type_bitsize.takeError();
+ scalar.TruncOrExtendTo(*type_bitsize, false);
+ return ValueObject::CreateValueObjectFromScalar(m_target, scalar, *type,
+ "result");
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const FloatLiteralNode *node) {
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_exe_ctx_scope);
+ if (!type_system)
+ return type_system.takeError();
+
+ bool isFloat =
+ &node->GetValue().getSemantics() == &llvm::APFloat::IEEEsingle();
+ lldb::BasicType basic_type =
+ isFloat ? lldb::eBasicTypeFloat : lldb::eBasicTypeDouble;
+ CompilerType type = GetBasicType(*type_system, basic_type);
+
+ if (!type)
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "unable to create a const literal", node->GetLocation());
+
+ Scalar scalar = node->GetValue();
+ return ValueObject::CreateValueObjectFromScalar(m_target, scalar, type,
+ "result");
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
index eaefaf4..0b2288a 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -28,18 +28,23 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "coloncolon";
case Kind::eof:
return "eof";
+ case Kind::float_constant:
+ return "float_constant";
case Kind::identifier:
return "identifier";
+ case Kind::integer_constant:
+ return "integer_constant";
case Kind::l_paren:
return "l_paren";
case Kind::l_square:
return "l_square";
case Kind::minus:
return "minus";
- case Kind::numeric_constant:
- return "numeric_constant";
case Kind::period:
return "period";
+ return "l_square";
+ case Kind::plus:
+ return "plus";
case Kind::r_paren:
return "r_paren";
case Kind::r_square:
@@ -70,13 +75,32 @@ static std::optional<llvm::StringRef> IsWord(llvm::StringRef expr,
return candidate;
}
-static bool IsNumberBodyChar(char ch) { return IsDigit(ch) || IsLetter(ch); }
+static bool IsNumberBodyChar(char ch) {
+ return IsDigit(ch) || IsLetter(ch) || ch == '.';
+}
-static std::optional<llvm::StringRef> IsNumber(llvm::StringRef expr,
- llvm::StringRef &remainder) {
- if (IsDigit(remainder[0])) {
- llvm::StringRef number = remainder.take_while(IsNumberBodyChar);
- remainder = remainder.drop_front(number.size());
+static std::optional<llvm::StringRef> IsNumber(llvm::StringRef &remainder,
+ bool &isFloat) {
+ llvm::StringRef tail = remainder;
+ llvm::StringRef body = tail.take_while(IsNumberBodyChar);
+ size_t dots = body.count('.');
+ if (dots > 1 || dots == body.size())
+ return std::nullopt;
+ if (IsDigit(body.front()) || (body[0] == '.' && IsDigit(body[1]))) {
+ isFloat = dots == 1;
+ tail = tail.drop_front(body.size());
+ bool isHex = body.contains_insensitive('x');
+ bool hasExp = !isHex && body.contains_insensitive('e');
+ bool hasHexExp = isHex && body.contains_insensitive('p');
+ if (hasExp || hasHexExp) {
+ isFloat = true; // This marks numbers like 0x1p1 and 1e1 as float
+ if (body.ends_with_insensitive("e") || body.ends_with_insensitive("p"))
+ if (tail.consume_front("+") || tail.consume_front("-"))
+ tail = tail.drop_while(IsNumberBodyChar);
+ }
+ size_t number_length = remainder.size() - tail.size();
+ llvm::StringRef number = remainder.take_front(number_length);
+ remainder = remainder.drop_front(number_length);
return number;
}
return std::nullopt;
@@ -106,18 +130,21 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
return Token(Token::eof, "", (uint32_t)expr.size());
uint32_t position = cur_pos - expr.begin();
- std::optional<llvm::StringRef> maybe_number = IsNumber(expr, remainder);
- if (maybe_number)
- return Token(Token::numeric_constant, maybe_number->str(), position);
+ bool isFloat = false;
+ std::optional<llvm::StringRef> maybe_number = IsNumber(remainder, isFloat);
+ if (maybe_number) {
+ auto kind = isFloat ? Token::float_constant : Token::integer_constant;
+ return Token(kind, maybe_number->str(), position);
+ }
std::optional<llvm::StringRef> maybe_word = IsWord(expr, remainder);
if (maybe_word)
return Token(Token::identifier, maybe_word->str(), position);
constexpr std::pair<Token::Kind, const char *> operators[] = {
- {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
- {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
- {Token::period, "."}, {Token::r_paren, ")"}, {Token::r_square, "]"},
- {Token::star, "*"},
+ {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
+ {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
+ {Token::period, "."}, {Token::plus, "+"}, {Token::r_paren, ")"},
+ {Token::r_square, "]"}, {Token::star, "*"},
};
for (auto [kind, str] : operators) {
if (remainder.consume_front(str))
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index eac41fa..8c4f7fd 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -179,10 +179,13 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
// Parse a primary_expression.
//
// primary_expression:
+// numeric_literal
// id_expression
// "(" expression ")"
//
ASTNodeUP DILParser::ParsePrimaryExpression() {
+ if (CurToken().IsOneOf({Token::integer_constant, Token::float_constant}))
+ return ParseNumericLiteral();
if (CurToken().IsOneOf(
{Token::coloncolon, Token::identifier, Token::l_paren})) {
// Save the source location for the diagnostics message.
@@ -346,6 +349,7 @@ void DILParser::BailOut(const std::string &error, uint32_t loc,
m_dil_lexer.ResetTokenIdx(m_dil_lexer.NumLexedTokens() - 1);
}
+// FIXME: Remove this once subscript operator uses ScalarLiteralNode.
// Parse a integer_literal.
//
// integer_literal:
@@ -370,6 +374,69 @@ std::optional<int64_t> DILParser::ParseIntegerConstant() {
return std::nullopt;
}
+// Parse a numeric_literal.
+//
+// numeric_literal:
+// ? Token::integer_constant ?
+// ? Token::floating_constant ?
+//
+ASTNodeUP DILParser::ParseNumericLiteral() {
+ ASTNodeUP numeric_constant;
+ if (CurToken().Is(Token::integer_constant))
+ numeric_constant = ParseIntegerLiteral();
+ else
+ numeric_constant = ParseFloatingPointLiteral();
+ if (!numeric_constant) {
+ BailOut(llvm::formatv("Failed to parse token as numeric-constant: {0}",
+ CurToken()),
+ CurToken().GetLocation(), CurToken().GetSpelling().length());
+ return std::make_unique<ErrorNode>();
+ }
+ m_dil_lexer.Advance();
+ return numeric_constant;
+}
+
+ASTNodeUP DILParser::ParseIntegerLiteral() {
+ Token token = CurToken();
+ auto spelling = token.GetSpelling();
+ llvm::StringRef spelling_ref = spelling;
+
+ auto radix = llvm::getAutoSenseRadix(spelling_ref);
+ IntegerTypeSuffix type = IntegerTypeSuffix::None;
+ bool is_unsigned = false;
+ if (spelling_ref.consume_back_insensitive("u"))
+ is_unsigned = true;
+ if (spelling_ref.consume_back_insensitive("ll"))
+ type = IntegerTypeSuffix::LongLong;
+ else if (spelling_ref.consume_back_insensitive("l"))
+ type = IntegerTypeSuffix::Long;
+ // Suffix 'u' can be only specified only once, before or after 'l'
+ if (!is_unsigned && spelling_ref.consume_back_insensitive("u"))
+ is_unsigned = true;
+
+ llvm::APInt raw_value;
+ if (!spelling_ref.getAsInteger(radix, raw_value))
+ return std::make_unique<IntegerLiteralNode>(token.GetLocation(), raw_value,
+ radix, is_unsigned, type);
+ return nullptr;
+}
+
+ASTNodeUP DILParser::ParseFloatingPointLiteral() {
+ Token token = CurToken();
+ auto spelling = token.GetSpelling();
+ llvm::StringRef spelling_ref = spelling;
+
+ llvm::APFloat raw_float(llvm::APFloat::IEEEdouble());
+ if (spelling_ref.consume_back_insensitive("f"))
+ raw_float = llvm::APFloat(llvm::APFloat::IEEEsingle());
+
+ auto StatusOrErr = raw_float.convertFromString(
+ spelling_ref, llvm::APFloat::rmNearestTiesToEven);
+ if (!errorToBool(StatusOrErr.takeError()))
+ return std::make_unique<FloatLiteralNode>(token.GetLocation(), raw_float);
+ return nullptr;
+}
+
void DILParser::Expect(Token::Kind kind) {
if (CurToken().IsNot(kind)) {
BailOut(llvm::formatv("expected {0}, got: {1}", kind, CurToken()),