aboutsummaryrefslogtreecommitdiff
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/CMakeLists.txt1
-rw-r--r--lldb/source/API/SBCommandReturnObject.cpp7
-rw-r--r--lldb/source/API/SBDebugger.cpp70
-rw-r--r--lldb/source/API/SBFile.cpp17
-rw-r--r--lldb/source/API/SBFrameList.cpp97
-rw-r--r--lldb/source/API/SBInstruction.cpp5
-rw-r--r--lldb/source/API/SBLineEntry.cpp2
-rw-r--r--lldb/source/API/SBModule.cpp4
-rw-r--r--lldb/source/API/SBModuleSpec.cpp13
-rw-r--r--lldb/source/API/SBProcess.cpp4
-rw-r--r--lldb/source/API/SBStream.cpp3
-rw-r--r--lldb/source/API/SBTarget.cpp109
-rw-r--r--lldb/source/API/SBThread.cpp21
-rw-r--r--lldb/source/Breakpoint/BreakpointLocation.cpp2
-rw-r--r--lldb/source/Breakpoint/BreakpointLocationCollection.cpp20
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverFileLine.cpp2
-rw-r--r--lldb/source/Breakpoint/BreakpointResolverName.cpp33
-rw-r--r--lldb/source/Breakpoint/BreakpointSite.cpp16
-rw-r--r--lldb/source/Commands/CMakeLists.txt3
-rw-r--r--lldb/source/Commands/CommandObjectBreakpoint.cpp1349
-rw-r--r--lldb/source/Commands/CommandObjectDWIMPrint.cpp13
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectFrame.cpp52
-rw-r--r--lldb/source/Commands/CommandObjectMultiword.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectProcess.cpp13
-rw-r--r--lldb/source/Commands/CommandObjectSource.cpp4
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp208
-rw-r--r--lldb/source/Commands/CommandObjectVersion.cpp48
-rw-r--r--lldb/source/Commands/CommandObjectVersion.h40
-rw-r--r--lldb/source/Commands/Options.td131
-rw-r--r--lldb/source/Core/CoreProperties.td4
-rw-r--r--lldb/source/Core/Debugger.cpp64
-rw-r--r--lldb/source/Core/DemangledNameInfo.cpp4
-rw-r--r--lldb/source/Core/Disassembler.cpp130
-rw-r--r--lldb/source/Core/DynamicLoader.cpp8
-rw-r--r--lldb/source/Core/FormatEntity.cpp180
-rw-r--r--lldb/source/Core/Module.cpp102
-rw-r--r--lldb/source/Core/ModuleList.cpp102
-rw-r--r--lldb/source/Core/PluginManager.cpp55
-rw-r--r--lldb/source/Core/Section.cpp33
-rw-r--r--lldb/source/Core/SourceManager.cpp81
-rw-r--r--lldb/source/Core/Statusline.cpp9
-rw-r--r--lldb/source/Expression/CMakeLists.txt1
-rw-r--r--lldb/source/Expression/DWARFExpression.cpp301
-rw-r--r--lldb/source/Expression/ObjectFileJIT.cpp10
-rw-r--r--lldb/source/Expression/REPL.cpp2
-rw-r--r--lldb/source/Expression/UserExpression.cpp2
-rw-r--r--lldb/source/Host/CMakeLists.txt1
-rw-r--r--lldb/source/Host/common/DiagnosticsRendering.cpp (renamed from lldb/source/Utility/DiagnosticsRendering.cpp)2
-rw-r--r--lldb/source/Host/common/Editline.cpp3
-rw-r--r--lldb/source/Host/common/File.cpp42
-rw-r--r--lldb/source/Host/common/FileAction.cpp4
-rw-r--r--lldb/source/Host/common/StreamFile.cpp3
-rw-r--r--lldb/source/Host/macosx/objcxx/Host.mm39
-rw-r--r--lldb/source/Host/posix/ProcessLauncherPosixFork.cpp4
-rw-r--r--lldb/source/Host/windows/ProcessLauncherWindows.cpp198
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp2
-rw-r--r--lldb/source/Interpreter/CommandReturnObject.cpp11
-rw-r--r--lldb/source/Interpreter/Options.cpp6
-rw-r--r--lldb/source/Interpreter/ScriptInterpreter.cpp14
-rw-r--r--lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp2
-rw-r--r--lldb/source/Plugins/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp13
-rw-r--r--lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp6
-rw-r--r--lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp11
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt2
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp22
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp9
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp4
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp111
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h22
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp24
-rw-r--r--lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp43
-rw-r--r--lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp30
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/CMakeLists.txt13
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.cpp481
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.h61
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp5
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt3
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp70
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h4
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp11
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/Generic.h3
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp145
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp18
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.h4
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp124
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp3
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h4
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp112
-rw-r--r--lldb/source/Plugins/Language/ObjC/NSSet.cpp2
-rw-r--r--lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp9
-rw-r--r--lldb/source/Plugins/Language/ObjC/ObjCLanguage.h10
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt3
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp6
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.cpp (renamed from lldb/source/Target/VerboseTrapFrameRecognizer.cpp)33
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.h47
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp5
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h3
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp273
-rw-r--r--lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp8
-rw-r--r--lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp4
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp67
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp261
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h2
-rw-r--r--lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp88
-rw-r--r--lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp2
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp12
-rw-r--r--lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp298
-rw-r--r--lldb/source/Plugins/Platform/Android/PlatformAndroid.h11
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp10
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp51
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h3
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp10
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp22
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h11
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp9
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h1
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp20
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h1
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp4
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp3
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp61
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h2
-rw-r--r--lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp3
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp230
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedFrame.h48
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedThread.cpp6
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp2
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp113
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.h63
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp30
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h212
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp11
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h3
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp6
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h3
-rw-r--r--lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp21
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h9
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp8
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h5
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp35
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h1
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp29
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp55
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp23
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp9
-rw-r--r--lldb/source/Plugins/SyntheticFrameProvider/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/CMakeLists.txt12
-rw-r--r--lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp221
-rw-r--r--lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.h53
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp102
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h8
-rw-r--r--lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp293
-rw-r--r--lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h12
-rw-r--r--lldb/source/Symbol/CompileUnit.cpp4
-rw-r--r--lldb/source/Symbol/CompilerType.cpp28
-rw-r--r--lldb/source/Symbol/Function.cpp6
-rw-r--r--lldb/source/Symbol/LineEntry.cpp5
-rw-r--r--lldb/source/Symbol/LineTable.cpp2
-rw-r--r--lldb/source/Symbol/ObjectFile.cpp22
-rw-r--r--lldb/source/Symbol/SymbolContext.cpp29
-rw-r--r--lldb/source/Symbol/SymbolFile.cpp8
-rw-r--r--lldb/source/Symbol/Symtab.cpp28
-rw-r--r--lldb/source/Symbol/TypeSystem.cpp11
-rw-r--r--lldb/source/Target/BorrowedStackFrame.cpp187
-rw-r--r--lldb/source/Target/CMakeLists.txt3
-rw-r--r--lldb/source/Target/ExecutionContext.cpp17
-rw-r--r--lldb/source/Target/InstrumentationRuntime.cpp3
-rw-r--r--lldb/source/Target/Language.cpp42
-rw-r--r--lldb/source/Target/ModuleCache.cpp2
-rw-r--r--lldb/source/Target/Platform.cpp44
-rw-r--r--lldb/source/Target/Process.cpp24
-rw-r--r--lldb/source/Target/RemoteAwarePlatform.cpp11
-rw-r--r--lldb/source/Target/StackFrame.cpp20
-rw-r--r--lldb/source/Target/StackFrameList.cpp49
-rw-r--r--lldb/source/Target/SyntheticFrameProvider.cpp121
-rw-r--r--lldb/source/Target/Target.cpp137
-rw-r--r--lldb/source/Target/TargetList.cpp13
-rw-r--r--lldb/source/Target/Thread.cpp72
-rw-r--r--lldb/source/Target/ThreadPlanStepOut.cpp11
-rw-r--r--lldb/source/Target/ThreadPlanStepRange.cpp4
-rw-r--r--lldb/source/Target/ThreadSpec.cpp4
-rw-r--r--lldb/source/Target/UnixSignals.cpp7
-rw-r--r--lldb/source/Utility/CMakeLists.txt2
-rw-r--r--lldb/source/Utility/DataExtractor.cpp4
-rw-r--r--lldb/source/Utility/FileSpecList.cpp12
-rw-r--r--lldb/source/Utility/LLDBLog.cpp3
-rw-r--r--lldb/source/Utility/RegisterValue.cpp52
-rw-r--r--lldb/source/Utility/Stream.cpp8
-rw-r--r--lldb/source/Utility/StringExtractorGDBRemote.cpp3
-rw-r--r--lldb/source/Utility/VirtualDataExtractor.cpp139
-rw-r--r--lldb/source/ValueObject/CMakeLists.txt4
-rw-r--r--lldb/source/ValueObject/DILAST.cpp4
-rw-r--r--lldb/source/ValueObject/DILEval.cpp208
-rw-r--r--lldb/source/ValueObject/DILParser.cpp181
-rw-r--r--lldb/source/ValueObject/ValueObjectSynthetic.cpp15
-rw-r--r--lldb/source/Version/CMakeLists.txt3
204 files changed, 7378 insertions, 2229 deletions
diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt
index ce59ee5..ac47580 100644
--- a/lldb/source/API/CMakeLists.txt
+++ b/lldb/source/API/CMakeLists.txt
@@ -69,6 +69,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
SBFileSpecList.cpp
SBFormat.cpp
SBFrame.cpp
+ SBFrameList.cpp
SBFunction.cpp
SBHostOS.cpp
SBInstruction.cpp
diff --git a/lldb/source/API/SBCommandReturnObject.cpp b/lldb/source/API/SBCommandReturnObject.cpp
index e78e213a..da7e288 100644
--- a/lldb/source/API/SBCommandReturnObject.cpp
+++ b/lldb/source/API/SBCommandReturnObject.cpp
@@ -15,6 +15,7 @@
#include "lldb/API/SBValue.h"
#include "lldb/API/SBValueList.h"
#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Host/File.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Instrumentation.h"
@@ -275,14 +276,16 @@ void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh) {
void SBCommandReturnObject::SetImmediateOutputFile(FILE *fh,
bool transfer_ownership) {
LLDB_INSTRUMENT_VA(this, fh, transfer_ownership);
- FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership);
+ FileSP file = std::make_shared<NativeFile>(fh, File::eOpenOptionWriteOnly,
+ transfer_ownership);
ref().SetImmediateOutputFile(file);
}
void SBCommandReturnObject::SetImmediateErrorFile(FILE *fh,
bool transfer_ownership) {
LLDB_INSTRUMENT_VA(this, fh, transfer_ownership);
- FileSP file = std::make_shared<NativeFile>(fh, transfer_ownership);
+ FileSP file = std::make_shared<NativeFile>(fh, File::eOpenOptionWriteOnly,
+ transfer_ownership);
ref().SetImmediateErrorFile(file);
}
diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp
index 5c4c653..3f34e7a 100644
--- a/lldb/source/API/SBDebugger.cpp
+++ b/lldb/source/API/SBDebugger.cpp
@@ -179,7 +179,7 @@ void SBDebugger::Initialize() {
lldb::SBError SBDebugger::InitializeWithErrorHandling() {
LLDB_INSTRUMENT();
- SBError error;
+ SBError error((Status()));
if (auto e = g_debugger_lifetime->Initialize(
std::make_unique<SystemInitializerFull>())) {
error.SetError(Status::FromError(std::move(e)));
@@ -327,8 +327,8 @@ void SBDebugger::SkipAppInitFiles(bool b) {
void SBDebugger::SetInputFileHandle(FILE *fh, bool transfer_ownership) {
LLDB_INSTRUMENT_VA(this, fh, transfer_ownership);
if (m_opaque_sp)
- m_opaque_sp->SetInputFile(
- (FileSP)std::make_shared<NativeFile>(fh, transfer_ownership));
+ m_opaque_sp->SetInputFile((FileSP)std::make_shared<NativeFile>(
+ fh, File::eOpenOptionReadOnly, transfer_ownership));
}
SBError SBDebugger::SetInputString(const char *data) {
@@ -385,7 +385,8 @@ SBError SBDebugger::SetOutputFile(FileSP file_sp) {
void SBDebugger::SetOutputFileHandle(FILE *fh, bool transfer_ownership) {
LLDB_INSTRUMENT_VA(this, fh, transfer_ownership);
- SetOutputFile((FileSP)std::make_shared<NativeFile>(fh, transfer_ownership));
+ SetOutputFile((FileSP)std::make_shared<NativeFile>(
+ fh, File::eOpenOptionWriteOnly, transfer_ownership));
}
SBError SBDebugger::SetOutputFile(SBFile file) {
@@ -405,7 +406,8 @@ SBError SBDebugger::SetOutputFile(SBFile file) {
void SBDebugger::SetErrorFileHandle(FILE *fh, bool transfer_ownership) {
LLDB_INSTRUMENT_VA(this, fh, transfer_ownership);
- SetErrorFile((FileSP)std::make_shared<NativeFile>(fh, transfer_ownership));
+ SetErrorFile((FileSP)std::make_shared<NativeFile>(
+ fh, File::eOpenOptionWriteOnly, transfer_ownership));
}
SBError SBDebugger::SetErrorFile(FileSP file_sp) {
@@ -576,8 +578,10 @@ void SBDebugger::HandleProcessEvent(const SBProcess &process,
FILE *err) {
LLDB_INSTRUMENT_VA(this, process, event, out, err);
- FileSP outfile = std::make_shared<NativeFile>(out, false);
- FileSP errfile = std::make_shared<NativeFile>(err, false);
+ FileSP outfile =
+ std::make_shared<NativeFile>(out, File::eOpenOptionWriteOnly, false);
+ FileSP errfile =
+ std::make_shared<NativeFile>(err, File::eOpenOptionWriteOnly, false);
return HandleProcessEvent(process, event, outfile, errfile);
}
@@ -705,61 +709,11 @@ const char *SBDebugger::StateAsCString(StateType state) {
return lldb_private::StateAsCString(state);
}
-static void AddBoolConfigEntry(StructuredData::Dictionary &dict,
- llvm::StringRef name, bool value,
- llvm::StringRef description) {
- auto entry_up = std::make_unique<StructuredData::Dictionary>();
- entry_up->AddBooleanItem("value", value);
- entry_up->AddStringItem("description", description);
- dict.AddItem(name, std::move(entry_up));
-}
-
-static void AddLLVMTargets(StructuredData::Dictionary &dict) {
- auto array_up = std::make_unique<StructuredData::Array>();
-#define LLVM_TARGET(target) \
- array_up->AddItem(std::make_unique<StructuredData::String>(#target));
-#include "llvm/Config/Targets.def"
- auto entry_up = std::make_unique<StructuredData::Dictionary>();
- entry_up->AddItem("value", std::move(array_up));
- entry_up->AddStringItem("description", "A list of configured LLVM targets.");
- dict.AddItem("targets", std::move(entry_up));
-}
-
SBStructuredData SBDebugger::GetBuildConfiguration() {
LLDB_INSTRUMENT();
- auto config_up = std::make_unique<StructuredData::Dictionary>();
- AddBoolConfigEntry(
- *config_up, "xml", XMLDocument::XMLEnabled(),
- "A boolean value that indicates if XML support is enabled in LLDB");
- AddBoolConfigEntry(
- *config_up, "curl", LLVM_ENABLE_CURL,
- "A boolean value that indicates if CURL support is enabled in LLDB");
- AddBoolConfigEntry(
- *config_up, "curses", LLDB_ENABLE_CURSES,
- "A boolean value that indicates if curses support is enabled in LLDB");
- AddBoolConfigEntry(
- *config_up, "editline", LLDB_ENABLE_LIBEDIT,
- "A boolean value that indicates if editline support is enabled in LLDB");
- AddBoolConfigEntry(*config_up, "editline_wchar", LLDB_EDITLINE_USE_WCHAR,
- "A boolean value that indicates if editline wide "
- "characters support is enabled in LLDB");
- AddBoolConfigEntry(
- *config_up, "lzma", LLDB_ENABLE_LZMA,
- "A boolean value that indicates if lzma support is enabled in LLDB");
- AddBoolConfigEntry(
- *config_up, "python", LLDB_ENABLE_PYTHON,
- "A boolean value that indicates if python support is enabled in LLDB");
- AddBoolConfigEntry(
- *config_up, "lua", LLDB_ENABLE_LUA,
- "A boolean value that indicates if lua support is enabled in LLDB");
- AddBoolConfigEntry(*config_up, "fbsdvmcore", LLDB_ENABLE_FBSDVMCORE,
- "A boolean value that indicates if fbsdvmcore support is "
- "enabled in LLDB");
- AddLLVMTargets(*config_up);
-
SBStructuredData data;
- data.m_impl_up->SetObjectSP(std::move(config_up));
+ data.m_impl_up->SetObjectSP(Debugger::GetBuildConfiguration());
return data;
}
diff --git a/lldb/source/API/SBFile.cpp b/lldb/source/API/SBFile.cpp
index 2ae4b14..5690992 100644
--- a/lldb/source/API/SBFile.cpp
+++ b/lldb/source/API/SBFile.cpp
@@ -39,7 +39,22 @@ SBFile::SBFile() { LLDB_INSTRUMENT_VA(this); }
SBFile::SBFile(FILE *file, bool transfer_ownership) {
LLDB_INSTRUMENT_VA(this, file, transfer_ownership);
- m_opaque_sp = std::make_shared<NativeFile>(file, transfer_ownership);
+ // For backwards comptability, this defaulted to ReadOnly previously.
+ m_opaque_sp = std::make_shared<NativeFile>(file, File::eOpenOptionReadOnly,
+ transfer_ownership);
+}
+
+SBFile::SBFile(FILE *file, const char *mode, bool transfer_ownership) {
+ LLDB_INSTRUMENT_VA(this, file, transfer_ownership);
+
+ auto options = File::GetOptionsFromMode(mode);
+ if (!options) {
+ llvm::consumeError(options.takeError());
+ return;
+ }
+
+ m_opaque_sp =
+ std::make_shared<NativeFile>(file, options.get(), transfer_ownership);
}
SBFile::SBFile(int fd, const char *mode, bool transfer_owndership) {
diff --git a/lldb/source/API/SBFrameList.cpp b/lldb/source/API/SBFrameList.cpp
new file mode 100644
index 0000000..d5fa955
--- /dev/null
+++ b/lldb/source/API/SBFrameList.cpp
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "lldb/API/SBFrameList.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBThread.h"
+#include "lldb/Target/StackFrameList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Instrumentation.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBFrameList::SBFrameList() : m_opaque_sp() { LLDB_INSTRUMENT_VA(this); }
+
+SBFrameList::SBFrameList(const SBFrameList &rhs)
+ : m_opaque_sp(rhs.m_opaque_sp) {
+ LLDB_INSTRUMENT_VA(this, rhs);
+}
+
+SBFrameList::~SBFrameList() = default;
+
+const SBFrameList &SBFrameList::operator=(const SBFrameList &rhs) {
+ LLDB_INSTRUMENT_VA(this, rhs);
+
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+SBFrameList::SBFrameList(const lldb::StackFrameListSP &frame_list_sp)
+ : m_opaque_sp(frame_list_sp) {}
+
+void SBFrameList::SetFrameList(const lldb::StackFrameListSP &frame_list_sp) {
+ m_opaque_sp = frame_list_sp;
+}
+
+SBFrameList::operator bool() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ return m_opaque_sp.get() != nullptr;
+}
+
+bool SBFrameList::IsValid() const {
+ LLDB_INSTRUMENT_VA(this);
+ return this->operator bool();
+}
+
+uint32_t SBFrameList::GetSize() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (m_opaque_sp)
+ return m_opaque_sp->GetNumFrames();
+ return 0;
+}
+
+SBFrame SBFrameList::GetFrameAtIndex(uint32_t idx) const {
+ LLDB_INSTRUMENT_VA(this, idx);
+
+ SBFrame sb_frame;
+ if (m_opaque_sp)
+ sb_frame.SetFrameSP(m_opaque_sp->GetFrameAtIndex(idx));
+ return sb_frame;
+}
+
+SBThread SBFrameList::GetThread() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ SBThread sb_thread;
+ if (m_opaque_sp)
+ sb_thread.SetThread(m_opaque_sp->GetThread().shared_from_this());
+ return sb_thread;
+}
+
+void SBFrameList::Clear() {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (m_opaque_sp)
+ m_opaque_sp->Clear();
+}
+
+bool SBFrameList::GetDescription(SBStream &description) const {
+ LLDB_INSTRUMENT_VA(this, description);
+
+ if (!m_opaque_sp)
+ return false;
+
+ Stream &strm = description.ref();
+ m_opaque_sp->Dump(&strm);
+ return true;
+}
diff --git a/lldb/source/API/SBInstruction.cpp b/lldb/source/API/SBInstruction.cpp
index 6755089..5921511 100644
--- a/lldb/source/API/SBInstruction.cpp
+++ b/lldb/source/API/SBInstruction.cpp
@@ -10,8 +10,8 @@
#include "lldb/Utility/Instrumentation.h"
#include "lldb/API/SBAddress.h"
-#include "lldb/API/SBFrame.h"
#include "lldb/API/SBFile.h"
+#include "lldb/API/SBFrame.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBTarget.h"
@@ -268,7 +268,8 @@ bool SBInstruction::GetDescription(lldb::SBStream &s) {
void SBInstruction::Print(FILE *outp) {
LLDB_INSTRUMENT_VA(this, outp);
- FileSP out = std::make_shared<NativeFile>(outp, /*take_ownership=*/false);
+ FileSP out = std::make_shared<NativeFile>(outp, File::eOpenOptionWriteOnly,
+ /*take_ownership=*/false);
Print(out);
}
diff --git a/lldb/source/API/SBLineEntry.cpp b/lldb/source/API/SBLineEntry.cpp
index 0f4936f..2257294 100644
--- a/lldb/source/API/SBLineEntry.cpp
+++ b/lldb/source/API/SBLineEntry.cpp
@@ -132,6 +132,8 @@ void SBLineEntry::SetLine(uint32_t line) {
LLDB_INSTRUMENT_VA(this, line);
ref().line = line;
+ if (!ref().range.IsValid())
+ ref().synthetic = true;
}
void SBLineEntry::SetColumn(uint32_t column) {
diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp
index 5a57f45..32067ac 100644
--- a/lldb/source/API/SBModule.cpp
+++ b/lldb/source/API/SBModule.cpp
@@ -37,8 +37,8 @@ SBModule::SBModule(const SBModuleSpec &module_spec) {
LLDB_INSTRUMENT_VA(this, module_spec);
ModuleSP module_sp;
- Status error = ModuleList::GetSharedModule(
- *module_spec.m_opaque_up, module_sp, nullptr, nullptr, nullptr);
+ Status error = ModuleList::GetSharedModule(*module_spec.m_opaque_up,
+ module_sp, nullptr, nullptr);
if (module_sp)
SetSP(module_sp);
}
diff --git a/lldb/source/API/SBModuleSpec.cpp b/lldb/source/API/SBModuleSpec.cpp
index fbbcfea..031ba12 100644
--- a/lldb/source/API/SBModuleSpec.cpp
+++ b/lldb/source/API/SBModuleSpec.cpp
@@ -9,6 +9,7 @@
#include "lldb/API/SBModuleSpec.h"
#include "Utils.h"
#include "lldb/API/SBStream.h"
+#include "lldb/API/SBTarget.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/Host.h"
@@ -174,6 +175,18 @@ void SBModuleSpec::SetObjectSize(uint64_t object_size) {
m_opaque_up->SetObjectSize(object_size);
}
+SBTarget SBModuleSpec::GetTarget() {
+ LLDB_INSTRUMENT_VA(this);
+
+ return SBTarget(m_opaque_up->GetTargetSP());
+}
+
+void SBModuleSpec::SetTarget(SBTarget target) {
+ LLDB_INSTRUMENT_VA(this, target);
+
+ m_opaque_up->SetTarget(target.GetSP());
+}
+
SBModuleSpecList::SBModuleSpecList() : m_opaque_up(new ModuleSpecList()) {
LLDB_INSTRUMENT_VA(this);
}
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index d4be64b..14aa943 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/API/SBProcess.h"
+#include "lldb/Host/File.h"
#include "lldb/Utility/Instrumentation.h"
#include <cinttypes>
@@ -310,7 +311,8 @@ void SBProcess::ReportEventState(const SBEvent &event, SBFile out) const {
void SBProcess::ReportEventState(const SBEvent &event, FILE *out) const {
LLDB_INSTRUMENT_VA(this, event, out);
- FileSP outfile = std::make_shared<NativeFile>(out, false);
+ FileSP outfile =
+ std::make_shared<NativeFile>(out, File::eOpenOptionWriteOnly, false);
return ReportEventState(event, outfile);
}
diff --git a/lldb/source/API/SBStream.cpp b/lldb/source/API/SBStream.cpp
index fc8f09a..2fc5fcf 100644
--- a/lldb/source/API/SBStream.cpp
+++ b/lldb/source/API/SBStream.cpp
@@ -116,7 +116,8 @@ void SBStream::RedirectToFile(const char *path, bool append) {
void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) {
LLDB_INSTRUMENT_VA(this, fh, transfer_fh_ownership);
- FileSP file = std::make_unique<NativeFile>(fh, transfer_fh_ownership);
+ FileSP file = std::make_unique<NativeFile>(fh, File::eOpenOptionReadWrite,
+ transfer_fh_ownership);
return RedirectToFile(file);
}
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 98d10aa..78c2d49 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -23,6 +23,7 @@
#include "lldb/API/SBStringList.h"
#include "lldb/API/SBStructuredData.h"
#include "lldb/API/SBSymbolContextList.h"
+#include "lldb/API/SBThreadCollection.h"
#include "lldb/API/SBTrace.h"
#include "lldb/Breakpoint/BreakpointID.h"
#include "lldb/Breakpoint/BreakpointIDList.h"
@@ -39,6 +40,7 @@
#include "lldb/Core/Section.h"
#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
#include "lldb/Symbol/DeclVendor.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
@@ -50,6 +52,7 @@
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/SyntheticFrameProvider.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Utility/ArchSpec.h"
@@ -59,6 +62,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/ScriptedMetadata.h"
#include "lldb/ValueObject/ValueObjectConstResult.h"
#include "lldb/ValueObject/ValueObjectList.h"
#include "lldb/ValueObject/ValueObjectVariable.h"
@@ -128,6 +132,12 @@ SBTarget SBTarget::GetTargetFromEvent(const SBEvent &event) {
return Target::TargetEventData::GetTargetFromEvent(event.get());
}
+SBTarget SBTarget::GetCreatedTargetFromEvent(const SBEvent &event) {
+ LLDB_INSTRUMENT_VA(event);
+
+ return Target::TargetEventData::GetCreatedTargetFromEvent(event.get());
+}
+
uint32_t SBTarget::GetNumModulesFromEvent(const SBEvent &event) {
LLDB_INSTRUMENT_VA(event);
@@ -1614,6 +1624,19 @@ const char *SBTarget::GetTriple() {
return nullptr;
}
+const char *SBTarget::GetArchName() {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (TargetSP target_sp = GetSP()) {
+ llvm::StringRef arch_name =
+ target_sp->GetArchitecture().GetTriple().getArchName();
+ ConstString const_arch_name(arch_name);
+
+ return const_arch_name.GetCString();
+ }
+ return nullptr;
+}
+
const char *SBTarget::GetABIName() {
LLDB_INSTRUMENT_VA(this);
@@ -1641,6 +1664,14 @@ lldb::user_id_t SBTarget::GetGloballyUniqueID() const {
return LLDB_INVALID_GLOBALLY_UNIQUE_TARGET_ID;
}
+const char *SBTarget::GetTargetSessionName() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (TargetSP target_sp = GetSP())
+ return ConstString(target_sp->GetTargetSessionName()).AsCString();
+ return nullptr;
+}
+
SBError SBTarget::SetLabel(const char *label) {
LLDB_INSTRUMENT_VA(this, label);
@@ -2408,3 +2439,81 @@ lldb::SBMutex SBTarget::GetAPIMutex() const {
return lldb::SBMutex(target_sp);
return lldb::SBMutex();
}
+
+uint32_t
+SBTarget::RegisterScriptedFrameProvider(const char *class_name,
+ lldb::SBStructuredData args_dict,
+ lldb::SBError &error) {
+ LLDB_INSTRUMENT_VA(this, class_name, args_dict, error);
+
+ TargetSP target_sp = GetSP();
+ if (!target_sp) {
+ error.SetErrorString("invalid target");
+ return 0;
+ }
+
+ if (!class_name || !class_name[0]) {
+ error.SetErrorString("invalid class name");
+ return 0;
+ }
+
+ // Extract the dictionary from SBStructuredData.
+ StructuredData::DictionarySP dict_sp;
+ if (args_dict.IsValid() && args_dict.m_impl_up) {
+ StructuredData::ObjectSP obj_sp = args_dict.m_impl_up->GetObjectSP();
+ if (obj_sp && obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) {
+ error.SetErrorString("SBStructuredData argument isn't a dictionary");
+ return 0;
+ }
+ dict_sp = std::make_shared<StructuredData::Dictionary>(obj_sp);
+ }
+
+ // Create the ScriptedMetadata.
+ ScriptedMetadataSP metadata_sp =
+ std::make_shared<ScriptedMetadata>(class_name, dict_sp);
+
+ // Create the interface for calling static methods.
+ ScriptedFrameProviderInterfaceSP interface_sp =
+ target_sp->GetDebugger()
+ .GetScriptInterpreter()
+ ->CreateScriptedFrameProviderInterface();
+
+ // Create a descriptor (applies to all threads by default).
+ ScriptedFrameProviderDescriptor descriptor(metadata_sp);
+ descriptor.interface_sp = interface_sp;
+
+ llvm::Expected<uint32_t> descriptor_id_or_err =
+ target_sp->AddScriptedFrameProviderDescriptor(descriptor);
+ if (!descriptor_id_or_err) {
+ error.SetErrorString(
+ llvm::toString(descriptor_id_or_err.takeError()).c_str());
+ return 0;
+ }
+
+ // Register the descriptor with the target.
+ return *descriptor_id_or_err;
+}
+
+lldb::SBError SBTarget::RemoveScriptedFrameProvider(uint32_t provider_id) {
+ LLDB_INSTRUMENT_VA(this, provider_id);
+
+ SBError error;
+ TargetSP target_sp = GetSP();
+ if (!target_sp) {
+ error.SetErrorString("invalid target");
+ return error;
+ }
+
+ if (!provider_id) {
+ error.SetErrorString("invalid provider id");
+ return error;
+ }
+
+ if (!target_sp->RemoveScriptedFrameProviderDescriptor(provider_id)) {
+ error.SetErrorStringWithFormat("no frame provider named '%u' found",
+ provider_id);
+ return error;
+ }
+
+ return {};
+}
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index f58a1b5..f32c5c5 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -14,6 +14,7 @@
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBFormat.h"
#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBFrameList.h"
#include "lldb/API/SBProcess.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBStructuredData.h"
@@ -1102,6 +1103,26 @@ SBFrame SBThread::GetFrameAtIndex(uint32_t idx) {
return sb_frame;
}
+lldb::SBFrameList SBThread::GetFrames() {
+ LLDB_INSTRUMENT_VA(this);
+
+ SBFrameList sb_frame_list;
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return SBFrameList();
+ }
+
+ if (exe_ctx->HasThreadScope()) {
+ StackFrameListSP frame_list_sp =
+ exe_ctx->GetThreadPtr()->GetStackFrameList();
+ sb_frame_list.SetFrameList(frame_list_sp);
+ }
+
+ return sb_frame_list;
+}
+
lldb::SBFrame SBThread::GetSelectedFrame() {
LLDB_INSTRUMENT_VA(this);
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp
index f25209c..25285be 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -251,7 +251,7 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx,
}
m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(
- condition.GetText(), llvm::StringRef(), language,
+ condition.GetText(), llvm::StringRef(), SourceLanguage{language},
Expression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
error));
if (error.Fail()) {
diff --git a/lldb/source/Breakpoint/BreakpointLocationCollection.cpp b/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
index 9771583..adff429 100644
--- a/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -24,7 +24,7 @@ BreakpointLocationCollection::BreakpointLocationCollection(bool preserving)
BreakpointLocationCollection::~BreakpointLocationCollection() = default;
void BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc) {
- std::lock_guard<std::mutex> guard(m_collection_mutex);
+ std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);
BreakpointLocationSP old_bp_loc =
FindByIDPair(bp_loc->GetBreakpoint().GetID(), bp_loc->GetID());
if (!old_bp_loc.get()) {
@@ -44,7 +44,7 @@ void BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc) {
bool BreakpointLocationCollection::Remove(lldb::break_id_t bp_id,
lldb::break_id_t bp_loc_id) {
- std::lock_guard<std::mutex> guard(m_collection_mutex);
+ std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);
collection::iterator pos = GetIDPairIterator(bp_id, bp_loc_id); // Predicate
if (pos != m_break_loc_collection.end()) {
if (m_preserving_bkpts) {
@@ -117,7 +117,7 @@ const BreakpointLocationSP BreakpointLocationCollection::FindByIDPair(
}
BreakpointLocationSP BreakpointLocationCollection::GetByIndex(size_t i) {
- std::lock_guard<std::mutex> guard(m_collection_mutex);
+ std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);
BreakpointLocationSP stop_sp;
if (i < m_break_loc_collection.size())
stop_sp = m_break_loc_collection[i];
@@ -127,7 +127,7 @@ BreakpointLocationSP BreakpointLocationCollection::GetByIndex(size_t i) {
const BreakpointLocationSP
BreakpointLocationCollection::GetByIndex(size_t i) const {
- std::lock_guard<std::mutex> guard(m_collection_mutex);
+ std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);
BreakpointLocationSP stop_sp;
if (i < m_break_loc_collection.size())
stop_sp = m_break_loc_collection[i];
@@ -168,7 +168,7 @@ bool BreakpointLocationCollection::ShouldStop(
}
bool BreakpointLocationCollection::ValidForThisThread(Thread &thread) {
- std::lock_guard<std::mutex> guard(m_collection_mutex);
+ std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);
collection::iterator pos, begin = m_break_loc_collection.begin(),
end = m_break_loc_collection.end();
@@ -180,7 +180,7 @@ bool BreakpointLocationCollection::ValidForThisThread(Thread &thread) {
}
bool BreakpointLocationCollection::IsInternal() const {
- std::lock_guard<std::mutex> guard(m_collection_mutex);
+ std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);
collection::const_iterator pos, begin = m_break_loc_collection.begin(),
end = m_break_loc_collection.end();
@@ -197,7 +197,7 @@ bool BreakpointLocationCollection::IsInternal() const {
void BreakpointLocationCollection::GetDescription(
Stream *s, lldb::DescriptionLevel level) {
- std::lock_guard<std::mutex> guard(m_collection_mutex);
+ std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);
collection::iterator pos, begin = m_break_loc_collection.begin(),
end = m_break_loc_collection.end();
@@ -212,8 +212,10 @@ BreakpointLocationCollection &BreakpointLocationCollection::operator=(
const BreakpointLocationCollection &rhs) {
if (this != &rhs) {
std::lock(m_collection_mutex, rhs.m_collection_mutex);
- std::lock_guard<std::mutex> lhs_guard(m_collection_mutex, std::adopt_lock);
- std::lock_guard<std::mutex> rhs_guard(rhs.m_collection_mutex, std::adopt_lock);
+ std::lock_guard<std::recursive_mutex> lhs_guard(m_collection_mutex,
+ std::adopt_lock);
+ std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_collection_mutex,
+ std::adopt_lock);
m_break_loc_collection = rhs.m_break_loc_collection;
}
return *this;
diff --git a/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
index a94e9e2..cef1ef1 100644
--- a/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -139,7 +139,7 @@ void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list) {
if (!sc.block)
continue;
- SupportFileSP file_sp;
+ SupportFileNSP file_sp = std::make_shared<SupportFile>();
uint32_t line;
const Block *inline_block = sc.block->GetContainingInlinedBlock();
if (inline_block) {
diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp
index 4f252f9..2025f59 100644
--- a/lldb/source/Breakpoint/BreakpointResolverName.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp
@@ -218,19 +218,22 @@ StructuredData::ObjectSP BreakpointResolverName::SerializeToStructuredData() {
void BreakpointResolverName::AddNameLookup(ConstString name,
FunctionNameType name_type_mask) {
-
- Module::LookupInfo lookup(name, name_type_mask, m_language);
- m_lookups.emplace_back(lookup);
+ std::vector<Module::LookupInfo> infos =
+ Module::LookupInfo::MakeLookupInfos(name, name_type_mask, m_language);
+ llvm::append_range(m_lookups, infos);
auto add_variant_funcs = [&](Language *lang) {
for (Language::MethodNameVariant variant :
lang->GetMethodNameVariants(name)) {
// FIXME: Should we be adding variants that aren't of type Full?
if (variant.GetType() & lldb::eFunctionNameTypeFull) {
- Module::LookupInfo variant_lookup(name, variant.GetType(),
- lang->GetLanguageType());
- variant_lookup.SetLookupName(variant.GetName());
- m_lookups.emplace_back(variant_lookup);
+ std::vector<Module::LookupInfo> variant_lookups =
+ Module::LookupInfo::MakeLookupInfos(name, variant.GetType(),
+ lang->GetLanguageType());
+ llvm::for_each(variant_lookups, [&](auto &variant_lookup) {
+ variant_lookup.SetLookupName(variant.GetName());
+ });
+ llvm::append_range(m_lookups, variant_lookups);
}
}
return IterationAction::Continue;
@@ -401,14 +404,22 @@ void BreakpointResolverName::GetDescription(Stream *s) {
if (m_match_type == Breakpoint::Regexp)
s->Printf("regex = '%s'", m_regex.GetText().str().c_str());
else {
- size_t num_names = m_lookups.size();
- if (num_names == 1)
- s->Printf("name = '%s'", m_lookups[0].GetName().GetCString());
+ // Since there may be many lookups objects for the same name breakpoint (one
+ // per language available), unique them by name, and operate on those unique
+ // names.
+ std::vector<ConstString> unique_lookups;
+ for (auto &lookup : m_lookups) {
+ if (!llvm::is_contained(unique_lookups, lookup.GetName()))
+ unique_lookups.push_back(lookup.GetName());
+ }
+ if (unique_lookups.size() == 1)
+ s->Printf("name = '%s'", unique_lookups[0].GetCString());
else {
+ size_t num_names = unique_lookups.size();
s->Printf("names = {");
for (size_t i = 0; i < num_names; i++) {
s->Printf("%s'%s'", (i == 0 ? "" : ", "),
- m_lookups[i].GetName().GetCString());
+ unique_lookups[i].GetCString());
}
s->Printf("}");
}
diff --git a/lldb/source/Breakpoint/BreakpointSite.cpp b/lldb/source/Breakpoint/BreakpointSite.cpp
index fd7666b..8639379 100644
--- a/lldb/source/Breakpoint/BreakpointSite.cpp
+++ b/lldb/source/Breakpoint/BreakpointSite.cpp
@@ -168,6 +168,22 @@ bool BreakpointSite::ValidForThisThread(Thread &thread) {
return m_constituents.ValidForThisThread(thread);
}
+bool BreakpointSite::ContainsUserBreakpointForThread(Thread &thread) {
+ if (ThreadSP backed_thread = thread.GetBackedThread())
+ return ContainsUserBreakpointForThread(*backed_thread);
+
+ std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+ for (const BreakpointLocationSP &bp_loc :
+ m_constituents.BreakpointLocations()) {
+ const Breakpoint &bp = bp_loc->GetBreakpoint();
+ if (bp.IsInternal())
+ continue;
+ if (bp_loc->ValidForThisThread(thread))
+ return true;
+ }
+ return false;
+}
+
void BreakpointSite::BumpHitCounts() {
std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
for (BreakpointLocationSP loc_sp : m_constituents.BreakpointLocations()) {
diff --git a/lldb/source/Commands/CMakeLists.txt b/lldb/source/Commands/CMakeLists.txt
index 69e4c45..f2e6224 100644
--- a/lldb/source/Commands/CMakeLists.txt
+++ b/lldb/source/Commands/CMakeLists.txt
@@ -58,6 +58,9 @@ add_lldb_library(lldbCommands NO_PLUGIN_DEPENDENCIES
lldbUtility
lldbValueObject
lldbVersion
+ CLANG_LIBS
+ clangFrontend
+ clangSerialization
)
add_dependencies(lldbCommands LLDBOptionsGen)
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp
index 5a55126..75dc890 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -45,6 +45,38 @@ static void AddBreakpointDescription(Stream *s, Breakpoint *bp,
s->EOL();
}
+static bool GetDefaultFile(Target &target, StackFrame *cur_frame,
+ FileSpec &file, CommandReturnObject &result) {
+ // First use the Source Manager's default file. Then use the current stack
+ // frame's file.
+ if (auto maybe_file_and_line =
+ target.GetSourceManager().GetDefaultFileAndLine()) {
+ file = maybe_file_and_line->support_file_nsp->GetSpecOnly();
+ return true;
+ }
+
+ if (cur_frame == nullptr) {
+ result.AppendError("No selected frame to use to find the default file.");
+ return false;
+ }
+ if (!cur_frame->HasDebugInformation()) {
+ result.AppendError("Cannot use the selected frame to find the default "
+ "file, it has no debug info.");
+ return false;
+ }
+
+ const SymbolContext &sc =
+ cur_frame->GetSymbolContext(eSymbolContextLineEntry);
+ if (sc.line_entry.GetFile()) {
+ file = sc.line_entry.GetFile();
+ } else {
+ result.AppendError("Can't find the file for the selected frame to "
+ "use as the default file.");
+ return false;
+ }
+ return true;
+}
+
// Modifiable Breakpoint Options
#pragma mark Modify::CommandOptions
#define LLDB_OPTIONS_breakpoint_modify
@@ -200,6 +232,53 @@ public:
BreakpointOptions m_bp_opts;
};
+// This is the Breakpoint Names option group - used to add Names to breakpoints
+// while making them. Not to be confused with the "Breakpoint Name" option
+// group which is the common options of various "breakpoint name" commands.
+#define LLDB_OPTIONS_breakpoint_names
+#include "CommandOptions.inc"
+
+class BreakpointNamesOptionGroup : public OptionGroup {
+public:
+ BreakpointNamesOptionGroup() = default;
+
+ ~BreakpointNamesOptionGroup() override = default;
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return g_breakpoint_names_options;
+ }
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = GetDefinitions()[option_idx].short_option;
+ const char *long_option = GetDefinitions()[option_idx].long_option;
+
+ switch (short_option) {
+ case 'N':
+ if (BreakpointID::StringIsBreakpointName(option_value, error))
+ m_breakpoint_names.push_back(std::string(option_value));
+ else
+ error = Status::FromError(
+ CreateOptionParsingError(option_value, short_option, long_option,
+ "Invalid breakpoint name"));
+ break;
+ }
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_breakpoint_names.clear();
+ }
+
+ const std::vector<std::string> &GetBreakpointNames() {
+ return m_breakpoint_names;
+ }
+
+protected:
+ std::vector<std::string> m_breakpoint_names;
+};
+
#define LLDB_OPTIONS_breakpoint_dummy
#include "CommandOptions.inc"
@@ -237,6 +316,1190 @@ public:
bool m_use_dummy;
};
+#pragma mark AddAddress::CommandOptions
+#define LLDB_OPTIONS_breakpoint_add_address
+#include "CommandOptions.inc"
+
+#pragma mark Add Address
+
+static bool CopyOverBreakpointOptions(BreakpointSP bp_sp,
+ BreakpointOptionGroup &bp_opts,
+ const std::vector<std::string> &bp_names,
+ CommandReturnObject &result) {
+ assert(bp_sp && "CopyOverBreakpointOptions called with no breakpoint");
+
+ bp_sp->GetOptions().CopyOverSetOptions(bp_opts.GetBreakpointOptions());
+ Target &target = bp_sp->GetTarget();
+ if (!bp_names.empty()) {
+ Status name_error;
+ for (auto name : bp_names) {
+ target.AddNameToBreakpoint(bp_sp, name.c_str(), name_error);
+ if (name_error.Fail()) {
+ result.AppendErrorWithFormat("Invalid breakpoint name: %s",
+ name.c_str());
+ target.RemoveBreakpointByID(bp_sp->GetID());
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static llvm::Expected<LanguageType>
+GetExceptionLanguageForLanguage(llvm::StringRef lang_name,
+ char short_option = '\0',
+ llvm::StringRef long_option = {}) {
+ llvm::Expected<LanguageType> exception_language =
+ Language::GetExceptionLanguageForLanguage(lang_name);
+ if (!exception_language) {
+ std::string error_msg = llvm::toString(exception_language.takeError());
+ return CreateOptionParsingError(lang_name, short_option, long_option,
+ error_msg);
+ }
+ return exception_language;
+}
+
+static Status CompleteLineEntry(ExecutionContext &exe_ctx,
+ OptionValueFileColonLine &line_entry) {
+ Status error;
+ uint32_t line_num = line_entry.GetLineNumber();
+ if (!line_entry.GetFileSpec()) {
+ FileSpec default_file_spec;
+ std::string error_msg;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (!target) {
+ error.FromErrorString("Can't complete a line entry with no "
+ "target");
+ return error;
+ }
+ Debugger &dbg = target->GetDebugger();
+ CommandReturnObject result(dbg.GetUseColor());
+ if (!GetDefaultFile(*target, exe_ctx.GetFramePtr(), default_file_spec,
+ result)) {
+ error.FromErrorStringWithFormatv("{0}/nCouldn't get default file for "
+ "line {1}: {2}",
+ result.GetErrorString(), line_num,
+ error_msg);
+ return error;
+ }
+ line_entry.SetFile(default_file_spec);
+ }
+ return error;
+}
+
+class CommandObjectBreakpointAddAddress : public CommandObjectParsed {
+public:
+ CommandObjectBreakpointAddAddress(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "breakpoint add address",
+ "Add breakpoints by raw address", nullptr) {
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ m_all_options.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_name_opts);
+ m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Finalize();
+
+ AddSimpleArgumentList(eArgTypeAddress, eArgRepeatPlus);
+ }
+
+ ~CommandObjectBreakpointAddAddress() override = default;
+
+ Options *GetOptions() override { return &m_all_options; }
+
+ class CommandOptions : public OptionGroup {
+ public:
+ CommandOptions() = default;
+
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = GetDefinitions()[option_idx].short_option;
+ const char *long_option = GetDefinitions()[option_idx].long_option;
+
+ switch (short_option) {
+ case 'H':
+ m_hardware = true;
+ break;
+
+ case 's':
+ if (m_modules.GetSize() == 0)
+ m_modules.AppendIfUnique(FileSpec(option_arg));
+ else
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ "Only one shared library can be "
+ "specified for address breakpoints."));
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_hardware = false;
+ m_modules.Clear();
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_breakpoint_add_address_options);
+ }
+
+ // Instance variables to hold the values for command options.
+ bool m_hardware = false; // FIXME - this can go in the "modify" options.
+ FileSpecList m_modules;
+ };
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ // We've already asserted that there can only be one entry in m_modules:
+ const ExecutionContext &exe_ctx = m_interpreter.GetExecutionContext();
+ // We don't set address breakpoints in the dummy target.
+ if (!exe_ctx.HasTargetScope() || exe_ctx.GetTargetPtr()->IsDummyTarget()) {
+ result.AppendError(
+ "can't set address breakpoints without a real target.");
+ return;
+ }
+ // Commands can't set internal breakpoints:
+ const bool internal = false;
+
+ Target &target = exe_ctx.GetTargetRef();
+
+ FileSpec module_spec;
+ bool has_module = false;
+ if (m_options.m_modules.GetSize() != 0) {
+ has_module = true;
+ module_spec = m_options.m_modules.GetFileSpecAtIndex(0);
+ }
+ BreakpointSP bp_sp;
+ // Let's process the arguments first so we can short-circuit if there are
+ // any errors:
+ std::vector<lldb::addr_t> bp_addrs;
+ for (const Args::ArgEntry &arg_entry : command) {
+ Address bp_address;
+ Status error;
+ lldb::addr_t bp_load_addr = OptionArgParser::ToAddress(
+ &exe_ctx, arg_entry.ref(), LLDB_INVALID_ADDRESS, &error);
+ if (error.Fail()) {
+ result.AppendErrorWithFormatv("invalid argument value '{0}': {1}",
+ arg_entry.ref(), error);
+ return;
+ }
+ bp_addrs.push_back(bp_load_addr);
+ }
+ for (auto bp_addr : bp_addrs) {
+ if (has_module)
+ bp_sp = target.CreateAddressInModuleBreakpoint(
+ bp_addr, internal, module_spec, m_options.m_hardware);
+ else
+ // ENHANCEMENT: we should see if bp_addr is in a single loaded module,
+ // and pass that module in if it is.
+ bp_sp =
+ target.CreateBreakpoint(bp_addr, internal, m_options.m_hardware);
+ }
+
+ if (bp_sp) {
+ CopyOverBreakpointOptions(bp_sp, m_bp_opts,
+ m_name_opts.GetBreakpointNames(), result);
+ Stream &output_stream = result.GetOutputStream();
+ bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
+ /*show_locations=*/false);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError("Breakpoint creation failed: No breakpoint created.");
+ }
+ }
+
+private:
+ BreakpointOptionGroup m_bp_opts;
+ BreakpointNamesOptionGroup m_name_opts;
+ BreakpointDummyOptionGroup m_dummy_options;
+ CommandOptions m_options;
+ OptionGroupOptions m_all_options;
+};
+
+#pragma mark AddException::CommandOptions
+#define LLDB_OPTIONS_breakpoint_add_exception
+#include "CommandOptions.inc"
+
+#pragma mark Add Exception
+
+class CommandObjectBreakpointAddException : public CommandObjectParsed {
+public:
+ CommandObjectBreakpointAddException(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "breakpoint add exception",
+ "Add breakpoints on language exceptions. If no language is "
+ "specified, break on exceptions for all supported languages",
+ nullptr) {
+ // Define the first (and only) variant of this arg.
+ AddSimpleArgumentList(eArgTypeLanguage, eArgRepeatStar);
+
+ // Next add all the options.
+ m_all_options.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_name_opts);
+ m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_options);
+ m_all_options.Finalize();
+ }
+
+ ~CommandObjectBreakpointAddException() override = default;
+
+ Options *GetOptions() override { return &m_all_options; }
+
+ class CommandOptions : public OptionGroup {
+ public:
+ CommandOptions() = default;
+
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = GetDefinitions()[option_idx].short_option;
+
+ switch (short_option) {
+ case 'E': {
+ uint32_t this_val = (uint32_t)OptionArgParser::ToOptionEnum(
+ option_arg, GetDefinitions()[option_idx].enum_values,
+ eExceptionStageThrow, error);
+ if (error.Fail())
+ return error;
+ m_exception_stage |= this_val;
+ } break;
+ case 'H':
+ m_hardware = true;
+ break;
+
+ case 'O':
+ m_exception_extra_args.AppendArgument("-O");
+ m_exception_extra_args.AppendArgument(option_arg);
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_hardware = false;
+ m_exception_extra_args.Clear();
+ m_exception_stage = eExceptionStageThrow;
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_breakpoint_add_exception_options);
+ }
+
+ // Instance variables to hold the values for command options.
+ bool m_hardware = false; // FIXME - this can go in the "modify" options.
+ Args m_exception_extra_args;
+ uint32_t m_exception_stage = eExceptionStageThrow;
+ };
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ Target &target =
+ m_dummy_options.m_use_dummy ? GetDummyTarget() : GetTarget();
+ BreakpointSP bp_sp;
+ LanguageType exception_language = eLanguageTypeUnknown;
+
+ if (command.size() == 0) {
+ result.AppendError("no languages specified");
+ } else if (command.size() > 1) {
+ result.AppendError(
+ "can only set exception breakpoints on one language at a time");
+ } else {
+ llvm::Expected<LanguageType> language =
+ GetExceptionLanguageForLanguage(command[0].ref());
+ if (language)
+ exception_language = *language;
+ else {
+ result.SetError(language.takeError());
+ return;
+ }
+ }
+ Status precond_error;
+ const bool internal = false;
+ bool catch_bp = (m_options.m_exception_stage & eExceptionStageCatch) != 0;
+ bool throw_bp = (m_options.m_exception_stage & eExceptionStageThrow) != 0;
+ bp_sp = target.CreateExceptionBreakpoint(
+ exception_language, catch_bp, throw_bp, internal,
+ &m_options.m_exception_extra_args, &precond_error);
+ if (precond_error.Fail()) {
+ result.AppendErrorWithFormat(
+ "Error setting extra exception arguments: %s",
+ precond_error.AsCString());
+ target.RemoveBreakpointByID(bp_sp->GetID());
+ return;
+ }
+
+ if (bp_sp) {
+ CopyOverBreakpointOptions(bp_sp, m_bp_opts,
+ m_name_opts.GetBreakpointNames(), result);
+ Stream &output_stream = result.GetOutputStream();
+ bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
+ /*show_locations=*/false);
+ // Note, we don't print a "got no locations" warning for exception
+ // breakpoints. They can get set in the dummy target, and we won't know
+ // how to actually set the breakpoint till we know what version of the
+ // relevant LanguageRuntime gets loaded.
+ if (&target == &GetDummyTarget())
+ output_stream.Printf("Breakpoint set in dummy target, will get copied "
+ "into future targets.\n");
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError("Breakpoint creation failed: No breakpoint created.");
+ }
+ }
+
+private:
+ BreakpointOptionGroup m_bp_opts;
+ BreakpointNamesOptionGroup m_name_opts;
+ BreakpointDummyOptionGroup m_dummy_options;
+ CommandOptions m_options;
+ OptionGroupOptions m_all_options;
+};
+
+#pragma mark AddFile::CommandOptions
+#define LLDB_OPTIONS_breakpoint_add_file
+#include "CommandOptions.inc"
+
+#pragma mark Add File
+
+class CommandObjectBreakpointAddFile : public CommandObjectParsed {
+public:
+ CommandObjectBreakpointAddFile(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "breakpoint add file",
+ "Add breakpoints on lines in specified source files", nullptr) {
+ CommandArgumentEntry arg1;
+ CommandArgumentData linespec_arg;
+ CommandArgumentData no_arg;
+
+ // Any number of linespecs in group 1:
+ linespec_arg.arg_type = eArgTypeFileLineColumn;
+ linespec_arg.arg_repetition = eArgRepeatPlus;
+ linespec_arg.arg_opt_set_association = LLDB_OPT_SET_1;
+
+ arg1.push_back(linespec_arg);
+
+ // Leave arg2 empty, there are no arguments to this variant.
+ CommandArgumentEntry arg2;
+ no_arg.arg_type = eArgTypeNone;
+ no_arg.arg_repetition = eArgRepeatOptional;
+ no_arg.arg_opt_set_association = LLDB_OPT_SET_2;
+
+ arg2.push_back(linespec_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back(arg1);
+ m_arguments.push_back(arg2);
+
+ // Define the first (and only) variant of this arg.
+ m_all_options.Append(&m_bp_opts, LLDB_OPT_SET_ALL,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
+ m_all_options.Append(&m_name_opts);
+ m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
+ m_all_options.Append(&m_options);
+ m_all_options.Finalize();
+ }
+
+ ~CommandObjectBreakpointAddFile() override = default;
+
+ Options *GetOptions() override { return &m_all_options; }
+
+ class CommandOptions : public OptionGroup {
+ public:
+ CommandOptions() = default;
+
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = GetDefinitions()[option_idx].short_option;
+ const char *long_option = GetDefinitions()[option_idx].long_option;
+
+ switch (short_option) {
+ case 'f':
+ m_cur_value.SetFile(FileSpec(option_arg));
+ break;
+ case 'l':
+ uint32_t line_num;
+ if (option_arg.getAsInteger(0, line_num))
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ g_int_parsing_error_message));
+ else {
+ // The line number is the only required part of the options for a
+ // specifying the location - since we will fill in the file with the
+ // default file. So when we see a new line, the old line entry we
+ // were building is done. If we haven't gotten a file, try to fill
+ // in the default file, and then finish up this linespec and start
+ // the next one.
+ if (m_cur_value.GetLineNumber() != LLDB_INVALID_LINE_NUMBER) {
+ // FIXME: It should be possible to create a breakpoint with a list
+ // of file, line, column values. But for now we can only create
+ // one, so return an error here. The commented out code is what we
+ // will do when I come back to add that capability.
+ return Status::FromErrorString("Can only specify one file and line "
+ "pair at a time.");
+#if 0 // This code will be appropriate once we have a resolver that can take
+ // more than one linespec at a time.
+ error = CompleteLineEntry(*execution_context, m_cur_value);
+ if (error.Fail())
+ return error;
+
+ m_line_specs.push_back(m_cur_value);
+ m_cur_value.Clear();
+#endif
+ }
+ m_cur_value.SetLine(line_num);
+ }
+ break;
+ case 'u':
+ uint32_t column_num;
+ if (option_arg.getAsInteger(0, column_num))
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ g_int_parsing_error_message));
+ else
+ m_cur_value.SetColumn(column_num);
+ break;
+ case 'K': {
+ bool success;
+ bool value;
+ value = OptionArgParser::ToBoolean(option_arg, true, &success);
+ if (value)
+ m_skip_prologue = eLazyBoolYes;
+ else
+ m_skip_prologue = eLazyBoolNo;
+
+ if (!success)
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ g_bool_parsing_error_message));
+ } break;
+ case 'm': {
+ bool success;
+ bool value;
+ value = OptionArgParser::ToBoolean(option_arg, true, &success);
+ if (value)
+ m_move_to_nearest_code = eLazyBoolYes;
+ else
+ m_move_to_nearest_code = eLazyBoolNo;
+
+ if (!success)
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ g_bool_parsing_error_message));
+ } break;
+ case 's':
+ m_modules.AppendIfUnique(FileSpec(option_arg));
+ break;
+ case 'H':
+ m_hardware = true;
+ break;
+ case 'S': {
+ lldb::addr_t tmp_offset_addr;
+ tmp_offset_addr = OptionArgParser::ToAddress(execution_context,
+ option_arg, 0, &error);
+ if (error.Success())
+ m_offset_addr = tmp_offset_addr;
+ } break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_hardware = false;
+ m_line_specs.clear();
+ m_cur_value.Clear();
+ m_skip_prologue = eLazyBoolCalculate;
+ m_modules.Clear();
+ m_move_to_nearest_code = eLazyBoolCalculate;
+ m_offset_addr = 0;
+ }
+
+ Status OptionParsingFinished(ExecutionContext *execution_context) override {
+ // We were supplied at least a line from the options, so fill in the
+ // default file if needed.
+ if (m_cur_value.GetLineNumber() != LLDB_INVALID_LINE_NUMBER) {
+ Status error = CompleteLineEntry(*execution_context, m_cur_value);
+ if (error.Fail())
+ return error;
+ m_line_specs.push_back(m_cur_value);
+ m_cur_value.Clear();
+ }
+ return {};
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_breakpoint_add_file_options);
+ }
+
+ // Instance variables to hold the values for command options.
+ bool m_hardware = false; // FIXME - this can go in the "modify" options.
+ std::vector<OptionValueFileColonLine> m_line_specs;
+ LazyBool m_skip_prologue = eLazyBoolCalculate;
+ OptionValueFileColonLine m_cur_value;
+ FileSpecList m_modules;
+ LazyBool m_move_to_nearest_code = eLazyBoolCalculate;
+ lldb::addr_t m_offset_addr = 0;
+ };
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ bool internal = false;
+ Target &target =
+ m_dummy_options.m_use_dummy ? GetDummyTarget() : GetTarget();
+ // FIXME: At present we can only make file & line breakpoints for one file
+ // and line pair. It wouldn't be hard to extend that, but I'm not adding
+ // features at this point so I'll leave that for a future patch. For now,
+ // flag this as an error.
+
+ // I'm leaving this as a loop since that's how it should be when we can
+ // do more than one linespec at a time.
+ FileSpec default_file;
+ for (const Args::ArgEntry &this_arg : command) {
+ OptionValueFileColonLine value;
+ uint32_t line_value = LLDB_INVALID_LINE_NUMBER;
+ if (!this_arg.ref().getAsInteger(0, line_value)) {
+ // The argument is a plain number. Treat that as a line number, and
+ // allow it if we can find a default file & line.
+ std::string error_msg;
+ if (!GetDefaultFile(target, m_exe_ctx.GetFramePtr(), default_file,
+ result)) {
+ result.AppendErrorWithFormatv("Couldn't find default file for line "
+ "input: {0} - {1}",
+ line_value, error_msg);
+ return;
+ }
+ value.SetLine(line_value);
+ value.SetFile(default_file);
+ } else {
+ Status error = value.SetValueFromString(this_arg.c_str());
+ if (error.Fail()) {
+ result.AppendErrorWithFormatv("Failed to parse linespec: {0}", error);
+ return;
+ }
+ }
+ m_options.m_line_specs.push_back(value);
+ }
+
+ if (m_options.m_line_specs.size() != 1) {
+ result.AppendError("Can only make file and line breakpoints with one "
+ "specification at a time.");
+ return;
+ }
+
+ BreakpointSP bp_sp;
+ // Only check for inline functions if
+ LazyBool check_inlines = eLazyBoolCalculate;
+
+ OptionValueFileColonLine &this_spec = m_options.m_line_specs[0];
+ bp_sp = target.CreateBreakpoint(
+ &(m_options.m_modules), this_spec.GetFileSpec(),
+ this_spec.GetLineNumber(), this_spec.GetColumnNumber(),
+ m_options.m_offset_addr, check_inlines, m_options.m_skip_prologue,
+ internal, m_options.m_hardware, m_options.m_move_to_nearest_code);
+
+ if (bp_sp) {
+ CopyOverBreakpointOptions(bp_sp, m_bp_opts,
+ m_name_opts.GetBreakpointNames(), result);
+ Stream &output_stream = result.GetOutputStream();
+ bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
+ /*show_locations=*/false);
+ if (&target == &GetDummyTarget())
+ output_stream.Printf("Breakpoint set in dummy target, will get copied "
+ "into future targets.\n");
+ else {
+ // Don't print out this warning for exception breakpoints. They can
+ // get set before the target is set, but we won't know how to actually
+ // set the breakpoint till we run.
+ if (bp_sp->GetNumLocations() == 0) {
+ output_stream.Printf("WARNING: Unable to resolve breakpoint to any "
+ "actual locations.\n");
+ }
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError("Breakpoint creation failed: No breakpoint created.");
+ }
+ }
+
+private:
+ BreakpointOptionGroup m_bp_opts;
+ BreakpointNamesOptionGroup m_name_opts;
+ BreakpointDummyOptionGroup m_dummy_options;
+ CommandOptions m_options;
+ OptionGroupOptions m_all_options;
+};
+
+#pragma mark AddName::CommandOptions
+#define LLDB_OPTIONS_breakpoint_add_name
+#include "CommandOptions.inc"
+
+#pragma mark Add Name
+
+class CommandObjectBreakpointAddName : public CommandObjectParsed {
+public:
+ CommandObjectBreakpointAddName(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "breakpoint add name",
+ "Add breakpoints matching function or symbol names",
+ nullptr) {
+ // FIXME: Add a completer that's aware of the name match style.
+ // Define the first (and only) variant of this arg.
+ AddSimpleArgumentList(eArgTypeFunctionOrSymbol, eArgRepeatPlus);
+
+ // Now add all the options groups.
+ m_all_options.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_name_opts);
+ m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_options);
+ m_all_options.Finalize();
+ }
+
+ ~CommandObjectBreakpointAddName() override = default;
+
+ Options *GetOptions() override { return &m_all_options; }
+
+ class CommandOptions : public OptionGroup {
+ public:
+ CommandOptions() = default;
+
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = GetDefinitions()[option_idx].short_option;
+ const char *long_option = GetDefinitions()[option_idx].long_option;
+
+ switch (short_option) {
+ case 'f':
+ m_files.AppendIfUnique(FileSpec(option_arg));
+ break;
+ case 'K': {
+ bool success;
+ bool value;
+ value = OptionArgParser::ToBoolean(option_arg, true, &success);
+ if (!success)
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ g_bool_parsing_error_message));
+ else {
+ if (value)
+ m_skip_prologue = eLazyBoolYes;
+ else
+ m_skip_prologue = eLazyBoolNo;
+ }
+ } break;
+ case 'L': {
+ m_language = Language::GetLanguageTypeFromString(option_arg);
+ if (m_language == eLanguageTypeUnknown)
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ g_language_parsing_error_message));
+ } break;
+ case 'm': {
+ uint32_t this_val = (uint32_t)OptionArgParser::ToOptionEnum(
+ option_arg, GetDefinitions()[option_idx].enum_values,
+ eNameMatchStyleAuto, error);
+ if (error.Fail())
+ return error;
+ m_lookup_style = (NameMatchStyle)this_val;
+ } break;
+ case 's':
+ m_modules.AppendIfUnique(FileSpec(option_arg));
+ break;
+ case 'H':
+ m_hardware = true;
+ break;
+ case 'S': {
+ lldb::addr_t tmp_offset_addr;
+ tmp_offset_addr = OptionArgParser::ToAddress(execution_context,
+ option_arg, 0, &error);
+ if (error.Success())
+ m_offset_addr = tmp_offset_addr;
+ } break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_hardware = false;
+ m_skip_prologue = eLazyBoolCalculate;
+ m_files.Clear();
+ m_language = eLanguageTypeUnknown;
+ m_modules.Clear();
+ m_offset_addr = 0;
+ m_lookup_style = eNameMatchStyleAuto;
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_breakpoint_add_name_options);
+ }
+
+ // Instance variables to hold the values for command options.
+ bool m_hardware = false; // FIXME - this can go in the "modify" options.
+ LazyBool m_skip_prologue = eLazyBoolCalculate;
+ FileSpecList m_modules;
+ LanguageType m_language = eLanguageTypeUnknown;
+ FileSpecList m_files;
+ LazyBool m_move_to_nearest_code = eLazyBoolCalculate;
+ lldb::addr_t m_offset_addr = 0;
+ NameMatchStyle m_lookup_style = eNameMatchStyleAuto;
+ };
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ const bool internal = false;
+ Target &target =
+ m_dummy_options.m_use_dummy ? GetDummyTarget() : GetTarget();
+ // Parse the argument list - this is a simple list of names.
+ std::vector<std::string> func_names;
+ for (const Args::ArgEntry &this_arg : command) {
+ func_names.push_back(this_arg.ref().str());
+ }
+ BreakpointSP bp_sp;
+ if (!(m_options.m_lookup_style & eNameMatchStyleRegex))
+ bp_sp = target.CreateBreakpoint(
+ &m_options.m_modules, &m_options.m_files, func_names,
+ (FunctionNameType)m_options.m_lookup_style, m_options.m_language,
+ m_options.m_offset_addr, m_options.m_skip_prologue, internal,
+ m_options.m_hardware);
+ else {
+ if (func_names.size() != 1) {
+ result.AppendError("Can only set function regular expression "
+ "breakpoints on one regex at a time.");
+ return;
+ }
+ std::string &func_regexp = func_names[0];
+ RegularExpression regexp(func_regexp);
+ if (llvm::Error err = regexp.GetError()) {
+ result.AppendErrorWithFormat(
+ "Function name regular expression could not be compiled: %s",
+ llvm::toString(std::move(err)).c_str());
+ // Check if the incorrect regex looks like a globbing expression and
+ // warn the user about it.
+ if (!func_regexp.empty()) {
+ if (func_regexp[0] == '*' || func_regexp[0] == '?')
+ result.AppendWarning(
+ "Function name regex does not accept glob patterns.");
+ }
+ return;
+ }
+
+ bp_sp = target.CreateFuncRegexBreakpoint(
+ &(m_options.m_modules), &(m_options.m_files), std::move(regexp),
+ m_options.m_language, m_options.m_skip_prologue, internal,
+ m_options.m_hardware);
+ }
+ if (bp_sp) {
+ CopyOverBreakpointOptions(bp_sp, m_bp_opts,
+ m_name_opts.GetBreakpointNames(), result);
+ Stream &output_stream = result.GetOutputStream();
+ bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
+ /*show_locations=*/false);
+ if (&target == &GetDummyTarget())
+ output_stream.Printf("Breakpoint set in dummy target, will get copied "
+ "into future targets.\n");
+ else {
+ if (bp_sp->GetNumLocations() == 0) {
+ output_stream.Printf("WARNING: Unable to resolve breakpoint to any "
+ "actual locations.\n");
+ }
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError("Breakpoint creation failed: No breakpoint created.");
+ }
+ }
+
+private:
+ BreakpointOptionGroup m_bp_opts;
+ BreakpointNamesOptionGroup m_name_opts;
+ BreakpointDummyOptionGroup m_dummy_options;
+ CommandOptions m_options;
+ OptionGroupOptions m_all_options;
+};
+
+#pragma mark AddPattern::CommandOptions
+#define LLDB_OPTIONS_breakpoint_add_pattern
+#include "CommandOptions.inc"
+
+#pragma mark Add Pattern
+
+class CommandObjectBreakpointAddPattern : public CommandObjectRaw {
+public:
+ CommandObjectBreakpointAddPattern(CommandInterpreter &interpreter)
+ : CommandObjectRaw(interpreter, "breakpoint add pattern",
+ "Add breakpoints matching patterns in the source text",
+ "breakpoint add pattern [options] -- <pattern>") {
+ AddSimpleArgumentList(eArgTypeRegularExpression, eArgRepeatPlain);
+ // Now add all the options groups.
+ m_all_options.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_name_opts);
+ m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_options);
+ m_all_options.Finalize();
+ }
+
+ ~CommandObjectBreakpointAddPattern() override = default;
+
+ Options *GetOptions() override { return &m_all_options; }
+
+ class CommandOptions : public OptionGroup {
+ public:
+ CommandOptions() = default;
+
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = GetDefinitions()[option_idx].short_option;
+ const char *long_option = GetDefinitions()[option_idx].long_option;
+
+ switch (short_option) {
+ case 'a': {
+ bool success;
+ bool value;
+ value = OptionArgParser::ToBoolean(option_arg, true, &success);
+ if (!success)
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ g_bool_parsing_error_message));
+ else
+ m_all_files = value;
+ } break;
+ case 'f':
+ m_files.AppendIfUnique(FileSpec(option_arg));
+ break;
+ case 'm': {
+ bool success;
+ bool value;
+ value = OptionArgParser::ToBoolean(option_arg, true, &success);
+ if (!success)
+ error = Status::FromError(
+ CreateOptionParsingError(option_arg, short_option, long_option,
+ g_bool_parsing_error_message));
+ else {
+ if (value)
+ m_move_to_nearest_code = eLazyBoolYes;
+ else
+ m_move_to_nearest_code = eLazyBoolNo;
+ }
+ } break;
+ case 'n':
+ m_func_names.insert(option_arg.str());
+ break;
+ case 's':
+ m_modules.AppendIfUnique(FileSpec(option_arg));
+ break;
+ case 'H':
+ m_hardware = true;
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_hardware = false;
+ m_skip_prologue = eLazyBoolCalculate;
+ m_modules.Clear();
+ m_files.Clear();
+ m_func_names.clear();
+ m_all_files = false;
+ m_move_to_nearest_code = eLazyBoolCalculate;
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_breakpoint_add_pattern_options);
+ }
+
+ // Instance variables to hold the values for command options.
+ bool m_hardware = false; // FIXME - this can go in the "modify" options.
+ LazyBool m_skip_prologue = eLazyBoolCalculate;
+ FileSpecList m_modules;
+ FileSpecList m_files;
+ std::unordered_set<std::string> m_func_names;
+ bool m_all_files = false;
+ LazyBool m_move_to_nearest_code = eLazyBoolCalculate;
+ };
+
+protected:
+ void DoExecute(llvm::StringRef command,
+ CommandReturnObject &result) override {
+ const bool internal = false;
+ ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
+ m_all_options.NotifyOptionParsingStarting(&exe_ctx);
+
+ if (command.empty()) {
+ result.AppendError("no pattern to seek.");
+ return;
+ }
+
+ OptionsWithRaw args(command);
+
+ if (args.HasArgs()) {
+ if (!ParseOptionsAndNotify(args.GetArgs(), result, m_all_options,
+ exe_ctx))
+ return;
+ }
+ llvm::StringRef pattern = args.GetRawPart();
+ if (pattern.empty()) {
+ result.AppendError("no pattern to seek");
+ return;
+ }
+
+ Target &target =
+ m_dummy_options.m_use_dummy ? GetDummyTarget() : GetTarget();
+
+ BreakpointSP bp_sp;
+ const size_t num_files = m_options.m_files.GetSize();
+
+ if (num_files == 0 && !m_options.m_all_files) {
+ FileSpec file;
+ if (!GetDefaultFile(target, m_exe_ctx.GetFramePtr(), file, result)) {
+ result.AppendError(
+ "No files provided and could not find default file.");
+ return;
+ } else {
+ m_options.m_files.Append(file);
+ }
+ }
+
+ RegularExpression regexp(pattern);
+ if (llvm::Error err = regexp.GetError()) {
+ result.AppendErrorWithFormat(
+ "Source text regular expression could not be compiled: \"%s\"",
+ llvm::toString(std::move(err)).c_str());
+ return;
+ }
+ bp_sp = target.CreateSourceRegexBreakpoint(
+ &(m_options.m_modules), &(m_options.m_files), m_options.m_func_names,
+ std::move(regexp), internal, m_options.m_hardware,
+ m_options.m_move_to_nearest_code);
+
+ if (bp_sp) {
+ CopyOverBreakpointOptions(bp_sp, m_bp_opts,
+ m_name_opts.GetBreakpointNames(), result);
+ Stream &output_stream = result.GetOutputStream();
+ bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
+ /*show_locations=*/false);
+ if (&target == &GetDummyTarget())
+ output_stream.Printf("Breakpoint set in dummy target, will get copied "
+ "into future targets.\n");
+ else {
+ // Don't print out this warning for exception breakpoints. They can
+ // get set before the target is set, but we won't know how to actually
+ // set the breakpoint till we run.
+ if (bp_sp->GetNumLocations() == 0) {
+ output_stream.Printf("WARNING: Unable to resolve breakpoint to any "
+ "actual locations.\n");
+ }
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError("Breakpoint creation failed: No breakpoint created.");
+ }
+ }
+
+private:
+ BreakpointOptionGroup m_bp_opts;
+ BreakpointNamesOptionGroup m_name_opts;
+ BreakpointDummyOptionGroup m_dummy_options;
+ CommandOptions m_options;
+ OptionGroupOptions m_all_options;
+};
+
+#pragma mark AddScripted::CommandOptions
+#define LLDB_OPTIONS_breakpoint_add_scripted
+#include "CommandOptions.inc"
+
+#pragma mark Add Scripted
+
+class CommandObjectBreakpointAddScripted : public CommandObjectParsed {
+public:
+ CommandObjectBreakpointAddScripted(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "breakpoint add scripted",
+ "Add breakpoints using a scripted breakpoint resolver.", nullptr),
+ m_python_class_options("scripted breakpoint", true, 'P') {
+ // We're picking up all the normal options, commands and disable.
+ m_all_options.Append(&m_python_class_options,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_2, LLDB_OPT_SET_1);
+ // Define the first (and only) variant of this arg.
+ m_all_options.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_name_opts);
+ m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_all_options.Append(&m_options);
+ m_all_options.Finalize();
+ }
+
+ ~CommandObjectBreakpointAddScripted() override = default;
+
+ Options *GetOptions() override { return &m_all_options; }
+
+ class CommandOptions : public OptionGroup {
+ public:
+ CommandOptions() = default;
+
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = GetDefinitions()[option_idx].short_option;
+
+ switch (short_option) {
+ case 'f':
+ m_files.Append(FileSpec(option_arg));
+ break;
+ case 's':
+ m_modules.AppendIfUnique(FileSpec(option_arg));
+ break;
+ case 'H':
+ m_hardware = true;
+ break;
+
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_hardware = false;
+ m_files.Clear();
+ m_modules.Clear();
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::ArrayRef(g_breakpoint_add_scripted_options);
+ }
+
+ // Instance variables to hold the values for command options.
+ bool m_hardware = false; // FIXME - this can go in the "modify" options.
+ FileSpecList m_files;
+ FileSpecList m_modules;
+ };
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ Target &target =
+ m_dummy_options.m_use_dummy ? GetDummyTarget() : GetTarget();
+
+ BreakpointSP bp_sp;
+ Status error;
+ bp_sp = target.CreateScriptedBreakpoint(
+ m_python_class_options.GetName().c_str(), &(m_options.m_modules),
+ &(m_options.m_files), false, m_options.m_hardware,
+ m_python_class_options.GetStructuredData(), &error);
+ if (error.Fail()) {
+ result.AppendErrorWithFormat(
+ "error setting extra exception arguments: %s", error.AsCString());
+ target.RemoveBreakpointByID(bp_sp->GetID());
+ return;
+ }
+
+ if (bp_sp) {
+ CopyOverBreakpointOptions(bp_sp, m_bp_opts,
+ m_name_opts.GetBreakpointNames(), result);
+ Stream &output_stream = result.GetOutputStream();
+ bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
+ /*show_locations=*/false);
+ if (&target == &GetDummyTarget())
+ output_stream.Printf("Breakpoint set in dummy target, will get copied "
+ "into future targets.\n");
+ else {
+ // Don't print out this warning for exception breakpoints. They can
+ // get set before the target is set, but we won't know how to actually
+ // set the breakpoint till we run.
+ if (bp_sp->GetNumLocations() == 0) {
+ output_stream.Printf("WARNING: Unable to resolve breakpoint to any "
+ "actual locations.\n");
+ }
+ }
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError("breakpoint creation failed: No breakpoint created.");
+ }
+ }
+
+private:
+ BreakpointOptionGroup m_bp_opts;
+ BreakpointNamesOptionGroup m_name_opts;
+ BreakpointDummyOptionGroup m_dummy_options;
+ OptionGroupPythonClassWithDict m_python_class_options;
+ CommandOptions m_options;
+ OptionGroupOptions m_all_options;
+};
+
+#pragma mark Add::CommandOptions
+#define LLDB_OPTIONS_breakpoint_add
+#include "CommandOptions.inc"
+
+#pragma mark Add
+
+class CommandObjectBreakpointAdd : public CommandObjectMultiword {
+public:
+ CommandObjectBreakpointAdd(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "add",
+ "Commands to add breakpoints of various types") {
+ SetHelpLong(
+ R"(
+Access the breakpoint search kernels built into lldb. Along with specifying the
+search kernel, each breakpoint add operation can specify a common set of
+"reaction" options for each breakpoint. The reaction options can also be
+modified after breakpoint creation using the "breakpoint modify" command.
+ )");
+ CommandObjectSP address_command_object(
+ new CommandObjectBreakpointAddAddress(interpreter));
+ CommandObjectSP exception_command_object(
+ new CommandObjectBreakpointAddException(interpreter));
+ CommandObjectSP file_command_object(
+ new CommandObjectBreakpointAddFile(interpreter));
+ CommandObjectSP name_command_object(
+ new CommandObjectBreakpointAddName(interpreter));
+ CommandObjectSP pattern_command_object(
+ new CommandObjectBreakpointAddPattern(interpreter));
+ CommandObjectSP scripted_command_object(
+ new CommandObjectBreakpointAddScripted(interpreter));
+
+ LoadSubCommand("address", address_command_object);
+ LoadSubCommand("exception", exception_command_object);
+ LoadSubCommand("file", file_command_object);
+ LoadSubCommand("name", name_command_object);
+ LoadSubCommand("pattern", pattern_command_object);
+ LoadSubCommand("scripted", scripted_command_object);
+ }
+};
+
#define LLDB_OPTIONS_breakpoint_set
#include "CommandOptions.inc"
@@ -313,42 +1576,12 @@ public:
break;
case 'E': {
- LanguageType language = Language::GetLanguageTypeFromString(option_arg);
-
- llvm::StringRef error_context;
- switch (language) {
- case eLanguageTypeC89:
- case eLanguageTypeC:
- case eLanguageTypeC99:
- case eLanguageTypeC11:
- m_exception_language = eLanguageTypeC;
- break;
- case eLanguageTypeC_plus_plus:
- case eLanguageTypeC_plus_plus_03:
- case eLanguageTypeC_plus_plus_11:
- case eLanguageTypeC_plus_plus_14:
- m_exception_language = eLanguageTypeC_plus_plus;
- break;
- case eLanguageTypeObjC_plus_plus:
- error_context =
- "Set exception breakpoints separately for c++ and objective-c";
- break;
- case eLanguageTypeUnknown:
- error_context = "Unknown language type for exception breakpoint";
- break;
- default:
- if (Language *languagePlugin = Language::FindPlugin(language)) {
- if (languagePlugin->SupportsExceptionBreakpointsOnThrow() ||
- languagePlugin->SupportsExceptionBreakpointsOnCatch()) {
- m_exception_language = language;
- break;
- }
- }
- error_context = "Unsupported language type for exception breakpoint";
- }
- if (!error_context.empty())
- error = Status::FromError(CreateOptionParsingError(
- option_arg, short_option, long_option, error_context));
+ llvm::Expected<LanguageType> language = GetExceptionLanguageForLanguage(
+ option_arg, short_option, long_option);
+ if (language)
+ m_exception_language = *language;
+ else
+ error = Status::FromError(language.takeError());
} break;
case 'f':
@@ -608,8 +1841,8 @@ protected:
FileSpec file;
const size_t num_files = m_options.m_filenames.GetSize();
if (num_files == 0) {
- if (!GetDefaultFile(target, file, result)) {
- result.AppendError("no file supplied and no default file available");
+ if (!GetDefaultFile(target, m_exe_ctx.GetFramePtr(), file, result)) {
+ result.AppendError("no file supplied and no default file available.");
return;
}
} else if (num_files > 1) {
@@ -694,7 +1927,7 @@ protected:
if (num_files == 0 && !m_options.m_all_files) {
FileSpec file;
- if (!GetDefaultFile(target, file, result)) {
+ if (!GetDefaultFile(target, m_exe_ctx.GetFramePtr(), file, result)) {
result.AppendError(
"No files provided and could not find default file.");
return;
@@ -789,40 +2022,6 @@ protected:
}
private:
- bool GetDefaultFile(Target &target, FileSpec &file,
- CommandReturnObject &result) {
- // First use the Source Manager's default file. Then use the current stack
- // frame's file.
- if (auto maybe_file_and_line =
- target.GetSourceManager().GetDefaultFileAndLine()) {
- file = maybe_file_and_line->support_file_sp->GetSpecOnly();
- return true;
- }
-
- StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
- if (cur_frame == nullptr) {
- result.AppendError(
- "No selected frame to use to find the default file.");
- return false;
- }
- if (!cur_frame->HasDebugInformation()) {
- result.AppendError("Cannot use the selected frame to find the default "
- "file, it has no debug info.");
- return false;
- }
-
- const SymbolContext &sc =
- cur_frame->GetSymbolContext(eSymbolContextLineEntry);
- if (sc.line_entry.GetFile()) {
- file = sc.line_entry.GetFile();
- } else {
- result.AppendError("Can't find the file for the selected frame to "
- "use as the default file.");
- return false;
- }
- return true;
- }
-
BreakpointOptionGroup m_bp_opts;
BreakpointDummyOptionGroup m_dummy_options;
OptionGroupPythonClassWithDict m_python_class_options;
@@ -2408,6 +3607,8 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
new CommandObjectBreakpointDelete(interpreter));
CommandObjectSP set_command_object(
new CommandObjectBreakpointSet(interpreter));
+ CommandObjectSP add_command_object(
+ new CommandObjectBreakpointAdd(interpreter));
CommandObjectSP command_command_object(
new CommandObjectBreakpointCommand(interpreter));
CommandObjectSP modify_command_object(
@@ -2425,6 +3626,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
clear_command_object->SetCommandName("breakpoint clear");
delete_command_object->SetCommandName("breakpoint delete");
set_command_object->SetCommandName("breakpoint set");
+ add_command_object->SetCommandName("breakpoint add");
command_command_object->SetCommandName("breakpoint command");
modify_command_object->SetCommandName("breakpoint modify");
name_command_object->SetCommandName("breakpoint name");
@@ -2437,6 +3639,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
LoadSubCommand("clear", clear_command_object);
LoadSubCommand("delete", delete_command_object);
LoadSubCommand("set", set_command_object);
+ LoadSubCommand("add", add_command_object);
LoadSubCommand("command", command_command_object);
LoadSubCommand("modify", modify_command_object);
LoadSubCommand("name", name_command_object);
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index 0d9eb45..40f00c9 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -95,9 +95,9 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
StackFrame *frame = m_exe_ctx.GetFramePtr();
// Either the language was explicitly specified, or we check the frame.
- lldb::LanguageType language = m_expr_options.language;
- if (language == lldb::eLanguageTypeUnknown && frame)
- language = frame->GuessLanguage().AsLanguageType();
+ SourceLanguage language{m_expr_options.language};
+ if (!language && frame)
+ language = frame->GuessLanguage();
// Add a hint if object description was requested, but no description
// function was implemented.
@@ -119,8 +119,8 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
"^<\\S+: 0x[[:xdigit:]]{5,}>\\s*$");
if (GetDebugger().GetShowDontUsePoHint() && target_ptr &&
- (language == lldb::eLanguageTypeSwift ||
- language == lldb::eLanguageTypeObjC) &&
+ (language.AsLanguageType() == lldb::eLanguageTypeSwift ||
+ language.IsObjC()) &&
std::regex_match(output.data(), swift_class_regex)) {
result.AppendNote(
@@ -193,7 +193,8 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
// Second, try `expr` as a persistent variable.
if (expr.starts_with("$"))
- if (auto *state = target.GetPersistentExpressionStateForLanguage(language))
+ if (auto *state = target.GetPersistentExpressionStateForLanguage(
+ language.AsLanguageType()))
if (auto var_sp = state->GetVariable(expr))
if (auto valobj_sp = var_sp->GetValueObject()) {
dump_val_object(*valobj_sp);
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index 197bffe9..4919bd3 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -13,6 +13,7 @@
#include "lldb/Expression/UserExpression.h"
#include "lldb/Host/OptionParser.h"
#include "lldb/Host/StreamFile.h"
+#include "lldb/Host/common/DiagnosticsRendering.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -21,7 +22,6 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
-#include "lldb/Utility/DiagnosticsRendering.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 88a02dc..9133359 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -265,6 +265,29 @@ public:
Options *GetOptions() override { return &m_options; }
+private:
+ void SkipHiddenFrames(Thread &thread, uint32_t frame_idx) {
+ uint32_t candidate_idx = frame_idx;
+ const unsigned max_depth = 12;
+ for (unsigned num_try = 0; num_try < max_depth; ++num_try) {
+ if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {
+ candidate_idx = UINT32_MAX;
+ break;
+ }
+ candidate_idx += *m_options.relative_frame_offset;
+ if (auto candidate_sp = thread.GetStackFrameAtIndex(candidate_idx)) {
+ if (candidate_sp->IsHidden())
+ continue;
+ // Now candidate_idx is the first non-hidden frame.
+ break;
+ }
+ candidate_idx = UINT32_MAX;
+ break;
+ };
+ if (candidate_idx != UINT32_MAX)
+ m_options.relative_frame_offset = candidate_idx - frame_idx;
+ }
+
protected:
void DoExecute(Args &command, CommandReturnObject &result) override {
// No need to check "thread" for validity as eCommandRequiresThread ensures
@@ -278,28 +301,13 @@ protected:
if (frame_idx == UINT32_MAX)
frame_idx = 0;
- // If moving up/down by one, skip over hidden frames.
- if (*m_options.relative_frame_offset == 1 ||
- *m_options.relative_frame_offset == -1) {
- uint32_t candidate_idx = frame_idx;
- const unsigned max_depth = 12;
- for (unsigned num_try = 0; num_try < max_depth; ++num_try) {
- if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {
- candidate_idx = UINT32_MAX;
- break;
- }
- candidate_idx += *m_options.relative_frame_offset;
- if (auto candidate_sp = thread->GetStackFrameAtIndex(candidate_idx)) {
- if (candidate_sp->IsHidden())
- continue;
- // Now candidate_idx is the first non-hidden frame.
- break;
- }
- candidate_idx = UINT32_MAX;
- break;
- };
- if (candidate_idx != UINT32_MAX)
- m_options.relative_frame_offset = candidate_idx - frame_idx;
+ // If moving up/down by one, skip over hidden frames, unless we started
+ // in a hidden frame.
+ if ((*m_options.relative_frame_offset == 1 ||
+ *m_options.relative_frame_offset == -1)) {
+ if (auto current_frame_sp = thread->GetStackFrameAtIndex(frame_idx);
+ !current_frame_sp->IsHidden())
+ SkipHiddenFrames(*thread, frame_idx);
}
if (*m_options.relative_frame_offset < 0) {
diff --git a/lldb/source/Commands/CommandObjectMultiword.cpp b/lldb/source/Commands/CommandObjectMultiword.cpp
index a369557..e08b33c 100644
--- a/lldb/source/Commands/CommandObjectMultiword.cpp
+++ b/lldb/source/Commands/CommandObjectMultiword.cpp
@@ -205,7 +205,7 @@ void CommandObjectMultiword::Execute(const char *args_string,
.str());
}
error_msg.append("\n");
- result.AppendRawError(error_msg.c_str());
+ result.AppendError(error_msg);
}
std::string CommandObjectMultiword::GetSubcommandsHintText() {
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 7d326404..c17f12f 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -1603,8 +1603,8 @@ public:
Options *GetOptions() override { return &m_options; }
void PrintSignalHeader(Stream &str) {
- str.Printf("NAME PASS STOP NOTIFY\n");
- str.Printf("=========== ===== ===== ======\n");
+ str.Printf("NAME PASS STOP NOTIFY DESCRIPTION\n");
+ str.Printf("=========== ===== ===== ====== ===================\n");
}
void PrintSignal(Stream &str, int32_t signo, llvm::StringRef sig_name,
@@ -1615,9 +1615,16 @@ public:
str.Format("{0, -11} ", sig_name);
if (signals_sp->GetSignalInfo(signo, suppress, stop, notify)) {
- bool pass = !suppress;
+ const bool pass = !suppress;
str.Printf("%s %s %s", (pass ? "true " : "false"),
(stop ? "true " : "false"), (notify ? "true " : "false"));
+
+ const llvm::StringRef sig_description =
+ signals_sp->GetSignalNumberDescription(signo);
+ if (!sig_description.empty()) {
+ str.PutCString(" ");
+ str.PutCString(sig_description);
+ }
}
str.Printf("\n");
}
diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp
index 0b4599b..c9835e7 100644
--- a/lldb/source/Commands/CommandObjectSource.cpp
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -777,7 +777,7 @@ protected:
if (sc.function) {
Target &target = GetTarget();
- SupportFileSP start_file = std::make_shared<SupportFile>();
+ SupportFileNSP start_file = std::make_shared<SupportFile>();
uint32_t start_line;
uint32_t end_line;
FileSpec end_file;
@@ -1194,7 +1194,7 @@ protected:
// file(s) will be found and assigned to
// sc.comp_unit->GetPrimarySupportFile, which is NOT what we want to
// print. Instead, we want to print the one from the line entry.
- lldb::SupportFileSP found_file_sp = sc.line_entry.file_sp;
+ SupportFileNSP found_file_sp = sc.line_entry.file_sp;
target.GetSourceManager().DisplaySourceLinesWithLineNumbers(
found_file_sp, m_options.start_line, column, 0,
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 8de6521..322dd6c 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -51,6 +51,7 @@
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/ScriptedMetadata.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StructuredData.h"
@@ -60,6 +61,7 @@
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
@@ -5121,6 +5123,15 @@ public:
: CommandObjectParsed(interpreter, "target stop-hook delete",
"Delete a stop-hook.",
"target stop-hook delete [<idx>]") {
+ SetHelpLong(
+ R"(
+Deletes the stop hook by index.
+
+At any given stop, all enabled stop hooks that pass the stop filter will
+get a chance to run. That means if one stop-hook deletes another stop hook
+while executing, the deleted stop hook will still fire for the stop at which
+it was deleted.
+ )");
AddSimpleArgumentList(eArgTypeStopHookID, eArgRepeatStar);
}
@@ -5392,6 +5403,200 @@ public:
~CommandObjectTargetDump() override = default;
};
+#pragma mark CommandObjectTargetFrameProvider
+
+#define LLDB_OPTIONS_target_frame_provider_register
+#include "CommandOptions.inc"
+
+class CommandObjectTargetFrameProviderRegister : public CommandObjectParsed {
+public:
+ CommandObjectTargetFrameProviderRegister(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "target frame-provider register",
+ "Register frame provider for all threads in this target.", nullptr,
+ eCommandRequiresTarget),
+
+ m_class_options("target frame-provider", true, 'C', 'k', 'v', 0) {
+ m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
+ LLDB_OPT_SET_ALL);
+ m_all_options.Finalize();
+ }
+
+ ~CommandObjectTargetFrameProviderRegister() override = default;
+
+ Options *GetOptions() override { return &m_all_options; }
+
+ std::optional<std::string> GetRepeatCommand(Args &current_command_args,
+ uint32_t index) override {
+ return std::string("");
+ }
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(
+ m_class_options.GetName(), m_class_options.GetStructuredData());
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (!target)
+ target = &GetDebugger().GetDummyTarget();
+
+ // Create the interface for calling static methods.
+ ScriptedFrameProviderInterfaceSP interface_sp =
+ GetDebugger()
+ .GetScriptInterpreter()
+ ->CreateScriptedFrameProviderInterface();
+
+ // Create a descriptor from the metadata (applies to all threads by
+ // default).
+ ScriptedFrameProviderDescriptor descriptor(metadata_sp);
+ descriptor.interface_sp = interface_sp;
+
+ auto id_or_err = target->AddScriptedFrameProviderDescriptor(descriptor);
+ if (!id_or_err) {
+ result.SetError(id_or_err.takeError());
+ return;
+ }
+
+ result.AppendMessageWithFormat(
+ "successfully registered scripted frame provider '%s' for target\n",
+ m_class_options.GetName().c_str());
+ }
+
+ OptionGroupPythonClassWithDict m_class_options;
+ OptionGroupOptions m_all_options;
+};
+
+class CommandObjectTargetFrameProviderClear : public CommandObjectParsed {
+public:
+ CommandObjectTargetFrameProviderClear(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "target frame-provider clear",
+ "Clear all registered frame providers from this target.", nullptr,
+ eCommandRequiresTarget) {}
+
+ ~CommandObjectTargetFrameProviderClear() override = default;
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (!target) {
+ result.AppendError("invalid target");
+ return;
+ }
+
+ target->ClearScriptedFrameProviderDescriptors();
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+};
+
+class CommandObjectTargetFrameProviderList : public CommandObjectParsed {
+public:
+ CommandObjectTargetFrameProviderList(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "target frame-provider list",
+ "List all registered frame providers for the target.", nullptr,
+ eCommandRequiresTarget) {}
+
+ ~CommandObjectTargetFrameProviderList() override = default;
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (!target)
+ target = &GetDebugger().GetDummyTarget();
+
+ const auto &descriptors = target->GetScriptedFrameProviderDescriptors();
+ if (descriptors.empty()) {
+ result.AppendMessage("no frame providers registered for this target.");
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return;
+ }
+
+ result.AppendMessageWithFormat("%u frame provider(s) registered:\n\n",
+ descriptors.size());
+
+ for (const auto &entry : descriptors) {
+ const ScriptedFrameProviderDescriptor &descriptor = entry.second;
+ descriptor.Dump(&result.GetOutputStream());
+ result.GetOutputStream().PutChar('\n');
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+};
+
+class CommandObjectTargetFrameProviderRemove : public CommandObjectParsed {
+public:
+ CommandObjectTargetFrameProviderRemove(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "target frame-provider remove",
+ "Remove a registered frame provider from the target by id.",
+ "target frame-provider remove <provider-id>",
+ eCommandRequiresTarget) {
+ AddSimpleArgumentList(eArgTypeUnsignedInteger, eArgRepeatPlus);
+ }
+
+ ~CommandObjectTargetFrameProviderRemove() override = default;
+
+protected:
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (!target)
+ target = &GetDebugger().GetDummyTarget();
+
+ std::vector<uint32_t> removed_provider_ids;
+ for (size_t i = 0; i < command.GetArgumentCount(); i++) {
+ uint32_t provider_id = 0;
+ if (!llvm::to_integer(command[i].ref(), provider_id)) {
+ result.AppendError("target frame-provider remove requires integer "
+ "provider id argument");
+ return;
+ }
+
+ if (!target->RemoveScriptedFrameProviderDescriptor(provider_id)) {
+ result.AppendErrorWithFormat(
+ "no frame provider named '%u' found in target\n", provider_id);
+ return;
+ }
+ removed_provider_ids.push_back(provider_id);
+ }
+
+ if (size_t num_removed_providers = removed_provider_ids.size()) {
+ result.AppendMessageWithFormat(
+ "Successfully removed %zu frame-providers.\n", num_removed_providers);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ } else {
+ result.AppendError("0 frame providers removed.\n");
+ }
+ }
+};
+
+class CommandObjectTargetFrameProvider : public CommandObjectMultiword {
+public:
+ CommandObjectTargetFrameProvider(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(
+ interpreter, "target frame-provider",
+ "Commands for registering and viewing frame providers for the "
+ "target.",
+ "target frame-provider [<sub-command-options>] ") {
+ LoadSubCommand("register",
+ CommandObjectSP(new CommandObjectTargetFrameProviderRegister(
+ interpreter)));
+ LoadSubCommand("clear",
+ CommandObjectSP(
+ new CommandObjectTargetFrameProviderClear(interpreter)));
+ LoadSubCommand(
+ "list",
+ CommandObjectSP(new CommandObjectTargetFrameProviderList(interpreter)));
+ LoadSubCommand(
+ "remove", CommandObjectSP(
+ new CommandObjectTargetFrameProviderRemove(interpreter)));
+ }
+
+ ~CommandObjectTargetFrameProvider() override = default;
+};
+
#pragma mark CommandObjectMultiwordTarget
// CommandObjectMultiwordTarget
@@ -5407,6 +5612,9 @@ CommandObjectMultiwordTarget::CommandObjectMultiwordTarget(
CommandObjectSP(new CommandObjectTargetDelete(interpreter)));
LoadSubCommand("dump",
CommandObjectSP(new CommandObjectTargetDump(interpreter)));
+ LoadSubCommand(
+ "frame-provider",
+ CommandObjectSP(new CommandObjectTargetFrameProvider(interpreter)));
LoadSubCommand("list",
CommandObjectSP(new CommandObjectTargetList(interpreter)));
LoadSubCommand("select",
diff --git a/lldb/source/Commands/CommandObjectVersion.cpp b/lldb/source/Commands/CommandObjectVersion.cpp
index f13ec18..fb7e399 100644
--- a/lldb/source/Commands/CommandObjectVersion.cpp
+++ b/lldb/source/Commands/CommandObjectVersion.cpp
@@ -8,13 +8,21 @@
#include "CommandObjectVersion.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Version/Version.h"
+#include "llvm/ADT/StringExtras.h"
using namespace lldb;
using namespace lldb_private;
-// CommandObjectVersion
+#define LLDB_OPTIONS_version
+#include "CommandOptions.inc"
+
+llvm::ArrayRef<OptionDefinition>
+CommandObjectVersion::CommandOptions::GetDefinitions() {
+ return llvm::ArrayRef(g_version_options);
+}
CommandObjectVersion::CommandObjectVersion(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "version",
@@ -22,7 +30,45 @@ CommandObjectVersion::CommandObjectVersion(CommandInterpreter &interpreter)
CommandObjectVersion::~CommandObjectVersion() = default;
+// Dump the array values on a single line.
+static void dump(const StructuredData::Array &array, Stream &s) {
+ std::vector<std::string> values;
+ array.ForEach([&](StructuredData::Object *object) -> bool {
+ values.emplace_back(object->GetStringValue().str());
+ return true;
+ });
+
+ s << '[' << llvm::join(values, ", ") << ']';
+}
+
+// The default dump output is too verbose.
+static void dump(const StructuredData::Dictionary &config, Stream &s) {
+ config.ForEach(
+ [&](llvm::StringRef key, StructuredData::Object *object) -> bool {
+ assert(object);
+
+ StructuredData::Dictionary *value_dict = object->GetAsDictionary();
+ assert(value_dict);
+
+ StructuredData::ObjectSP value_sp = value_dict->GetValueForKey("value");
+ assert(value_sp);
+
+ s << " " << key << ": ";
+ if (StructuredData::Boolean *boolean = value_sp->GetAsBoolean())
+ s << (boolean ? "yes" : "no");
+ else if (StructuredData::Array *array = value_sp->GetAsArray())
+ dump(*array, s);
+ s << '\n';
+
+ return true;
+ });
+}
+
void CommandObjectVersion::DoExecute(Args &args, CommandReturnObject &result) {
result.AppendMessageWithFormat("%s\n", lldb_private::GetVersion());
+
+ if (m_options.verbose)
+ dump(*Debugger::GetBuildConfiguration(), result.GetOutputStream());
+
result.SetStatus(eReturnStatusSuccessFinishResult);
}
diff --git a/lldb/source/Commands/CommandObjectVersion.h b/lldb/source/Commands/CommandObjectVersion.h
index 4ba081b..ea2741c 100644
--- a/lldb/source/Commands/CommandObjectVersion.h
+++ b/lldb/source/Commands/CommandObjectVersion.h
@@ -9,20 +9,56 @@
#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTVERSION_H
#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTVERSION_H
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/Options.h"
namespace lldb_private {
-// CommandObjectVersion
-
class CommandObjectVersion : public CommandObjectParsed {
public:
CommandObjectVersion(CommandInterpreter &interpreter);
~CommandObjectVersion() override;
+ class CommandOptions : public Options {
+ public:
+ CommandOptions() = default;
+
+ ~CommandOptions() override = default;
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option) {
+ case 'v':
+ verbose = true;
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ verbose = false;
+ }
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
+
+ bool verbose;
+ };
+
+ Options *GetOptions() override { return &m_options; }
+
protected:
void DoExecute(Args &args, CommandReturnObject &result) override;
+
+private:
+ CommandOptions m_options;
};
} // namespace lldb_private
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index ed06131..d96354a 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -173,6 +173,14 @@ let Command = "breakpoint dummy" in {
"is provided, which prime new targets.">;
}
+let Command = "breakpoint names" in {
+ def breakpoint_name_option_names :
+ Option<"breakpoint-name", "N">, Group<1>,
+ Arg<"BreakpointName">,
+ Desc<"Adds this name to the list of names for this breakpoint. "
+ "Can be specified more than once.">;
+}
+
let Command = "breakpoint set" in {
def breakpoint_set_shlib
: Option<"shlib", "s">,
@@ -357,6 +365,124 @@ let Command = "breakpoint set" in {
*/
}
+let Command = "breakpoint add address" in {
+ def breakpoint_add_address_shlib : Option<"shlib", "s">, Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"Set the breakpoint at an address relative to sections in this shared"
+ " library.">;
+ def breakpoint_add_address_hardware : Option<"hardware", "H">,
+ Desc<"Require the breakpoint to use hardware breakpoints.">;
+}
+
+let Command = "breakpoint add exception" in {
+ def breakpoint_add_exception_hardware : Option<"hardware", "H">,
+ Desc<"Require the breakpoint to use hardware breakpoints.">;
+ def breakpoint_add_exception_typename : Option<"exception-typename", "O">,
+ Arg<"TypeName">, Desc<"The breakpoint will only stop if an "
+ "exception Object of this type is thrown. Can be repeated multiple times "
+ "to stop for multiple object types">;
+ def breakpoint_add_exception_stage : Option<"exception-stage", "E">,
+ Arg<"ExceptionStage">,
+ Desc<"Stop only at the specified exception stage. Can be specified more "
+ "than once to create a mask of stages.">;
+}
+
+let Command = "breakpoint add file" in {
+ def breakpoint_add_file_hardware : Option<"hardware", "H">,
+ Desc<"Require the breakpoint to use hardware breakpoints.">;
+ def breakpoint_add_file_line : Option<"line", "l">, Group<2>, Arg<"LineNum">,
+ Required,
+ Desc<"Specifies the line number on which to set this breakpoint.">;
+ def breakpoint_add_file_filename : Option<"filename", "f">, Group<2>,
+ Arg<"Filename">, Completion<"SourceFile">, Desc<"The file in which to seek "
+ "the specified source line.">;
+ def breakpoint_add_file_column : Option<"column", "u">, Arg<"ColumnNum">, Group<2>,
+ Desc<"Specifies the column number on which to set this breakpoint.">;
+ def breakpoint_add_file_shlib : Option<"shlib", "s">, Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"Set the breakpoint only in this shared library. Can repeat this "
+ "option multiple times to specify multiple shared libraries.">;
+ def breakpoint_add_file_move_to_nearest_code : Option<"move-to-nearest-code", "m">,
+ Arg<"Boolean">,
+ Desc<"Move breakpoints to nearest code. If not set the "
+ "target.move-to-nearest-code setting is used.">;
+ def breakpoint_add_file_address_slide : Option<"address-slide", "S">,
+ Arg<"Offset">,
+ Desc<"Add the specified offset to whatever address(es) the breakpoint "
+ "resolves to. At present this applies the offset directly as given, and "
+ "doesn't try to align it to instruction boundaries.">;
+ def breakpoint_add_file_skip_prologue : Option<"skip-prologue", "K">,
+ Arg<"Boolean">,
+ Desc<"Skip the prologue if the breakpoint is at the beginning of a "
+ "function. If not set the target.skip-prologue setting is used.">;
+}
+
+let Command = "breakpoint add name" in {
+ def breakpoint_add_name_hardware : Option<"hardware", "H">,
+ Desc<"Require the breakpoint to use hardware breakpoints.">;
+ def breakpoint_add_name_address_slide : Option<"address-slide", "S">,
+ Arg<"Offset">,
+ Desc<"Add the specified offset to whatever address(es) the breakpoint "
+ "resolves to. At present this applies the offset directly as given, and "
+ "doesn't try to align it to instruction boundaries.">;
+ def breakpoint_add_name_shlib : Option<"shlib", "s">, Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"Search for names only in this shared library. Can repeat this "
+ "option multiple times to specify multiple shared libraries.">;
+ def breakpoint_add_name_filename : Option<"filename", "f">,
+ Arg<"Filename">, Completion<"SourceFile">, Desc<"Only search for functions "
+ "defined in the given source file. Can be specified more than once.">;
+ def breakpoint_add_name_skip_prologue : Option<"skip-prologue", "K">,
+ Arg<"Boolean">,
+ 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_add_name_match_style : Option<"match-style", "m">,
+ Arg<"NameMatchStyle">,
+ Desc<"The style of matching to do when looking for candidate symbols - "
+ "auto if not specified.">;
+ def breakpoint_add_name_language : Option<"name-language", "L">,
+ Arg<"Language">,
+ Desc<"Only consider indentifiers from the given language when looking for "
+ "match candidates.">;
+}
+
+let Command = "breakpoint add pattern" in {
+ def breakpoint_add_pattern_hardware : Option<"hardware", "H">,
+ Desc<"Require the breakpoint to use hardware breakpoints.">;
+ def breakpoint_add_pattern_move_to_nearest_code : Option<"move-to-nearest-code", "m">,
+ Arg<"Boolean">,
+ Desc<"Move breakpoints to nearest code. If not set the "
+ "target.move-to-nearest-code setting is used.">;
+ def breakpoint_add_pattern_shlib : Option<"shlib", "s">, Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"Search for pattern matches only in this shared library. Can repeat this "
+ "option multiple times to specify multiple shared libraries.">;
+ def breakpoint_add_pattern_filename : Option<"filename", "f">, Group<1>,
+ Arg<"Filename">, Completion<"SourceFile">, Desc<"Limit the pattern search "
+ "to the specified source file. Can be specified more than once.">;
+ def breakpoint_add_pattern_name : Option<"name", "n">, Arg<"FunctionName">,
+ Completion<"Symbol">, Group<1>,
+ Desc<"Search for pattern matches only in functions matching the specified "
+ "function name using the 'auto' match style. Can be specified more than "
+ "once, and composes with the filename option.">;
+ def breakpoint_add_pattern_all_files : Option<"all-files", "a">, Group<2>,
+ Desc<"All files are searched for source pattern matches, limited by the "
+ "shlib argument.">;
+}
+
+let Command = "breakpoint add scripted" in {
+ def breakpoint_add_scripted_hardware : Option<"hardware", "H">,
+ Desc<"Require the breakpoint to use hardware breakpoints.">;
+ def breakpoint_add_scripted_filename : Option<"filename", "f">,
+ Arg<"Filename">, Completion<"SourceFile">, Desc<"The files in which to apply "
+ "the scripted resolver callback. Can repeat the option multiple times.">;
+ def breakpoint_add_scripted_shlib : Option<"shlib", "s">, Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"The module in which to apply the scripted resolver callback. Can "
+ "repeat this option multiple times to specify multiple shared libraries.">;
+}
+
+
let Command = "breakpoint clear" in {
def breakpoint_clear_file : Option<"file", "f">,
Group<1>,
@@ -2432,3 +2558,8 @@ let Command = "statistics dump" in {
"enabled state. Defaults to true for both summary and default "
"mode.">;
}
+
+let Command = "version" in {
+ def version_verbose : Option<"verbose", "v">,
+ Desc<"Include build configuration in version output.">;
+}
diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td
index 1be911c..a54d553 100644
--- a/lldb/source/Core/CoreProperties.td
+++ b/lldb/source/Core/CoreProperties.td
@@ -59,7 +59,7 @@ let Definition = "debugger" in {
Desc<"The default disassembly format string to use when disassembling instruction sequences.">;
def FrameFormat: Property<"frame-format", "FormatEntity">,
Global,
- DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
+ DefaultStringValue<"frame #${frame.index}: {${ansi.fg.cyan}${frame.pc}${ansi.normal}}{ ${module.file.basename}{`}}{${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
Desc<"The default frame format string to use when displaying stack frame information for threads.">;
def NotiftVoid: Property<"notify-void", "Boolean">,
Global,
@@ -235,7 +235,7 @@ let Definition = "debugger" in {
Desc<"If true, LLDB will automatically escape non-printable and escape characters when formatting strings.">;
def FrameFormatUnique: Property<"frame-format-unique", "FormatEntity">,
Global,
- DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
+ DefaultStringValue<"frame #${frame.index}: {${ansi.fg.cyan}${frame.pc}${ansi.normal}}{ ${module.file.basename}{`}}{${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
Desc<"The default frame format string to use when displaying stack frame information for threads from thread backtrace unique.">;
def ShowAutosuggestion: Property<"show-autosuggestion", "Boolean">,
Global,
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index b37d9d3..99f4a72 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -21,12 +21,14 @@
#include "lldb/Core/Telemetry.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/Expression/REPL.h"
+#include "lldb/Host/Config.h"
#include "lldb/Host/File.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/StreamFile.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/XML.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionValue.h"
@@ -965,7 +967,8 @@ llvm::StringRef Debugger::GetStaticBroadcasterClass() {
Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
: UserID(g_unique_id++),
Properties(std::make_shared<OptionValueProperties>()),
- m_input_file_sp(std::make_shared<NativeFile>(stdin, NativeFile::Unowned)),
+ m_input_file_sp(std::make_shared<NativeFile>(
+ stdin, File::eOpenOptionReadOnly, NativeFile::Unowned)),
m_output_stream_sp(std::make_shared<LockableStreamFile>(
stdout, NativeFile::Unowned, m_output_mutex)),
m_error_stream_sp(std::make_shared<LockableStreamFile>(
@@ -1172,7 +1175,8 @@ Status Debugger::SetInputString(const char *data) {
return result;
}
- SetInputFile((FileSP)std::make_shared<NativeFile>(commands_file, true));
+ SetInputFile((FileSP)std::make_shared<NativeFile>(
+ commands_file, File::eOpenOptionReadOnly, true));
return result;
}
@@ -1378,7 +1382,8 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in,
in = GetInputFileSP();
// If there is nothing, use stdin
if (!in)
- in = std::make_shared<NativeFile>(stdin, NativeFile::Unowned);
+ in = std::make_shared<NativeFile>(stdin, File::eOpenOptionReadOnly,
+ NativeFile::Unowned);
}
// If no STDOUT has been set, then set it appropriately
if (!out || !out->GetUnlockedFile().IsValid()) {
@@ -2439,3 +2444,56 @@ llvm::ThreadPoolInterface &Debugger::GetThreadPool() {
"Debugger::GetThreadPool called before Debugger::Initialize");
return *g_thread_pool;
}
+
+static void AddBoolConfigEntry(StructuredData::Dictionary &dict,
+ llvm::StringRef name, bool value,
+ llvm::StringRef description) {
+ auto entry_up = std::make_unique<StructuredData::Dictionary>();
+ entry_up->AddBooleanItem("value", value);
+ entry_up->AddStringItem("description", description);
+ dict.AddItem(name, std::move(entry_up));
+}
+
+static void AddLLVMTargets(StructuredData::Dictionary &dict) {
+ auto array_up = std::make_unique<StructuredData::Array>();
+#define LLVM_TARGET(target) \
+ array_up->AddItem(std::make_unique<StructuredData::String>(#target));
+#include "llvm/Config/Targets.def"
+ auto entry_up = std::make_unique<StructuredData::Dictionary>();
+ entry_up->AddItem("value", std::move(array_up));
+ entry_up->AddStringItem("description", "A list of configured LLVM targets.");
+ dict.AddItem("targets", std::move(entry_up));
+}
+
+StructuredData::DictionarySP Debugger::GetBuildConfiguration() {
+ auto config_up = std::make_unique<StructuredData::Dictionary>();
+ AddBoolConfigEntry(
+ *config_up, "xml", XMLDocument::XMLEnabled(),
+ "A boolean value that indicates if XML support is enabled in LLDB");
+ AddBoolConfigEntry(
+ *config_up, "curl", LLVM_ENABLE_CURL,
+ "A boolean value that indicates if CURL support is enabled in LLDB");
+ AddBoolConfigEntry(
+ *config_up, "curses", LLDB_ENABLE_CURSES,
+ "A boolean value that indicates if curses support is enabled in LLDB");
+ AddBoolConfigEntry(
+ *config_up, "editline", LLDB_ENABLE_LIBEDIT,
+ "A boolean value that indicates if editline support is enabled in LLDB");
+ AddBoolConfigEntry(*config_up, "editline_wchar", LLDB_EDITLINE_USE_WCHAR,
+ "A boolean value that indicates if editline wide "
+ "characters support is enabled in LLDB");
+ AddBoolConfigEntry(
+ *config_up, "lzma", LLDB_ENABLE_LZMA,
+ "A boolean value that indicates if lzma support is enabled in LLDB");
+ AddBoolConfigEntry(
+ *config_up, "python", LLDB_ENABLE_PYTHON,
+ "A boolean value that indicates if python support is enabled in LLDB");
+ AddBoolConfigEntry(
+ *config_up, "lua", LLDB_ENABLE_LUA,
+ "A boolean value that indicates if lua support is enabled in LLDB");
+ AddBoolConfigEntry(*config_up, "fbsdvmcore", LLDB_ENABLE_FBSDVMCORE,
+ "A boolean value that indicates if fbsdvmcore support is "
+ "enabled in LLDB");
+ AddLLVMTargets(*config_up);
+ return config_up;
+}
diff --git a/lldb/source/Core/DemangledNameInfo.cpp b/lldb/source/Core/DemangledNameInfo.cpp
index 76f8987..16fbfda 100644
--- a/lldb/source/Core/DemangledNameInfo.cpp
+++ b/lldb/source/Core/DemangledNameInfo.cpp
@@ -16,7 +16,7 @@ bool TrackingOutputBuffer::shouldTrack() const {
if (!isPrintingTopLevelFunctionType())
return false;
- if (isGtInsideTemplateArgs())
+ if (isInsideTemplateArgs())
return false;
if (NameInfo.ArgumentsRange.first > 0)
@@ -29,7 +29,7 @@ bool TrackingOutputBuffer::canFinalize() const {
if (!isPrintingTopLevelFunctionType())
return false;
- if (isGtInsideTemplateArgs())
+ if (isInsideTemplateArgs())
return false;
if (NameInfo.ArgumentsRange.first == 0)
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
index f2ed1f7..2d73df1 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -208,7 +208,7 @@ Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {
return {};
LineEntry prologue_end_line = sc.line_entry;
- SupportFileSP func_decl_file_sp;
+ SupportFileNSP func_decl_file_sp = std::make_shared<SupportFile>();
uint32_t func_decl_line;
sc.function->GetStartLineSourceInfo(func_decl_file_sp, func_decl_line);
@@ -286,6 +286,18 @@ bool Disassembler::ElideMixedSourceAndDisassemblyLine(
return false;
}
+static constexpr const llvm::StringLiteral kUndefLocation = "undef";
+static constexpr const llvm::StringLiteral kUndefLocationFormatted = "<undef>";
+static void
+AddVariableAnnotationToVector(std::vector<VariableAnnotation> &annotations,
+ VariableAnnotation annotation_entity,
+ const bool is_live) {
+ annotation_entity.is_live = is_live;
+ if (!is_live)
+ annotation_entity.location_description = kUndefLocation;
+ annotations.push_back(std::move(annotation_entity));
+}
+
// 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
@@ -299,17 +311,38 @@ bool Disassembler::ElideMixedSourceAndDisassemblyLine(
// 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> VariableAnnotator::Annotate(Instruction &inst) {
+ std::vector<VariableAnnotation> structured_annotations =
+ AnnotateStructured(inst);
+
std::vector<std::string> events;
+ events.reserve(structured_annotations.size());
+
+ for (const VariableAnnotation &annotation : structured_annotations) {
+ const llvm::StringRef location =
+ (annotation.location_description == kUndefLocation
+ ? llvm::StringRef(kUndefLocationFormatted)
+ : llvm::StringRef(annotation.location_description));
+
+ events.push_back(
+ llvm::formatv("{0} = {1}", annotation.variable_name, location).str());
+ }
+
+ return events;
+}
+
+std::vector<VariableAnnotation>
+VariableAnnotator::AnnotateStructured(Instruction &inst) {
+ std::vector<VariableAnnotation> annotations;
+
+ auto module_sp = inst.GetAddress().GetModule();
- // If we lost module context, everything becomes <undef>.
+ // If we lost module context, mark all live variables as UndefLocation.
if (!module_sp) {
- for (const auto &KV : Live_)
- events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
- Live_.clear();
- return events;
+ for (const auto &KV : m_live_vars)
+ AddVariableAnnotationToVector(annotations, KV.second, false);
+ m_live_vars.clear();
+ return annotations;
}
// Resolve function/block at this *file* address.
@@ -319,13 +352,13 @@ VariableAnnotator::annotate(Instruction &inst, Target &target,
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;
+ for (const auto &KV : m_live_vars)
+ AddVariableAnnotationToVector(annotations, KV.second, false);
+ m_live_vars.clear();
+ return annotations;
}
- // Collect in-scope variables for this instruction into Current.
+ // Collect in-scope variables for this instruction into current_vars.
VariableList var_list;
// Innermost block containing iaddr.
if (Block *B = sc.block) {
@@ -341,7 +374,7 @@ VariableAnnotator::annotate(Instruction &inst, Target &target,
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());
+ lldb::ABISP abi_sp = ABI::FindPlugin(nullptr, module_sp->GetArchitecture());
ABI *abi = abi_sp.get();
llvm::DIDumpOptions opts;
@@ -349,7 +382,7 @@ VariableAnnotator::annotate(Instruction &inst, Target &target,
// Prefer "register-only" output when we have an ABI.
opts.PrintRegisterOnly = static_cast<bool>(abi_sp);
- llvm::DenseMap<lldb::user_id_t, VarState> Current;
+ llvm::DenseMap<lldb::user_id_t, VariableAnnotation> current_vars;
for (size_t i = 0, e = var_list.GetSize(); i != e; ++i) {
lldb::VariableSP v = var_list.GetVariableAtIndex(i);
@@ -376,35 +409,50 @@ VariableAnnotator::annotate(Instruction &inst, Target &target,
if (loc.empty())
continue;
- Current.try_emplace(v->GetID(),
- VarState{std::string(name), std::string(loc)});
+ std::optional<std::string> decl_file;
+ std::optional<uint32_t> decl_line;
+ std::optional<std::string> type_name;
+
+ const Declaration &decl = v->GetDeclaration();
+ if (decl.GetFile()) {
+ decl_file = decl.GetFile().GetFilename().AsCString();
+ if (decl.GetLine() > 0)
+ decl_line = decl.GetLine();
+ }
+
+ if (Type *type = v->GetType())
+ if (const char *type_str = type->GetName().AsCString())
+ type_name = type_str;
+
+ current_vars.try_emplace(
+ v->GetID(),
+ VariableAnnotation{std::string(name), std::string(loc), true,
+ entry.expr->GetRegisterKind(), entry.file_range,
+ decl_file, decl_line, type_name});
}
- // Diff Live_ → Current.
+ // Diff m_live_vars → current_vars.
- // 1) Starts/changes: iterate Current and compare with Live_.
- for (const auto &KV : Current) {
- auto it = Live_.find(KV.first);
- if (it == Live_.end()) {
+ // 1) Starts/changes: iterate current_vars and compare with m_live_vars.
+ for (const auto &KV : current_vars) {
+ auto it = m_live_vars.find(KV.first);
+ if (it == m_live_vars.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) {
+ AddVariableAnnotationToVector(annotations, KV.second, true);
+ else if (it->second.location_description != KV.second.location_description)
// Location changed.
- events.emplace_back(
- llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());
- }
+ AddVariableAnnotationToVector(annotations, KV.second, true);
}
- // 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());
- }
+ // 2) Ends: anything that was live but is not in current_vars becomes
+ // UndefLocation.
+ for (const auto &KV : m_live_vars)
+ if (!current_vars.count(KV.first))
+ AddVariableAnnotationToVector(annotations, KV.second, false);
// Commit new state.
- Live_ = std::move(Current);
- return events;
+ m_live_vars = std::move(current_vars);
+ return annotations;
}
void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
@@ -539,7 +587,8 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
LineEntry prologue_end_line = sc.line_entry;
if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc,
prologue_end_line)) {
- SupportFileSP func_decl_file_sp;
+ SupportFileNSP func_decl_file_sp =
+ std::make_shared<SupportFile>();
uint32_t func_decl_line;
sc.function->GetStartLineSourceInfo(func_decl_file_sp,
func_decl_line);
@@ -676,7 +725,7 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
address_text_size);
if ((options & eOptionVariableAnnotations) && target_sp) {
- auto annotations = annot.annotate(*inst, *target_sp, module_sp);
+ auto annotations = annot.Annotate(*inst);
if (!annotations.empty()) {
const size_t annotation_column = 100;
inst_line.FillLastLineToColumn(annotation_column, ' ');
@@ -1340,6 +1389,11 @@ bool PseudoInstruction::DoesBranch() {
return false;
}
+bool PseudoInstruction::IsBarrier() {
+ // This is NOT a valid question for a pseudo instruction.
+ return false;
+}
+
bool PseudoInstruction::HasDelaySlot() {
// This is NOT a valid question for a pseudo instruction.
return false;
diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp
index 7580b15..31d277b 100644
--- a/lldb/source/Core/DynamicLoader.cpp
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -165,7 +165,8 @@ ModuleSP DynamicLoader::FindModuleViaTarget(const FileSpec &file) {
if (ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec))
return module_sp;
- if (ModuleSP module_sp = target.GetOrCreateModule(module_spec, false))
+ if (ModuleSP module_sp =
+ target.GetOrCreateModule(module_spec, /*notify=*/false))
return module_sp;
return nullptr;
@@ -227,6 +228,7 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress(
}
}
ModuleSpec module_spec;
+ module_spec.SetTarget(target.shared_from_this());
module_spec.GetUUID() = uuid;
FileSpec name_filespec(name);
if (FileSystem::Instance().Exists(name_filespec))
@@ -238,8 +240,8 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress(
// Has lldb already seen a module with this UUID?
// Or have external lookup enabled in DebugSymbols on macOS.
if (!module_sp)
- error = ModuleList::GetSharedModule(module_spec, module_sp, nullptr,
- nullptr, nullptr);
+ error =
+ ModuleList::GetSharedModule(module_spec, module_sp, nullptr, nullptr);
// Can lldb's symbol/executable location schemes
// find an executable and symbol file.
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 491f5c6..faafb5e 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -27,6 +27,7 @@
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/BorrowedStackFrame.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/Language.h"
@@ -109,6 +110,7 @@ constexpr Definition g_frame_child_entries[] = {
g_string_entry),
Definition("is-artificial", EntryType::FrameIsArtificial),
Definition("kind", EntryType::FrameKind),
+ Definition("borrowed-info", EntryType::FrameBorrowedInfo),
};
constexpr Definition g_function_child_entries[] = {
@@ -382,6 +384,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) {
ENUM_TO_CSTR(FrameRegisterByName);
ENUM_TO_CSTR(FrameIsArtificial);
ENUM_TO_CSTR(FrameKind);
+ ENUM_TO_CSTR(FrameBorrowedInfo);
ENUM_TO_CSTR(ScriptFrame);
ENUM_TO_CSTR(FunctionID);
ENUM_TO_CSTR(FunctionDidChange);
@@ -1681,10 +1684,9 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
const Address &pc_addr = frame->GetFrameCodeAddress();
- if (pc_addr.IsValid() || frame->IsSynthetic()) {
+ if (pc_addr.IsValid())
if (DumpAddressAndContent(s, sc, exe_ctx, pc_addr, false))
return true;
- }
}
}
return false;
@@ -1761,6 +1763,22 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
return false;
}
+ case Entry::Type::FrameBorrowedInfo: {
+ if (exe_ctx)
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
+ if (BorrowedStackFrame *borrowed_frame =
+ llvm::dyn_cast<BorrowedStackFrame>(frame)) {
+ if (lldb::StackFrameSP borrowed_from_sp =
+ borrowed_frame->GetBorrowedFrame()) {
+ s.Printf(" [borrowed from frame #%u]",
+ borrowed_from_sp->GetFrameIndex());
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
case Entry::Type::ScriptFrame:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
@@ -1789,70 +1807,91 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
return initial_function;
case Entry::Type::FunctionName: {
- if (!sc)
- return false;
+ if (sc) {
+ Language *language_plugin = nullptr;
+ bool language_plugin_handled = false;
+ StreamString ss;
- Language *language_plugin = nullptr;
- bool language_plugin_handled = false;
- StreamString ss;
+ if (sc->function)
+ language_plugin = Language::FindPlugin(sc->function->GetLanguage());
+ else if (sc->symbol)
+ language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
- if (sc->function)
- language_plugin = Language::FindPlugin(sc->function->GetLanguage());
- else if (sc->symbol)
- language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
+ if (language_plugin)
+ language_plugin_handled = language_plugin->GetFunctionDisplayName(
+ *sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
- if (language_plugin)
- language_plugin_handled = language_plugin->GetFunctionDisplayName(
- *sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
+ if (language_plugin_handled) {
+ s << ss.GetString();
+ return true;
+ }
- if (language_plugin_handled) {
- s << ss.GetString();
- return true;
+ const char *name = sc->GetPossiblyInlinedFunctionName()
+ .GetName(Mangled::NamePreference::ePreferDemangled)
+ .AsCString();
+ if (name) {
+ s.PutCString(name);
+ return true;
+ }
}
- const char *name = sc->GetPossiblyInlinedFunctionName()
- .GetName(Mangled::NamePreference::ePreferDemangled)
- .AsCString();
- if (!name)
- return false;
-
- s.PutCString(name);
-
- return true;
+ // Fallback to frame methods if available.
+ if (exe_ctx) {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ if (frame) {
+ const char *name = frame->GetFunctionName();
+ if (name) {
+ s.PutCString(name);
+ return true;
+ }
+ }
+ }
+ return false;
}
case Entry::Type::FunctionNameNoArgs: {
- if (!sc)
- return false;
-
- Language *language_plugin = nullptr;
- bool language_plugin_handled = false;
- StreamString ss;
- if (sc->function)
- language_plugin = Language::FindPlugin(sc->function->GetLanguage());
- else if (sc->symbol)
- language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
-
- if (language_plugin)
- language_plugin_handled = language_plugin->GetFunctionDisplayName(
- *sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
- ss);
+ if (sc) {
+ Language *language_plugin = nullptr;
+ bool language_plugin_handled = false;
+ StreamString ss;
+ if (sc->function)
+ language_plugin = Language::FindPlugin(sc->function->GetLanguage());
+ else if (sc->symbol)
+ language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
+
+ if (language_plugin)
+ language_plugin_handled = language_plugin->GetFunctionDisplayName(
+ *sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
+ ss);
+
+ if (language_plugin_handled) {
+ s << ss.GetString();
+ return true;
+ }
- if (language_plugin_handled) {
- s << ss.GetString();
- return true;
+ const char *name =
+ sc->GetPossiblyInlinedFunctionName()
+ .GetName(
+ Mangled::NamePreference::ePreferDemangledWithoutArguments)
+ .AsCString();
+ if (name) {
+ s.PutCString(name);
+ return true;
+ }
}
- const char *name =
- sc->GetPossiblyInlinedFunctionName()
- .GetName(Mangled::NamePreference::ePreferDemangledWithoutArguments)
- .AsCString();
- if (!name)
- return false;
-
- s.PutCString(name);
-
- return true;
+ // Fallback to frame methods if available.
+ if (exe_ctx) {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ if (frame) {
+ const char *name = frame->GetFunctionName();
+ if (name) {
+ s.PutCString(name);
+ return true;
+ }
+ }
+ }
+ return false;
}
case Entry::Type::FunctionPrefix:
@@ -1879,13 +1918,26 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
}
case Entry::Type::FunctionNameWithArgs: {
- if (!sc)
- return false;
+ if (sc) {
+ if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
+ return true;
- if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
- return true;
+ if (HandleFunctionNameWithArgs(s, exe_ctx, *sc))
+ return true;
+ }
- return HandleFunctionNameWithArgs(s, exe_ctx, *sc);
+ // Fallback to frame methods if available.
+ if (exe_ctx) {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ if (frame) {
+ const char *name = frame->GetDisplayFunctionName();
+ if (name) {
+ s.PutCString(name);
+ return true;
+ }
+ }
+ }
+ return false;
}
case Entry::Type::FunctionMangledName: {
if (!sc)
@@ -1927,12 +1979,11 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
case Entry::Type::FunctionPCOffset:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
- if (frame) {
+ if (frame)
if (DumpAddressOffsetFromFunction(s, sc, exe_ctx,
frame->GetFrameCodeAddress(), false,
false, false))
return true;
- }
}
return false;
@@ -1956,11 +2007,8 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
case Entry::Type::LineEntryFile:
if (sc && sc->line_entry.IsValid()) {
- Module *module = sc->module_sp.get();
- if (module) {
- if (DumpFile(s, sc->line_entry.GetFile(), (FileKind)entry.number))
- return true;
- }
+ if (DumpFile(s, sc->line_entry.GetFile(), (FileKind)entry.number))
+ return true;
}
return false;
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index f27a95d..da2c188 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -52,9 +52,6 @@
#include "lldb/Host/windows/PosixApi.h"
#endif
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
-#include "Plugins/Language/ObjC/ObjCLanguage.h"
-
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DJB.h"
@@ -646,26 +643,13 @@ void Module::FindCompileUnits(const FileSpec &path,
Module::LookupInfo::LookupInfo(ConstString name,
FunctionNameType name_type_mask,
- LanguageType language)
- : m_name(name), m_lookup_name(name), m_language(language) {
+ LanguageType lang_type)
+ : m_name(name), m_lookup_name(name), m_language(lang_type) {
std::optional<ConstString> basename;
-
- std::vector<Language *> languages;
- {
- std::vector<LanguageType> lang_types;
- if (language != eLanguageTypeUnknown)
- lang_types.push_back(language);
- else
- lang_types = {eLanguageTypeObjC, eLanguageTypeC_plus_plus};
-
- for (LanguageType lang_type : lang_types) {
- if (Language *lang = Language::FindPlugin(lang_type))
- languages.push_back(lang);
- }
- }
+ Language *lang = Language::FindPlugin(lang_type);
if (name_type_mask & eFunctionNameTypeAuto) {
- for (Language *lang : languages) {
+ if (lang) {
auto info = lang->GetFunctionNameInfo(name);
if (info.first != eFunctionNameTypeNone) {
m_name_type_mask |= info.first;
@@ -682,7 +666,7 @@ Module::LookupInfo::LookupInfo(ConstString name,
} else {
m_name_type_mask = name_type_mask;
- for (Language *lang : languages) {
+ if (lang) {
auto info = lang->GetFunctionNameInfo(name);
if (info.first & m_name_type_mask) {
// If the user asked for FunctionNameTypes that aren't possible,
@@ -691,14 +675,12 @@ Module::LookupInfo::LookupInfo(ConstString name,
// ObjC)
m_name_type_mask &= info.first;
basename = info.second;
- break;
- }
- // Still try and get a basename in case someone specifies a name type mask
- // of eFunctionNameTypeFull and a name like "A::func"
- if (name_type_mask & eFunctionNameTypeFull &&
- info.first != eFunctionNameTypeNone && !basename && info.second) {
+ } else if (name_type_mask & eFunctionNameTypeFull &&
+ info.first != eFunctionNameTypeNone && !basename &&
+ info.second) {
+ // Still try and get a basename in case someone specifies a name type
+ // mask of eFunctionNameTypeFull and a name like "A::func"
basename = info.second;
- break;
}
}
}
@@ -714,6 +696,36 @@ Module::LookupInfo::LookupInfo(ConstString name,
}
}
+std::vector<Module::LookupInfo>
+Module::LookupInfo::MakeLookupInfos(ConstString name,
+ lldb::FunctionNameType name_type_mask,
+ lldb::LanguageType lang_type) {
+ std::vector<LanguageType> lang_types;
+ if (lang_type != eLanguageTypeUnknown) {
+ lang_types.push_back(lang_type);
+ } else {
+ // If the language type was not specified, look up in every language
+ // available.
+ Language::ForEach([&](Language *lang) {
+ auto lang_type = lang->GetLanguageType();
+ if (!llvm::is_contained(lang_types, lang_type))
+ lang_types.push_back(lang_type);
+ return IterationAction::Continue;
+ });
+
+ if (lang_types.empty())
+ lang_types = {eLanguageTypeObjC, eLanguageTypeC_plus_plus};
+ }
+
+ std::vector<Module::LookupInfo> infos;
+ infos.reserve(lang_types.size());
+ for (LanguageType lang_type : lang_types) {
+ Module::LookupInfo info(name, name_type_mask, lang_type);
+ infos.push_back(info);
+ }
+ return infos;
+}
+
bool Module::LookupInfo::NameMatchesLookupInfo(
ConstString function_name, LanguageType language_type) const {
// We always keep unnamed symbols
@@ -808,22 +820,21 @@ void Module::LookupInfo::Prune(SymbolContextList &sc_list,
}
}
-void Module::FindFunctions(const Module::LookupInfo &lookup_info,
+void Module::FindFunctions(llvm::ArrayRef<Module::LookupInfo> lookup_infos,
const CompilerDeclContext &parent_decl_ctx,
const ModuleFunctionSearchOptions &options,
SymbolContextList &sc_list) {
- // Find all the functions (not symbols, but debug information functions...
- if (SymbolFile *symbols = GetSymbolFile()) {
+ for (auto &lookup_info : lookup_infos) {
+ SymbolFile *symbols = GetSymbolFile();
+ if (!symbols)
+ continue;
+
symbols->FindFunctions(lookup_info, parent_decl_ctx,
options.include_inlines, sc_list);
- // Now check our symbol table for symbols that are code symbols if
- // requested
- if (options.include_symbols) {
- if (Symtab *symtab = symbols->GetSymtab()) {
+ if (options.include_symbols)
+ if (Symtab *symtab = symbols->GetSymtab())
symtab->FindFunctionSymbols(lookup_info.GetLookupName(),
lookup_info.GetNameTypeMask(), sc_list);
- }
- }
}
}
@@ -832,13 +843,16 @@ void Module::FindFunctions(ConstString name,
FunctionNameType name_type_mask,
const ModuleFunctionSearchOptions &options,
SymbolContextList &sc_list) {
- const size_t old_size = sc_list.GetSize();
- LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown);
- FindFunctions(lookup_info, parent_decl_ctx, options, sc_list);
- if (name_type_mask & eFunctionNameTypeAuto) {
- const size_t new_size = sc_list.GetSize();
- if (old_size < new_size)
- lookup_info.Prune(sc_list, old_size);
+ std::vector<LookupInfo> lookup_infos =
+ LookupInfo::MakeLookupInfos(name, name_type_mask, eLanguageTypeUnknown);
+ for (auto &lookup_info : lookup_infos) {
+ const size_t old_size = sc_list.GetSize();
+ FindFunctions(lookup_info, parent_decl_ctx, options, sc_list);
+ if (name_type_mask & eFunctionNameTypeAuto) {
+ const size_t new_size = sc_list.GetSize();
+ if (old_size < new_size)
+ lookup_info.Prune(sc_list, old_size);
+ }
}
}
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index c40612c..be6ff72 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
@@ -19,6 +20,8 @@
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Target.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpecList.h"
@@ -26,6 +29,7 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/UUID.h"
#include "lldb/lldb-defines.h"
+#include "llvm/Support/ThreadPool.h"
#if defined(_WIN32)
#include "lldb/Host/windows/PosixApi.h"
@@ -449,21 +453,22 @@ void ModuleList::FindFunctions(ConstString name,
FunctionNameType name_type_mask,
const ModuleFunctionSearchOptions &options,
SymbolContextList &sc_list) const {
- const size_t old_size = sc_list.GetSize();
-
if (name_type_mask & eFunctionNameTypeAuto) {
- Module::LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown);
-
+ std::vector<Module::LookupInfo> lookup_infos =
+ Module::LookupInfo::MakeLookupInfos(name, name_type_mask,
+ eLanguageTypeUnknown);
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
- for (const ModuleSP &module_sp : m_modules) {
- module_sp->FindFunctions(lookup_info, CompilerDeclContext(), options,
- sc_list);
- }
-
- const size_t new_size = sc_list.GetSize();
+ for (const auto &lookup_info : lookup_infos) {
+ const size_t old_size = sc_list.GetSize();
+ for (const ModuleSP &module_sp : m_modules) {
+ module_sp->FindFunctions(lookup_info, CompilerDeclContext(), options,
+ sc_list);
+ }
- if (old_size < new_size)
- lookup_info.Prune(sc_list, old_size);
+ const size_t new_size = sc_list.GetSize();
+ if (old_size < new_size)
+ lookup_info.Prune(sc_list, old_size);
+ }
} else {
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
for (const ModuleSP &module_sp : m_modules) {
@@ -476,21 +481,24 @@ void ModuleList::FindFunctions(ConstString name,
void ModuleList::FindFunctionSymbols(ConstString name,
lldb::FunctionNameType name_type_mask,
SymbolContextList &sc_list) {
- const size_t old_size = sc_list.GetSize();
-
if (name_type_mask & eFunctionNameTypeAuto) {
- Module::LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown);
+ std::vector<Module::LookupInfo> lookup_infos =
+ Module::LookupInfo::MakeLookupInfos(name, name_type_mask,
+ eLanguageTypeUnknown);
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
- for (const ModuleSP &module_sp : m_modules) {
- module_sp->FindFunctionSymbols(lookup_info.GetLookupName(),
- lookup_info.GetNameTypeMask(), sc_list);
- }
+ for (const auto &lookup_info : lookup_infos) {
+ const size_t old_size = sc_list.GetSize();
+ for (const ModuleSP &module_sp : m_modules) {
+ module_sp->FindFunctionSymbols(lookup_info.GetLookupName(),
+ lookup_info.GetNameTypeMask(), sc_list);
+ }
- const size_t new_size = sc_list.GetSize();
+ const size_t new_size = sc_list.GetSize();
- if (old_size < new_size)
- lookup_info.Prune(sc_list, old_size);
+ if (old_size < new_size)
+ lookup_info.Prune(sc_list, old_size);
+ }
} else {
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
for (const ModuleSP &module_sp : m_modules) {
@@ -1038,9 +1046,9 @@ size_t ModuleList::RemoveOrphanSharedModules(bool mandatory) {
Status
ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
- bool *did_create_ptr, bool always_create) {
+ bool *did_create_ptr, bool always_create,
+ bool invoke_locate_callback) {
SharedModuleList &shared_module_list = GetSharedModuleList();
std::lock_guard<std::recursive_mutex> guard(shared_module_list.GetMutex());
char path[PATH_MAX];
@@ -1095,6 +1103,22 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
if (module_sp)
return error;
+ // Try target's platform locate module callback before second attempt.
+ if (invoke_locate_callback) {
+ TargetSP target_sp = module_spec.GetTargetSP();
+ if (target_sp && target_sp->IsValid()) {
+ if (PlatformSP platform_sp = target_sp->GetPlatform()) {
+ FileSpec symbol_file_spec;
+ platform_sp->CallLocateModuleCallbackIfSet(
+ module_spec, module_sp, symbol_file_spec, did_create_ptr);
+ if (module_sp) {
+ // The callback found a module.
+ return error;
+ }
+ }
+ }
+ }
+
module_sp = std::make_shared<Module>(module_spec);
// Make sure there are a module and an object file since we can specify a
// valid file path with an architecture that might not be in that file. By
@@ -1122,10 +1146,16 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp,
module_sp.reset();
}
- if (module_search_paths_ptr) {
- const auto num_directories = module_search_paths_ptr->GetSize();
+ // Get module search paths from the target if available.
+ lldb::TargetSP target_sp = module_spec.GetTargetSP();
+ FileSpecList module_search_paths;
+ if (target_sp)
+ module_search_paths = target_sp->GetExecutableSearchPaths();
+
+ if (!module_search_paths.IsEmpty()) {
+ const auto num_directories = module_search_paths.GetSize();
for (size_t idx = 0; idx < num_directories; ++idx) {
- auto search_path_spec = module_search_paths_ptr->GetFileSpecAtIndex(idx);
+ auto search_path_spec = module_search_paths.GetFileSpecAtIndex(idx);
FileSystem::Instance().Resolve(search_path_spec);
namespace fs = llvm::sys::fs;
if (!FileSystem::Instance().IsDirectory(search_path_spec))
@@ -1357,3 +1387,21 @@ void ModuleList::Swap(ModuleList &other) {
m_modules_mutex, other.m_modules_mutex);
m_modules.swap(other.m_modules);
}
+
+void ModuleList::PreloadSymbols(bool parallelize) const {
+ std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
+
+ if (!parallelize) {
+ for (const ModuleSP &module_sp : m_modules)
+ module_sp->PreloadSymbols();
+ return;
+ }
+
+ llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
+ for (const ModuleSP &module_sp : m_modules)
+ task_group.async([module_sp] {
+ if (module_sp)
+ module_sp->PreloadSymbols();
+ });
+ task_group.wait();
+}
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index 5887367..4e3563c 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -1300,6 +1300,61 @@ PluginManager::GetScriptInterpreterForLanguage(lldb::ScriptLanguage script_lang,
return none_instance(debugger);
}
+#pragma mark SyntheticFrameProvider
+
+typedef PluginInstance<SyntheticFrameProviderCreateInstance>
+ SyntheticFrameProviderInstance;
+typedef PluginInstance<ScriptedFrameProviderCreateInstance>
+ ScriptedFrameProviderInstance;
+typedef PluginInstances<SyntheticFrameProviderInstance>
+ SyntheticFrameProviderInstances;
+typedef PluginInstances<ScriptedFrameProviderInstance>
+ ScriptedFrameProviderInstances;
+
+static SyntheticFrameProviderInstances &GetSyntheticFrameProviderInstances() {
+ static SyntheticFrameProviderInstances g_instances;
+ return g_instances;
+}
+
+static ScriptedFrameProviderInstances &GetScriptedFrameProviderInstances() {
+ static ScriptedFrameProviderInstances g_instances;
+ return g_instances;
+}
+
+bool PluginManager::RegisterPlugin(
+ llvm::StringRef name, llvm::StringRef description,
+ SyntheticFrameProviderCreateInstance create_native_callback,
+ ScriptedFrameProviderCreateInstance create_scripted_callback) {
+ if (create_native_callback)
+ return GetSyntheticFrameProviderInstances().RegisterPlugin(
+ name, description, create_native_callback);
+ else if (create_scripted_callback)
+ return GetScriptedFrameProviderInstances().RegisterPlugin(
+ name, description, create_scripted_callback);
+ return false;
+}
+
+bool PluginManager::UnregisterPlugin(
+ SyntheticFrameProviderCreateInstance create_callback) {
+ return GetSyntheticFrameProviderInstances().UnregisterPlugin(create_callback);
+}
+
+bool PluginManager::UnregisterPlugin(
+ ScriptedFrameProviderCreateInstance create_callback) {
+ return GetScriptedFrameProviderInstances().UnregisterPlugin(create_callback);
+}
+
+SyntheticFrameProviderCreateInstance
+PluginManager::GetSyntheticFrameProviderCreateCallbackForPluginName(
+ llvm::StringRef name) {
+ return GetSyntheticFrameProviderInstances().GetCallbackForName(name);
+}
+
+ScriptedFrameProviderCreateInstance
+PluginManager::GetScriptedFrameProviderCreateCallbackAtIndex(uint32_t idx) {
+ return GetScriptedFrameProviderInstances().GetCallbackAtIndex(idx);
+}
+
#pragma mark StructuredDataPlugin
struct StructuredDataPluginInstance
diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp
index 02d9d86..f16035b 100644
--- a/lldb/source/Core/Section.cpp
+++ b/lldb/source/Core/Section.cpp
@@ -471,8 +471,14 @@ bool Section::ContainsOnlyDebugInfo() const {
return false;
}
+bool Section::IsGOTSection() const {
+ return GetObjectFile()->IsGOTSection(*this);
+}
+
#pragma mark SectionList
+SectionList::SectionList(const SectionList &rhs) : m_sections(rhs.m_sections) {}
+
SectionList &SectionList::operator=(const SectionList &rhs) {
if (this != &rhs)
m_sections = rhs.m_sections;
@@ -683,6 +689,33 @@ uint64_t SectionList::GetDebugInfoSize() const {
return debug_info_size;
}
+SectionList SectionList::Merge(SectionList &lhs, SectionList &rhs,
+ MergeCallback filter) {
+ SectionList output_list;
+
+ // Iterate through all the sections in lhs and see if we have matches in
+ // the rhs list.
+ for (const auto &lhs_section : lhs) {
+ auto rhs_section = rhs.FindSectionByName(lhs_section->GetName());
+ if (rhs_section)
+ output_list.AddSection(filter(lhs_section, rhs_section));
+ else
+ output_list.AddSection(lhs_section);
+ }
+
+ // Now that we've visited all possible duplicates, we can iterate over
+ // the rhs and take any values not in lhs.
+ for (const auto &rhs_section : rhs) {
+ auto lhs_section = lhs.FindSectionByName(rhs_section->GetName());
+ // Because we already visited everything overlapping between rhs
+ // and lhs, any section not in lhs is unique and can be output.
+ if (!lhs_section)
+ output_list.AddSection(rhs_section);
+ }
+
+ return output_list;
+}
+
namespace llvm {
namespace json {
diff --git a/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp
index 097173f..c60288c 100644
--- a/lldb/source/Core/SourceManager.cpp
+++ b/lldb/source/Core/SourceManager.cpp
@@ -30,6 +30,7 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/SupportFile.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/Twine.h"
@@ -69,22 +70,20 @@ static std::string toString(const Checksum &checksum) {
// SourceManager constructor
SourceManager::SourceManager(const TargetSP &target_sp)
- : m_last_support_file_sp(std::make_shared<SupportFile>()), m_last_line(0),
+ : m_last_support_file_nsp(std::make_shared<SupportFile>()), m_last_line(0),
m_last_count(0), m_default_set(false), m_target_wp(target_sp),
m_debugger_wp(target_sp->GetDebugger().shared_from_this()) {}
SourceManager::SourceManager(const DebuggerSP &debugger_sp)
- : m_last_support_file_sp(std::make_shared<SupportFile>()), m_last_line(0),
+ : m_last_support_file_nsp(std::make_shared<SupportFile>()), m_last_line(0),
m_last_count(0), m_default_set(false), m_target_wp(),
m_debugger_wp(debugger_sp) {}
// Destructor
SourceManager::~SourceManager() = default;
-SourceManager::FileSP SourceManager::GetFile(SupportFileSP support_file_sp) {
- assert(support_file_sp && "SupportFileSP must be valid");
-
- FileSpec file_spec = support_file_sp->GetSpecOnly();
+SourceManager::FileSP SourceManager::GetFile(SupportFileNSP support_file_nsp) {
+ FileSpec file_spec = support_file_nsp->GetSpecOnly();
if (!file_spec)
return {};
@@ -97,8 +96,8 @@ SourceManager::FileSP SourceManager::GetFile(SupportFileSP support_file_sp) {
LLDB_LOG(log, "Source file caching disabled: creating new source file: {0}",
file_spec);
if (target_sp)
- return std::make_shared<File>(support_file_sp, target_sp);
- return std::make_shared<File>(support_file_sp, debugger_sp);
+ return std::make_shared<File>(support_file_nsp, target_sp);
+ return std::make_shared<File>(support_file_nsp, debugger_sp);
}
ProcessSP process_sp = target_sp ? target_sp->GetProcessSP() : ProcessSP();
@@ -159,9 +158,9 @@ SourceManager::FileSP SourceManager::GetFile(SupportFileSP support_file_sp) {
// (Re)create the file.
if (target_sp)
- file_sp = std::make_shared<File>(support_file_sp, target_sp);
+ file_sp = std::make_shared<File>(support_file_nsp, target_sp);
else
- file_sp = std::make_shared<File>(support_file_sp, debugger_sp);
+ file_sp = std::make_shared<File>(support_file_nsp, debugger_sp);
// Add the file to the debugger and process cache. If the file was
// invalidated, this will overwrite it.
@@ -325,12 +324,12 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile(
}
size_t SourceManager::DisplaySourceLinesWithLineNumbers(
- lldb::SupportFileSP support_file_sp, uint32_t line, uint32_t column,
+ SupportFileNSP support_file_nsp, uint32_t line, uint32_t column,
uint32_t context_before, uint32_t context_after,
const char *current_line_cstr, Stream *s,
const SymbolContextList *bp_locs) {
- assert(support_file_sp && "SupportFile must be valid");
- FileSP file_sp(GetFile(support_file_sp));
+ assert(support_file_nsp && "SupportFile must be valid");
+ FileSP file_sp(GetFile(support_file_nsp));
uint32_t start_line;
uint32_t count = context_before + context_after + 1;
@@ -343,7 +342,7 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbers(
if (last_file_sp.get() != file_sp.get()) {
if (line == 0)
m_last_line = 0;
- m_last_support_file_sp = support_file_sp;
+ m_last_support_file_nsp = support_file_nsp;
}
return DisplaySourceLinesWithLineNumbersUsingLastFile(
@@ -389,15 +388,15 @@ size_t SourceManager::DisplayMoreWithLineNumbers(
return 0;
}
-bool SourceManager::SetDefaultFileAndLine(lldb::SupportFileSP support_file_sp,
+bool SourceManager::SetDefaultFileAndLine(SupportFileNSP support_file_nsp,
uint32_t line) {
- assert(support_file_sp && "SupportFile must be valid");
+ assert(support_file_nsp && "SupportFile must be valid");
m_default_set = true;
- if (FileSP file_sp = GetFile(support_file_sp)) {
+ if (FileSP file_sp = GetFile(support_file_nsp)) {
m_last_line = line;
- m_last_support_file_sp = support_file_sp;
+ m_last_support_file_nsp = support_file_nsp;
return true;
}
@@ -407,7 +406,7 @@ bool SourceManager::SetDefaultFileAndLine(lldb::SupportFileSP support_file_sp,
std::optional<SourceManager::SupportFileAndLine>
SourceManager::GetDefaultFileAndLine() {
if (FileSP last_file_sp = GetLastFile())
- return SupportFileAndLine(m_last_support_file_sp, m_last_line);
+ return SupportFileAndLine(m_last_support_file_nsp, m_last_line);
if (!m_default_set) {
TargetSP target_sp(m_target_wp.lock());
@@ -446,36 +445,36 @@ SourceManager::GetDefaultFileAndLine() {
return std::nullopt;
}
-void SourceManager::FindLinesMatchingRegex(SupportFileSP support_file_sp,
+void SourceManager::FindLinesMatchingRegex(SupportFileNSP support_file_nsp,
RegularExpression &regex,
uint32_t start_line,
uint32_t end_line,
std::vector<uint32_t> &match_lines) {
match_lines.clear();
- FileSP file_sp = GetFile(support_file_sp);
+ FileSP file_sp = GetFile(support_file_nsp);
if (!file_sp)
return;
return file_sp->FindLinesMatchingRegex(regex, start_line, end_line,
match_lines);
}
-SourceManager::File::File(SupportFileSP support_file_sp,
+SourceManager::File::File(SupportFileNSP support_file_nsp,
lldb::DebuggerSP debugger_sp)
- : m_support_file_sp(std::make_shared<SupportFile>()), m_checksum(),
+ : m_support_file_nsp(std::make_shared<SupportFile>()), m_checksum(),
m_mod_time(), m_debugger_wp(debugger_sp), m_target_wp(TargetSP()) {
- CommonInitializer(support_file_sp, {});
+ CommonInitializer(support_file_nsp, {});
}
-SourceManager::File::File(SupportFileSP support_file_sp, TargetSP target_sp)
- : m_support_file_sp(std::make_shared<SupportFile>()), m_checksum(),
+SourceManager::File::File(SupportFileNSP support_file_nsp, TargetSP target_sp)
+ : m_support_file_nsp(std::make_shared<SupportFile>()), m_checksum(),
m_mod_time(),
m_debugger_wp(target_sp ? target_sp->GetDebugger().shared_from_this()
: DebuggerSP()),
m_target_wp(target_sp) {
- CommonInitializer(support_file_sp, target_sp);
+ CommonInitializer(support_file_nsp, target_sp);
}
-void SourceManager::File::CommonInitializer(SupportFileSP support_file_sp,
+void SourceManager::File::CommonInitializer(SupportFileNSP support_file_nsp,
TargetSP target_sp) {
// It might take a while to read a source file, for example because it's
// coming from a virtual file system that's fetching the data on demand. When
@@ -484,23 +483,23 @@ void SourceManager::File::CommonInitializer(SupportFileSP support_file_sp,
static constexpr auto g_progress_delay = std::chrono::milliseconds(500);
std::future<void> future = std::async(std::launch::async, [=]() {
- CommonInitializerImpl(support_file_sp, target_sp);
+ CommonInitializerImpl(support_file_nsp, target_sp);
});
std::optional<Progress> progress;
if (future.wait_for(g_progress_delay) == std::future_status::timeout) {
Debugger *debugger = target_sp ? &target_sp->GetDebugger() : nullptr;
progress.emplace("Loading source file",
- support_file_sp->GetSpecOnly().GetFilename().GetString(),
+ support_file_nsp->GetSpecOnly().GetFilename().GetString(),
1, debugger);
}
future.wait();
}
-void SourceManager::File::CommonInitializerImpl(SupportFileSP support_file_sp,
+void SourceManager::File::CommonInitializerImpl(SupportFileNSP support_file_nsp,
TargetSP target_sp) {
// Set the file and update the modification time.
- SetSupportFile(support_file_sp);
+ SetSupportFile(support_file_nsp);
// Always update the source map modification ID if we have a target.
if (target_sp)
@@ -511,7 +510,7 @@ void SourceManager::File::CommonInitializerImpl(SupportFileSP support_file_sp,
if (target_sp) {
// If this is just a file name, try finding it in the target.
{
- FileSpec file_spec = support_file_sp->GetSpecOnly();
+ FileSpec file_spec = support_file_nsp->GetSpecOnly();
if (!file_spec.GetDirectory() && file_spec.GetFilename()) {
bool check_inlines = false;
SymbolContextList sc_list;
@@ -548,7 +547,7 @@ void SourceManager::File::CommonInitializerImpl(SupportFileSP support_file_sp,
// Try remapping the file if it doesn't exist.
{
- FileSpec file_spec = support_file_sp->GetSpecOnly();
+ FileSpec file_spec = support_file_nsp->GetSpecOnly();
if (!FileSystem::Instance().Exists(file_spec)) {
// Check target specific source remappings (i.e., the
// target.source-map setting), then fall back to the module
@@ -561,7 +560,7 @@ void SourceManager::File::CommonInitializerImpl(SupportFileSP support_file_sp,
}
if (remapped)
SetSupportFile(std::make_shared<SupportFile>(
- *remapped, support_file_sp->GetChecksum()));
+ *remapped, support_file_nsp->GetChecksum()));
}
}
}
@@ -570,16 +569,16 @@ void SourceManager::File::CommonInitializerImpl(SupportFileSP support_file_sp,
// If the file exists, read in the data.
if (m_mod_time != llvm::sys::TimePoint<>()) {
m_data_sp = FileSystem::Instance().CreateDataBuffer(
- m_support_file_sp->GetSpecOnly());
+ m_support_file_nsp->GetSpecOnly());
m_checksum = llvm::MD5::hash(m_data_sp->GetData());
}
}
-void SourceManager::File::SetSupportFile(lldb::SupportFileSP support_file_sp) {
- FileSpec file_spec = support_file_sp->GetSpecOnly();
+void SourceManager::File::SetSupportFile(SupportFileNSP support_file_nsp) {
+ FileSpec file_spec = support_file_nsp->GetSpecOnly();
resolve_tilde(file_spec);
- m_support_file_sp =
- std::make_shared<SupportFile>(file_spec, support_file_sp->GetChecksum());
+ m_support_file_nsp =
+ std::make_shared<SupportFile>(file_spec, support_file_nsp->GetChecksum());
m_mod_time = FileSystem::Instance().GetModificationTime(file_spec);
}
@@ -654,7 +653,7 @@ bool SourceManager::File::ModificationTimeIsStale() const {
// source cache and only update when we determine a file has been updated.
// For now we check each time we want to display info for the file.
auto curr_mod_time = FileSystem::Instance().GetModificationTime(
- m_support_file_sp->GetSpecOnly());
+ m_support_file_nsp->GetSpecOnly());
return curr_mod_time != llvm::sys::TimePoint<>() &&
m_mod_time != curr_mod_time;
}
diff --git a/lldb/source/Core/Statusline.cpp b/lldb/source/Core/Statusline.cpp
index bfbd190..922aada 100644
--- a/lldb/source/Core/Statusline.cpp
+++ b/lldb/source/Core/Statusline.cpp
@@ -91,7 +91,7 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
if (!stream_sp)
return;
- const unsigned reduced_scroll_window = m_terminal_height - 1;
+ const unsigned reduced_scroll_rows = m_terminal_height - 1;
LockedStreamFile locked_stream = stream_sp->Lock();
switch (mode) {
@@ -101,13 +101,14 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
locked_stream.Printf(ANSI_UP_ROWS, 1);
// Reduce the scroll window.
locked_stream << ANSI_SAVE_CURSOR;
- locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_window);
+ locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_rows);
locked_stream << ANSI_RESTORE_CURSOR;
break;
case DisableStatusline:
// Reset the scroll window.
locked_stream << ANSI_SAVE_CURSOR;
- locked_stream.Printf(ANSI_SET_SCROLL_ROWS, 0);
+ locked_stream.Printf(ANSI_SET_SCROLL_ROWS,
+ static_cast<unsigned>(m_terminal_height));
locked_stream << ANSI_RESTORE_CURSOR;
// Clear the screen below to hide the old statusline.
locked_stream << ANSI_CLEAR_BELOW;
@@ -116,7 +117,7 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) {
// Clear the screen and update the scroll window.
// FIXME: Find a better solution (#146919).
locked_stream << ANSI_CLEAR_SCREEN;
- locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_window);
+ locked_stream.Printf(ANSI_SET_SCROLL_ROWS, reduced_scroll_rows);
break;
}
diff --git a/lldb/source/Expression/CMakeLists.txt b/lldb/source/Expression/CMakeLists.txt
index 08dc536..515289c 100644
--- a/lldb/source/Expression/CMakeLists.txt
+++ b/lldb/source/Expression/CMakeLists.txt
@@ -24,6 +24,7 @@ add_lldb_library(lldbExpression NO_PLUGIN_DEPENDENCIES
LINK_COMPONENTS
Core
+ DebugInfoDWARF
ExecutionEngine
Support
LINK_LIBS
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 4f9d6eb..364b2ec 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -861,32 +861,130 @@ ResolveLoadAddress(ExecutionContext *exe_ctx, lldb::ModuleSP &module_sp,
return load_addr;
}
-static llvm::Error Evaluate_DW_OP_deref(DWARFExpression::Stack &stack,
- ExecutionContext *exe_ctx,
- lldb::ModuleSP module_sp,
- Process *process) {
+/// @brief Helper function to load sized data from a uint8_t buffer.
+///
+/// @param addr_bytes The buffer containing raw data.
+/// @param size_addr_bytes How large is the underlying raw data.
+/// @param byte_order What is the byte order of the underlying data.
+/// @param size How much of the underlying data we want to use.
+/// @return The underlying data converted into a Scalar.
+static Scalar DerefSizeExtractDataHelper(uint8_t *addr_bytes,
+ size_t size_addr_bytes,
+ ByteOrder byte_order, size_t size) {
+ DataExtractor addr_data(addr_bytes, size_addr_bytes, byte_order, size);
+
+ lldb::offset_t addr_data_offset = 0;
+ if (size <= 8)
+ return addr_data.GetMaxU64(&addr_data_offset, size);
+ return addr_data.GetAddress(&addr_data_offset);
+}
+
+static llvm::Error Evaluate_DW_OP_deref_size(
+ DWARFExpression::Stack &stack, ExecutionContext *exe_ctx,
+ lldb::ModuleSP module_sp, Process *process, Target *target, uint8_t size,
+ size_t size_addr_bytes,
+ LocationDescriptionKind &dwarf4_location_description_kind) {
if (stack.empty())
- return llvm::createStringError("expression stack empty for DW_OP_deref");
+ return llvm::createStringError(
+ "expression stack empty for DW_OP_deref_size");
- const Value::ValueType value_type = stack.back().GetValueType();
+ if (size > 8)
+ return llvm::createStringError(
+ "Invalid address size for DW_OP_deref_size: %d\n", size);
+
+ // Deref a register or implicit location and truncate the value to `size`
+ // bytes. See the corresponding comment in DW_OP_deref for more details on
+ // why we deref these locations this way.
+ if (dwarf4_location_description_kind == Register ||
+ dwarf4_location_description_kind == Implicit) {
+ // Reset context to default values.
+ dwarf4_location_description_kind = Memory;
+ stack.back().ClearContext();
+
+ // Truncate the value on top of the stack to *size* bytes then
+ // extend to the size of an address (e.g. generic type).
+ Scalar scalar = stack.back().GetScalar();
+ scalar.TruncOrExtendTo(size * 8, /*sign=*/false);
+ scalar.TruncOrExtendTo(size_addr_bytes * 8,
+ /*sign=*/false);
+ stack.back().GetScalar() = scalar;
+ return llvm::Error::success();
+ }
+
+ Value::ValueType value_type = stack.back().GetValueType();
switch (value_type) {
case Value::ValueType::HostAddress: {
void *src = (void *)stack.back().GetScalar().ULongLong();
intptr_t ptr;
::memcpy(&ptr, src, sizeof(void *));
+ // I can't decide whether the size operand should apply to the bytes in
+ // their lldb-host endianness or the target endianness.. I doubt this'll
+ // ever come up but I'll opt for assuming big endian regardless.
+ switch (size) {
+ case 1:
+ ptr = ptr & 0xff;
+ break;
+ case 2:
+ ptr = ptr & 0xffff;
+ break;
+ case 3:
+ ptr = ptr & 0xffffff;
+ break;
+ case 4:
+ ptr = ptr & 0xffffffff;
+ break;
+ // The casts are added to work around the case where intptr_t is a 32-bit
+ // quantity. Presumably we won't hit the 5..7 cases if (void*) is 32-bits in
+ // this program.
+ case 5:
+ ptr = (intptr_t)ptr & 0xffffffffffULL;
+ break;
+ case 6:
+ ptr = (intptr_t)ptr & 0xffffffffffffULL;
+ break;
+ case 7:
+ ptr = (intptr_t)ptr & 0xffffffffffffffULL;
+ break;
+ default:
+ break;
+ }
stack.back().GetScalar() = ptr;
stack.back().ClearContext();
} break;
case Value::ValueType::FileAddress: {
auto file_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
Address so_addr;
- auto maybe_load_addr = ResolveLoadAddress(exe_ctx, module_sp, "DW_OP_deref",
- file_addr, so_addr);
+ auto maybe_load_addr = ResolveLoadAddress(
+ exe_ctx, module_sp, "DW_OP_deref_size", file_addr, so_addr,
+ /*check_sectionoffset=*/true);
+
if (!maybe_load_addr)
return maybe_load_addr.takeError();
- stack.back().GetScalar() = *maybe_load_addr;
+
+ addr_t load_addr = *maybe_load_addr;
+
+ if (load_addr == LLDB_INVALID_ADDRESS && so_addr.IsSectionOffset()) {
+ uint8_t addr_bytes[8];
+ Status error;
+
+ if (!target || target->ReadMemory(so_addr, &addr_bytes, size, error,
+ /*force_live_memory=*/false) != size)
+ return llvm::createStringError(
+ "failed to dereference pointer for DW_OP_deref_size: "
+ "%s\n",
+ error.AsCString());
+
+ ObjectFile *objfile = module_sp->GetObjectFile();
+
+ stack.back().GetScalar() = DerefSizeExtractDataHelper(
+ addr_bytes, size, objfile->GetByteOrder(), size);
+ stack.back().ClearContext();
+ break;
+ }
+ stack.back().GetScalar() = load_addr;
// Fall through to load address promotion code below.
}
+
[[fallthrough]];
case Value::ValueType::Scalar:
// Promote Scalar to LoadAddress and fall through.
@@ -894,51 +992,34 @@ static llvm::Error Evaluate_DW_OP_deref(DWARFExpression::Stack &stack,
[[fallthrough]];
case Value::ValueType::LoadAddress: {
if (!exe_ctx)
- return llvm::createStringError("NULL execution context for DW_OP_deref");
+ return llvm::createStringError(
+ "no execution context for DW_OP_deref_size");
if (!process)
- return llvm::createStringError("NULL process for DW_OP_deref");
+ return llvm::createStringError("no process for DW_OP_deref_size");
+
lldb::addr_t pointer_addr =
stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ uint8_t addr_bytes[sizeof(lldb::addr_t)];
Status error;
- lldb::addr_t pointer_value =
- process->ReadPointerFromMemory(pointer_addr, error);
- if (pointer_value == LLDB_INVALID_ADDRESS)
- return llvm::joinErrors(
- llvm::createStringError(
- "Failed to dereference pointer from 0x%" PRIx64
- " for DW_OP_deref",
- pointer_addr),
- error.takeError());
- stack.back().GetScalar() = pointer_value;
+
+ if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) != size)
+ return llvm::createStringError(
+ "failed to dereference pointer from 0x%" PRIx64
+ " for DW_OP_deref_size: %s\n",
+ pointer_addr, error.AsCString());
+
+ stack.back().GetScalar() = DerefSizeExtractDataHelper(
+ addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), size);
stack.back().ClearContext();
} break;
+
case Value::ValueType::Invalid:
- return llvm::createStringError("invalid value type for DW_OP_deref");
+ return llvm::createStringError("invalid value for DW_OP_deref_size");
}
return llvm::Error::success();
}
-/// Helper function to move common code used to load sized data from a uint8_t
-/// buffer.
-///
-/// \param addr_bytes uint8_t buffer containg raw data
-/// \param size_addr_bytes how large is the underlying raw data
-/// \param byte_order what is the byter order of the underlyig data
-/// \param size How much of the underlying data we want to use
-/// \return The underlying data converted into a Scalar
-static Scalar DerefSizeExtractDataHelper(uint8_t *addr_bytes,
- size_t size_addr_bytes,
- ByteOrder byte_order, size_t size) {
- DataExtractor addr_data(addr_bytes, size_addr_bytes, byte_order, size);
-
- lldb::offset_t addr_data_offset = 0;
- if (size <= 8)
- return addr_data.GetMaxU64(&addr_data_offset, size);
- else
- return addr_data.GetAddress(&addr_data_offset);
-}
-
llvm::Expected<Value> DWARFExpression::Evaluate(
ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
lldb::ModuleSP module_sp, const DataExtractor &opcodes,
@@ -1079,8 +1160,10 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
// retrieved from the dereferenced address is the size of an address on the
// target machine.
case DW_OP_deref: {
- if (llvm::Error err =
- Evaluate_DW_OP_deref(stack, exe_ctx, module_sp, process))
+ size_t size = opcodes.GetAddressByteSize();
+ if (llvm::Error err = Evaluate_DW_OP_deref_size(
+ stack, exe_ctx, module_sp, process, target, size, size,
+ dwarf4_location_description_kind))
return err;
} break;
@@ -1097,131 +1180,11 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
// the size of an address on the target machine before being pushed on the
// expression stack.
case DW_OP_deref_size: {
- if (stack.empty()) {
- return llvm::createStringError(
- "expression stack empty for DW_OP_deref_size");
- }
- uint8_t size = opcodes.GetU8(&offset);
- if (size > 8) {
- return llvm::createStringError(
- "Invalid address size for DW_OP_deref_size: %d\n", size);
- }
- Value::ValueType value_type = stack.back().GetValueType();
- switch (value_type) {
- case Value::ValueType::HostAddress: {
- void *src = (void *)stack.back().GetScalar().ULongLong();
- intptr_t ptr;
- ::memcpy(&ptr, src, sizeof(void *));
- // I can't decide whether the size operand should apply to the bytes in
- // their
- // lldb-host endianness or the target endianness.. I doubt this'll ever
- // come up but I'll opt for assuming big endian regardless.
- switch (size) {
- case 1:
- ptr = ptr & 0xff;
- break;
- case 2:
- ptr = ptr & 0xffff;
- break;
- case 3:
- ptr = ptr & 0xffffff;
- break;
- case 4:
- ptr = ptr & 0xffffffff;
- break;
- // the casts are added to work around the case where intptr_t is a 32
- // bit quantity;
- // presumably we won't hit the 5..7 cases if (void*) is 32-bits in this
- // program.
- case 5:
- ptr = (intptr_t)ptr & 0xffffffffffULL;
- break;
- case 6:
- ptr = (intptr_t)ptr & 0xffffffffffffULL;
- break;
- case 7:
- ptr = (intptr_t)ptr & 0xffffffffffffffULL;
- break;
- default:
- break;
- }
- stack.back().GetScalar() = ptr;
- stack.back().ClearContext();
- } break;
- case Value::ValueType::FileAddress: {
- auto file_addr =
- stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
- Address so_addr;
- auto maybe_load_addr = ResolveLoadAddress(
- exe_ctx, module_sp, "DW_OP_deref_size", file_addr, so_addr,
- /*check_sectionoffset=*/true);
-
- if (!maybe_load_addr)
- return maybe_load_addr.takeError();
-
- addr_t load_addr = *maybe_load_addr;
-
- if (load_addr == LLDB_INVALID_ADDRESS && so_addr.IsSectionOffset()) {
- uint8_t addr_bytes[8];
- Status error;
-
- if (target &&
- target->ReadMemory(so_addr, &addr_bytes, size, error,
- /*force_live_memory=*/false) == size) {
- ObjectFile *objfile = module_sp->GetObjectFile();
-
- stack.back().GetScalar() = DerefSizeExtractDataHelper(
- addr_bytes, size, objfile->GetByteOrder(), size);
- stack.back().ClearContext();
- break;
- } else {
- return llvm::createStringError(
- "Failed to dereference pointer for DW_OP_deref_size: "
- "%s\n",
- error.AsCString());
- }
- }
- stack.back().GetScalar() = load_addr;
- // Fall through to load address promotion code below.
- }
-
- [[fallthrough]];
- case Value::ValueType::Scalar:
- case Value::ValueType::LoadAddress:
- if (exe_ctx) {
- if (process) {
- lldb::addr_t pointer_addr =
- stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
- uint8_t addr_bytes[sizeof(lldb::addr_t)];
- Status error;
- if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) ==
- size) {
-
- stack.back().GetScalar() =
- DerefSizeExtractDataHelper(addr_bytes, sizeof(addr_bytes),
- process->GetByteOrder(), size);
- stack.back().ClearContext();
- } else {
- return llvm::createStringError(
- "Failed to dereference pointer from 0x%" PRIx64
- " for DW_OP_deref: %s\n",
- pointer_addr, error.AsCString());
- }
- } else {
-
- return llvm::createStringError("NULL process for DW_OP_deref_size");
- }
- } else {
- return llvm::createStringError(
- "NULL execution context for DW_OP_deref_size");
- }
- break;
-
- case Value::ValueType::Invalid:
-
- return llvm::createStringError("invalid value for DW_OP_deref_size");
- }
-
+ size_t size = opcodes.GetU8(&offset);
+ if (llvm::Error err = Evaluate_DW_OP_deref_size(
+ stack, exe_ctx, module_sp, process, target, size,
+ opcodes.GetAddressByteSize(), dwarf4_location_description_kind))
+ return err;
} break;
// OPCODE: DW_OP_xderef_size
diff --git a/lldb/source/Expression/ObjectFileJIT.cpp b/lldb/source/Expression/ObjectFileJIT.cpp
index e4a6135..46ceb75 100644
--- a/lldb/source/Expression/ObjectFileJIT.cpp
+++ b/lldb/source/Expression/ObjectFileJIT.cpp
@@ -73,8 +73,8 @@ ObjectFileJIT::ObjectFileJIT(const lldb::ModuleSP &module_sp,
: ObjectFile(module_sp, nullptr, 0, 0, DataBufferSP(), 0), m_delegate_wp() {
if (delegate_sp) {
m_delegate_wp = delegate_sp;
- m_data.SetByteOrder(delegate_sp->GetByteOrder());
- m_data.SetAddressByteSize(delegate_sp->GetAddressByteSize());
+ m_data_nsp->SetByteOrder(delegate_sp->GetByteOrder());
+ m_data_nsp->SetAddressByteSize(delegate_sp->GetAddressByteSize());
}
}
@@ -85,12 +85,14 @@ bool ObjectFileJIT::ParseHeader() {
return false;
}
-ByteOrder ObjectFileJIT::GetByteOrder() const { return m_data.GetByteOrder(); }
+ByteOrder ObjectFileJIT::GetByteOrder() const {
+ return m_data_nsp->GetByteOrder();
+}
bool ObjectFileJIT::IsExecutable() const { return false; }
uint32_t ObjectFileJIT::GetAddressByteSize() const {
- return m_data.GetAddressByteSize();
+ return m_data_nsp->GetAddressByteSize();
}
void ObjectFileJIT::ParseSymtab(Symtab &symtab) {
diff --git a/lldb/source/Expression/REPL.cpp b/lldb/source/Expression/REPL.cpp
index 92017d2..c6cf6d8 100644
--- a/lldb/source/Expression/REPL.cpp
+++ b/lldb/source/Expression/REPL.cpp
@@ -615,6 +615,6 @@ Status REPL::RunLoop() {
// Restore the default file and line
if (default_file_line)
m_target.GetSourceManager().SetDefaultFileAndLine(
- default_file_line->support_file_sp, default_file_line->line);
+ default_file_line->support_file_nsp, default_file_line->line);
return error;
}
diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp
index af4b477..5563eba 100644
--- a/lldb/source/Expression/UserExpression.cpp
+++ b/lldb/source/Expression/UserExpression.cpp
@@ -246,7 +246,7 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx,
// language in the target's properties if specified, else default to the
// langage for the frame.
if (!language) {
- if (target->GetLanguage() != lldb::eLanguageTypeUnknown)
+ if (target->GetLanguage())
language = target->GetLanguage();
else if (StackFrame *frame = exe_ctx.GetFramePtr())
language = frame->GetLanguage();
diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt
index c9e8afe..3184d3a 100644
--- a/lldb/source/Host/CMakeLists.txt
+++ b/lldb/source/Host/CMakeLists.txt
@@ -17,6 +17,7 @@ macro(add_host_subdirectory group)
endmacro()
add_host_subdirectory(common
+ common/DiagnosticsRendering.cpp
common/FileAction.cpp
common/FileCache.cpp
common/File.cpp
diff --git a/lldb/source/Utility/DiagnosticsRendering.cpp b/lldb/source/Host/common/DiagnosticsRendering.cpp
index 8c21e661..f2cd396 100644
--- a/lldb/source/Utility/DiagnosticsRendering.cpp
+++ b/lldb/source/Host/common/DiagnosticsRendering.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Utility/DiagnosticsRendering.h"
+#include "lldb/Host/common/DiagnosticsRendering.h"
#include <cstdint>
using namespace lldb_private;
diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index 1b1922e..e2995b3 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -1626,6 +1626,9 @@ bool Editline::GetLine(std::string &line, bool &interrupted) {
m_editor_status = EditorStatus::Editing;
m_revert_cursor_index = -1;
+ lldbassert(m_output_stream_sp);
+ fprintf(m_locked_output->GetFile().GetStream(), "\r" ANSI_CLEAR_RIGHT);
+
int count;
auto input = el_wgets(m_editline, &count);
diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp
index 65b75bd..4fad93f 100644
--- a/lldb/source/Host/common/File.cpp
+++ b/lldb/source/Host/common/File.cpp
@@ -249,8 +249,8 @@ uint32_t File::GetPermissions(Status &error) const {
NativeFile::NativeFile() = default;
-NativeFile::NativeFile(FILE *fh, bool transfer_ownership)
- : m_stream(fh), m_own_stream(transfer_ownership) {
+NativeFile::NativeFile(FILE *fh, OpenOptions options, bool transfer_ownership)
+ : m_stream(fh), m_options(options), m_own_stream(transfer_ownership) {
#ifdef _WIN32
// In order to properly display non ASCII characters in Windows, we need to
// use Windows APIs to print to the console. This is only required if the
@@ -258,6 +258,26 @@ NativeFile::NativeFile(FILE *fh, bool transfer_ownership)
int fd = _fileno(fh);
is_windows_console =
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
+#else
+#ifndef NDEBUG
+ int fd = fileno(fh);
+ if (fd != -1) {
+ int required_mode = ConvertOpenOptionsForPOSIXOpen(options) & O_ACCMODE;
+ int mode = fcntl(fd, F_GETFL);
+ if (mode != -1) {
+ mode &= O_ACCMODE;
+ // Check that the file is open with a valid subset of the requested file
+ // access mode, e.g. if we expected the file to be writable then ensure it
+ // was opened with O_WRONLY or O_RDWR.
+ assert(
+ (required_mode == O_RDWR && mode == O_RDWR) ||
+ (required_mode == O_RDONLY && (mode == O_RDWR || mode == O_RDONLY) ||
+ (required_mode == O_WRONLY &&
+ (mode == O_RDWR || mode == O_WRONLY))) &&
+ "invalid file access mode");
+ }
+ }
+#endif
#endif
}
@@ -274,7 +294,8 @@ NativeFile::NativeFile(int fd, OpenOptions options, bool transfer_ownership)
}
bool NativeFile::IsValid() const {
- std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
+ std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex,
+ m_stream_mutex);
return DescriptorIsValidUnlocked() || StreamIsValidUnlocked();
}
@@ -343,7 +364,8 @@ FILE *NativeFile::GetStream() {
}
Status NativeFile::Close() {
- std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
+ std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex,
+ m_stream_mutex);
Status error;
@@ -548,6 +570,10 @@ Status NativeFile::Sync() {
Status NativeFile::Read(void *buf, size_t &num_bytes) {
Status error;
+ // Ensure the file is open for reading.
+ if ((m_options & File::OpenOptionsModeMask) == eOpenOptionWriteOnly)
+ return Status(std::make_error_code(std::errc::bad_file_descriptor));
+
#if defined(MAX_READ_SIZE)
if (num_bytes > MAX_READ_SIZE) {
uint8_t *p = (uint8_t *)buf;
@@ -612,6 +638,10 @@ Status NativeFile::Read(void *buf, size_t &num_bytes) {
Status NativeFile::Write(const void *buf, size_t &num_bytes) {
Status error;
+ // Ensure the file is open for writing.
+ if ((m_options & File::OpenOptionsModeMask) == File::eOpenOptionReadOnly)
+ return Status(std::make_error_code(std::errc::bad_file_descriptor));
+
#if defined(MAX_WRITE_SIZE)
if (num_bytes > MAX_WRITE_SIZE) {
const uint8_t *p = (const uint8_t *)buf;
@@ -776,8 +806,8 @@ Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
int fd = GetDescriptor();
if (fd != kInvalidDescriptor) {
#ifndef _WIN32
- ssize_t bytes_written =
- llvm::sys::RetryAfterSignal(-1, ::pwrite, m_descriptor, buf, num_bytes, offset);
+ ssize_t bytes_written = llvm::sys::RetryAfterSignal(
+ -1, ::pwrite, m_descriptor, buf, num_bytes, offset);
if (bytes_written < 0) {
num_bytes = 0;
error = Status::FromErrno();
diff --git a/lldb/source/Host/common/FileAction.cpp b/lldb/source/Host/common/FileAction.cpp
index e1c3e14..ec271f7 100644
--- a/lldb/source/Host/common/FileAction.cpp
+++ b/lldb/source/Host/common/FileAction.cpp
@@ -25,10 +25,6 @@ void FileAction::Clear() {
m_file_spec.Clear();
}
-llvm::StringRef FileAction::GetPath() const {
- return m_file_spec.GetPathAsConstString().AsCString();
-}
-
const FileSpec &FileAction::GetFileSpec() const { return m_file_spec; }
bool FileAction::Open(int fd, const FileSpec &file_spec, bool read,
diff --git a/lldb/source/Host/common/StreamFile.cpp b/lldb/source/Host/common/StreamFile.cpp
index 099980a..131412d 100644
--- a/lldb/source/Host/common/StreamFile.cpp
+++ b/lldb/source/Host/common/StreamFile.cpp
@@ -27,7 +27,8 @@ StreamFile::StreamFile(int fd, bool transfer_ownership) : Stream() {
}
StreamFile::StreamFile(FILE *fh, bool transfer_ownership) : Stream() {
- m_file_sp = std::make_shared<NativeFile>(fh, transfer_ownership);
+ m_file_sp = std::make_shared<NativeFile>(fh, File::eOpenOptionWriteOnly,
+ transfer_ownership);
}
StreamFile::StreamFile(const char *path, File::OpenOptions options,
diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm
index 96a282c..16bca0f1 100644
--- a/lldb/source/Host/macosx/objcxx/Host.mm
+++ b/lldb/source/Host/macosx/objcxx/Host.mm
@@ -1013,20 +1013,29 @@ static Status LaunchProcessXPC(const char *exe_path,
xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey,
GetPosixspawnFlags(launch_info));
const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
- if (file_action && !file_action->GetPath().empty()) {
+ std::string file_action_path;
+ if (file_action)
+ file_action_path = file_action->GetFileSpec().GetPath();
+
+ if (!file_action_path.empty())
xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey,
- file_action->GetPath().str().c_str());
- }
+ file_action_path.c_str());
+
file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
- if (file_action && !file_action->GetPath().empty()) {
+ if (file_action)
+ file_action_path = file_action->GetFileSpec().GetPath();
+
+ if (!file_action_path.empty())
xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey,
- file_action->GetPath().str().c_str());
- }
+ file_action_path.c_str());
+
file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
- if (file_action && !file_action->GetPath().empty()) {
+ if (file_action)
+ file_action_path = file_action->GetFileSpec().GetPath();
+
+ if (!file_action_path.empty())
xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey,
- file_action->GetPath().str().c_str());
- }
+ file_action_path.c_str());
xpc_object_t reply =
xpc_connection_send_message_with_reply_sync(conn, message);
@@ -1135,16 +1144,16 @@ static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
if (oflag & O_CREAT)
mode = 0640;
- error = Status(::posix_spawn_file_actions_addopen(
- file_actions, info->GetFD(),
- info->GetPath().str().c_str(), oflag, mode),
- eErrorTypePOSIX);
+ const std::string file_path(info->GetFileSpec().GetPath());
+ error = Status(
+ ::posix_spawn_file_actions_addopen(file_actions, info->GetFD(),
+ file_path.c_str(), oflag, mode),
+ eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log,
"error: {0}, posix_spawn_file_actions_addopen (action={1}, "
"fd={2}, path='{3}', oflag={4}, mode={5})",
- error, file_actions, info->GetFD(), info->GetPath(), oflag,
- mode);
+ error, file_actions, info->GetFD(), file_path, oflag, mode);
}
break;
}
diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
index 15a8097..a5f5cc5 100644
--- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
+++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
@@ -229,8 +229,8 @@ struct ForkLaunchInfo {
// End of code running in the child process.
ForkFileAction::ForkFileAction(const FileAction &act)
- : action(act.GetAction()), fd(act.GetFD()), path(act.GetPath().str()),
- arg(act.GetActionArgument()) {}
+ : action(act.GetAction()), fd(act.GetFD()),
+ path(act.GetFileSpec().GetPath()), arg(act.GetActionArgument()) {}
static std::vector<ForkFileAction>
MakeForkActions(const ProcessLaunchInfo &info) {
diff --git a/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/lldb/source/Host/windows/ProcessLauncherWindows.cpp
index f5adada..e983c52 100644
--- a/lldb/source/Host/windows/ProcessLauncherWindows.cpp
+++ b/lldb/source/Host/windows/ProcessLauncherWindows.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/WindowsError.h"
#include <string>
#include <vector>
@@ -21,42 +22,63 @@
using namespace lldb;
using namespace lldb_private;
-static void CreateEnvironmentBuffer(const Environment &env,
- std::vector<char> &buffer) {
- // The buffer is a list of null-terminated UTF-16 strings, followed by an
- // extra L'\0' (two bytes of 0). An empty environment must have one
- // empty string, followed by an extra L'\0'.
+/// Create a UTF-16 environment block to use with CreateProcessW.
+///
+/// The buffer is a sequence of null-terminated UTF-16 strings, followed by an
+/// extra L'\0' (two bytes of 0). An empty environment must have one
+/// empty string, followed by an extra L'\0'.
+///
+/// The keys are sorted to comply with the CreateProcess API calling convention.
+///
+/// Ensure that the resulting buffer is used in conjunction with
+/// CreateProcessW and be sure that dwCreationFlags includes
+/// CREATE_UNICODE_ENVIRONMENT.
+///
+/// \param env The Environment object to convert.
+/// \returns The sorted sequence of environment variables and their values,
+/// separated by null terminators. The vector is guaranteed to never be empty.
+static std::vector<wchar_t> CreateEnvironmentBufferW(const Environment &env) {
+ std::vector<std::wstring> env_entries;
for (const auto &KV : env) {
- std::wstring warg;
- if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) {
- buffer.insert(
- buffer.end(), reinterpret_cast<const char *>(warg.c_str()),
- reinterpret_cast<const char *>(warg.c_str() + warg.size() + 1));
- }
+ std::wstring wentry;
+ if (llvm::ConvertUTF8toWide(Environment::compose(KV), wentry))
+ env_entries.push_back(std::move(wentry));
}
- // One null wchar_t (to end the block) is two null bytes
- buffer.push_back(0);
- buffer.push_back(0);
- // Insert extra two bytes, just in case the environment was empty.
- buffer.push_back(0);
- buffer.push_back(0);
+ std::sort(env_entries.begin(), env_entries.end(),
+ [](const std::wstring &a, const std::wstring &b) {
+ return _wcsicmp(a.c_str(), b.c_str()) < 0;
+ });
+
+ std::vector<wchar_t> buffer;
+ for (const auto &env_entry : env_entries) {
+ buffer.insert(buffer.end(), env_entry.begin(), env_entry.end());
+ buffer.push_back(L'\0');
+ }
+
+ if (buffer.empty())
+ buffer.push_back(L'\0'); // If there are no environment variables, we have
+ // to ensure there are 4 zero bytes in the buffer.
+ buffer.push_back(L'\0');
+
+ return buffer;
}
-static bool GetFlattenedWindowsCommandString(Args args, std::wstring &command) {
+/// Flattens an Args object into a Windows command-line wide string.
+///
+/// Returns an empty string if args is empty.
+///
+/// \param args The Args object to flatten.
+/// \returns A wide string containing the flattened command line.
+static llvm::ErrorOr<std::wstring>
+GetFlattenedWindowsCommandStringW(Args args) {
if (args.empty())
- return false;
+ return L"";
std::vector<llvm::StringRef> args_ref;
for (auto &entry : args.entries())
args_ref.push_back(entry.ref());
- llvm::ErrorOr<std::wstring> result =
- llvm::sys::flattenWindowsCommandLine(args_ref);
- if (result.getError())
- return false;
-
- command = *result;
- return true;
+ return llvm::sys::flattenWindowsCommandLine(args_ref);
}
HostProcess
@@ -64,11 +86,9 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
Status &error) {
error.Clear();
- std::string executable;
- std::vector<char> environment;
- STARTUPINFOEX startupinfoex = {};
- STARTUPINFO &startupinfo = startupinfoex.StartupInfo;
- PROCESS_INFORMATION pi = {};
+ STARTUPINFOEXW startupinfoex = {};
+ startupinfoex.StartupInfo.cb = sizeof(startupinfoex);
+ startupinfoex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO);
HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO);
@@ -82,23 +102,6 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
::CloseHandle(stderr_handle);
});
- startupinfo.cb = sizeof(startupinfoex);
- startupinfo.dwFlags |= STARTF_USESTDHANDLES;
- startupinfo.hStdError =
- stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE);
- startupinfo.hStdInput =
- stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE);
- startupinfo.hStdOutput =
- stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE);
-
- std::vector<HANDLE> inherited_handles;
- if (startupinfo.hStdError)
- inherited_handles.push_back(startupinfo.hStdError);
- if (startupinfo.hStdInput)
- inherited_handles.push_back(startupinfo.hStdInput);
- if (startupinfo.hStdOutput)
- inherited_handles.push_back(startupinfo.hStdOutput);
-
SIZE_T attributelist_size = 0;
InitializeProcThreadAttributeList(/*lpAttributeList=*/nullptr,
/*dwAttributeCount=*/1, /*dwFlags=*/0,
@@ -116,29 +119,21 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
}
auto delete_attributelist = llvm::make_scope_exit(
[&] { DeleteProcThreadAttributeList(startupinfoex.lpAttributeList); });
- for (size_t i = 0; i < launch_info.GetNumFileActions(); ++i) {
- const FileAction *act = launch_info.GetFileActionAtIndex(i);
- if (act->GetAction() == FileAction::eFileActionDuplicate &&
- act->GetFD() == act->GetActionArgument())
- inherited_handles.push_back(reinterpret_cast<HANDLE>(act->GetFD()));
- }
- if (!inherited_handles.empty()) {
- if (!UpdateProcThreadAttribute(
- startupinfoex.lpAttributeList, /*dwFlags=*/0,
- PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited_handles.data(),
- inherited_handles.size() * sizeof(HANDLE),
- /*lpPreviousValue=*/nullptr, /*lpReturnSize=*/nullptr)) {
- error = Status(::GetLastError(), eErrorTypeWin32);
- return HostProcess();
- }
+
+ auto inherited_handles_or_err = GetInheritedHandles(
+ launch_info, startupinfoex, stdout_handle, stderr_handle, stdin_handle);
+ if (!inherited_handles_or_err) {
+ error = Status(inherited_handles_or_err.getError());
+ return HostProcess();
}
+ std::vector<HANDLE> inherited_handles = *inherited_handles_or_err;
const char *hide_console_var =
getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE");
if (hide_console_var &&
llvm::StringRef(hide_console_var).equals_insensitive("true")) {
- startupinfo.dwFlags |= STARTF_USESHOWWINDOW;
- startupinfo.wShowWindow = SW_HIDE;
+ startupinfoex.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
+ startupinfoex.StartupInfo.wShowWindow = SW_HIDE;
}
DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT |
@@ -149,28 +144,34 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO))
flags &= ~CREATE_NEW_CONSOLE;
- LPVOID env_block = nullptr;
- ::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment);
- env_block = environment.data();
+ std::vector<wchar_t> environment =
+ CreateEnvironmentBufferW(launch_info.GetEnvironment());
- executable = launch_info.GetExecutableFile().GetPath();
- std::wstring wcommandLine;
- GetFlattenedWindowsCommandString(launch_info.GetArguments(), wcommandLine);
-
- std::wstring wexecutable, wworkingDirectory;
- llvm::ConvertUTF8toWide(executable, wexecutable);
- llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetPath(),
- wworkingDirectory);
+ auto wcommandLineOrErr =
+ GetFlattenedWindowsCommandStringW(launch_info.GetArguments());
+ if (!wcommandLineOrErr) {
+ error = Status(wcommandLineOrErr.getError());
+ return HostProcess();
+ }
+ std::wstring wcommandLine = *wcommandLineOrErr;
// If the command line is empty, it's best to pass a null pointer to tell
// CreateProcessW to use the executable name as the command line. If the
// command line is not empty, its contents may be modified by CreateProcessW.
WCHAR *pwcommandLine = wcommandLine.empty() ? nullptr : &wcommandLine[0];
+ std::wstring wexecutable, wworkingDirectory;
+ llvm::ConvertUTF8toWide(launch_info.GetExecutableFile().GetPath(),
+ wexecutable);
+ llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetPath(),
+ wworkingDirectory);
+
+ PROCESS_INFORMATION pi = {};
+
BOOL result = ::CreateProcessW(
wexecutable.c_str(), pwcommandLine, NULL, NULL,
- /*bInheritHandles=*/!inherited_handles.empty(), flags, env_block,
+ /*bInheritHandles=*/!inherited_handles.empty(), flags, environment.data(),
wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(),
- reinterpret_cast<STARTUPINFO *>(&startupinfoex), &pi);
+ reinterpret_cast<STARTUPINFOW *>(&startupinfoex), &pi);
if (!result) {
// Call GetLastError before we make any other system calls.
@@ -191,6 +192,45 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info,
return HostProcess(pi.hProcess);
}
+llvm::ErrorOr<std::vector<HANDLE>> ProcessLauncherWindows::GetInheritedHandles(
+ const ProcessLaunchInfo &launch_info, STARTUPINFOEXW &startupinfoex,
+ HANDLE stdout_handle, HANDLE stderr_handle, HANDLE stdin_handle) {
+ std::vector<HANDLE> inherited_handles;
+
+ startupinfoex.StartupInfo.hStdError =
+ stderr_handle ? stderr_handle : GetStdHandle(STD_ERROR_HANDLE);
+ startupinfoex.StartupInfo.hStdInput =
+ stdin_handle ? stdin_handle : GetStdHandle(STD_INPUT_HANDLE);
+ startupinfoex.StartupInfo.hStdOutput =
+ stdout_handle ? stdout_handle : GetStdHandle(STD_OUTPUT_HANDLE);
+
+ if (startupinfoex.StartupInfo.hStdError)
+ inherited_handles.push_back(startupinfoex.StartupInfo.hStdError);
+ if (startupinfoex.StartupInfo.hStdInput)
+ inherited_handles.push_back(startupinfoex.StartupInfo.hStdInput);
+ if (startupinfoex.StartupInfo.hStdOutput)
+ inherited_handles.push_back(startupinfoex.StartupInfo.hStdOutput);
+
+ for (size_t i = 0; i < launch_info.GetNumFileActions(); ++i) {
+ const FileAction *act = launch_info.GetFileActionAtIndex(i);
+ if (act->GetAction() == FileAction::eFileActionDuplicate &&
+ act->GetFD() == act->GetActionArgument())
+ inherited_handles.push_back(reinterpret_cast<HANDLE>(act->GetFD()));
+ }
+
+ if (inherited_handles.empty())
+ return inherited_handles;
+
+ if (!UpdateProcThreadAttribute(
+ startupinfoex.lpAttributeList, /*dwFlags=*/0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST, inherited_handles.data(),
+ inherited_handles.size() * sizeof(HANDLE),
+ /*lpPreviousValue=*/nullptr, /*lpReturnSize=*/nullptr))
+ return llvm::mapWindowsError(::GetLastError());
+
+ return inherited_handles;
+}
+
HANDLE
ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info,
int fd) {
@@ -201,7 +241,6 @@ ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info,
secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
secattr.bInheritHandle = TRUE;
- llvm::StringRef path = action->GetPath();
DWORD access = 0;
DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
DWORD create = 0;
@@ -218,6 +257,7 @@ ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info,
flags = FILE_FLAG_WRITE_THROUGH;
}
+ const std::string path = action->GetFileSpec().GetPath();
std::wstring wpath;
llvm::ConvertUTF8toWide(path, wpath);
HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create,
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index ffcc9ce..cb6acfc 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -3708,7 +3708,7 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line,
for (uint32_t i = 0; i < num_matches; ++i) {
error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
}
- result.AppendRawError(error_msg.GetString());
+ result.AppendError(error_msg.GetString());
}
} else {
// We didn't have only one match, otherwise we wouldn't get here.
diff --git a/lldb/source/Interpreter/CommandReturnObject.cpp b/lldb/source/Interpreter/CommandReturnObject.cpp
index 0a2948e..85b058e 100644
--- a/lldb/source/Interpreter/CommandReturnObject.cpp
+++ b/lldb/source/Interpreter/CommandReturnObject.cpp
@@ -8,7 +8,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Utility/DiagnosticsRendering.h"
+#include "lldb/Host/common/DiagnosticsRendering.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
@@ -173,15 +173,6 @@ StructuredData::ObjectSP CommandReturnObject::GetErrorData() {
return Serialize(m_diagnostics);
}
-// Similar to AppendError, but do not prepend 'Status: ' to message, and don't
-// append "\n" to the end of it.
-
-void CommandReturnObject::AppendRawError(llvm::StringRef in_string) {
- SetStatus(eReturnStatusFailed);
- assert(!in_string.empty() && "Expected a non-empty error message");
- GetErrorStream() << in_string;
-}
-
void CommandReturnObject::SetStatus(ReturnStatus status) { m_status = status; }
ReturnStatus CommandReturnObject::GetStatus() const { return m_status; }
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index cae61781..eab452c 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -14,13 +14,13 @@
#include <set>
#include "lldb/Host/OptionParser.h"
+#include "lldb/Host/common/DiagnosticsRendering.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#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"
@@ -1410,7 +1410,9 @@ llvm::Error lldb_private::CreateOptionParsingError(
llvm::StringRef long_option, llvm::StringRef additional_context) {
std::string buffer;
llvm::raw_string_ostream stream(buffer);
- stream << "Invalid value ('" << option_arg << "') for -" << short_option;
+ stream << "invalid value ('" << option_arg << "')";
+ if (short_option)
+ stream << " for -" << short_option;
if (!long_option.empty())
stream << " (" << long_option << ")";
if (!additional_context.empty())
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index ca768db..7bad10f 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -106,6 +106,13 @@ ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
return Status();
}
+lldb::ThreadSP ScriptInterpreter::GetOpaqueTypeFromSBThread(
+ const lldb::SBThread &thread) const {
+ if (thread.m_opaque_sp)
+ return thread.m_opaque_sp->GetThreadSP();
+ return nullptr;
+}
+
lldb::StackFrameSP
ScriptInterpreter::GetOpaqueTypeFromSBFrame(const lldb::SBFrame &frame) const {
if (frame.m_opaque_sp)
@@ -136,7 +143,7 @@ SymbolContext ScriptInterpreter::GetOpaqueTypeFromSBSymbolContext(
return {};
}
-std::optional<MemoryRegionInfo>
+std::optional<lldb_private::MemoryRegionInfo>
ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
const lldb::SBMemoryRegionInfo &mem_region) const {
if (!mem_region.m_opaque_up)
@@ -150,6 +157,11 @@ ScriptInterpreter::GetOpaqueTypeFromSBExecutionContext(
return exe_ctx.m_exe_ctx_sp;
}
+lldb::StackFrameListSP ScriptInterpreter::GetOpaqueTypeFromSBFrameList(
+ const lldb::SBFrameList &frame_list) const {
+ return frame_list.m_opaque_sp;
+}
+
lldb::ScriptLanguage
ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
index ff37b48..a5547a4 100644
--- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
+++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
@@ -798,6 +798,8 @@ bool ABISysV_riscv::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
.Cases({"f8", "f9", "f18", "f19", "f20", "f21", "f22", "f23"},
is_hw_fp)
.Cases({"f24", "f25", "f26", "f27"}, is_hw_fp)
+ // vlenb is constant and needed for vector unwinding.
+ .Case("vlenb", true)
.Default(false);
return is_callee_saved;
diff --git a/lldb/source/Plugins/CMakeLists.txt b/lldb/source/Plugins/CMakeLists.txt
index 08f444e..b6878b2 100644
--- a/lldb/source/Plugins/CMakeLists.txt
+++ b/lldb/source/Plugins/CMakeLists.txt
@@ -22,6 +22,7 @@ add_subdirectory(SymbolFile)
add_subdirectory(SystemRuntime)
add_subdirectory(SymbolLocator)
add_subdirectory(SymbolVendor)
+add_subdirectory(SyntheticFrameProvider)
add_subdirectory(Trace)
add_subdirectory(TraceExporter)
add_subdirectory(TypeSystem)
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index 66d0a50..e8bb706 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -70,6 +70,7 @@ public:
bool HasDelaySlot(llvm::MCInst &mc_inst) const;
bool IsCall(llvm::MCInst &mc_inst) const;
bool IsLoad(llvm::MCInst &mc_inst) const;
+ bool IsBarrier(llvm::MCInst &mc_inst) const;
bool IsAuthenticated(llvm::MCInst &mc_inst) const;
private:
@@ -436,6 +437,11 @@ public:
return m_is_load;
}
+ bool IsBarrier() override {
+ VisitInstruction();
+ return m_is_barrier;
+ }
+
bool IsAuthenticated() override {
VisitInstruction();
return m_is_authenticated;
@@ -1195,6 +1201,7 @@ protected:
bool m_is_call = false;
bool m_is_load = false;
bool m_is_authenticated = false;
+ bool m_is_barrier = false;
void VisitInstruction() {
if (m_has_visited_instruction)
@@ -1227,6 +1234,7 @@ protected:
m_is_call = mc_disasm_ptr->IsCall(inst);
m_is_load = mc_disasm_ptr->IsLoad(inst);
m_is_authenticated = mc_disasm_ptr->IsAuthenticated(inst);
+ m_is_barrier = mc_disasm_ptr->IsBarrier(inst);
}
private:
@@ -1432,6 +1440,11 @@ bool DisassemblerLLVMC::MCDisasmInstance::IsLoad(llvm::MCInst &mc_inst) const {
return m_instr_info_up->get(mc_inst.getOpcode()).mayLoad();
}
+bool DisassemblerLLVMC::MCDisasmInstance::IsBarrier(
+ llvm::MCInst &mc_inst) const {
+ return m_instr_info_up->get(mc_inst.getOpcode()).isBarrier();
+}
+
bool DisassemblerLLVMC::MCDisasmInstance::IsAuthenticated(
llvm::MCInst &mc_inst) const {
const auto &InstrDesc = m_instr_info_up->get(mc_inst.getOpcode());
diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index 1d210ea..2d0a4f67 100644
--- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -789,6 +789,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule(
// Search for the kext on the local filesystem via the UUID
if (!m_module_sp && m_uuid.IsValid()) {
ModuleSpec module_spec;
+ module_spec.SetTarget(target.shared_from_this());
module_spec.GetUUID() = m_uuid;
if (!m_uuid.IsValid())
module_spec.GetArchitecture() = target.GetArchitecture();
@@ -801,9 +802,8 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule(
// system.
PlatformSP platform_sp(target.GetPlatform());
if (platform_sp) {
- FileSpecList search_paths = target.GetExecutableSearchPaths();
- platform_sp->GetSharedModule(module_spec, process, m_module_sp,
- &search_paths, nullptr, nullptr);
+ platform_sp->GetSharedModule(module_spec, process, m_module_sp, nullptr,
+ nullptr);
}
// Ask the Target to find this file on the local system, if possible.
diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 326b691..3605e7b2 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -469,7 +469,8 @@ void DynamicLoaderPOSIXDYLD::RefreshModules() {
}
ModuleSP module_sp = LoadModuleAtAddress(
- so_entry.file_spec, so_entry.link_addr, so_entry.base_addr, true);
+ so_entry.file_spec, so_entry.link_addr, so_entry.base_addr,
+ /*base_addr_is_offset=*/true);
if (!module_sp.get())
return;
@@ -726,9 +727,8 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
task_group.async(load_module_fn, *I);
task_group.wait();
} else {
- for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) {
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
load_module_fn(*I);
- }
}
m_process->GetTarget().ModulesDidLoad(module_list);
@@ -901,10 +901,9 @@ void DynamicLoaderPOSIXDYLD::ResolveExecutableModule(
if (module_sp && module_sp->MatchesModuleSpec(module_spec))
return;
+ module_spec.SetTarget(target.shared_from_this());
const auto executable_search_paths(Target::GetDefaultExecutableSearchPaths());
- auto error = platform_sp->ResolveExecutable(
- module_spec, module_sp,
- !executable_search_paths.IsEmpty() ? &executable_search_paths : nullptr);
+ auto error = platform_sp->ResolveExecutable(module_spec, module_sp);
if (error.Fail()) {
StreamString stream;
module_spec.Dump(stream);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
index 01d588f..759a7c4 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
@@ -51,10 +51,10 @@ add_lldb_library(lldbPluginExpressionParserClang
CLANG_LIBS
clangAST
clangCodeGen
- clangDriver
clangEdit
clangFrontend
clangLex
+ clangOptions
clangParse
clangRewrite
clangRewriteFrontend
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 9900745..bae3c44 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DarwinSDKInfo.h"
+#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
@@ -25,7 +26,6 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
@@ -115,6 +115,7 @@ class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks {
ClangModulesDeclVendor &m_decl_vendor;
ClangPersistentVariables &m_persistent_vars;
clang::SourceManager &m_source_mgr;
+ /// Accumulates error messages across all moduleImport calls.
StreamString m_error_stream;
bool m_has_errors = false;
@@ -140,11 +141,12 @@ public:
module.path.push_back(
ConstString(component.getIdentifierInfo()->getName()));
- StreamString error_stream;
-
ClangModulesDeclVendor::ModuleVector exported_modules;
- if (!m_decl_vendor.AddModule(module, &exported_modules, m_error_stream))
+ if (auto err = m_decl_vendor.AddModule(module, &exported_modules)) {
m_has_errors = true;
+ m_error_stream.PutCString(llvm::toString(std::move(err)));
+ m_error_stream.PutChar('\n');
+ }
for (ClangModulesDeclVendor::ModuleID module : exported_modules)
m_persistent_vars.AddHandLoadedClangModule(module);
@@ -169,9 +171,9 @@ public:
: m_options(opts), m_filename(filename) {
m_options.ShowPresumedLoc = true;
m_options.ShowLevel = false;
- m_os = std::make_shared<llvm::raw_string_ostream>(m_output);
+ m_os = std::make_unique<llvm::raw_string_ostream>(m_output);
m_passthrough =
- std::make_shared<clang::TextDiagnosticPrinter>(*m_os, m_options);
+ std::make_unique<clang::TextDiagnosticPrinter>(*m_os, m_options);
}
void ResetManager(DiagnosticManager *manager = nullptr) {
@@ -313,11 +315,11 @@ public:
private:
DiagnosticManager *m_manager = nullptr;
DiagnosticOptions m_options;
- std::shared_ptr<clang::TextDiagnosticPrinter> m_passthrough;
- /// Output stream of m_passthrough.
- std::shared_ptr<llvm::raw_string_ostream> m_os;
/// Output string filled by m_os.
std::string m_output;
+ /// Output stream of m_passthrough.
+ std::unique_ptr<llvm::raw_string_ostream> m_os;
+ std::unique_ptr<clang::TextDiagnosticPrinter> m_passthrough;
StringRef m_filename;
};
@@ -1502,7 +1504,7 @@ lldb_private::Status ClangExpressionParser::DoPrepareForExecution(
LLDB_LOGF(log, "%s - Current expression language is %s\n", __FUNCTION__,
lang.GetDescription().data());
lldb::ProcessSP process_sp = exe_ctx.GetProcessSP();
- if (process_sp && lang != lldb::eLanguageTypeUnknown) {
+ if (process_sp && lang) {
auto runtime = process_sp->GetLanguageRuntime(lang.AsLanguageType());
if (runtime)
runtime->GetIRPasses(custom_passes);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index ff9ed9c..ad48d29 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -383,10 +383,11 @@ bool ClangExpressionSourceCode::GetText(
block->CalculateSymbolContext(&sc);
if (sc.comp_unit) {
- StreamString error_stream;
-
- decl_vendor->AddModulesForCompileUnit(
- *sc.comp_unit, modules_for_macros, error_stream);
+ if (auto err = decl_vendor->AddModulesForCompileUnit(
+ *sc.comp_unit, modules_for_macros))
+ LLDB_LOG_ERROR(
+ GetLog(LLDBLog::Expressions), std::move(err),
+ "Error while loading hand-imported modules:\n{0}");
}
}
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
index 6de8510..660a21e 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
@@ -10,7 +10,7 @@
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
-#include "clang/Driver/Driver.h"
+#include "clang/Options/OptionUtils.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -53,7 +53,7 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
std::string raw_path = lldb_shlib_spec.GetPath();
llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path);
static const std::string clang_resource_path =
- clang::driver::Driver::GetResourcesPath("bin/lldb");
+ clang::GetResourcesPath("bin/lldb");
static const llvm::StringRef kResourceDirSuffixes[] = {
// LLVM.org's build of LLDB uses the clang resource directory placed
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index b77e269..ce8dc50b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -10,6 +10,7 @@
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Driver/CreateInvocationFromArgs.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -67,13 +68,13 @@ private:
IDAndDiagnostic;
std::vector<IDAndDiagnostic> m_diagnostics;
std::unique_ptr<clang::DiagnosticOptions> m_diag_opts;
+ /// Output string filled by m_os. Will be reused for different diagnostics.
+ std::string m_output;
+ /// Output stream of m_diag_printer.
+ std::unique_ptr<llvm::raw_string_ostream> m_os;
/// The DiagnosticPrinter used for creating the full diagnostic messages
/// that are stored in m_diagnostics.
std::unique_ptr<clang::TextDiagnosticPrinter> m_diag_printer;
- /// Output stream of m_diag_printer.
- std::unique_ptr<llvm::raw_string_ostream> m_os;
- /// Output string filled by m_os. Will be reused for different diagnostics.
- std::string m_output;
/// A Progress with explicitly managed lifetime.
std::unique_ptr<Progress> m_current_progress_up;
std::vector<std::string> m_module_build_stack;
@@ -92,11 +93,11 @@ public:
~ClangModulesDeclVendorImpl() override = default;
- bool AddModule(const SourceModule &module, ModuleVector *exported_modules,
- Stream &error_stream) override;
+ llvm::Error AddModule(const SourceModule &module,
+ ModuleVector *exported_modules) override;
- bool AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules,
- Stream &error_stream) override;
+ llvm::Error AddModulesForCompileUnit(CompileUnit &cu,
+ ModuleVector &exported_modules) override;
uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches,
std::vector<CompilerDecl> &decls) override;
@@ -273,16 +274,14 @@ void ClangModulesDeclVendorImpl::ReportModuleExports(
exports.push_back(module);
}
-bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
- ModuleVector *exported_modules,
- Stream &error_stream) {
+llvm::Error
+ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
+ ModuleVector *exported_modules) {
// Fail early.
- if (m_compiler_instance->hadModuleLoaderFatalFailure()) {
- error_stream.PutCString("error: Couldn't load a module because the module "
- "loader is in a fatal state.\n");
- return false;
- }
+ if (m_compiler_instance->hadModuleLoaderFatalFailure())
+ return llvm::createStringError(
+ "couldn't load a module because the module loader is in a fatal state");
// Check if we've already imported this module.
@@ -297,7 +296,7 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
if (mi != m_imported_modules.end()) {
if (exported_modules)
ReportModuleExports(*exported_modules, mi->second);
- return true;
+ return llvm::Error::success();
}
}
@@ -315,30 +314,30 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
std::equal(sysroot_begin, sysroot_end, path_begin);
// No need to inject search paths to modules in the sysroot.
if (!is_system_module) {
- auto error = [&]() {
- error_stream.Printf("error: No module map file in %s\n",
- module.search_path.AsCString());
- return false;
- };
-
bool is_system = true;
bool is_framework = false;
auto dir = HS.getFileMgr().getOptionalDirectoryRef(
module.search_path.GetStringRef());
if (!dir)
- return error();
+ return llvm::createStringError(
+ "couldn't find module search path directory %s",
+ module.search_path.GetCString());
+
auto file = HS.lookupModuleMapFile(*dir, is_framework);
if (!file)
- return error();
+ return llvm::createStringError("couldn't find modulemap file in %s",
+ module.search_path.GetCString());
+
if (HS.parseAndLoadModuleMapFile(*file, is_system))
- return error();
+ return llvm::createStringError(
+ "failed to parse and load modulemap file in %s",
+ module.search_path.GetCString());
}
}
- if (!HS.lookupModule(module.path.front().GetStringRef())) {
- error_stream.Printf("error: Header search couldn't locate module '%s'\n",
- module.path.front().AsCString());
- return false;
- }
+
+ if (!HS.lookupModule(module.path.front().GetStringRef()))
+ return llvm::createStringError("header search couldn't locate module '%s'",
+ module.path.front().AsCString());
llvm::SmallVector<clang::IdentifierLoc, 4> clang_path;
@@ -364,22 +363,29 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
clang::Module *top_level_module = DoGetModule(clang_path.front(), false);
if (!top_level_module) {
+ lldb_private::StreamString error_stream;
diagnostic_consumer->DumpDiagnostics(error_stream);
- error_stream.Printf("error: Couldn't load top-level module %s\n",
- module.path.front().AsCString());
- return false;
+
+ return llvm::createStringError(llvm::formatv(
+ "couldn't load top-level module {0}:\n{1}",
+ module.path.front().GetStringRef(), error_stream.GetString()));
}
clang::Module *submodule = top_level_module;
for (auto &component : llvm::ArrayRef<ConstString>(module.path).drop_front()) {
- submodule = submodule->findSubmodule(component.GetStringRef());
- if (!submodule) {
+ clang::Module *found = submodule->findSubmodule(component.GetStringRef());
+ if (!found) {
+ lldb_private::StreamString error_stream;
diagnostic_consumer->DumpDiagnostics(error_stream);
- error_stream.Printf("error: Couldn't load submodule %s\n",
- component.GetCString());
- return false;
+
+ return llvm::createStringError(llvm::formatv(
+ "couldn't load submodule '{0}' of module '{1}':\n{2}",
+ component.GetStringRef(), submodule->getFullModuleName(),
+ error_stream.GetString()));
}
+
+ submodule = found;
}
// If we didn't make the submodule visible here, Clang wouldn't allow LLDB to
@@ -399,10 +405,12 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
m_enabled = true;
- return true;
+ return llvm::Error::success();
}
- return false;
+ return llvm::createStringError(
+ llvm::formatv("unknown error while loading module {0}\n",
+ module.path.front().GetStringRef()));
}
bool ClangModulesDeclVendor::LanguageSupportsClangModules(
@@ -424,15 +432,18 @@ bool ClangModulesDeclVendor::LanguageSupportsClangModules(
}
}
-bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit(
- CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules,
- Stream &error_stream) {
- if (LanguageSupportsClangModules(cu.GetLanguage())) {
- for (auto &imported_module : cu.GetImportedModules())
- if (!AddModule(imported_module, &exported_modules, error_stream))
- return false;
- }
- return true;
+llvm::Error ClangModulesDeclVendorImpl::AddModulesForCompileUnit(
+ CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules) {
+ if (!LanguageSupportsClangModules(cu.GetLanguage()))
+ return llvm::Error::success();
+
+ llvm::Error errors = llvm::Error::success();
+
+ for (auto &imported_module : cu.GetImportedModules())
+ if (auto err = AddModule(imported_module, &exported_modules))
+ errors = llvm::joinErrors(std::move(errors), std::move(err));
+
+ return errors;
}
// ClangImporter::lookupValue
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
index ad4d060..0436320 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
@@ -41,21 +41,16 @@ public:
/// The path to the exact module to be loaded. E.g., if the desired
/// module is std.io, then this should be { "std", "io" }.
///
- /// \param[in] exported_modules
+ /// \param[out] exported_modules
/// If non-NULL, a pointer to a vector to populate with the ID of every
/// module that is re-exported by the specified module.
///
- /// \param[in] error_stream
- /// A stream to populate with the output of the Clang parser when
- /// it tries to load the module.
- ///
/// \return
/// True if the module could be loaded; false if not. If the
/// compiler encountered a fatal error during a previous module
/// load, then this will always return false for this ModuleImporter.
- virtual bool AddModule(const SourceModule &module,
- ModuleVector *exported_modules,
- Stream &error_stream) = 0;
+ virtual llvm::Error AddModule(const SourceModule &module,
+ ModuleVector *exported_modules) = 0;
/// Add all modules referred to in a given compilation unit to the list
/// of modules to search.
@@ -63,22 +58,17 @@ public:
/// \param[in] cu
/// The compilation unit to scan for imported modules.
///
- /// \param[in] exported_modules
+ /// \param[out] exported_modules
/// A vector to populate with the ID of each module loaded (directly
/// and via re-exports) in this way.
///
- /// \param[in] error_stream
- /// A stream to populate with the output of the Clang parser when
- /// it tries to load the modules.
- ///
/// \return
/// True if all modules referred to by the compilation unit could be
/// loaded; false if one could not be loaded. If the compiler
/// encountered a fatal error during a previous module
/// load, then this will always return false for this ModuleImporter.
- virtual bool AddModulesForCompileUnit(CompileUnit &cu,
- ModuleVector &exported_modules,
- Stream &error_stream) = 0;
+ virtual llvm::Error
+ AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules) = 0;
/// Enumerate all the macros that are defined by a given set of modules
/// that are already imported.
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index e8d5ec3..d1feda1 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -371,26 +371,20 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target,
if (!sc.comp_unit)
return;
- StreamString error_stream;
-
ClangModulesDeclVendor::ModuleVector modules_for_macros =
persistent_state->GetHandLoadedClangModules();
- if (decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros,
- error_stream))
- return;
- // Failed to load some modules, so emit the error stream as a diagnostic.
- if (!error_stream.Empty()) {
- // The error stream already contains several Clang diagnostics that might
- // be either errors or warnings, so just print them all as one remark
- // diagnostic to prevent that the message starts with "error: error:".
- diagnostic_manager.PutString(lldb::eSeverityInfo, error_stream.GetString());
+ auto err =
+ decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros);
+ if (!err)
return;
- }
- diagnostic_manager.PutString(lldb::eSeverityError,
- "Unknown error while loading modules needed for "
- "current compilation unit.");
+ // Module load errors aren't fatal to the expression evaluator. Printing
+ // them as diagnostics to the console would be too noisy and misleading
+ // Hence just print them to the expression log.
+ llvm::handleAllErrors(std::move(err), [](const llvm::StringError &e) {
+ LLDB_LOG(GetLog(LLDBLog::Expressions), "{0}", e.getMessage());
+ });
}
ClangExpressionSourceCode::WrapKind ClangUserExpression::GetWrapKind() const {
diff --git a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
index a8901be..f124424 100644
--- a/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
+++ b/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp
@@ -346,6 +346,16 @@ EmulateInstructionARM64::GetOpcodeForInstruction(const uint32_t opcode) {
&EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
"LDR <Xt>, [<Xn|SP>{, #<pimm>}]"},
+ {0x3f200c00, 0x3c000400, No_VFP,
+ &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_POST>,
+ "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>], #<simm>"},
+ {0x3f200c00, 0x3c000c00, No_VFP,
+ &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_PRE>,
+ "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>, #<simm>]!"},
+ {0x3f000000, 0x3d000000, No_VFP,
+ &EmulateInstructionARM64::EmulateLDRSTRImm<AddrMode_OFF>,
+ "LDR|STR <Bt|Ht|St|Dt|Qt>, [<Xn|SP>{, #<pimm>}]"},
+
{0xfc000000, 0x14000000, No_VFP, &EmulateInstructionARM64::EmulateB,
"B <label>"},
{0xff000010, 0x54000000, No_VFP, &EmulateInstructionARM64::EmulateBcond,
@@ -930,9 +940,29 @@ template <EmulateInstructionARM64::AddrMode a_mode>
bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
uint32_t size = Bits32(opcode, 31, 30);
uint32_t opc = Bits32(opcode, 23, 22);
+ uint32_t vr = Bit32(opcode, 26);
uint32_t n = Bits32(opcode, 9, 5);
uint32_t t = Bits32(opcode, 4, 0);
+ MemOp memop;
+ if (vr) {
+ // opc<1> == 1 && size != 0 is an undefined encoding.
+ if (Bit32(opc, 1) == 1 && size != 0)
+ return false;
+ // opc<1> == 1 && size == 0 encode the 128-bit variant.
+ if (Bit32(opc, 1) == 1)
+ size = 4;
+ memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
+ } else {
+ if (Bit32(opc, 1) == 0) {
+ memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
+ } else {
+ memop = MemOp_LOAD;
+ if (size == 2 && Bit32(opc, 0) == 1)
+ return false;
+ }
+ }
+
bool wback;
bool postindex;
uint64_t offset;
@@ -955,16 +985,6 @@ bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
break;
}
- MemOp memop;
-
- if (Bit32(opc, 1) == 0) {
- memop = Bit32(opc, 0) == 1 ? MemOp_LOAD : MemOp_STORE;
- } else {
- memop = MemOp_LOAD;
- if (size == 2 && Bit32(opc, 0) == 1)
- return false;
- }
-
Status error;
bool success = false;
uint64_t address;
@@ -989,7 +1009,8 @@ bool EmulateInstructionARM64::EmulateLDRSTRImm(const uint32_t opcode) {
return false;
std::optional<RegisterInfo> reg_info_Rt =
- GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);
+ vr ? GetRegisterInfo(eRegisterKindLLDB, fpu_d0_arm64 + t)
+ : GetRegisterInfo(eRegisterKindLLDB, gpr_x0_arm64 + t);
if (!reg_info_Rt)
return false;
diff --git a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
index 5c1b7d4..2957cb71 100644
--- a/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
+++ b/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp
@@ -1328,32 +1328,36 @@ public:
m_emu, inst, 8, ZextD,
[](uint64_t a, uint64_t b) { return std::max(a, b); });
}
- template <typename T>
- bool F_Load(T inst, const fltSemantics &(*semantics)(),
- unsigned int numBits) {
+ template <typename I, typename T>
+ bool F_Load(I inst, const fltSemantics &(*semantics)()) {
return transformOptional(inst.rs1.Read(m_emu),
[&](auto &&rs1) {
- uint64_t addr = rs1 + uint64_t(inst.imm);
- uint64_t bits = *m_emu.ReadMem<uint64_t>(addr);
+ uint64_t addr =
+ rs1 + uint64_t(SignExt(inst.imm));
+ uint64_t bits = *m_emu.ReadMem<T>(addr);
+ unsigned numBits = sizeof(T) * 8;
APFloat f(semantics(), APInt(numBits, bits));
return inst.rd.WriteAPFloat(m_emu, f);
})
.value_or(false);
}
- bool operator()(FLW inst) { return F_Load(inst, &APFloat::IEEEsingle, 32); }
- template <typename T> bool F_Store(T inst, bool isDouble) {
+ bool operator()(FLW inst) {
+ return F_Load<FLW, uint32_t>(inst, &APFloat::IEEEsingle);
+ }
+ template <typename I, typename T> bool F_Store(I inst, bool isDouble) {
return transformOptional(zipOpt(inst.rs1.Read(m_emu),
inst.rs2.ReadAPFloat(m_emu, isDouble)),
[&](auto &&tup) {
auto [rs1, rs2] = tup;
- uint64_t addr = rs1 + uint64_t(inst.imm);
+ uint64_t addr =
+ rs1 + uint64_t(SignExt(inst.imm));
uint64_t bits =
rs2.bitcastToAPInt().getZExtValue();
- return m_emu.WriteMem<uint64_t>(addr, bits);
+ return m_emu.WriteMem<T>(addr, bits);
})
.value_or(false);
}
- bool operator()(FSW inst) { return F_Store(inst, false); }
+ bool operator()(FSW inst) { return F_Store<FSW, uint32_t>(inst, false); }
std::tuple<bool, APFloat> FusedMultiplyAdd(APFloat rs1, APFloat rs2,
APFloat rs3) {
auto opStatus = rs1.fusedMultiplyAdd(rs2, rs3, m_emu.GetRoundingMode());
@@ -1616,8 +1620,10 @@ public:
bool operator()(FCVT_S_LU inst) {
return FCVT_f2i(inst, &Rs::Read, APFloat::IEEEsingle());
}
- bool operator()(FLD inst) { return F_Load(inst, &APFloat::IEEEdouble, 64); }
- bool operator()(FSD inst) { return F_Store(inst, true); }
+ bool operator()(FLD inst) {
+ return F_Load<FLD, uint64_t>(inst, &APFloat::IEEEdouble);
+ }
+ bool operator()(FSD inst) { return F_Store<FSD, uint64_t>(inst, true); }
bool operator()(FMADD_D inst) { return FMA(inst, true, 1.0f, 1.0f); }
bool operator()(FMSUB_D inst) { return FMA(inst, true, 1.0f, -1.0f); }
bool operator()(FNMSUB_D inst) { return FMA(inst, true, -1.0f, 1.0f); }
diff --git a/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/CMakeLists.txt
new file mode 100644
index 0000000..adbd6c4
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_lldb_library(lldbPluginInstrumentationRuntimeBoundsSafety PLUGIN
+ InstrumentationRuntimeBoundsSafety.cpp
+
+ LINK_LIBS
+ lldbBreakpoint
+ lldbCore
+ lldbSymbol
+ lldbTarget
+ lldbPluginInstrumentationRuntimeUtility
+
+ CLANG_LIBS
+ clangCodeGen
+ )
diff --git a/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.cpp b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.cpp
new file mode 100644
index 0000000..db9b213
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.cpp
@@ -0,0 +1,481 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "InstrumentationRuntimeBoundsSafety.h"
+
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+
+#include <memory>
+#include <type_traits>
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(InstrumentationRuntimeBoundsSafety)
+
+constexpr llvm::StringLiteral
+ BoundsSafetySoftTrapMinimal("__bounds_safety_soft_trap");
+constexpr llvm::StringLiteral
+ BoundsSafetySoftTrapStr("__bounds_safety_soft_trap_s");
+
+constexpr std::array<llvm::StringLiteral, 2>
+getBoundsSafetySoftTrapRuntimeFuncs() {
+ return {BoundsSafetySoftTrapMinimal, BoundsSafetySoftTrapStr};
+}
+
+#define SOFT_TRAP_CATEGORY_PREFIX "Soft "
+#define SOFT_TRAP_FALLBACK_CATEGORY \
+ SOFT_TRAP_CATEGORY_PREFIX "Bounds check failed"
+
+using ComputedStopInfo =
+ std::pair<std::optional<std::string>, std::optional<uint32_t>>;
+
+class InstrumentationBoundsSafetyStopInfo : public StopInfo {
+public:
+ ~InstrumentationBoundsSafetyStopInfo() override = default;
+
+ lldb::StopReason GetStopReason() const override {
+ return lldb::eStopReasonInstrumentation;
+ }
+
+ std::optional<uint32_t>
+ GetSuggestedStackFrameIndex(bool inlined_stack) override {
+ return m_value;
+ }
+
+ const char *GetDescription() override { return m_description.c_str(); }
+
+ bool DoShouldNotify(Event *event_ptr) override { return true; }
+
+ static lldb::StopInfoSP
+ CreateInstrumentationBoundsSafetyStopInfo(Thread &thread) {
+ return StopInfoSP(new InstrumentationBoundsSafetyStopInfo(thread));
+ }
+
+private:
+ InstrumentationBoundsSafetyStopInfo(Thread &thread);
+
+ ComputedStopInfo
+ ComputeStopReasonAndSuggestedStackFrame(bool &warning_emitted_for_failure);
+
+ ComputedStopInfo ComputeStopReasonAndSuggestedStackFrameWithDebugInfo(
+ lldb::StackFrameSP parent_sf, lldb::user_id_t debugger_id,
+ bool &warning_emitted_for_failure);
+
+ ComputedStopInfo ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo(
+ ThreadSP thread_sp, lldb::user_id_t debugger_id,
+ bool &warning_emitted_for_failure);
+};
+
+InstrumentationBoundsSafetyStopInfo::InstrumentationBoundsSafetyStopInfo(
+ Thread &thread)
+ : StopInfo(thread, 0) {
+ // No additional data describing the reason for stopping.
+ m_extended_info = nullptr;
+ m_description = SOFT_TRAP_FALLBACK_CATEGORY;
+
+ bool warning_emitted_for_failure = false;
+ auto [MaybeDescription, MaybeSuggestedStackIndex] =
+ ComputeStopReasonAndSuggestedStackFrame(warning_emitted_for_failure);
+ if (MaybeDescription)
+ m_description = MaybeDescription.value();
+ if (MaybeSuggestedStackIndex)
+ m_value = MaybeSuggestedStackIndex.value();
+
+ // Emit warning about the failure to compute the stop info if one wasn't
+ // already emitted.
+ if ((!MaybeDescription.has_value()) && !warning_emitted_for_failure) {
+ if (ThreadSP thread_sp = GetThread()) {
+ lldb::user_id_t debugger_id =
+ thread_sp->GetProcess()->GetTarget().GetDebugger().GetID();
+ Debugger::ReportWarning(
+ "specific BoundsSafety trap reason could not be computed",
+ debugger_id);
+ }
+ }
+}
+
+// Helper functions to make it convenient to log a failure and then return.
+template <typename T, typename... ArgTys>
+[[nodiscard]] T LogBeforeReturn(ArgTys &&...Args) {
+ LLDB_LOG(GetLog(LLDBLog::InstrumentationRuntime), Args...);
+ return T();
+}
+
+template <typename... ArgTys>
+[[nodiscard]] ComputedStopInfo LogFailedCSI(ArgTys &&...Args) {
+ return LogBeforeReturn<ComputedStopInfo>(Args...);
+}
+
+ComputedStopInfo
+InstrumentationBoundsSafetyStopInfo::ComputeStopReasonAndSuggestedStackFrame(
+ bool &warning_emitted_for_failure) {
+ ThreadSP thread_sp = GetThread();
+ if (!thread_sp)
+ return LogFailedCSI("failed to get thread while stopped");
+
+ lldb::user_id_t debugger_id =
+ thread_sp->GetProcess()->GetTarget().GetDebugger().GetID();
+
+ StackFrameSP parent_sf = thread_sp->GetStackFrameAtIndex(1);
+ if (!parent_sf)
+ return LogFailedCSI("got nullptr when fetching stackframe at index 1");
+
+ if (parent_sf->HasDebugInformation())
+ return ComputeStopReasonAndSuggestedStackFrameWithDebugInfo(
+ parent_sf, debugger_id, warning_emitted_for_failure);
+
+ // If the debug info is missing we can still get some information
+ // from the parameter in the soft trap runtime call.
+ return ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo(
+ thread_sp, debugger_id, warning_emitted_for_failure);
+}
+
+ComputedStopInfo InstrumentationBoundsSafetyStopInfo::
+ ComputeStopReasonAndSuggestedStackFrameWithDebugInfo(
+ lldb::StackFrameSP parent_sf, lldb::user_id_t debugger_id,
+ bool &warning_emitted_for_failure) {
+ // First try to use debug info to understand the reason for trapping. The
+ // call stack will look something like this:
+ //
+ // ```
+ // frame #0: `__bounds_safety_soft_trap_s(reason="")
+ // frame #1: `__clang_trap_msg$Bounds check failed$<reason>'
+ // frame #2: `bad_read(index=10)
+ // ```
+ // ....
+ const char *TrapReasonFuncName = parent_sf->GetFunctionName();
+
+ auto MaybeTrapReason =
+ clang::CodeGen::DemangleTrapReasonInDebugInfo(TrapReasonFuncName);
+ if (!MaybeTrapReason.has_value())
+ return LogFailedCSI(
+ "clang::CodeGen::DemangleTrapReasonInDebugInfo(\"{0}\") call failed",
+ TrapReasonFuncName);
+
+ llvm::StringRef category = MaybeTrapReason.value().first;
+ llvm::StringRef message = MaybeTrapReason.value().second;
+
+ // TODO: Clang should probably be changed to emit the "Soft " prefix itself
+ std::string stop_reason;
+ llvm::raw_string_ostream ss(stop_reason);
+ ss << SOFT_TRAP_CATEGORY_PREFIX;
+ if (category.empty())
+ ss << "<empty category>";
+ else
+ ss << category;
+ if (message.empty()) {
+ // This is not a failure so leave `warning_emitted_for_failure` untouched.
+ Debugger::ReportWarning(
+ "specific BoundsSafety trap reason is not "
+ "available because the compiler omitted it from the debug info",
+ debugger_id);
+ } else {
+ ss << ": " << message;
+ }
+ // Use computed stop-reason and assume the parent of `parent_sf` is the
+ // the place in the user's code where the call to the soft trap runtime
+ // originated.
+ return std::make_pair(stop_reason, parent_sf->GetFrameIndex() + 1);
+}
+
+ComputedStopInfo InstrumentationBoundsSafetyStopInfo::
+ ComputeStopReasonAndSuggestedStackFrameWithoutDebugInfo(
+ ThreadSP thread_sp, lldb::user_id_t debugger_id,
+ bool &warning_emitted_for_failure) {
+
+ StackFrameSP softtrap_sf = thread_sp->GetStackFrameAtIndex(0);
+ if (!softtrap_sf)
+ return LogFailedCSI("got nullptr when fetching stackframe at index 0");
+ llvm::StringRef trap_reason_func_name = softtrap_sf->GetFunctionName();
+
+ if (trap_reason_func_name == BoundsSafetySoftTrapMinimal) {
+ // This function has no arguments so there's no additional information
+ // that would allow us to identify the trap reason.
+ //
+ // Use the fallback stop reason and the current frame.
+ // While we "could" set the suggested frame to our parent (where the
+ // bounds check failed), doing this leads to very misleading output in
+ // LLDB. E.g.:
+ //
+ // ```
+ // 0x100003b40 <+104>: bl 0x100003d64 ; __bounds_safety_soft_trap
+ // -> 0x100003b44 <+108>: b 0x100003b48 ; <+112>
+ // ```
+ //
+ // This makes it look we stopped after finishing the call to
+ // `__bounds_safety_soft_trap` but actually we are in the middle of the
+ // call. To avoid this confusion just use the current frame.
+ std::string warning;
+ llvm::raw_string_ostream ss(warning);
+ ss << "specific BoundsSafety trap reason is not available because debug "
+ "info is missing on the caller of '"
+ << BoundsSafetySoftTrapMinimal << "'";
+ Debugger::ReportWarning(warning.c_str(), debugger_id);
+ warning_emitted_for_failure = true;
+ return {};
+ }
+
+ // __bounds_safety_soft_trap_s has one argument which is a pointer to a string
+ // describing the trap or a nullptr.
+ if (trap_reason_func_name != BoundsSafetySoftTrapStr) {
+ assert(0 && "hit breakpoint for unexpected function name");
+ return LogFailedCSI(
+ "unexpected function name. Expected \"{0}\" but got \"{1}\"",
+ BoundsSafetySoftTrapStr.data(), trap_reason_func_name.data());
+ }
+
+ RegisterContextSP rc = thread_sp->GetRegisterContext();
+ if (!rc)
+ return LogFailedCSI("failed to get register context");
+
+ // FIXME: LLDB should have an API that tells us for the current target if
+ // `LLDB_REGNUM_GENERIC_ARG1` can be used.
+ // https://github.com/llvm/llvm-project/issues/168602
+ // Don't try for architectures where examining the first register won't
+ // work.
+ ProcessSP process = thread_sp->GetProcess();
+ if (!process)
+ return LogFailedCSI("failed to get process");
+
+ switch (process->GetTarget().GetArchitecture().GetCore()) {
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_32_i686: {
+ // Technically some x86 calling conventions do use a register for
+ // passing the first argument but let's ignore that for now.
+ std::string warning;
+ llvm::raw_string_ostream ss(warning);
+ ss << "specific BoundsSafety trap reason cannot be inferred on x86 when "
+ "the caller of '"
+ << BoundsSafetySoftTrapStr << "' is missing debug info";
+ Debugger::ReportWarning(warning.c_str(), debugger_id);
+ warning_emitted_for_failure = true;
+ return {};
+ }
+ default: {
+ }
+ };
+
+ // Examine the register for the first argument.
+ const RegisterInfo *arg0_info = rc->GetRegisterInfo(
+ lldb::RegisterKind::eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
+ if (!arg0_info)
+ return LogFailedCSI(
+ "failed to get register info for LLDB_REGNUM_GENERIC_ARG1");
+ RegisterValue reg_value;
+ if (!rc->ReadRegister(arg0_info, reg_value))
+ return LogFailedCSI("failed to read register {0}", arg0_info->name);
+ uint64_t reg_value_as_int = reg_value.GetAsUInt64(UINT64_MAX);
+ if (reg_value_as_int == UINT64_MAX)
+ return LogFailedCSI("failed to read register {0} as a UInt64",
+ arg0_info->name);
+
+ if (reg_value_as_int == 0) {
+ // nullptr arg. The compiler will pass that if no trap reason string was
+ // available.
+ Debugger::ReportWarning(
+ "specific BoundsSafety trap reason cannot be inferred because the "
+ "compiler omitted the reason",
+ debugger_id);
+ warning_emitted_for_failure = true;
+ return {};
+ }
+
+ // The first argument to the call is a pointer to a global C string
+ // containing the trap reason.
+ std::string out_string;
+ Status error_status;
+ thread_sp->GetProcess()->ReadCStringFromMemory(reg_value_as_int, out_string,
+ error_status);
+ if (error_status.Fail())
+ return LogFailedCSI("failed to read C string from address {0}",
+ (void *)reg_value_as_int);
+
+ LLDB_LOG(GetLog(LLDBLog::InstrumentationRuntime),
+ "read C string from {0} found in register {1}: \"{2}\"",
+ (void *)reg_value_as_int, arg0_info->name, out_string.c_str());
+ std::string stop_reason;
+ llvm::raw_string_ostream SS(stop_reason);
+ SS << SOFT_TRAP_FALLBACK_CATEGORY;
+ if (!stop_reason.empty()) {
+ SS << ": " << out_string;
+ }
+ // Use the current frame as the suggested frame for the same reason as for
+ // `__bounds_safety_soft_trap`.
+ return {stop_reason, 0};
+}
+
+InstrumentationRuntimeBoundsSafety::~InstrumentationRuntimeBoundsSafety() {
+ Deactivate();
+}
+
+lldb::InstrumentationRuntimeSP
+InstrumentationRuntimeBoundsSafety::CreateInstance(
+ const lldb::ProcessSP &process_sp) {
+ return InstrumentationRuntimeSP(
+ new InstrumentationRuntimeBoundsSafety(process_sp));
+}
+
+void InstrumentationRuntimeBoundsSafety::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ "BoundsSafety instrumentation runtime plugin.",
+ CreateInstance, GetTypeStatic);
+}
+
+void InstrumentationRuntimeBoundsSafety::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb::InstrumentationRuntimeType
+InstrumentationRuntimeBoundsSafety::GetTypeStatic() {
+ return lldb::eInstrumentationRuntimeTypeBoundsSafety;
+}
+
+const RegularExpression &
+InstrumentationRuntimeBoundsSafety::GetPatternForRuntimeLibrary() {
+ static RegularExpression regex;
+ return regex;
+}
+
+bool InstrumentationRuntimeBoundsSafety::CheckIfRuntimeIsValid(
+ const lldb::ModuleSP module_sp) {
+ Log *log_category = GetLog(LLDBLog::InstrumentationRuntime);
+ for (const auto &SoftTrapFunc : getBoundsSafetySoftTrapRuntimeFuncs()) {
+ ConstString test_sym(SoftTrapFunc);
+
+ if (module_sp->FindFirstSymbolWithNameAndType(test_sym,
+ lldb::eSymbolTypeAny)) {
+ LLDB_LOG(log_category, "found \"{0}\" in {1}",
+ test_sym.AsCString("<unknown symbol>"),
+ module_sp->GetObjectName().AsCString("<unknown module>"));
+ return true;
+ }
+ }
+ LLDB_LOG(log_category,
+ "did not find BoundsSafety soft trap functions in module {0}",
+ module_sp->GetObjectName().AsCString("<unknown module>"));
+ return false;
+}
+
+bool InstrumentationRuntimeBoundsSafety::NotifyBreakpointHit(
+ void *baton, StoppointCallbackContext *context, user_id_t break_id,
+ user_id_t break_loc_id) {
+ assert(baton && "null baton");
+ if (!baton)
+ return false; ///< false => resume execution.
+
+ InstrumentationRuntimeBoundsSafety *const instance =
+ static_cast<InstrumentationRuntimeBoundsSafety *>(baton);
+
+ ProcessSP process_sp = instance->GetProcessSP();
+ if (!process_sp)
+ return LogBeforeReturn<bool>("failed to get process from baton");
+ ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
+ if (!thread_sp)
+ return LogBeforeReturn<bool>(
+ "failed to get thread from StoppointCallbackContext");
+
+ if (process_sp != context->exe_ctx_ref.GetProcessSP())
+ return LogBeforeReturn<bool>(
+ "process from baton ({0}) and StoppointCallbackContext ({1}) do "
+ "not match",
+ (void *)process_sp.get(),
+ (void *)context->exe_ctx_ref.GetProcessSP().get());
+
+ if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
+ return LogBeforeReturn<bool>("IsLastResumeForUserExpression is true");
+
+ // Maybe the stop reason and stackframe selection should be done by
+ // a stackframe recognizer instead?
+ thread_sp->SetStopInfo(
+ InstrumentationBoundsSafetyStopInfo::
+ CreateInstrumentationBoundsSafetyStopInfo(*thread_sp));
+ return true;
+}
+
+void InstrumentationRuntimeBoundsSafety::Activate() {
+ if (IsActive())
+ return;
+
+ ProcessSP process_sp = GetProcessSP();
+ if (!process_sp)
+ return LogBeforeReturn<void>("could not get process during Activate()");
+
+ std::vector<std::string> breakpoints;
+ for (auto &breakpoint_func : getBoundsSafetySoftTrapRuntimeFuncs())
+ breakpoints.emplace_back(breakpoint_func);
+
+ BreakpointSP breakpoint = process_sp->GetTarget().CreateBreakpoint(
+ /*containingModules=*/nullptr,
+ /*containingSourceFiles=*/nullptr, breakpoints, eFunctionNameTypeFull,
+ eLanguageTypeUnknown,
+ /*m_offset=*/0,
+ /*skip_prologue*/ eLazyBoolNo,
+ /*internal=*/true,
+ /*request_hardware*/ false);
+
+ if (!breakpoint)
+ return LogBeforeReturn<void>("failed to create breakpoint");
+
+ if (!breakpoint->HasResolvedLocations()) {
+ assert(0 && "breakpoint has no resolved locations");
+ process_sp->GetTarget().RemoveBreakpointByID(breakpoint->GetID());
+ return LogBeforeReturn<void>(
+ "breakpoint {0} for BoundsSafety soft traps did not resolve to "
+ "any locations",
+ breakpoint->GetID());
+ }
+
+ // Note: When `sync=true` the suggested stackframe is completely ignored. So
+ // we use `sync=false`. Is that a bug?
+ breakpoint->SetCallback(
+ InstrumentationRuntimeBoundsSafety::NotifyBreakpointHit, this,
+ /*sync=*/false);
+ breakpoint->SetBreakpointKind("bounds-safety-soft-trap");
+ SetBreakpointID(breakpoint->GetID());
+ LLDB_LOG(GetLog(LLDBLog::InstrumentationRuntime),
+ "created breakpoint {0} for BoundsSafety soft traps",
+ breakpoint->GetID());
+ SetActive(true);
+}
+
+void InstrumentationRuntimeBoundsSafety::Deactivate() {
+ SetActive(false);
+ Log *log_category = GetLog(LLDBLog::InstrumentationRuntime);
+ if (ProcessSP process_sp = GetProcessSP()) {
+ bool success =
+ process_sp->GetTarget().RemoveBreakpointByID(GetBreakpointID());
+ LLDB_LOG(log_category,
+ "{0}removed breakpoint {1} for BoundsSafety soft traps",
+ success ? "" : "failed to ", GetBreakpointID());
+ } else {
+ LLDB_LOG(log_category, "no process available during Deactivate()");
+ }
+
+ SetBreakpointID(LLDB_INVALID_BREAK_ID);
+}
diff --git a/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.h b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.h
new file mode 100644
index 0000000..06c30f8
--- /dev/null
+++ b/lldb/source/Plugins/InstrumentationRuntime/BoundsSafety/InstrumentationRuntimeBoundsSafety.h
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_BOUNDS_SAFETY_SOFT_TRAP_H
+#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_BOUNDS_SAFETY_SOFT_TRAP_H
+
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class InstrumentationRuntimeBoundsSafety
+ : public lldb_private::InstrumentationRuntime {
+public:
+ ~InstrumentationRuntimeBoundsSafety() override;
+
+ static lldb::InstrumentationRuntimeSP
+ CreateInstance(const lldb::ProcessSP &process_sp);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "BoundsSafety"; }
+
+ static lldb::InstrumentationRuntimeType GetTypeStatic();
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
+
+private:
+ InstrumentationRuntimeBoundsSafety(const lldb::ProcessSP &process_sp)
+ : lldb_private::InstrumentationRuntime(process_sp) {}
+
+ const RegularExpression &GetPatternForRuntimeLibrary() override;
+
+ bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
+
+ void Activate() override;
+
+ void Deactivate();
+
+ static bool NotifyBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ bool MatchAllModules() override { return true; }
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
index 2a6cf93..b7e1a60 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
+++ b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt
@@ -2,6 +2,7 @@ set_property(DIRECTORY PROPERTY LLDB_PLUGIN_KIND InstrumentationRuntime)
add_subdirectory(ASan)
add_subdirectory(ASanLibsanitizers)
+add_subdirectory(BoundsSafety)
add_subdirectory(MainThreadChecker)
add_subdirectory(TSan)
add_subdirectory(UBSan)
diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
index 38c334b..3642cb1 100644
--- a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
+++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp
@@ -207,8 +207,11 @@ bool ReportRetriever::NotifyBreakpointHit(ProcessSP process_sp,
return false;
StructuredData::ObjectSP report = RetrieveReportData(process_sp);
- if (!report || report->GetType() != lldb::eStructuredDataTypeDictionary)
+ if (!report || report->GetType() != lldb::eStructuredDataTypeDictionary) {
+ LLDB_LOGF(GetLog(LLDBLog::InstrumentationRuntime),
+ "ReportRetriever::RetrieveReportData() failed");
return false;
+ }
std::string description = FormatDescription(report);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index cbc6f14..c52d3bd 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -14,11 +14,11 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
CxxStringTypes.cpp
Generic.cpp
GenericBitset.cpp
+ GenericInitializerList.cpp
GenericList.cpp
GenericOptional.cpp
LibCxx.cpp
LibCxxAtomic.cpp
- LibCxxInitializerList.cpp
LibCxxMap.cpp
LibCxxQueue.cpp
LibCxxRangesRefView.cpp
@@ -31,6 +31,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibCxxValarray.cpp
LibCxxVector.cpp
LibStdcpp.cpp
+ LibStdcppSpan.cpp
LibStdcppTuple.cpp
LibStdcppUniquePointer.cpp
MsvcStl.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index a2199cb..ae6086f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -84,7 +84,7 @@ CPlusPlusLanguage::GetFunctionNameInfo(ConstString name) const {
if (basename.empty()) {
llvm::StringRef context;
func_name_type |=
- (ExtractContextAndIdentifier(name.GetCString(), context, basename)
+ (ExtractContextAndIdentifier(name.GetStringRef(), context, basename)
? (eFunctionNameTypeMethod | eFunctionNameTypeBase)
: eFunctionNameTypeFull);
} else {
@@ -103,7 +103,7 @@ CPlusPlusLanguage::GetFunctionNameInfo(ConstString name) const {
return {func_name_type, ConstString(basename)};
}
-bool CPlusPlusLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
+bool CPlusPlusLanguage::SymbolNameFitsToLanguage(const Mangled &mangled) const {
auto mangling_scheme =
Mangled::GetManglingScheme(mangled.GetMangledName().GetStringRef());
return mangling_scheme == Mangled::eManglingSchemeItanium ||
@@ -208,6 +208,20 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) {
return idx == basename.size();
}
+/// A context is trivial if an only if it matches this pattern.
+/// "^\s*([A-Za-z_:]*)\s*$". for example function `foo::bar::func()`
+/// has a trivial context but. but `foo<int>::bar::func()` doesn't.
+static bool IsTrivialContext(llvm::StringRef context) {
+ // remove trailing or leading whitespace.
+ context = context.trim();
+
+ const auto iter = context.find_if_not([](char current) {
+ return std::isalnum(static_cast<unsigned char>(current)) ||
+ current == '_' || current == ':';
+ });
+ return iter == llvm::StringRef::npos;
+}
+
/// Writes out the function name in 'full_name' to 'out_stream'
/// but replaces each argument type with the variable name
/// and the corresponding pretty-printed value
@@ -481,18 +495,17 @@ bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() {
m_basename = full.substr(basename_begin, basename_end - basename_begin);
}
- if (IsTrivialBasename(m_basename)) {
+ if (IsTrivialBasename(m_basename) && IsTrivialContext(m_context)) {
return true;
- } else {
- // The C++ basename doesn't match our regular expressions so this can't
- // be a valid C++ method, clear everything out and indicate an error
- m_context = llvm::StringRef();
- m_basename = llvm::StringRef();
- m_arguments = llvm::StringRef();
- m_qualifiers = llvm::StringRef();
- m_return_type = llvm::StringRef();
- return false;
}
+ // The C++ basename doesn't match our regular expressions so this can't
+ // be a valid C++ method, clear everything out and indicate an error
+ m_context = llvm::StringRef();
+ m_basename = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ m_return_type = llvm::StringRef();
+ return false;
}
return false;
}
@@ -546,9 +559,8 @@ bool CPlusPlusLanguage::CxxMethodName::ContainsPath(llvm::StringRef path) {
llvm::StringRef identifier;
llvm::StringRef context;
- std::string path_str = path.str();
- bool success = CPlusPlusLanguage::ExtractContextAndIdentifier(
- path_str.c_str(), context, identifier);
+ const bool success =
+ CPlusPlusLanguage::ExtractContextAndIdentifier(path, context, identifier);
if (!success)
return m_full.GetStringRef().contains(path);
@@ -592,7 +604,8 @@ bool CPlusPlusLanguage::DemangledNameContainsPath(llvm::StringRef path,
}
bool CPlusPlusLanguage::ExtractContextAndIdentifier(
- const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
+ llvm::StringRef name, llvm::StringRef &context,
+ llvm::StringRef &identifier) {
if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
identifier);
@@ -899,11 +912,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::unordered containers synthetic children",
"^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$",
stl_synth_flags, true);
- AddCXXSynthetic(
- cpp_category_sp,
- lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator,
- "libc++ std::initializer_list synthetic children",
- "^std::initializer_list<.+>$", stl_synth_flags, true);
AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator,
"libc++ std::queue synthetic children",
"^std::__[[:alnum:]]+::queue<.+>$", stl_synth_flags, true);
@@ -1416,6 +1424,10 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
stl_synth_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
+ AddCXXSynthetic(cpp_category_sp, LibStdcppSpanSyntheticFrontEndCreator,
+ "libstdc++ std::span synthetic children", "^std::span<.+>$",
+ stl_deref_flags, true);
+
stl_summary_flags.SetDontShowChildren(false);
stl_summary_flags.SetSkipPointers(false);
@@ -1506,6 +1518,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
"libstdc++ std::coroutine_handle summary provider",
libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::ContainerSizeSummaryProvider,
+ "libstdc++ std::span summary provider", "^std::span<.+>$",
+ stl_summary_flags, true);
}
static lldb_private::SyntheticChildrenFrontEnd *
@@ -1705,6 +1722,14 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
},
"MSVC STL/libstdc++ std::wstring summary provider"));
+ // NOTE: it is loaded as a common formatter because the libc++ version is not
+ // in the `__1` namespace, hence we need to dispatch based on the class
+ // layout.
+ AddCXXSynthetic(cpp_category_sp,
+ GenericInitializerListSyntheticFrontEndCreator,
+ "std::initializer_list synthetic children",
+ "^std::initializer_list<.+>$", stl_synth_flags, true);
+
stl_summary_flags.SetDontShowChildren(false);
stl_summary_flags.SetSkipPointers(false);
@@ -1748,6 +1773,9 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"^std::(multi)?(map|set)<.+>(( )?&)?$", stl_synth_flags,
true);
+ AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider,
+ "std::initializer_list summary provider",
+ "^std::initializer_list<.+>$", stl_summary_flags, true);
AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
"MSVC STL/libstdc++ std::shared_ptr summary provider",
"^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 9a528ca..b547234 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -92,7 +92,7 @@ public:
static llvm::StringRef GetPluginNameStatic() { return "cplusplus"; }
- bool SymbolNameFitsToLanguage(Mangled mangled) const override;
+ bool SymbolNameFitsToLanguage(const Mangled &mangled) const override;
bool DemangledNameContainsPath(llvm::StringRef path,
ConstString demangled) const override;
@@ -154,7 +154,7 @@ public:
// C/C++ identifier, then it will return false
// and identifier and context will be unchanged.
- static bool ExtractContextAndIdentifier(const char *name,
+ static bool ExtractContextAndIdentifier(llvm::StringRef name,
llvm::StringRef &context,
llvm::StringRef &identifier);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
index d8c095d..4d283bb 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -315,7 +315,7 @@ bool CPlusPlusNameParser::ConsumeAbiTag() {
// Consume the actual tag string (and allow some special characters)
while (ConsumeToken(tok::raw_identifier, tok::comma, tok::period,
- tok::numeric_constant))
+ tok::numeric_constant, tok::kw_operator))
;
if (!ConsumeToken(tok::r_square))
@@ -420,10 +420,11 @@ bool CPlusPlusNameParser::ConsumeOperator() {
// Make sure we have more tokens before attempting to look ahead one more.
if (m_next_token_index + 1 < m_tokens.size()) {
// Look ahead two tokens.
- clang::Token n_token = m_tokens[m_next_token_index + 1];
- // If we find ( or < then this is indeed operator<< no need for fix.
- if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) {
- clang::Token tmp_tok;
+ const clang::Token n_token = m_tokens[m_next_token_index + 1];
+ // If we find `(`, `<` or `[` then this is indeed operator<< no need for
+ // fix.
+ if (!n_token.isOneOf(tok::l_paren, tok::less, tok::l_square)) {
+ clang::Token tmp_tok{};
tmp_tok.startToken();
tmp_tok.setLength(1);
tmp_tok.setLocation(token.getLocation().getLocWithOffset(1));
diff --git a/lldb/source/Plugins/Language/CPlusPlus/Generic.h b/lldb/source/Plugins/Language/CPlusPlus/Generic.h
index f394622..539eddd 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/Generic.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/Generic.h
@@ -24,6 +24,9 @@ bool GenericOptionalSummaryProvider(ValueObject &valobj, Stream &stream,
lldb::ValueObjectSP GetDesugaredSmartPointerValue(ValueObject &ptr,
ValueObject &container);
+SyntheticChildrenFrontEnd *
+GenericInitializerListSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
} // namespace formatters
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp
new file mode 100644
index 0000000..7f012b7
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericInitializerList.cpp
@@ -0,0 +1,145 @@
+//===-- GenericInitializerList.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 "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include <cstddef>
+#include <optional>
+#include <type_traits>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace generic_check {
+template <class T>
+using size_func = decltype(T::GetSizeMember(std::declval<ValueObject &>()));
+template <class T>
+using start_func = decltype(T::GetStartMember(std::declval<ValueObject &>()));
+namespace {
+template <typename...> struct check_func : std::true_type {};
+} // namespace
+
+template <typename T>
+using has_functions = check_func<size_func<T>, start_func<T>>;
+} // namespace generic_check
+
+struct LibCxx {
+ static ValueObjectSP GetStartMember(ValueObject &backend) {
+ return backend.GetChildMemberWithName("__begin_");
+ }
+
+ static ValueObjectSP GetSizeMember(ValueObject &backend) {
+ return backend.GetChildMemberWithName("__size_");
+ }
+};
+
+struct LibStdcpp {
+ static ValueObjectSP GetStartMember(ValueObject &backend) {
+ return backend.GetChildMemberWithName("_M_array");
+ }
+
+ static ValueObjectSP GetSizeMember(ValueObject &backend) {
+ return backend.GetChildMemberWithName("_M_len");
+ }
+};
+
+namespace lldb_private::formatters {
+
+template <class StandardImpl>
+class GenericInitializerListSyntheticFrontEnd
+ : public SyntheticChildrenFrontEnd {
+public:
+ static_assert(generic_check::has_functions<StandardImpl>::value,
+ "Missing Required Functions.");
+
+ GenericInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
+ if (valobj_sp)
+ Update();
+ }
+
+ ~GenericInitializerListSyntheticFrontEnd() override {
+ // this needs to stay around because it's a child object who will follow its
+ // parent's life cycle
+ // delete m_start;
+ }
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ m_num_elements = 0;
+
+ const ValueObjectSP size_sp(StandardImpl::GetSizeMember(m_backend));
+ if (size_sp)
+ m_num_elements = size_sp->GetValueAsUnsigned(0);
+ return m_num_elements;
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ if (!m_start)
+ return {};
+
+ uint64_t offset = static_cast<uint64_t>(idx) * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(name.GetString(), offset,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+ }
+
+ lldb::ChildCacheState Update() override {
+ m_start = nullptr;
+ m_num_elements = 0;
+ m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
+ if (!m_element_type.IsValid())
+ return lldb::ChildCacheState::eRefetch;
+
+ llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
+ if (!size_or_err)
+ LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
+ "{0}");
+ else {
+ m_element_size = *size_or_err;
+ // Store raw pointers or end up with a circular dependency.
+ m_start = StandardImpl::GetStartMember(m_backend).get();
+ }
+
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
+ if (!m_start) {
+ return llvm::createStringError("Type has no child named '%s'",
+ name.AsCString());
+ }
+ auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
+ if (!optional_idx) {
+ return llvm::createStringError("Type has no child named '%s'",
+ name.AsCString());
+ }
+ return *optional_idx;
+ }
+
+private:
+ ValueObject *m_start = nullptr;
+ CompilerType m_element_type;
+ uint32_t m_element_size = 0;
+ size_t m_num_elements = 0;
+};
+
+SyntheticChildrenFrontEnd *GenericInitializerListSyntheticFrontEndCreator(
+ CXXSyntheticChildren * /*unused*/, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+
+ if (LibCxx::GetStartMember(*valobj_sp) != nullptr)
+ return new GenericInitializerListSyntheticFrontEnd<LibCxx>(valobj_sp);
+
+ return new GenericInitializerListSyntheticFrontEnd<LibStdcpp>(valobj_sp);
+}
+} // namespace lldb_private::formatters
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index 5289027..8c5ac31 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -203,6 +203,16 @@ private:
ValueObject *m_tail = nullptr;
};
+/// Gets the (forward-)list element type from the head node instead of the
+/// template arguments. This is needed with PDB as it doesn't have info about
+/// the template arguments.
+CompilerType GetMsvcStlElementTypeFromHead(ValueObject &head) {
+ auto val_sp = head.GetChildMemberWithName("_Myval");
+ if (val_sp)
+ return val_sp->GetCompilerType();
+ return CompilerType();
+}
+
} // end anonymous namespace
template <StlType Stl>
@@ -530,6 +540,10 @@ lldb::ChildCacheState MsvcStlForwardListFrontEnd::Update() {
m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"}))
m_head = head_sp.get();
+ // With PDB, we can't get the element type from the template arguments
+ if (!m_element_type && m_head)
+ m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
+
return ChildCacheState::eRefetch;
}
@@ -606,6 +620,10 @@ lldb::ChildCacheState MsvcStlListFrontEnd::Update() {
m_head = first.get();
m_tail = last.get();
+ // With PDB, we can't get the element type from the template arguments
+ if (!m_element_type && m_head)
+ m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
+
return lldb::ChildCacheState::eRefetch;
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index 819f8a9..8fd2928 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -194,10 +194,6 @@ SyntheticChildrenFrontEnd *
LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
-SyntheticChildrenFrontEnd *
-LibcxxInitializerListSyntheticFrontEndCreator(CXXSyntheticChildren *,
- lldb::ValueObjectSP);
-
SyntheticChildrenFrontEnd *LibcxxQueueFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
deleted file mode 100644
index d952688..0000000
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-//===-- LibCxxInitializerList.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 "LibCxx.h"
-
-#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Utility/ConstString.h"
-#include "lldb/ValueObject/ValueObject.h"
-#include <optional>
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace lldb_private::formatters;
-
-namespace lldb_private {
-namespace formatters {
-class LibcxxInitializerListSyntheticFrontEnd
- : public SyntheticChildrenFrontEnd {
-public:
- LibcxxInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
-
- ~LibcxxInitializerListSyntheticFrontEnd() override;
-
- llvm::Expected<uint32_t> CalculateNumChildren() override;
-
- lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
-
- lldb::ChildCacheState Update() override;
-
- llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
-
-private:
- ValueObject *m_start = nullptr;
- CompilerType m_element_type;
- uint32_t m_element_size = 0;
- size_t m_num_elements = 0;
-};
-} // namespace formatters
-} // namespace lldb_private
-
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
- LibcxxInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
- : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
- if (valobj_sp)
- Update();
-}
-
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
- ~LibcxxInitializerListSyntheticFrontEnd() {
- // this needs to stay around because it's a child object who will follow its
- // parent's life cycle
- // delete m_start;
-}
-
-llvm::Expected<uint32_t> lldb_private::formatters::
- LibcxxInitializerListSyntheticFrontEnd::CalculateNumChildren() {
- m_num_elements = 0;
- ValueObjectSP size_sp(m_backend.GetChildMemberWithName("__size_"));
- if (size_sp)
- m_num_elements = size_sp->GetValueAsUnsigned(0);
- return m_num_elements;
-}
-
-lldb::ValueObjectSP lldb_private::formatters::
- LibcxxInitializerListSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
- if (!m_start)
- return lldb::ValueObjectSP();
-
- uint64_t offset = idx * m_element_size;
- offset = offset + m_start->GetValueAsUnsigned(0);
- StreamString name;
- name.Printf("[%" PRIu64 "]", (uint64_t)idx);
- return CreateValueObjectFromAddress(name.GetString(), offset,
- m_backend.GetExecutionContextRef(),
- m_element_type);
-}
-
-lldb::ChildCacheState
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::Update() {
- m_start = nullptr;
- m_num_elements = 0;
- m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
- if (!m_element_type.IsValid())
- return lldb::ChildCacheState::eRefetch;
-
- llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
- if (!size_or_err)
- LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
- "{0}");
- else {
- m_element_size = *size_or_err;
- // Store raw pointers or end up with a circular dependency.
- m_start = m_backend.GetChildMemberWithName("__begin_").get();
- }
-
- return lldb::ChildCacheState::eRefetch;
-}
-
-llvm::Expected<size_t>
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
- GetIndexOfChildWithName(ConstString name) {
- if (!m_start) {
- return llvm::createStringError("Type has no child named '%s'",
- name.AsCString());
- }
- auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
- if (!optional_idx) {
- return llvm::createStringError("Type has no child named '%s'",
- name.AsCString());
- }
- return *optional_idx;
-}
-
-lldb_private::SyntheticChildrenFrontEnd *
-lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator(
- CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
- return (valobj_sp ? new LibcxxInitializerListSyntheticFrontEnd(valobj_sp)
- : nullptr);
-}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index f4a695e..86f0a5a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -199,9 +199,6 @@ lldb::ChildCacheState VectorIteratorSyntheticFrontEnd::Update() {
if (!valobj_sp)
return lldb::ChildCacheState::eRefetch;
- if (!valobj_sp)
- return lldb::ChildCacheState::eRefetch;
-
ValueObjectSP item_ptr =
formatters::GetChildMemberWithName(*valobj_sp, m_item_names);
if (!item_ptr)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
index 429142f6..8d2c81f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
@@ -38,6 +38,10 @@ LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
SyntheticChildrenFrontEnd *
+LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
LibStdcppTupleSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
new file mode 100644
index 0000000..5e69792
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
@@ -0,0 +1,112 @@
+//===---------------------------------------------------------------------===//
+//
+// 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 "LibStdcpp.h"
+
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <optional>
+
+using namespace lldb;
+
+namespace lldb_private::formatters {
+
+class LibStdcppSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibStdcppSpanSyntheticFrontEnd(const lldb::ValueObjectSP &valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+ }
+
+ ~LibStdcppSpanSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_num_elements;
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ if (!m_start)
+ return {};
+
+ uint64_t offset = (static_cast<uint64_t>(idx) * m_element_size);
+ offset += m_start->GetValueAsUnsigned(0);
+ const std::string name = llvm::formatv("[{0}]", idx);
+ return CreateValueObjectFromAddress(
+ name, offset, m_backend.GetExecutionContextRef(), m_element_type);
+ }
+
+ lldb::ChildCacheState Update() override {
+ const ValueObjectSP data_ptr = m_backend.GetChildMemberWithName("_M_ptr");
+ if (!data_ptr)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_element_type = data_ptr->GetCompilerType().GetPointeeType();
+
+ // Get element size.
+ llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
+ if (!size_or_err) {
+ LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
+ "{0}");
+ return lldb::ChildCacheState::eReuse;
+ }
+
+ m_element_size = *size_or_err;
+ if (m_element_size > 0) {
+ m_start = data_ptr.get();
+ }
+
+ // Get number of elements.
+ if (const ValueObjectSP size_sp =
+ m_backend.GetChildAtNamePath({"_M_extent", "_M_extent_value"})) {
+ m_num_elements = size_sp->GetValueAsUnsigned(0);
+ } else if (const auto arg =
+ m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) {
+
+ m_num_elements = arg->value.GetAPSInt().getLimitedValue();
+ }
+
+ return lldb::ChildCacheState::eReuse;
+ }
+
+ llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
+ if (!m_start)
+ return llvm::createStringError(
+ llvm::formatv("Type has no child named {0}", name.GetStringRef()));
+
+ auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
+ if (!optional_idx) {
+ return llvm::createStringError(
+ llvm::formatv("Type has no child named {0}", name.GetStringRef()));
+ }
+ return *optional_idx;
+ }
+
+private:
+ ValueObject *m_start = nullptr; ///< First element of span. Held, not owned.
+ CompilerType m_element_type; ///< Type of span elements.
+ size_t m_num_elements = 0; ///< Number of elements in span.
+ uint32_t m_element_size = 0; ///< Size in bytes of each span element.
+};
+
+SyntheticChildrenFrontEnd *
+LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren * /*unused*/,
+ lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ const CompilerType type = valobj_sp->GetCompilerType();
+ if (!type || type.GetNumTemplateArguments() != 2)
+ return nullptr;
+ return new LibStdcppSpanSyntheticFrontEnd(valobj_sp);
+}
+
+} // namespace lldb_private::formatters
diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
index 7d814e65..150b233 100644
--- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp
+++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -419,8 +419,6 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::Update() {
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return lldb::ChildCacheState::eRefetch;
- if (!valobj_sp)
- return lldb::ChildCacheState::eRefetch;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
index 3b8e21c..c0dcb95 100644
--- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -235,7 +235,7 @@ ObjCLanguage::GetFunctionNameInfo(ConstString name) const {
return {func_name_type, std::nullopt};
}
-bool ObjCLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
+bool ObjCLanguage::SymbolNameFitsToLanguage(const Mangled &mangled) const {
ConstString demangled_name = mangled.GetDemangledName();
if (!demangled_name)
return false;
@@ -1065,3 +1065,10 @@ ObjCLanguage::GetBooleanFromString(llvm::StringRef str) const {
.Case("NO", {false})
.Default({});
}
+
+bool ObjCLanguage::IsPossibleObjCMethodName(llvm::StringRef name) {
+ if (!name.starts_with("-[") && !name.starts_with("+["))
+ return false;
+
+ return name.ends_with("]");
+}
diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
index a68ea41..ced6bd3 100644
--- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
+++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
@@ -145,7 +145,7 @@ public:
std::pair<lldb::FunctionNameType, std::optional<ConstString>>
GetFunctionNameInfo(ConstString name) const override;
- bool SymbolNameFitsToLanguage(Mangled mangled) const override;
+ bool SymbolNameFitsToLanguage(const Mangled &mangled) const override;
lldb::TypeCategoryImplSP GetFormatters() override;
@@ -175,13 +175,7 @@ public:
static llvm::StringRef GetPluginNameStatic() { return "objc"; }
- static bool IsPossibleObjCMethodName(const char *name) {
- if (!name)
- return false;
- bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
- bool ends_right = (name[strlen(name) - 1] == ']');
- return (starts_right && ends_right);
- }
+ static bool IsPossibleObjCMethodName(llvm::StringRef name);
static bool IsPossibleObjCSelector(const char *name) {
if (!name)
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
index 1717b0a..727c829 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
@@ -1,10 +1,13 @@
add_lldb_library(lldbPluginCPPRuntime
CPPLanguageRuntime.cpp
+ VerboseTrapFrameRecognizer.cpp
LINK_LIBS
lldbCore
lldbSymbol
lldbTarget
+ CLANG_LIBS
+ clangCodeGen
)
add_subdirectory(ItaniumABI)
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
index 21a5ebe..913678b 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp
@@ -12,6 +12,7 @@
#include <memory>
#include "CPPLanguageRuntime.h"
+#include "VerboseTrapFrameRecognizer.h"
#include "llvm/ADT/StringRef.h"
@@ -107,12 +108,15 @@ public:
CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
: LanguageRuntime(process) {
- if (process)
+ if (process) {
process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
StackFrameRecognizerSP(new LibCXXFrameRecognizer()), {},
std::make_shared<RegularExpression>("^std::__[^:]*::"),
/*mangling_preference=*/Mangled::ePreferDemangledWithoutArguments,
/*first_instruction_only=*/false);
+
+ RegisterVerboseTrapFrameRecognizer(*process);
+ }
}
bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) {
diff --git a/lldb/source/Target/VerboseTrapFrameRecognizer.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.cpp
index 03ab58b..2b6bf2c 100644
--- a/lldb/source/Target/VerboseTrapFrameRecognizer.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.cpp
@@ -1,4 +1,4 @@
-#include "lldb/Target/VerboseTrapFrameRecognizer.h"
+#include "VerboseTrapFrameRecognizer.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Function.h"
@@ -95,33 +95,14 @@ VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
if (func_name.empty())
return {};
- static auto trap_regex =
- llvm::Regex(llvm::formatv("^{0}\\$(.*)\\$(.*)$", ClangTrapPrefix).str());
- SmallVector<llvm::StringRef, 3> matches;
- std::string regex_err_msg;
- if (!trap_regex.match(func_name, &matches, &regex_err_msg)) {
- LLDB_LOGF(GetLog(LLDBLog::Unwind),
- "Failed to parse match trap regex for '%s': %s", func_name.data(),
- regex_err_msg.c_str());
-
- return {};
- }
-
- // For `__clang_trap_msg$category$message$` we expect 3 matches:
- // 1. entire string
- // 2. category
- // 3. message
- if (matches.size() != 3) {
- LLDB_LOGF(GetLog(LLDBLog::Unwind),
- "Unexpected function name format. Expected '<trap prefix>$<trap "
- "category>$<trap message>'$ but got: '%s'.",
- func_name.data());
-
+ auto maybe_trap_reason =
+ clang::CodeGen::DemangleTrapReasonInDebugInfo(func_name);
+ if (!maybe_trap_reason.has_value()) {
+ LLDB_LOGF(GetLog(LLDBLog::Unwind), "Failed to demangle '%s' as trap reason",
+ func_name.str().c_str());
return {};
}
-
- auto category = matches[1];
- auto message = matches[2];
+ auto [category, message] = maybe_trap_reason.value();
std::string stop_reason =
category.empty() ? "<empty category>" : category.str();
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.h
new file mode 100644
index 0000000..7d7020f
--- /dev/null
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.h
@@ -0,0 +1,47 @@
+//===-- VerboseTrapFrameRecognizer.h --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_C_PLUS_PLUS_VERBOSETRAPFRAMERECOGNIZER_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_C_PLUS_PLUS_VERBOSETRAPFRAMERECOGNIZER_H
+
+#include "lldb/Target/StackFrameRecognizer.h"
+
+namespace lldb_private {
+
+void RegisterVerboseTrapFrameRecognizer(Process &process);
+
+/// Holds the stack frame that caused the Verbose trap and the inlined stop
+/// reason message.
+class VerboseTrapRecognizedStackFrame : public RecognizedStackFrame {
+public:
+ VerboseTrapRecognizedStackFrame(lldb::StackFrameSP most_relevant_frame_sp,
+ std::string stop_desc);
+
+ lldb::StackFrameSP GetMostRelevantFrame() override;
+
+private:
+ lldb::StackFrameSP m_most_relevant_frame;
+};
+
+/// When a thread stops, it checks the current frame contains a
+/// Verbose Trap diagnostic. If so, it returns a \a
+/// VerboseTrapRecognizedStackFrame holding the diagnostic a stop reason
+/// description with and the parent frame as the most relavant frame.
+class VerboseTrapFrameRecognizer : public StackFrameRecognizer {
+public:
+ std::string GetName() override {
+ return "Verbose Trap StackFrame Recognizer";
+ }
+
+ lldb::RecognizedStackFrameSP
+ RecognizeFrame(lldb::StackFrameSP frame) override;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_C_PLUS_PLUS_VERBOSETRAPFRAMERECOGNIZER_H
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
index 954f269..ebde889 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
@@ -111,7 +111,6 @@ bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) {
process->GetAddressByteSize());
lldb::offset_t cursor = 0;
-
m_flags = extractor.GetU32_unchecked(&cursor);
m_version = extractor.GetU32_unchecked(&cursor);
m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
@@ -119,18 +118,16 @@ bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) {
m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr);
m_method_list_ptr = extractor.GetAddress_unchecked(&cursor);
m_properties_ptr = extractor.GetAddress_unchecked(&cursor);
- m_firstSubclass = extractor.GetAddress_unchecked(&cursor);
- m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor);
if (m_ro_ptr & 1) {
DataBufferHeap buffer(ptr_size, '\0');
process->ReadMemory(m_ro_ptr ^ 1, buffer.GetBytes(), ptr_size, error);
if (error.Fail())
return false;
- cursor = 0;
DataExtractor extractor(buffer.GetBytes(), ptr_size,
process->GetByteOrder(),
process->GetAddressByteSize());
+ lldb::offset_t cursor = 0;
m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
if (ABISP abi_sp = process->GetABI())
m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr);
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
index 0fff9af..8d19b00 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
@@ -133,9 +133,6 @@ private:
lldb::addr_t m_properties_ptr;
lldb::addr_t m_protocols_ptr;
- ObjCLanguageRuntime::ObjCISA m_firstSubclass;
- ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;
-
bool Read(Process *process, lldb::addr_t addr);
};
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 9beb133..83e39f3 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -320,7 +320,7 @@ extern "C"
static const char *g_get_shared_cache_class_info_name =
"__lldb_apple_objc_v2_get_shared_cache_class_info";
-static const char *g_get_shared_cache_class_info_body = R"(
+static const char *g_get_shared_cache_class_info_definitions = R"(
extern "C"
{
@@ -411,6 +411,9 @@ struct ClassInfo
Class isa;
uint32_t hash;
} __attribute__((__packed__));
+)";
+
+static const char *g_get_shared_cache_class_info_body = R"(
uint32_t
__lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
@@ -418,6 +421,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
void *class_infos_ptr,
uint64_t *relative_selector_offset,
uint32_t class_infos_byte_size,
+ uint32_t *start_idx,
uint32_t should_log)
{
*relative_selector_offset = 0;
@@ -426,6 +430,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);
DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
+ DEBUG_PRINTF ("start_idx = %u\n", *start_idx);
if (objc_opt_ro_ptr)
{
const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
@@ -480,7 +485,11 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
- for (uint32_t i=0; i<clsopt->capacity; ++i)
+ const uint32_t original_start_idx = *start_idx;
+
+ // Always start at the start_idx here. If it's greater than the capacity,
+ // it will skip the loop entirely and go to the duplicate handling below.
+ for (uint32_t i=*start_idx; i<clsopt->capacity; ++i)
{
const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
@@ -524,59 +533,78 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
else
{
DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
+ *start_idx = i;
+ break;
}
++idx;
}
- const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
- const uint32_t duplicate_count = *duplicate_count_ptr;
- const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
-
- DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
- DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
-
- for (uint32_t i=0; i<duplicate_count; ++i)
- {
- const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
- DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
+ if (idx < max_class_infos) {
+ const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
+ const uint32_t duplicate_count = *duplicate_count_ptr;
+ const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
- if (classOffsets[i].isDuplicate) {
- DEBUG_PRINTF("isDuplicate = true\n");
- continue; // duplicate
- }
+ DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
+ DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
- if (objectCacheOffset == 0) {
- DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
- continue; // invalid offset
- }
+ const uint32_t duplicate_start_idx =
+ *start_idx < clsopt->capacity ?
+ 0 :
+ *start_idx - clsopt->capacity;
- if (class_infos && idx < max_class_infos)
+ for (uint32_t i=duplicate_start_idx; i<duplicate_count; ++i)
{
- class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
+ const uint64_t objectCacheOffset = duplicateClassOffsets[i].objectCacheOffset;
+ DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
- // Lookup the class name.
- const char *name = class_name_lookup_func(class_infos[idx].isa);
- DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+ if (duplicateClassOffsets[i].isDuplicate) {
+ DEBUG_PRINTF("isDuplicate = true\n");
+ continue; // duplicate
+ }
- // Hash the class name so we don't have to read it.
- const char *s = name;
- uint32_t h = 5381;
- for (unsigned char c = *s; c; c = *++s)
+ if (objectCacheOffset == 0) {
+ DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
+ continue; // invalid offset
+ }
+
+ if (class_infos && idx < max_class_infos)
{
- // class_getName demangles swift names and the hash must
- // be calculated on the mangled name. hash==0 means lldb
- // will fetch the mangled name and compute the hash in
- // ParseClassInfoArray.
- if (c == '.')
+ class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
+
+ // Lookup the class name.
+ const char *name = class_name_lookup_func(class_infos[idx].isa);
+ DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
+
+ // Hash the class name so we don't have to read it.
+ const char *s = name;
+ uint32_t h = 5381;
+ for (unsigned char c = *s; c; c = *++s)
{
- h = 0;
- break;
+ // class_getName demangles swift names and the hash must
+ // be calculated on the mangled name. hash==0 means lldb
+ // will fetch the mangled name and compute the hash in
+ // ParseClassInfoArray.
+ if (c == '.')
+ {
+ h = 0;
+ break;
+ }
+ h = ((h << 5) + h) + c;
}
- h = ((h << 5) + h) + c;
+ class_infos[idx].hash = h;
+ } else {
+ DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
+ *start_idx = i;
+ break;
}
- class_infos[idx].hash = h;
+ ++idx;
}
}
+ // Always make sure start_idx gets updated. Otherwise we have an infinite
+ // loop if there are exactly max_class_infos number of classes.
+ if (*start_idx == original_start_idx) {
+ *start_idx = idx;
+ }
}
else if (objc_opt->version >= 12 && objc_opt->version <= 15)
{
@@ -1937,6 +1965,7 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
class_name_getter_function_name.AsCString(),
class_name_getter_function_name.AsCString());
+ shared_class_expression += g_get_shared_cache_class_info_definitions;
shared_class_expression += g_get_shared_cache_class_info_body;
auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
@@ -1958,6 +1987,9 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
CompilerType clang_uint64_t_pointer_type =
scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64)
.GetPointerType();
+ CompilerType clang_uint32_t_pointer_type =
+ scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32)
+ .GetPointerType();
// Next make the function caller for our implementation utility function.
ValueList arguments;
@@ -1975,6 +2007,13 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
value.SetValueType(Value::ValueType::Scalar);
value.SetCompilerType(clang_uint32_t_type);
arguments.PushValue(value);
+
+ value.SetValueType(Value::ValueType::Scalar);
+ value.SetCompilerType(clang_uint32_t_pointer_type);
+ arguments.PushValue(value);
+
+ value.SetValueType(Value::ValueType::Scalar);
+ value.SetCompilerType(clang_uint32_t_type);
arguments.PushValue(value);
std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);
@@ -2312,10 +2351,7 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
// The number of entries to pre-allocate room for.
// Each entry is (addrsize + 4) bytes
- // FIXME: It is not sustainable to continue incrementing this value every time
- // the shared cache grows. This is because it requires allocating memory in
- // the inferior process and some inferior processes have small memory limits.
- const uint32_t max_num_classes = 212992;
+ const uint32_t max_num_classes_in_buffer = 212992;
UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction(exe_ctx);
if (!get_class_info_code) {
@@ -2337,15 +2373,22 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
DiagnosticManager diagnostics;
const uint32_t class_info_byte_size = addr_size + 4;
- const uint32_t class_infos_byte_size = max_num_classes * class_info_byte_size;
+ const uint32_t class_infos_byte_size =
+ max_num_classes_in_buffer * class_info_byte_size;
lldb::addr_t class_infos_addr = process->AllocateMemory(
class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
const uint32_t relative_selector_offset_addr_size = 64;
lldb::addr_t relative_selector_offset_addr =
process->AllocateMemory(relative_selector_offset_addr_size,
ePermissionsReadable | ePermissionsWritable, err);
+ constexpr uint32_t class_info_start_idx_byte_size = sizeof(uint32_t);
+ lldb::addr_t class_info_start_idx_addr =
+ process->AllocateMemory(class_info_start_idx_byte_size,
+ ePermissionsReadable | ePermissionsWritable, err);
- if (class_infos_addr == LLDB_INVALID_ADDRESS) {
+ if (class_infos_addr == LLDB_INVALID_ADDRESS ||
+ relative_selector_offset_addr == LLDB_INVALID_ADDRESS ||
+ class_info_start_idx_addr == LLDB_INVALID_ADDRESS) {
LLDB_LOGF(log,
"unable to allocate %" PRIu32
" bytes in process for shared cache read",
@@ -2353,6 +2396,17 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
return DescriptorMapUpdateResult::Fail();
}
+ const uint32_t start_idx_init_value = 0;
+ size_t bytes_written = process->WriteMemory(
+ class_info_start_idx_addr, &start_idx_init_value, sizeof(uint32_t), err);
+ if (bytes_written != sizeof(uint32_t)) {
+ LLDB_LOGF(log,
+ "unable to write %" PRIu32
+ " bytes in process for shared cache read",
+ class_infos_byte_size);
+ return DescriptorMapUpdateResult::Fail();
+ }
+
std::lock_guard<std::mutex> guard(m_mutex);
// Fill in our function argument values
@@ -2361,12 +2415,13 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
arguments.GetValueAtIndex(2)->GetScalar() = class_infos_addr;
arguments.GetValueAtIndex(3)->GetScalar() = relative_selector_offset_addr;
arguments.GetValueAtIndex(4)->GetScalar() = class_infos_byte_size;
+ arguments.GetValueAtIndex(5)->GetScalar() = class_info_start_idx_addr;
// Only dump the runtime classes from the expression evaluation if the log is
// verbose:
Log *type_log = GetLog(LLDBLog::Types);
bool dump_log = type_log && type_log->GetVerbose();
- arguments.GetValueAtIndex(5)->GetScalar() = dump_log ? 1 : 0;
+ arguments.GetValueAtIndex(6)->GetScalar() = dump_log ? 1 : 0;
bool success = false;
@@ -2393,78 +2448,80 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
diagnostics.Clear();
- // Run the function
- ExpressionResults results =
- get_shared_cache_class_info_function->ExecuteFunction(
- exe_ctx, &m_args, options, diagnostics, return_value);
-
- if (results == eExpressionCompleted) {
- // The result is the number of ClassInfo structures that were filled in
- num_class_infos = return_value.GetScalar().ULong();
- LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache",
- num_class_infos);
- // Assert if there were more classes than we pre-allocated
- // room for.
- assert(num_class_infos <= max_num_classes);
- if (num_class_infos > 0) {
- if (num_class_infos > max_num_classes) {
- num_class_infos = max_num_classes;
-
- success = false;
- } else {
+ uint32_t num_class_infos_read = 0;
+ bool already_read_relative_selector_offset = false;
+
+ do {
+ // Run the function.
+ ExpressionResults results =
+ get_shared_cache_class_info_function->ExecuteFunction(
+ exe_ctx, &m_args, options, diagnostics, return_value);
+
+ if (results == eExpressionCompleted) {
+ // The result is the number of ClassInfo structures that were filled in.
+ num_class_infos_read = return_value.GetScalar().ULong();
+ num_class_infos += num_class_infos_read;
+ LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache",
+ num_class_infos_read);
+ if (num_class_infos_read > 0) {
success = true;
- }
- // Read the relative selector offset.
- DataBufferHeap relative_selector_offset_buffer(64, 0);
- if (process->ReadMemory(relative_selector_offset_addr,
- relative_selector_offset_buffer.GetBytes(),
- relative_selector_offset_buffer.GetByteSize(),
- err) ==
- relative_selector_offset_buffer.GetByteSize()) {
- DataExtractor relative_selector_offset_data(
- relative_selector_offset_buffer.GetBytes(),
- relative_selector_offset_buffer.GetByteSize(),
- process->GetByteOrder(), addr_size);
- lldb::offset_t offset = 0;
- uint64_t relative_selector_offset =
- relative_selector_offset_data.GetU64(&offset);
- if (relative_selector_offset > 0) {
- // The offset is relative to the objc_opt struct.
- m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +
- relative_selector_offset);
+ // Read the relative selector offset. This only needs to occur once no
+ // matter how many times the function is called.
+ if (!already_read_relative_selector_offset) {
+ DataBufferHeap relative_selector_offset_buffer(64, 0);
+ if (process->ReadMemory(
+ relative_selector_offset_addr,
+ relative_selector_offset_buffer.GetBytes(),
+ relative_selector_offset_buffer.GetByteSize(),
+ err) == relative_selector_offset_buffer.GetByteSize()) {
+ DataExtractor relative_selector_offset_data(
+ relative_selector_offset_buffer.GetBytes(),
+ relative_selector_offset_buffer.GetByteSize(),
+ process->GetByteOrder(), addr_size);
+ lldb::offset_t offset = 0;
+ uint64_t relative_selector_offset =
+ relative_selector_offset_data.GetU64(&offset);
+ if (relative_selector_offset > 0) {
+ // The offset is relative to the objc_opt struct.
+ m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +
+ relative_selector_offset);
+ }
+ }
+ already_read_relative_selector_offset = true;
}
- }
-
- // Read the ClassInfo structures
- DataBufferHeap class_infos_buffer(
- num_class_infos * class_info_byte_size, 0);
- if (process->ReadMemory(class_infos_addr, class_infos_buffer.GetBytes(),
- class_infos_buffer.GetByteSize(),
- err) == class_infos_buffer.GetByteSize()) {
- DataExtractor class_infos_data(class_infos_buffer.GetBytes(),
- class_infos_buffer.GetByteSize(),
- process->GetByteOrder(), addr_size);
- m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);
+ // Read the ClassInfo structures
+ DataBufferHeap class_infos_buffer(
+ num_class_infos_read * class_info_byte_size, 0);
+ if (process->ReadMemory(class_infos_addr,
+ class_infos_buffer.GetBytes(),
+ class_infos_buffer.GetByteSize(),
+ err) == class_infos_buffer.GetByteSize()) {
+ DataExtractor class_infos_data(class_infos_buffer.GetBytes(),
+ class_infos_buffer.GetByteSize(),
+ process->GetByteOrder(), addr_size);
+
+ m_runtime.ParseClassInfoArray(class_infos_data,
+ num_class_infos_read);
+ }
}
- } else {
- success = true;
- }
- } else {
- if (log) {
+ } else if (log) {
LLDB_LOGF(log, "Error evaluating our find class name function.");
diagnostics.Dump(log);
+ break;
}
- }
- } else {
- if (log) {
- LLDB_LOGF(log, "Error writing function arguments.");
- diagnostics.Dump(log);
- }
+ } while (num_class_infos_read == max_num_classes_in_buffer);
+ } else if (log) {
+ LLDB_LOGF(log, "Error writing function arguments.");
+ diagnostics.Dump(log);
}
- // Deallocate the memory we allocated for the ClassInfo array
+ LLDB_LOG(log, "Processed {0} Objective-C classes total from the shared cache",
+ num_class_infos);
+ // Cleanup memory we allocated in the process.
+ process->DeallocateMemory(relative_selector_offset_addr);
+ process->DeallocateMemory(class_info_start_idx_addr);
process->DeallocateMemory(class_infos_addr);
return DescriptorMapUpdateResult(success, false, num_class_infos);
diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
index 33673f1..53ff6ef6 100644
--- a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
+++ b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp
@@ -130,13 +130,13 @@ void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
std::optional<Record::Kind> current_section;
offset_t section_start;
- llvm::StringRef text = toStringRef(m_data.GetData());
+ llvm::StringRef text = toStringRef(m_data_nsp->GetData());
uint32_t next_section_id = 1;
auto maybe_add_section = [&](const uint8_t *end_ptr) {
if (!current_section)
return; // We have been called before parsing the first line.
- offset_t end_offset = end_ptr - m_data.GetDataStart();
+ offset_t end_offset = end_ptr - m_data_nsp->GetDataStart();
auto section_sp = std::make_shared<Section>(
GetModule(), this, next_section_id++,
ConstString(toString(*current_section)), eSectionTypeOther,
@@ -162,8 +162,8 @@ void ObjectFileBreakpad::CreateSections(SectionList &unified_section_list) {
maybe_add_section(line.bytes_begin());
// And start a new one.
current_section = next_section;
- section_start = line.bytes_begin() - m_data.GetDataStart();
+ section_start = line.bytes_begin() - m_data_nsp->GetDataStart();
}
// Finally, add the last section.
- maybe_add_section(m_data.GetDataEnd());
+ maybe_add_section(m_data_nsp->GetDataEnd());
}
diff --git a/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp b/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp
index 1121f69..e78f4f0 100644
--- a/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/COFF/ObjectFileCOFF.cpp
@@ -300,8 +300,8 @@ bool ObjectFileCOFF::ParseHeader() {
std::lock_guard<std::recursive_mutex> guard(module->GetMutex());
- m_data.SetByteOrder(eByteOrderLittle);
- m_data.SetAddressByteSize(GetAddressByteSize());
+ m_data_nsp->SetByteOrder(eByteOrderLittle);
+ m_data_nsp->SetAddressByteSize(GetAddressByteSize());
return true;
}
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 49841e7..5d81b11 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -130,6 +130,29 @@ private:
RelocUnion reloc;
};
+
+lldb::SectionSP MergeSections(lldb::SectionSP lhs, lldb::SectionSP rhs) {
+ assert(lhs && rhs);
+
+ lldb::ModuleSP lhs_module_parent = lhs->GetModule();
+ lldb::ModuleSP rhs_module_parent = rhs->GetModule();
+ assert(lhs_module_parent && rhs_module_parent);
+
+ // Do a sanity check, these should be the same.
+ if (lhs->GetFileAddress() != rhs->GetFileAddress())
+ lhs_module_parent->ReportWarning(
+ "Mismatch addresses for section {0} when "
+ "merging with {1}, expected: {2:x}, "
+ "actual: {3:x}",
+ lhs->GetTypeAsCString(),
+ rhs_module_parent->GetFileSpec().GetPathAsConstString().GetCString(),
+ lhs->GetByteSize(), rhs->GetByteSize());
+
+ // We want to take the greater of two sections. If LHS and RHS are both
+ // SHT_NOBITS, we should default to LHS. If RHS has a bigger section,
+ // indicating it has data that wasn't stripped, we should take that instead.
+ return rhs->GetFileSize() > lhs->GetFileSize() ? rhs : lhs;
+}
} // end anonymous namespace
ELFRelocation::ELFRelocation(unsigned type) {
@@ -781,7 +804,7 @@ ByteOrder ObjectFileELF::GetByteOrder() const {
}
uint32_t ObjectFileELF::GetAddressByteSize() const {
- return m_data.GetAddressByteSize();
+ return m_data_nsp->GetAddressByteSize();
}
AddressClass ObjectFileELF::GetAddressClass(addr_t file_addr) {
@@ -822,7 +845,7 @@ size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const {
bool ObjectFileELF::ParseHeader() {
lldb::offset_t offset = 0;
- return m_header.Parse(m_data, &offset);
+ return m_header.Parse(*m_data_nsp.get(), &offset);
}
UUID ObjectFileELF::GetUUID() {
@@ -858,7 +881,7 @@ UUID ObjectFileELF::GetUUID() {
return UUID();
core_notes_crc =
- CalculateELFNotesSegmentsCRC32(m_program_headers, m_data);
+ CalculateELFNotesSegmentsCRC32(m_program_headers, *m_data_nsp.get());
if (core_notes_crc) {
// Use 8 bytes - first 4 bytes for *magic* prefix, mainly to make it
@@ -869,7 +892,7 @@ UUID ObjectFileELF::GetUUID() {
}
} else {
if (!m_gnu_debuglink_crc)
- m_gnu_debuglink_crc = calc_crc32(0, m_data);
+ m_gnu_debuglink_crc = calc_crc32(0, *m_data_nsp.get());
if (m_gnu_debuglink_crc) {
// Use 4 bytes of crc from the .gnu_debuglink section.
u32le data(m_gnu_debuglink_crc);
@@ -1055,7 +1078,8 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
// ParseProgramHeaders
bool ObjectFileELF::ParseProgramHeaders() {
- return GetProgramHeaderInfo(m_program_headers, m_data, m_header) != 0;
+ return GetProgramHeaderInfo(m_program_headers, *m_data_nsp.get(), m_header) !=
+ 0;
}
lldb_private::Status
@@ -1645,8 +1669,8 @@ ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const {
// ParseSectionHeaders
size_t ObjectFileELF::ParseSectionHeaders() {
- return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid,
- m_gnu_debuglink_file, m_gnu_debuglink_crc,
+ return GetSectionHeaderInfo(m_section_headers, *m_data_nsp.get(), m_header,
+ m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc,
m_arch_spec);
}
@@ -1967,10 +1991,10 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) {
provider.AddSection(std::move(*InfoOr), std::move(section_sp));
}
- // For eTypeDebugInfo files, the Symbol Vendor will take care of updating the
- // unified section list.
- if (GetType() != eTypeDebugInfo)
- unified_section_list = *m_sections_up;
+ // Merge the two adding any new sections, and overwriting any existing
+ // sections that are SHT_NOBITS
+ unified_section_list =
+ SectionList::Merge(unified_section_list, *m_sections_up, MergeSections);
// If there's a .gnu_debugdata section, we'll try to read the .symtab that's
// embedded in there and replace the one in the original object file (if any).
@@ -2735,9 +2759,8 @@ static void ApplyELF64ABS64Relocation(Symtab *symtab, ELFRelocation &rel,
// ObjectFileELF creates a WritableDataBuffer in CreateInstance.
WritableDataBuffer *data_buffer =
llvm::cast<WritableDataBuffer>(data_buffer_sp.get());
- uint64_t *dst = reinterpret_cast<uint64_t *>(
- data_buffer->GetBytes() + rel_section->GetFileOffset() +
- ELFRelocation::RelocOffset64(rel));
+ void *const dst = data_buffer->GetBytes() + rel_section->GetFileOffset() +
+ ELFRelocation::RelocOffset64(rel);
uint64_t val_offset = value + ELFRelocation::RelocAddend64(rel);
memcpy(dst, &val_offset, sizeof(uint64_t));
}
@@ -2762,9 +2785,8 @@ static void ApplyELF64ABS32Relocation(Symtab *symtab, ELFRelocation &rel,
// ObjectFileELF creates a WritableDataBuffer in CreateInstance.
WritableDataBuffer *data_buffer =
llvm::cast<WritableDataBuffer>(data_buffer_sp.get());
- uint32_t *dst = reinterpret_cast<uint32_t *>(
- data_buffer->GetBytes() + rel_section->GetFileOffset() +
- ELFRelocation::RelocOffset32(rel));
+ void *const dst = data_buffer->GetBytes() + rel_section->GetFileOffset() +
+ ELFRelocation::RelocOffset32(rel);
memcpy(dst, &truncated_addr, sizeof(uint32_t));
}
}
@@ -3657,7 +3679,8 @@ ArchSpec ObjectFileELF::GetArchitecture() {
if (H.p_type != PT_NOTE || H.p_offset == 0 || H.p_filesz == 0)
continue;
DataExtractor data;
- if (data.SetData(m_data, H.p_offset, H.p_filesz) == H.p_filesz) {
+ if (data.SetData(*m_data_nsp.get(), H.p_offset, H.p_filesz) ==
+ H.p_filesz) {
UUID uuid;
RefineModuleDetailsFromNote(data, m_arch_spec, uuid);
}
@@ -3812,10 +3835,10 @@ llvm::ArrayRef<ELFProgramHeader> ObjectFileELF::ProgramHeaders() {
}
DataExtractor ObjectFileELF::GetSegmentData(const ELFProgramHeader &H) {
- // Try and read the program header from our cached m_data which can come from
- // the file on disk being mmap'ed or from the initial part of the ELF file we
- // read from memory and cached.
- DataExtractor data = DataExtractor(m_data, H.p_offset, H.p_filesz);
+ // Try and read the program header from our cached m_data_nsp which can come
+ // from the file on disk being mmap'ed or from the initial part of the ELF
+ // file we read from memory and cached.
+ DataExtractor data = DataExtractor(*m_data_nsp.get(), H.p_offset, H.p_filesz);
if (data.GetByteSize() == H.p_filesz)
return data;
if (IsInMemory()) {
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index c8e520d..dff9eab 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -1012,35 +1012,35 @@ bool ObjectFileMachO::ParseHeader() {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
bool can_parse = false;
lldb::offset_t offset = 0;
- m_data.SetByteOrder(endian::InlHostByteOrder());
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder());
// Leave magic in the original byte order
- m_header.magic = m_data.GetU32(&offset);
+ m_header.magic = m_data_nsp->GetU32(&offset);
switch (m_header.magic) {
case MH_MAGIC:
- m_data.SetByteOrder(endian::InlHostByteOrder());
- m_data.SetAddressByteSize(4);
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder());
+ m_data_nsp->SetAddressByteSize(4);
can_parse = true;
break;
case MH_MAGIC_64:
- m_data.SetByteOrder(endian::InlHostByteOrder());
- m_data.SetAddressByteSize(8);
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder());
+ m_data_nsp->SetAddressByteSize(8);
can_parse = true;
break;
case MH_CIGAM:
- m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
- ? eByteOrderLittle
- : eByteOrderBig);
- m_data.SetAddressByteSize(4);
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+ ? eByteOrderLittle
+ : eByteOrderBig);
+ m_data_nsp->SetAddressByteSize(4);
can_parse = true;
break;
case MH_CIGAM_64:
- m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
- ? eByteOrderLittle
- : eByteOrderBig);
- m_data.SetAddressByteSize(8);
+ m_data_nsp->SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+ ? eByteOrderLittle
+ : eByteOrderBig);
+ m_data_nsp->SetAddressByteSize(8);
can_parse = true;
break;
@@ -1049,12 +1049,13 @@ bool ObjectFileMachO::ParseHeader() {
}
if (can_parse) {
- m_data.GetU32(&offset, &m_header.cputype, 6);
+ m_data_nsp->GetU32(&offset, &m_header.cputype, 6);
ModuleSpecList all_specs;
ModuleSpec base_spec;
- GetAllArchSpecs(m_header, m_data, MachHeaderSizeFromMagic(m_header.magic),
- base_spec, all_specs);
+ GetAllArchSpecs(m_header, *m_data_nsp.get(),
+ MachHeaderSizeFromMagic(m_header.magic), base_spec,
+ all_specs);
for (unsigned i = 0, e = all_specs.GetSize(); i != e; ++i) {
ArchSpec mach_arch =
@@ -1068,7 +1069,7 @@ bool ObjectFileMachO::ParseHeader() {
if (SetModulesArchitecture(mach_arch)) {
const size_t header_and_lc_size =
m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic);
- if (m_data.GetByteSize() < header_and_lc_size) {
+ if (m_data_nsp->GetByteSize() < header_and_lc_size) {
DataBufferSP data_sp;
ProcessSP process_sp(m_process_wp.lock());
if (process_sp) {
@@ -1080,7 +1081,7 @@ bool ObjectFileMachO::ParseHeader() {
continue;
}
if (data_sp)
- m_data.SetData(data_sp);
+ m_data_nsp->SetData(data_sp);
}
}
return true;
@@ -1094,7 +1095,7 @@ bool ObjectFileMachO::ParseHeader() {
}
ByteOrder ObjectFileMachO::GetByteOrder() const {
- return m_data.GetByteOrder();
+ return m_data_nsp->GetByteOrder();
}
bool ObjectFileMachO::IsExecutable() const {
@@ -1114,7 +1115,7 @@ bool ObjectFileMachO::IsKext() const {
}
uint32_t ObjectFileMachO::GetAddressByteSize() const {
- return m_data.GetAddressByteSize();
+ return m_data_nsp->GetAddressByteSize();
}
AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) {
@@ -1297,13 +1298,13 @@ bool ObjectFileMachO::IsStripped() {
const lldb::offset_t load_cmd_offset = offset;
llvm::MachO::load_command lc = {};
- if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &lc.cmd, 2) == nullptr)
break;
if (lc.cmd == LC_DYSYMTAB) {
m_dysymtab.cmd = lc.cmd;
m_dysymtab.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &m_dysymtab.ilocalsym,
- (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) ==
+ if (m_data_nsp->GetU32(&offset, &m_dysymtab.ilocalsym,
+ (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) ==
nullptr) {
// Clear m_dysymtab if we were unable to read all items from the
// load command
@@ -1326,14 +1327,14 @@ ObjectFileMachO::EncryptedFileRanges ObjectFileMachO::GetEncryptedFileRanges() {
llvm::MachO::encryption_info_command encryption_cmd;
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const lldb::offset_t load_cmd_offset = offset;
- if (m_data.GetU32(&offset, &encryption_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &encryption_cmd, 2) == nullptr)
break;
// LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for the
// 3 fields we care about, so treat them the same.
if (encryption_cmd.cmd == LC_ENCRYPTION_INFO ||
encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) {
- if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) {
+ if (m_data_nsp->GetU32(&offset, &encryption_cmd.cryptoff, 3)) {
if (encryption_cmd.cryptid != 0) {
EncryptedFileRanges::Entry entry;
entry.SetRangeBase(encryption_cmd.cryptoff);
@@ -1562,7 +1563,7 @@ void ObjectFileMachO::ProcessSegmentCommand(
llvm::MachO::segment_command_64 load_cmd;
memcpy(&load_cmd, &load_cmd_, sizeof(load_cmd_));
- if (!m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16))
+ if (!m_data_nsp->GetU8(&offset, (uint8_t *)load_cmd.segname, 16))
return;
ModuleSP module_sp = GetModule();
@@ -1586,11 +1587,11 @@ void ObjectFileMachO::ProcessSegmentCommand(
add_section = false;
}
}
- load_cmd.vmaddr = m_data.GetAddress(&offset);
- load_cmd.vmsize = m_data.GetAddress(&offset);
- load_cmd.fileoff = m_data.GetAddress(&offset);
- load_cmd.filesize = m_data.GetAddress(&offset);
- if (!m_data.GetU32(&offset, &load_cmd.maxprot, 4))
+ load_cmd.vmaddr = m_data_nsp->GetAddress(&offset);
+ load_cmd.vmsize = m_data_nsp->GetAddress(&offset);
+ load_cmd.fileoff = m_data_nsp->GetAddress(&offset);
+ load_cmd.filesize = m_data_nsp->GetAddress(&offset);
+ if (!m_data_nsp->GetU32(&offset, &load_cmd.maxprot, 4))
return;
SanitizeSegmentCommand(load_cmd, cmd_idx);
@@ -1681,16 +1682,16 @@ void ObjectFileMachO::ProcessSegmentCommand(
const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects;
++segment_sect_idx) {
- if (m_data.GetU8(&offset, (uint8_t *)sect64.sectname,
- sizeof(sect64.sectname)) == nullptr)
+ if (m_data_nsp->GetU8(&offset, (uint8_t *)sect64.sectname,
+ sizeof(sect64.sectname)) == nullptr)
break;
- if (m_data.GetU8(&offset, (uint8_t *)sect64.segname,
- sizeof(sect64.segname)) == nullptr)
+ if (m_data_nsp->GetU8(&offset, (uint8_t *)sect64.segname,
+ sizeof(sect64.segname)) == nullptr)
break;
- sect64.addr = m_data.GetAddress(&offset);
- sect64.size = m_data.GetAddress(&offset);
+ sect64.addr = m_data_nsp->GetAddress(&offset);
+ sect64.size = m_data_nsp->GetAddress(&offset);
- if (m_data.GetU32(&offset, &sect64.offset, num_u32s) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &sect64.offset, num_u32s) == nullptr)
break;
if (IsSharedCacheBinary() && !IsInMemory()) {
@@ -1855,8 +1856,8 @@ void ObjectFileMachO::ProcessDysymtabCommand(
const llvm::MachO::load_command &load_cmd, lldb::offset_t offset) {
m_dysymtab.cmd = load_cmd.cmd;
m_dysymtab.cmdsize = load_cmd.cmdsize;
- m_data.GetU32(&offset, &m_dysymtab.ilocalsym,
- (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
+ m_data_nsp->GetU32(&offset, &m_dysymtab.ilocalsym,
+ (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
}
void ObjectFileMachO::CreateSections(SectionList &unified_section_list) {
@@ -1875,7 +1876,7 @@ void ObjectFileMachO::CreateSections(SectionList &unified_section_list) {
llvm::MachO::load_command load_cmd;
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const lldb::offset_t load_cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd, 2) == nullptr)
break;
if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64)
@@ -2240,13 +2241,13 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
const lldb::offset_t cmd_offset = offset;
// Read in the load command and load command size
llvm::MachO::load_command lc;
- if (m_data.GetU32(&offset, &lc, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &lc, 2) == nullptr)
break;
// Watch for the symbol table load command
switch (lc.cmd) {
case LC_SYMTAB: {
llvm::MachO::symtab_command lc_obj;
- if (m_data.GetU32(&offset, &lc_obj.symoff, 4)) {
+ if (m_data_nsp->GetU32(&offset, &lc_obj.symoff, 4)) {
lc_obj.cmd = lc.cmd;
lc_obj.cmdsize = lc.cmdsize;
symtab_load_command = lc_obj;
@@ -2256,7 +2257,7 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
case LC_DYLD_INFO:
case LC_DYLD_INFO_ONLY: {
llvm::MachO::dyld_info_command lc_obj;
- if (m_data.GetU32(&offset, &lc_obj.rebase_off, 10)) {
+ if (m_data_nsp->GetU32(&offset, &lc_obj.rebase_off, 10)) {
lc_obj.cmd = lc.cmd;
lc_obj.cmdsize = lc.cmdsize;
dyld_info = lc_obj;
@@ -2268,8 +2269,8 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
case LC_REEXPORT_DYLIB:
case LC_LOADFVMLIB:
case LC_LOAD_UPWARD_DYLIB: {
- uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
- const char *path = m_data.PeekCStr(name_offset);
+ uint32_t name_offset = cmd_offset + m_data_nsp->GetU32(&offset);
+ const char *path = m_data_nsp->PeekCStr(name_offset);
if (path) {
FileSpec file_spec(path);
// Strip the path if there is @rpath, @executable, etc so we just use
@@ -2289,19 +2290,19 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
llvm::MachO::linkedit_data_command lc_obj;
lc_obj.cmd = lc.cmd;
lc_obj.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &lc_obj.dataoff, 2))
+ if (m_data_nsp->GetU32(&offset, &lc_obj.dataoff, 2))
exports_trie_load_command = lc_obj;
} break;
case LC_FUNCTION_STARTS: {
llvm::MachO::linkedit_data_command lc_obj;
lc_obj.cmd = lc.cmd;
lc_obj.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &lc_obj.dataoff, 2))
+ if (m_data_nsp->GetU32(&offset, &lc_obj.dataoff, 2))
function_starts_load_command = lc_obj;
} break;
case LC_UUID: {
- const uint8_t *uuid_bytes = m_data.PeekData(offset, 16);
+ const uint8_t *uuid_bytes = m_data_nsp->PeekData(offset, 16);
if (uuid_bytes)
image_uuid = UUID(uuid_bytes, 16);
@@ -2321,8 +2322,8 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
if (section_list == nullptr)
return;
- const uint32_t addr_byte_size = m_data.GetAddressByteSize();
- const ByteOrder byte_order = m_data.GetByteOrder();
+ const uint32_t addr_byte_size = m_data_nsp->GetAddressByteSize();
+ const ByteOrder byte_order = m_data_nsp->GetByteOrder();
bool bit_width_32 = addr_byte_size == 4;
const size_t nlist_byte_size =
bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64);
@@ -2487,9 +2488,9 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
exports_trie_load_command.dataoff += linkedit_slide;
}
- nlist_data.SetData(m_data, symtab_load_command.symoff,
+ nlist_data.SetData(*m_data_nsp.get(), symtab_load_command.symoff,
nlist_data_byte_size);
- strtab_data.SetData(m_data, symtab_load_command.stroff,
+ strtab_data.SetData(*m_data_nsp.get(), symtab_load_command.stroff,
strtab_data_byte_size);
// We shouldn't have exports data from both the LC_DYLD_INFO command
@@ -2497,19 +2498,22 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
lldbassert(!((dyld_info.export_size > 0)
&& (exports_trie_load_command.datasize > 0)));
if (dyld_info.export_size > 0) {
- dyld_trie_data.SetData(m_data, dyld_info.export_off,
+ dyld_trie_data.SetData(*m_data_nsp.get(), dyld_info.export_off,
dyld_info.export_size);
} else if (exports_trie_load_command.datasize > 0) {
- dyld_trie_data.SetData(m_data, exports_trie_load_command.dataoff,
+ dyld_trie_data.SetData(*m_data_nsp.get(),
+ exports_trie_load_command.dataoff,
exports_trie_load_command.datasize);
}
if (dysymtab.nindirectsyms != 0) {
- indirect_symbol_index_data.SetData(m_data, dysymtab.indirectsymoff,
+ indirect_symbol_index_data.SetData(*m_data_nsp.get(),
+ dysymtab.indirectsymoff,
dysymtab.nindirectsyms * 4);
}
if (function_starts_load_command.cmd) {
- function_starts_data.SetData(m_data, function_starts_load_command.dataoff,
+ function_starts_data.SetData(*m_data_nsp.get(),
+ function_starts_load_command.dataoff,
function_starts_load_command.datasize);
}
}
@@ -4561,8 +4565,9 @@ void ObjectFileMachO::Dump(Stream *s) {
*s << ", file = '" << m_file;
ModuleSpecList all_specs;
ModuleSpec base_spec;
- GetAllArchSpecs(m_header, m_data, MachHeaderSizeFromMagic(m_header.magic),
- base_spec, all_specs);
+ GetAllArchSpecs(m_header, *m_data_nsp.get(),
+ MachHeaderSizeFromMagic(m_header.magic), base_spec,
+ all_specs);
for (unsigned i = 0, e = all_specs.GetSize(); i != e; ++i) {
*s << "', triple";
if (e)
@@ -4868,7 +4873,7 @@ UUID ObjectFileMachO::GetUUID() {
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- return GetUUID(m_header, m_data, offset);
+ return GetUUID(m_header, *m_data_nsp.get(), offset);
}
return UUID();
}
@@ -4888,7 +4893,7 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
uint32_t i;
for (i = 0; i < m_header.ncmds; ++i) {
const uint32_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd, 2) == nullptr)
break;
switch (load_cmd.cmd) {
@@ -4899,17 +4904,17 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
case LC_LOAD_DYLINKER:
case LC_LOADFVMLIB:
case LC_LOAD_UPWARD_DYLIB: {
- uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ uint32_t name_offset = cmd_offset + m_data_nsp->GetU32(&offset);
// For LC_LOAD_DYLIB there is an alternate encoding
// which adds a uint32_t `flags` field for `DYLD_USE_*`
// flags. This can be detected by a timestamp field with
// the `DYLIB_USE_MARKER` constant value.
bool is_delayed_init = false;
- uint32_t use_command_marker = m_data.GetU32(&offset);
+ uint32_t use_command_marker = m_data_nsp->GetU32(&offset);
if (use_command_marker == 0x1a741800 /* DYLIB_USE_MARKER */) {
offset += 4; /* uint32_t current_version */
offset += 4; /* uint32_t compat_version */
- uint32_t flags = m_data.GetU32(&offset);
+ uint32_t flags = m_data_nsp->GetU32(&offset);
// If this LC_LOAD_DYLIB is marked delay-init,
// don't report it as a dependent library -- it
// may be loaded in the process at some point,
@@ -4917,7 +4922,7 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
if (flags & 0x08 /* DYLIB_USE_DELAYED_INIT */)
is_delayed_init = true;
}
- const char *path = m_data.PeekCStr(name_offset);
+ const char *path = m_data_nsp->PeekCStr(name_offset);
if (path && !is_delayed_init) {
if (load_cmd.cmd == LC_RPATH)
rpath_paths.push_back(path);
@@ -5037,15 +5042,15 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
for (i = 0; i < m_header.ncmds; ++i) {
const lldb::offset_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd, 2) == nullptr)
break;
switch (load_cmd.cmd) {
case LC_UNIXTHREAD:
case LC_THREAD: {
while (offset < cmd_offset + load_cmd.cmdsize) {
- uint32_t flavor = m_data.GetU32(&offset);
- uint32_t count = m_data.GetU32(&offset);
+ uint32_t flavor = m_data_nsp->GetU32(&offset);
+ uint32_t count = m_data_nsp->GetU32(&offset);
if (count == 0) {
// We've gotten off somehow, log and exit;
return m_entry_point_address;
@@ -5059,7 +5064,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
{
offset += 60; // This is the offset of pc in the GPR thread state
// data structure.
- start_address = m_data.GetU32(&offset);
+ start_address = m_data_nsp->GetU32(&offset);
done = true;
}
break;
@@ -5069,7 +5074,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
{
offset += 256; // This is the offset of pc in the GPR thread state
// data structure.
- start_address = m_data.GetU64(&offset);
+ start_address = m_data_nsp->GetU64(&offset);
done = true;
}
break;
@@ -5079,7 +5084,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
{
offset += 16 * 8; // This is the offset of rip in the GPR thread
// state data structure.
- start_address = m_data.GetU64(&offset);
+ start_address = m_data_nsp->GetU64(&offset);
done = true;
}
break;
@@ -5094,7 +5099,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
}
} break;
case LC_MAIN: {
- uint64_t entryoffset = m_data.GetU64(&offset);
+ uint64_t entryoffset = m_data_nsp->GetU64(&offset);
SectionSP text_segment_sp =
GetSectionList()->FindSectionByName(GetSegmentNameTEXT());
if (text_segment_sp) {
@@ -5178,7 +5183,7 @@ uint32_t ObjectFileMachO::GetNumThreadContexts() {
llvm::MachO::thread_command thread_cmd;
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const uint32_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &thread_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &thread_cmd, 2) == nullptr)
break;
if (thread_cmd.cmd == LC_THREAD) {
@@ -5204,17 +5209,17 @@ ObjectFileMachO::FindLC_NOTEByName(std::string name) {
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const uint32_t cmd_offset = offset;
llvm::MachO::load_command lc = {};
- if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &lc.cmd, 2) == nullptr)
break;
if (lc.cmd == LC_NOTE) {
char data_owner[17];
- m_data.CopyData(offset, 16, data_owner);
+ m_data_nsp->CopyData(offset, 16, data_owner);
data_owner[16] = '\0';
offset += 16;
if (name == data_owner) {
- offset_t payload_offset = m_data.GetU64_unchecked(&offset);
- offset_t payload_size = m_data.GetU64_unchecked(&offset);
+ offset_t payload_offset = m_data_nsp->GetU64_unchecked(&offset);
+ offset_t payload_size = m_data_nsp->GetU64_unchecked(&offset);
results.push_back({payload_offset, payload_size});
}
}
@@ -5236,11 +5241,11 @@ std::string ObjectFileMachO::GetIdentifierString() {
offset_t payload_offset = std::get<0>(lc_note);
offset_t payload_size = std::get<1>(lc_note);
uint32_t version;
- if (m_data.GetU32(&payload_offset, &version, 1) != nullptr) {
+ if (m_data_nsp->GetU32(&payload_offset, &version, 1) != nullptr) {
if (version == 1) {
uint32_t strsize = payload_size - sizeof(uint32_t);
std::string result(strsize, '\0');
- m_data.CopyData(payload_offset, strsize, result.data());
+ m_data_nsp->CopyData(payload_offset, strsize, result.data());
LLDB_LOGF(log, "LC_NOTE 'kern ver str' found with text '%s'",
result.c_str());
return result;
@@ -5254,12 +5259,12 @@ std::string ObjectFileMachO::GetIdentifierString() {
for (uint32_t i = 0; i < m_header.ncmds; ++i) {
const uint32_t cmd_offset = offset;
llvm::MachO::ident_command ident_command;
- if (m_data.GetU32(&offset, &ident_command, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &ident_command, 2) == nullptr)
break;
if (ident_command.cmd == LC_IDENT && ident_command.cmdsize != 0) {
std::string result(ident_command.cmdsize, '\0');
- if (m_data.CopyData(offset, ident_command.cmdsize, result.data()) ==
- ident_command.cmdsize) {
+ if (m_data_nsp->CopyData(offset, ident_command.cmdsize,
+ result.data()) == ident_command.cmdsize) {
LLDB_LOGF(log, "LC_IDENT found with text '%s'", result.c_str());
return result;
}
@@ -5281,9 +5286,10 @@ AddressableBits ObjectFileMachO::GetAddressableBits() {
for (auto lc_note : lc_notes) {
offset_t payload_offset = std::get<0>(lc_note);
uint32_t version;
- if (m_data.GetU32(&payload_offset, &version, 1) != nullptr) {
+ if (m_data_nsp->GetU32(&payload_offset, &version, 1) != nullptr) {
if (version == 3) {
- uint32_t num_addr_bits = m_data.GetU32_unchecked(&payload_offset);
+ uint32_t num_addr_bits =
+ m_data_nsp->GetU32_unchecked(&payload_offset);
addressable_bits.SetAddressableBits(num_addr_bits);
LLDB_LOGF(log,
"LC_NOTE 'addrable bits' v3 found, value %d "
@@ -5291,8 +5297,8 @@ AddressableBits ObjectFileMachO::GetAddressableBits() {
num_addr_bits);
}
if (version == 4) {
- uint32_t lo_addr_bits = m_data.GetU32_unchecked(&payload_offset);
- uint32_t hi_addr_bits = m_data.GetU32_unchecked(&payload_offset);
+ uint32_t lo_addr_bits = m_data_nsp->GetU32_unchecked(&payload_offset);
+ uint32_t hi_addr_bits = m_data_nsp->GetU32_unchecked(&payload_offset);
if (lo_addr_bits == hi_addr_bits)
addressable_bits.SetAddressableBits(lo_addr_bits);
@@ -5363,25 +5369,26 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value,
// uint32_t unused [ for alignment ]
uint32_t version;
- if (m_data.GetU32(&payload_offset, &version, 1) != nullptr &&
+ if (m_data_nsp->GetU32(&payload_offset, &version, 1) != nullptr &&
version <= 2) {
uint32_t binspec_type = 0;
uuid_t raw_uuid;
memset(raw_uuid, 0, sizeof(uuid_t));
- if (!m_data.GetU32(&payload_offset, &binspec_type, 1))
+ if (!m_data_nsp->GetU32(&payload_offset, &binspec_type, 1))
return false;
- if (!m_data.GetU64(&payload_offset, &value, 1))
+ if (!m_data_nsp->GetU64(&payload_offset, &value, 1))
return false;
uint64_t slide = LLDB_INVALID_ADDRESS;
- if (version > 1 && !m_data.GetU64(&payload_offset, &slide, 1))
+ if (version > 1 && !m_data_nsp->GetU64(&payload_offset, &slide, 1))
return false;
if (value == LLDB_INVALID_ADDRESS && slide != LLDB_INVALID_ADDRESS) {
value = slide;
value_is_offset = true;
}
- if (m_data.CopyData(payload_offset, sizeof(uuid_t), raw_uuid) != 0) {
+ if (m_data_nsp->CopyData(payload_offset, sizeof(uuid_t), raw_uuid) !=
+ 0) {
uuid = UUID(raw_uuid, sizeof(uuid_t));
// convert the "main bin spec" type into our
// ObjectFile::BinaryType enum
@@ -5415,9 +5422,9 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value,
version, type, typestr, value,
value_is_offset ? "true" : "false",
uuid.GetAsString().c_str());
- if (!m_data.GetU32(&payload_offset, &log2_pagesize, 1))
+ if (!m_data_nsp->GetU32(&payload_offset, &log2_pagesize, 1))
return false;
- if (version > 1 && !m_data.GetU32(&payload_offset, &platform, 1))
+ if (version > 1 && !m_data_nsp->GetU32(&payload_offset, &platform, 1))
return false;
return true;
}
@@ -5497,7 +5504,7 @@ StructuredData::ObjectSP ObjectFileMachO::GetCorefileProcessMetadata() {
auto [payload_offset, strsize] = lc_notes[0];
std::string buf(strsize, '\0');
- if (m_data.CopyData(payload_offset, strsize, buf.data()) != strsize) {
+ if (m_data_nsp->CopyData(payload_offset, strsize, buf.data()) != strsize) {
LLDB_LOGF(log,
"Unable to read %" PRIu64
" bytes of 'process metadata' LC_NOTE JSON contents",
@@ -5537,7 +5544,8 @@ ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx,
m_thread_context_offsets.GetEntryAtIndex(idx);
if (thread_context_file_range) {
- DataExtractor data(m_data, thread_context_file_range->GetRangeBase(),
+ DataExtractor data(*m_data_nsp.get(),
+ thread_context_file_range->GetRangeBase(),
thread_context_file_range->GetByteSize());
switch (m_header.cputype) {
@@ -5677,13 +5685,13 @@ llvm::VersionTuple ObjectFileMachO::GetVersion() {
uint32_t i;
for (i = 0; i < m_header.ncmds; ++i) {
const lldb::offset_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd, 2) == nullptr)
break;
if (load_cmd.cmd == LC_ID_DYLIB) {
if (version_cmd == 0) {
version_cmd = load_cmd.cmd;
- if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == nullptr)
+ if (m_data_nsp->GetU32(&offset, &load_cmd.dylib, 4) == nullptr)
break;
version = load_cmd.dylib.current_version;
}
@@ -5709,7 +5717,7 @@ ArchSpec ObjectFileMachO::GetArchitecture() {
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- return GetArchitecture(module_sp, m_header, m_data,
+ return GetArchitecture(module_sp, m_header, *m_data_nsp.get(),
MachHeaderSizeFromMagic(m_header.magic));
}
return arch;
@@ -5880,14 +5888,16 @@ static llvm::VersionTuple FindMinimumVersionInfo(DataExtractor &data,
llvm::VersionTuple ObjectFileMachO::GetMinimumOSVersion() {
if (!m_min_os_version)
m_min_os_version = FindMinimumVersionInfo(
- m_data, MachHeaderSizeFromMagic(m_header.magic), m_header.ncmds);
+ *m_data_nsp.get(), MachHeaderSizeFromMagic(m_header.magic),
+ m_header.ncmds);
return *m_min_os_version;
}
llvm::VersionTuple ObjectFileMachO::GetSDKVersion() {
if (!m_sdk_versions)
m_sdk_versions = FindMinimumVersionInfo(
- m_data, MachHeaderSizeFromMagic(m_header.magic), m_header.ncmds);
+ *m_data_nsp.get(), MachHeaderSizeFromMagic(m_header.magic),
+ m_header.ncmds);
return *m_sdk_versions;
}
@@ -5936,6 +5946,20 @@ Section *ObjectFileMachO::GetMachHeaderSection() {
return nullptr;
}
+bool ObjectFileMachO::IsGOTSection(const lldb_private::Section &section) const {
+ assert(section.GetObjectFile() == this && "Wrong object file!");
+ SectionSP segment = section.GetParent();
+ if (!segment)
+ return false;
+
+ const bool is_data_const_got =
+ segment->GetName() == "__DATA_CONST" && section.GetName() == "__got";
+ const bool is_auth_const_ptr =
+ segment->GetName() == "__AUTH_CONST" &&
+ (section.GetName() == "__auth_got" || section.GetName() == "__auth_ptr");
+ return is_data_const_got || is_auth_const_ptr;
+}
+
bool ObjectFileMachO::SectionIsLoadable(const Section *section) {
if (!section)
return false;
@@ -6688,12 +6712,12 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
for (auto lc_note : lc_notes) {
offset_t payload_offset = std::get<0>(lc_note);
// Read the struct all_image_infos_header.
- uint32_t version = m_data.GetU32(&payload_offset);
+ uint32_t version = m_data_nsp->GetU32(&payload_offset);
if (version != 1) {
return image_infos;
}
- uint32_t imgcount = m_data.GetU32(&payload_offset);
- uint64_t entries_fileoff = m_data.GetU64(&payload_offset);
+ uint32_t imgcount = m_data_nsp->GetU32(&payload_offset);
+ uint64_t entries_fileoff = m_data_nsp->GetU64(&payload_offset);
// 'entries_size' is not used, nor is the 'unused' entry.
// offset += 4; // uint32_t entries_size;
// offset += 4; // uint32_t unused;
@@ -6703,17 +6727,18 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
payload_offset = entries_fileoff;
for (uint32_t i = 0; i < imgcount; i++) {
// Read the struct image_entry.
- offset_t filepath_offset = m_data.GetU64(&payload_offset);
+ offset_t filepath_offset = m_data_nsp->GetU64(&payload_offset);
uuid_t uuid;
- memcpy(&uuid, m_data.GetData(&payload_offset, sizeof(uuid_t)),
+ memcpy(&uuid, m_data_nsp->GetData(&payload_offset, sizeof(uuid_t)),
sizeof(uuid_t));
- uint64_t load_address = m_data.GetU64(&payload_offset);
- offset_t seg_addrs_offset = m_data.GetU64(&payload_offset);
- uint32_t segment_count = m_data.GetU32(&payload_offset);
- uint32_t currently_executing = m_data.GetU32(&payload_offset);
+ uint64_t load_address = m_data_nsp->GetU64(&payload_offset);
+ offset_t seg_addrs_offset = m_data_nsp->GetU64(&payload_offset);
+ uint32_t segment_count = m_data_nsp->GetU32(&payload_offset);
+ uint32_t currently_executing = m_data_nsp->GetU32(&payload_offset);
MachOCorefileImageEntry image_entry;
- image_entry.filename = (const char *)m_data.GetCStr(&filepath_offset);
+ image_entry.filename =
+ (const char *)m_data_nsp->GetCStr(&filepath_offset);
image_entry.uuid = UUID(uuid, sizeof(uuid_t));
image_entry.load_address = load_address;
image_entry.currently_executing = currently_executing;
@@ -6721,10 +6746,10 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
offset_t seg_vmaddrs_offset = seg_addrs_offset;
for (uint32_t j = 0; j < segment_count; j++) {
char segname[17];
- m_data.CopyData(seg_vmaddrs_offset, 16, segname);
+ m_data_nsp->CopyData(seg_vmaddrs_offset, 16, segname);
segname[16] = '\0';
seg_vmaddrs_offset += 16;
- uint64_t vmaddr = m_data.GetU64(&seg_vmaddrs_offset);
+ uint64_t vmaddr = m_data_nsp->GetU64(&seg_vmaddrs_offset);
seg_vmaddrs_offset += 8; /* unused */
std::tuple<ConstString, addr_t> new_seg{ConstString(segname), vmaddr};
@@ -6743,14 +6768,14 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
lc_notes = FindLC_NOTEByName("load binary");
for (auto lc_note : lc_notes) {
offset_t payload_offset = std::get<0>(lc_note);
- uint32_t version = m_data.GetU32(&payload_offset);
+ uint32_t version = m_data_nsp->GetU32(&payload_offset);
if (version == 1) {
uuid_t uuid;
- memcpy(&uuid, m_data.GetData(&payload_offset, sizeof(uuid_t)),
+ memcpy(&uuid, m_data_nsp->GetData(&payload_offset, sizeof(uuid_t)),
sizeof(uuid_t));
- uint64_t load_address = m_data.GetU64(&payload_offset);
- uint64_t slide = m_data.GetU64(&payload_offset);
- std::string filename = m_data.GetCStr(&payload_offset);
+ uint64_t load_address = m_data_nsp->GetU64(&payload_offset);
+ uint64_t slide = m_data_nsp->GetU64(&payload_offset);
+ std::string filename = m_data_nsp->GetCStr(&payload_offset);
MachOCorefileImageEntry image_entry;
image_entry.filename = filename;
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
index 25643aa..5456f03 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -162,6 +162,8 @@ public:
lldb_private::Section *GetMachHeaderSection();
+ bool IsGOTSection(const lldb_private::Section &section) const override;
+
// PluginInterface protocol
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
index 244489a..f25ed51 100644
--- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp
@@ -396,7 +396,7 @@ bool ObjectFilePECOFF::CreateBinary() {
Log *log = GetLog(LLDBLog::Object);
auto binary = llvm::object::createBinary(llvm::MemoryBufferRef(
- toStringRef(m_data.GetData()), m_file.GetFilename().GetStringRef()));
+ toStringRef(m_data_nsp->GetData()), m_file.GetFilename().GetStringRef()));
if (!binary) {
LLDB_LOG_ERROR(log, binary.takeError(),
"Failed to create binary for file ({1}): {0}", m_file);
@@ -442,20 +442,20 @@ bool ObjectFilePECOFF::ParseHeader() {
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
m_sect_headers.clear();
- m_data.SetByteOrder(eByteOrderLittle);
+ m_data_nsp->SetByteOrder(eByteOrderLittle);
lldb::offset_t offset = 0;
- if (ParseDOSHeader(m_data, m_dos_header)) {
+ if (ParseDOSHeader(*m_data_nsp.get(), m_dos_header)) {
offset = m_dos_header.e_lfanew;
- uint32_t pe_signature = m_data.GetU32(&offset);
+ uint32_t pe_signature = m_data_nsp->GetU32(&offset);
if (pe_signature != IMAGE_NT_SIGNATURE)
return false;
- if (ParseCOFFHeader(m_data, &offset, m_coff_header)) {
+ if (ParseCOFFHeader(*m_data_nsp.get(), &offset, m_coff_header)) {
if (m_coff_header.hdrsize > 0)
ParseCOFFOptionalHeader(&offset);
ParseSectionHeaders(offset);
}
- m_data.SetAddressByteSize(GetAddressByteSize());
+ m_data_nsp->SetAddressByteSize(GetAddressByteSize());
return true;
}
}
@@ -602,57 +602,63 @@ bool ObjectFilePECOFF::ParseCOFFOptionalHeader(lldb::offset_t *offset_ptr) {
const lldb::offset_t end_offset = *offset_ptr + m_coff_header.hdrsize;
if (*offset_ptr < end_offset) {
success = true;
- m_coff_header_opt.magic = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_linker_version = m_data.GetU8(offset_ptr);
- m_coff_header_opt.minor_linker_version = m_data.GetU8(offset_ptr);
- m_coff_header_opt.code_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.data_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.bss_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.entry = m_data.GetU32(offset_ptr);
- m_coff_header_opt.code_offset = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.magic = m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.major_linker_version = m_data_nsp->GetU8(offset_ptr);
+ m_coff_header_opt.minor_linker_version = m_data_nsp->GetU8(offset_ptr);
+ m_coff_header_opt.code_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.data_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.bss_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.entry = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.code_offset = m_data_nsp->GetU32(offset_ptr);
const uint32_t addr_byte_size = GetAddressByteSize();
if (*offset_ptr < end_offset) {
if (m_coff_header_opt.magic == OPT_HEADER_MAGIC_PE32) {
// PE32 only
- m_coff_header_opt.data_offset = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.data_offset = m_data_nsp->GetU32(offset_ptr);
} else
m_coff_header_opt.data_offset = 0;
if (*offset_ptr < end_offset) {
m_coff_header_opt.image_base =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.sect_alignment = m_data.GetU32(offset_ptr);
- m_coff_header_opt.file_alignment = m_data.GetU32(offset_ptr);
- m_coff_header_opt.major_os_system_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_os_system_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_image_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_image_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.major_subsystem_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.minor_subsystem_version = m_data.GetU16(offset_ptr);
- m_coff_header_opt.reserved1 = m_data.GetU32(offset_ptr);
- m_coff_header_opt.image_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.header_size = m_data.GetU32(offset_ptr);
- m_coff_header_opt.checksum = m_data.GetU32(offset_ptr);
- m_coff_header_opt.subsystem = m_data.GetU16(offset_ptr);
- m_coff_header_opt.dll_flags = m_data.GetU16(offset_ptr);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
+ m_coff_header_opt.sect_alignment = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.file_alignment = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.major_os_system_version =
+ m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.minor_os_system_version =
+ m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.major_image_version = m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.minor_image_version = m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.major_subsystem_version =
+ m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.minor_subsystem_version =
+ m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.reserved1 = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.image_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.header_size = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.checksum = m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.subsystem = m_data_nsp->GetU16(offset_ptr);
+ m_coff_header_opt.dll_flags = m_data_nsp->GetU16(offset_ptr);
m_coff_header_opt.stack_reserve_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
m_coff_header_opt.stack_commit_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
m_coff_header_opt.heap_reserve_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
m_coff_header_opt.heap_commit_size =
- m_data.GetMaxU64(offset_ptr, addr_byte_size);
- m_coff_header_opt.loader_flags = m_data.GetU32(offset_ptr);
- uint32_t num_data_dir_entries = m_data.GetU32(offset_ptr);
+ m_data_nsp->GetMaxU64(offset_ptr, addr_byte_size);
+ m_coff_header_opt.loader_flags = m_data_nsp->GetU32(offset_ptr);
+ uint32_t num_data_dir_entries = m_data_nsp->GetU32(offset_ptr);
m_coff_header_opt.data_dirs.clear();
m_coff_header_opt.data_dirs.resize(num_data_dir_entries);
uint32_t i;
for (i = 0; i < num_data_dir_entries; i++) {
- m_coff_header_opt.data_dirs[i].vmaddr = m_data.GetU32(offset_ptr);
- m_coff_header_opt.data_dirs[i].vmsize = m_data.GetU32(offset_ptr);
+ m_coff_header_opt.data_dirs[i].vmaddr =
+ m_data_nsp->GetU32(offset_ptr);
+ m_coff_header_opt.data_dirs[i].vmsize =
+ m_data_nsp->GetU32(offset_ptr);
}
m_image_base = m_coff_header_opt.image_base;
@@ -684,8 +690,8 @@ DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) {
if (!size)
return {};
- if (m_data.ValidOffsetForDataOfSize(offset, size))
- return DataExtractor(m_data, offset, size);
+ if (m_data_nsp->ValidOffsetForDataOfSize(offset, size))
+ return DataExtractor(*m_data_nsp.get(), offset, size);
ProcessSP process_sp(m_process_wp.lock());
DataExtractor data;
@@ -759,7 +765,7 @@ llvm::StringRef ObjectFilePECOFF::GetSectionName(const section_header_t &sect) {
return "";
lldb::offset_t string_file_offset =
m_coff_header.symoff + (m_coff_header.nsyms * 18) + stroff;
- if (const char *name = m_data.GetCStr(&string_file_offset))
+ if (const char *name = m_data_nsp->GetCStr(&string_file_offset))
return name;
return "";
}
diff --git a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
index d2c46ed..bfe1556 100644
--- a/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
+++ b/lldb/source/Plugins/ObjectFile/XCOFF/ObjectFileXCOFF.cpp
@@ -94,7 +94,7 @@ bool ObjectFileXCOFF::CreateBinary() {
Log *log = GetLog(LLDBLog::Object);
- auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data.GetData()),
+ auto memory_ref = llvm::MemoryBufferRef(toStringRef(m_data_nsp->GetData()),
m_file.GetFilename().GetStringRef());
llvm::file_magic magic = llvm::identify_magic(memory_ref.getBuffer());
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index 492b441..0bedb5e 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -287,7 +287,7 @@ ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP data_sp,
offset_t offset, offset_t length)
: ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
m_arch("wasm32-unknown-unknown-wasm") {
- m_data.SetAddressByteSize(4);
+ m_data_nsp->SetAddressByteSize(4);
}
ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
@@ -719,11 +719,11 @@ DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
DataBufferSP buffer_sp(data_up.release());
data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
}
- } else if (offset < m_data.GetByteSize()) {
- size =
- std::min(static_cast<uint64_t>(size), m_data.GetByteSize() - offset);
- return DataExtractor(m_data.GetDataStart() + offset, size, GetByteOrder(),
- GetAddressByteSize());
+ } else if (offset < m_data_nsp->GetByteSize()) {
+ size = std::min(static_cast<uint64_t>(size),
+ m_data_nsp->GetByteSize() - offset);
+ return DataExtractor(m_data_nsp->GetDataStart() + offset, size,
+ GetByteOrder(), GetAddressByteSize());
}
}
data.SetByteOrder(GetByteOrder());
diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
index 57d88f6..22b9711 100644
--- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
+++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
@@ -15,6 +15,8 @@
#include "lldb/Utility/UriParser.h"
#include "lldb/ValueObject/ValueObject.h"
+#include "llvm/ADT/DenseMap.h"
+
#include "AdbClient.h"
#include "PlatformAndroid.h"
#include "PlatformAndroidRemoteGDBServer.h"
@@ -479,136 +481,90 @@ std::string PlatformAndroid::GetRunAs() {
return run_as.str();
}
-// Helper function to populate process status information from
-// /proc/[pid]/status
-void PlatformAndroid::PopulateProcessStatusInfo(
- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
- // Read /proc/[pid]/status to get parent PID, UIDs, and GIDs
- Status error;
- AdbClientUP status_adb = GetAdbClient(error);
- if (error.Fail())
- return;
-
- std::string status_output;
- StreamString status_cmd;
- status_cmd.Printf(
- "cat /proc/%llu/status 2>/dev/null | grep -E '^(PPid|Uid|Gid):'",
- static_cast<unsigned long long>(pid));
- Status status_error =
- status_adb->Shell(status_cmd.GetData(), seconds(5), &status_output);
+static bool NeedsCmdlineSupplement(const ProcessInstanceInfo &proc_info) {
+ llvm::StringRef name =
+ proc_info.GetExecutableFile().GetFilename().GetStringRef();
+ return name.contains("app_process") || name.contains("zygote");
+}
- if (status_error.Fail() || status_output.empty())
+// Fetch /proc/PID/cmdline for processes to get actual package names.
+// Android apps often show as "zygote" or "app_process" without this.
+static void SupplementWithCmdlineInfo(ProcessInstanceInfoList &proc_infos,
+ AdbClient *adb) {
+ if (proc_infos.empty())
return;
- llvm::SmallVector<llvm::StringRef, 16> lines;
- llvm::StringRef(status_output).split(lines, '\n');
-
- for (llvm::StringRef line : lines) {
- line = line.trim();
- if (line.starts_with("PPid:")) {
- llvm::StringRef ppid_str = line.substr(5).trim();
- lldb::pid_t ppid;
- if (llvm::to_integer(ppid_str, ppid))
- process_info.SetParentProcessID(ppid);
- } else if (line.starts_with("Uid:")) {
- llvm::SmallVector<llvm::StringRef, 4> uid_parts;
- line.substr(4).trim().split(uid_parts, '\t', -1, false);
- if (uid_parts.size() >= 2) {
- uint32_t uid, euid;
- if (llvm::to_integer(uid_parts[0].trim(), uid))
- process_info.SetUserID(uid);
- if (llvm::to_integer(uid_parts[1].trim(), euid))
- process_info.SetEffectiveUserID(euid);
- }
- } else if (line.starts_with("Gid:")) {
- llvm::SmallVector<llvm::StringRef, 4> gid_parts;
- line.substr(4).trim().split(gid_parts, '\t', -1, false);
- if (gid_parts.size() >= 2) {
- uint32_t gid, egid;
- if (llvm::to_integer(gid_parts[0].trim(), gid))
- process_info.SetGroupID(gid);
- if (llvm::to_integer(gid_parts[1].trim(), egid))
- process_info.SetEffectiveGroupID(egid);
- }
+ llvm::DenseMap<lldb::pid_t, ProcessInstanceInfo *> pid_map;
+ std::string pid_list;
+ for (auto &proc_info : proc_infos) {
+ if (NeedsCmdlineSupplement(proc_info)) {
+ lldb::pid_t pid = proc_info.GetProcessID();
+ pid_map[pid] = &proc_info;
+ if (!pid_list.empty())
+ pid_list += " ";
+ pid_list += std::to_string(pid);
}
}
-}
-// Helper function to populate command line arguments from /proc/[pid]/cmdline
-void PlatformAndroid::PopulateProcessCommandLine(
- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
- // Read /proc/[pid]/cmdline to get command line arguments
- Status error;
- AdbClientUP cmdline_adb = GetAdbClient(error);
- if (error.Fail())
+ if (pid_list.empty())
return;
+ Log *log = GetLog(LLDBLog::Platform);
+
+ // Use xargs -P to parallelize cmdline fetching (up to 8 concurrent reads)
+ StreamString cmd;
+ cmd.Printf(
+ "echo '%s' | xargs -n 1 -P 8 sh -c "
+ "'echo \"$1:$(cat /proc/$1/cmdline 2>/dev/null | tr \"\\0\" \" \")\"' sh",
+ pid_list.c_str());
+
std::string cmdline_output;
- StreamString cmdline_cmd;
- cmdline_cmd.Printf("cat /proc/%llu/cmdline 2>/dev/null | tr '\\000' ' '",
- static_cast<unsigned long long>(pid));
- Status cmdline_error =
- cmdline_adb->Shell(cmdline_cmd.GetData(), seconds(5), &cmdline_output);
+ Status error = adb->Shell(cmd.GetData(), seconds(5), &cmdline_output);
- if (cmdline_error.Fail() || cmdline_output.empty())
+ if (error.Fail() || cmdline_output.empty())
return;
- cmdline_output = llvm::StringRef(cmdline_output).trim().str();
- if (cmdline_output.empty())
- return;
+ llvm::SmallVector<llvm::StringRef, 256> lines;
+ llvm::StringRef(cmdline_output).split(lines, '\n', -1, false);
- llvm::SmallVector<llvm::StringRef, 16> args;
- llvm::StringRef(cmdline_output).split(args, ' ', -1, false);
- if (args.empty())
- return;
+ for (llvm::StringRef line : lines) {
+ line = line.trim();
+ auto [pid_str, cmdline] = line.split(':');
+ if (pid_str.empty() || cmdline.empty())
+ continue;
- process_info.SetArg0(args[0]);
- Args process_args;
- for (size_t i = 1; i < args.size(); i++) {
- if (!args[i].empty())
- process_args.AppendArgument(args[i]);
- }
- process_info.SetArguments(process_args, false);
-}
+ cmdline = cmdline.trim();
-// Helper function to populate architecture from /proc/[pid]/exe
-void PlatformAndroid::PopulateProcessArchitecture(
- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
- // Read /proc/[pid]/exe to get executable path for architecture detection
- Status error;
- AdbClientUP exe_adb = GetAdbClient(error);
- if (error.Fail())
- return;
+ lldb::pid_t pid;
+ if (!llvm::to_integer(pid_str, pid) || cmdline.empty())
+ continue;
- std::string exe_output;
- StreamString exe_cmd;
- exe_cmd.Printf("readlink /proc/%llu/exe 2>/dev/null",
- static_cast<unsigned long long>(pid));
- Status exe_error = exe_adb->Shell(exe_cmd.GetData(), seconds(5), &exe_output);
+ auto it = pid_map.find(pid);
+ if (it == pid_map.end())
+ continue;
- if (exe_error.Fail() || exe_output.empty())
- return;
+ ProcessInstanceInfo *proc_info = it->second;
+ llvm::SmallVector<llvm::StringRef, 16> args;
+ cmdline.split(args, ' ', -1, false);
- exe_output = llvm::StringRef(exe_output).trim().str();
-
- // Determine architecture from exe path
- ArchSpec arch;
- if (exe_output.find("64") != std::string::npos ||
- exe_output.find("arm64") != std::string::npos ||
- exe_output.find("aarch64") != std::string::npos) {
- arch.SetTriple("aarch64-unknown-linux-android");
- } else if (exe_output.find("x86_64") != std::string::npos) {
- arch.SetTriple("x86_64-unknown-linux-android");
- } else if (exe_output.find("x86") != std::string::npos ||
- exe_output.find("i686") != std::string::npos) {
- arch.SetTriple("i686-unknown-linux-android");
- } else {
- // Default to armv7 for 32-bit ARM (most common on Android)
- arch.SetTriple("armv7-unknown-linux-android");
- }
+ if (!args.empty()) {
+ proc_info->GetExecutableFile().SetFile(args[0], FileSpec::Style::posix);
+
+ if (args.size() > 1) {
+ Args process_args;
+ for (size_t i = 1; i < args.size(); ++i) {
+ if (!args[i].empty())
+ process_args.AppendArgument(args[i]);
+ }
+ proc_info->SetArguments(process_args, false);
+ }
- if (arch.IsValid())
- process_info.SetArchitecture(arch);
+ LLDB_LOGF(log,
+ "PlatformAndroid::%s supplemented PID %llu with cmdline: %s",
+ __FUNCTION__, static_cast<unsigned long long>(pid),
+ cmdline.str().c_str());
+ }
+ }
}
uint32_t
@@ -616,109 +572,39 @@ PlatformAndroid::FindProcesses(const ProcessInstanceInfoMatch &match_info,
ProcessInstanceInfoList &proc_infos) {
proc_infos.clear();
- // When LLDB is running natively on an Android device (IsHost() == true),
- // use the parent class's standard Linux /proc enumeration. IsHost() is only
- // true when compiled for Android (#if defined(__ANDROID__)), so calling
- // PlatformLinux methods is safe (Android is Linux-based).
if (IsHost())
return PlatformLinux::FindProcesses(match_info, proc_infos);
- // Remote Android platform: implement process name lookup using 'pidof' over
- // adb.
-
- // LLDB stores the search name in GetExecutableFile() (even though it's
- // actually a process name like "com.android.chrome" rather than an
- // executable path). If no search name is provided, we can't use
- // 'pidof', so return early with no results.
- const ProcessInstanceInfo &match_process_info = match_info.GetProcessInfo();
- if (!match_process_info.GetExecutableFile() ||
- match_info.GetNameMatchType() == NameMatch::Ignore) {
- return 0;
- }
-
- // Extract the process name to search for (typically an Android package name
- // like "com.example.app" or binary name like "app_process64")
- std::string process_name = match_process_info.GetExecutableFile().GetPath();
- if (process_name.empty())
- return 0;
-
- // Use adb to find the process by name
- Status error;
- AdbClientUP adb(GetAdbClient(error));
- if (error.Fail()) {
- Log *log = GetLog(LLDBLog::Platform);
- LLDB_LOGF(log, "PlatformAndroid::%s failed to get ADB client: %s",
- __FUNCTION__, error.AsCString());
- return 0;
- }
-
- // Use 'pidof' command to get PIDs for the process name.
- // Quote the process name to handle special characters (spaces, etc.)
- std::string pidof_output;
- StreamString command;
- command.Printf("pidof '%s'", process_name.c_str());
- error = adb->Shell(command.GetData(), seconds(5), &pidof_output);
-
- if (error.Fail()) {
- Log *log = GetLog(LLDBLog::Platform);
- LLDB_LOG(log, "PlatformAndroid::{} 'pidof {}' failed: {}", __FUNCTION__,
- process_name.c_str(), error.AsCString());
- return 0;
- }
-
- // Parse PIDs from pidof output.
- // Note: pidof can return multiple PIDs (space-separated) if multiple
- // instances of the same executable are running.
- pidof_output = llvm::StringRef(pidof_output).trim().str();
- if (pidof_output.empty()) {
- Log *log = GetLog(LLDBLog::Platform);
- LLDB_LOGF(log, "PlatformAndroid::%s no process found with name '%s'",
- __FUNCTION__, process_name.c_str());
+ if (!m_remote_platform_sp)
return 0;
- }
-
- // Split the output by whitespace to handle multiple PIDs
- llvm::SmallVector<llvm::StringRef, 8> pid_strings;
- llvm::StringRef(pidof_output).split(pid_strings, ' ', -1, false);
-
- Log *log = GetLog(LLDBLog::Platform);
-
- // Process each PID and gather information
- uint32_t num_matches = 0;
- for (llvm::StringRef pid_str : pid_strings) {
- pid_str = pid_str.trim();
- if (pid_str.empty())
- continue;
-
- lldb::pid_t pid;
- if (!llvm::to_integer(pid_str, pid)) {
- LLDB_LOGF(log, "PlatformAndroid::%s failed to parse PID from: '%s'",
- __FUNCTION__, pid_str.str().c_str());
- continue;
- }
-
- ProcessInstanceInfo process_info;
- process_info.SetProcessID(pid);
- process_info.GetExecutableFile().SetFile(process_name,
- FileSpec::Style::posix);
-
- // Populate additional process information
- PopulateProcessStatusInfo(pid, process_info);
- PopulateProcessCommandLine(pid, process_info);
- PopulateProcessArchitecture(pid, process_info);
-
- // Check if this process matches the criteria
- if (match_info.Matches(process_info)) {
- proc_infos.push_back(process_info);
- num_matches++;
- LLDB_LOGF(log, "PlatformAndroid::%s found process '%s' with PID %llu",
- __FUNCTION__, process_name.c_str(),
- static_cast<unsigned long long>(pid));
+ // Android-specific process name handling:
+ // Apps spawned from zygote initially appear as "app_process" or "zygote"
+ // in the process list, but their actual package names (e.g.,
+ // "com.example.app") are only available in /proc/PID/cmdline. To support
+ // name-based matching, we must first fetch cmdline info for all processes,
+ // then apply the original name filter.
+ ProcessInstanceInfoMatch broad_match_info = match_info;
+ broad_match_info.SetNameMatchType(NameMatch::Ignore);
+
+ ProcessInstanceInfoList all_procs;
+ uint32_t count =
+ m_remote_platform_sp->FindProcesses(broad_match_info, all_procs);
+
+ if (count > 0) {
+ Status error;
+ AdbClientUP adb(GetAdbClient(error));
+ if (error.Success())
+ SupplementWithCmdlineInfo(all_procs, adb.get());
+
+ // Apply the original name matching against supplemented process info.
+ for (auto &proc_info : all_procs) {
+ if (match_info.Matches(proc_info))
+ proc_infos.push_back(proc_info);
}
}
- return num_matches;
+ return proc_infos.size();
}
std::unique_ptr<AdbSyncService> PlatformAndroid::GetSyncService(Status &error) {
diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h
index e771c6a..c6a412b 100644
--- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h
+++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h
@@ -60,7 +60,7 @@ public:
uint32_t GetDefaultMemoryCacheLineSize() override;
uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info,
- ProcessInstanceInfoList &proc_infos) override;
+ ProcessInstanceInfoList &process_infos) override;
protected:
const char *GetCacheHostname() override;
@@ -86,17 +86,8 @@ public:
protected:
virtual std::unique_ptr<AdbSyncService> GetSyncService(Status &error);
-private:
std::string m_device_id;
uint32_t m_sdk_version;
-
- // Helper functions for process information gathering
- void PopulateProcessStatusInfo(lldb::pid_t pid,
- ProcessInstanceInfo &process_info);
- void PopulateProcessCommandLine(lldb::pid_t pid,
- ProcessInstanceInfo &process_info);
- void PopulateProcessArchitecture(lldb::pid_t pid,
- ProcessInstanceInfo &process_info);
};
} // namespace platform_android
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
index 4cfb0a8..47111c9 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
@@ -90,7 +90,7 @@ void PlatformAppleSimulator::GetStatus(Stream &strm) {
if (!sdk.empty())
strm << " SDK Path: \"" << sdk << "\"\n";
else
- strm << " SDK Path: error: unable to locate SDK\n";
+ strm << " SDK Path: <unable to locate SDK>\n";
#if defined(__APPLE__)
// This will get called by subclasses, so just output status on the current
@@ -420,7 +420,6 @@ Status PlatformAppleSimulator::GetSymbolFile(const FileSpec &platform_file,
Status PlatformAppleSimulator::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
// For iOS/tvOS/watchOS, the SDK files are all cached locally on the
// host system. So first we ask for the file in the cached SDK, then
@@ -432,12 +431,10 @@ Status PlatformAppleSimulator::GetSharedModule(
error = GetSymbolFile(platform_file, module_spec.GetUUIDPtr(),
platform_module_spec.GetFileSpec());
if (error.Success()) {
- error = ResolveExecutable(platform_module_spec, module_sp,
- module_search_paths_ptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
} else {
const bool always_create = false;
- error = ModuleList::GetSharedModule(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ error = ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
did_create_ptr, always_create);
}
if (module_sp)
@@ -660,4 +657,3 @@ void PlatformAppleSimulator::Terminate() {
PlatformDarwin::Terminate();
}
}
-
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
index 7fcf2c5..77d2a3b 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h
@@ -89,7 +89,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index 5aad447..bfbd85e 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -56,7 +56,7 @@ using namespace lldb;
using namespace lldb_private;
#define OPTTABLE_STR_TABLE_CODE
-#include "clang/Driver/Options.inc"
+#include "clang/Options/Options.inc"
#undef OPTTABLE_STR_TABLE_CODE
static Status ExceptionMaskValidator(const char *string, void *unused) {
@@ -331,7 +331,6 @@ Status PlatformDarwin::ResolveSymbolFile(Target &target,
Status PlatformDarwin::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
Status error;
module_sp.reset();
@@ -341,19 +340,22 @@ Status PlatformDarwin::GetSharedModule(
// module first.
if (m_remote_platform_sp) {
error = m_remote_platform_sp->GetSharedModule(
- module_spec, process, module_sp, module_search_paths_ptr, old_modules,
- did_create_ptr);
+ module_spec, process, module_sp, old_modules, did_create_ptr);
}
}
if (!module_sp) {
// Fall back to the local platform and find the file locally
error = Platform::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
const FileSpec &platform_file = module_spec.GetFileSpec();
- if (!module_sp && module_search_paths_ptr && platform_file) {
+ // Get module search paths from the target if available.
+ TargetSP target_sp = module_spec.GetTargetSP();
+ FileSpecList module_search_paths;
+ if (target_sp)
+ module_search_paths = target_sp->GetExecutableSearchPaths();
+ if (!module_sp && !module_search_paths.IsEmpty() && platform_file) {
// We can try to pull off part of the file path up to the bundle
// directory level and try any module search paths...
FileSpec bundle_directory;
@@ -362,9 +364,9 @@ Status PlatformDarwin::GetSharedModule(
ModuleSpec new_module_spec(module_spec);
new_module_spec.GetFileSpec() = bundle_directory;
if (Host::ResolveExecutableInBundle(new_module_spec.GetFileSpec())) {
- Status new_error(Platform::GetSharedModule(
- new_module_spec, process, module_sp, nullptr, old_modules,
- did_create_ptr));
+ Status new_error(Platform::GetSharedModule(new_module_spec, process,
+ module_sp, old_modules,
+ did_create_ptr));
if (module_sp)
return new_error;
@@ -376,10 +378,10 @@ Status PlatformDarwin::GetSharedModule(
const size_t bundle_directory_len =
bundle_directory.GetPath(bundle_dir, sizeof(bundle_dir));
char new_path[PATH_MAX];
- size_t num_module_search_paths = module_search_paths_ptr->GetSize();
+ size_t num_module_search_paths = module_search_paths.GetSize();
for (size_t i = 0; i < num_module_search_paths; ++i) {
const size_t search_path_len =
- module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath(
+ module_search_paths.GetFileSpecAtIndex(i).GetPath(
new_path, sizeof(new_path));
if (search_path_len < sizeof(new_path)) {
snprintf(new_path + search_path_len,
@@ -390,7 +392,7 @@ Status PlatformDarwin::GetSharedModule(
ModuleSpec new_module_spec(module_spec);
new_module_spec.GetFileSpec() = new_file_spec;
Status new_error(Platform::GetSharedModule(
- new_module_spec, process, module_sp, nullptr, old_modules,
+ new_module_spec, process, module_sp, old_modules,
did_create_ptr));
if (module_sp) {
@@ -1122,7 +1124,7 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(
#define OPTION(PREFIX_OFFSET, NAME_OFFSET, VAR, ...) \
llvm::StringRef opt_##VAR = OptionStrTable[NAME_OFFSET]; \
(void)opt_##VAR;
-#include "clang/Driver/Options.inc"
+#include "clang/Options/Options.inc"
#undef OPTION
minimum_version_option << '-';
switch (sdk_type) {
@@ -1303,12 +1305,15 @@ PlatformDarwin::LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) {
lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
const FileSpec &platform_file = module_spec.GetFileSpec();
- // See if the file is present in any of the module_search_paths_ptr
+ TargetSP target_sp = module_spec.GetTargetSP();
+ FileSpecList module_search_paths;
+ if (target_sp)
+ module_search_paths = target_sp->GetExecutableSearchPaths();
+ // See if the file is present in any of the module_search_paths
// directories.
- if (!module_sp && module_search_paths_ptr && platform_file) {
+ if (!module_sp && !module_search_paths.IsEmpty() && platform_file) {
// create a vector of all the file / directory names in platform_file e.g.
// this might be
// /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation
@@ -1322,21 +1327,21 @@ lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths(
std::reverse(path_parts.begin(), path_parts.end());
const size_t path_parts_size = path_parts.size();
- size_t num_module_search_paths = module_search_paths_ptr->GetSize();
+ size_t num_module_search_paths = module_search_paths.GetSize();
for (size_t i = 0; i < num_module_search_paths; ++i) {
Log *log_verbose = GetLog(LLDBLog::Host);
LLDB_LOGF(
log_verbose,
"PlatformRemoteDarwinDevice::GetSharedModule searching for binary in "
"search-path %s",
- module_search_paths_ptr->GetFileSpecAtIndex(i).GetPath().c_str());
+ module_search_paths.GetFileSpecAtIndex(i).GetPath().c_str());
// Create a new FileSpec with this module_search_paths_ptr plus just the
// filename ("UIFoundation"), then the parent dir plus filename
// ("UIFoundation.framework/UIFoundation") etc - up to four names (to
// handle "Foo.framework/Contents/MacOS/Foo")
for (size_t j = 0; j < 4 && j < path_parts_size - 1; ++j) {
- FileSpec path_to_try(module_search_paths_ptr->GetFileSpecAtIndex(i));
+ FileSpec path_to_try(module_search_paths.GetFileSpecAtIndex(i));
// Add the components backwards. For
// .../PrivateFrameworks/UIFoundation.framework/UIFoundation path_parts
@@ -1356,9 +1361,9 @@ lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths(
if (FileSystem::Instance().Exists(path_to_try)) {
ModuleSpec new_module_spec(module_spec);
new_module_spec.GetFileSpec() = path_to_try;
- Status new_error(
- Platform::GetSharedModule(new_module_spec, process, module_sp,
- nullptr, old_modules, did_create_ptr));
+ Status new_error(Platform::GetSharedModule(new_module_spec, process,
+ module_sp, old_modules,
+ did_create_ptr));
if (module_sp) {
module_sp->SetPlatformFileSpec(path_to_try);
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
index f8a62ce..82e69e3 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
@@ -73,7 +73,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
@@ -189,7 +188,7 @@ protected:
Status FindBundleBinaryInExecSearchPaths(
const ModuleSpec &module_spec, Process *process,
- lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP &module_sp,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr);
// The OSType where lldb is running.
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
index 68ef817..a72d94e 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.cpp
@@ -295,7 +295,6 @@ BringInRemoteFile(Platform *platform,
lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
- const lldb_private::FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
Log *log = GetLog(LLDBLog::Platform);
@@ -329,8 +328,7 @@ lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid,
image_info.data_sp);
err = ModuleList::GetSharedModule(shared_cache_spec, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
if (module_sp) {
LLDB_LOGF(log, "[%s] module %s was found in the in-memory shared cache",
(IsHost() ? "host" : "remote"),
@@ -348,8 +346,7 @@ lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
FileSystem::Instance().Resolve(device_support_spec);
if (FileSystem::Instance().Exists(device_support_spec)) {
ModuleSpec local_spec(device_support_spec, module_spec.GetUUID());
- err = ModuleList::GetSharedModule(local_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ err = ModuleList::GetSharedModule(local_spec, module_sp, old_modules,
did_create_ptr);
if (module_sp) {
LLDB_LOGF(log,
@@ -363,8 +360,7 @@ lldb_private::Status PlatformDarwinDevice::GetSharedModuleWithLocalCache(
}
}
- err = ModuleList::GetSharedModule(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ err = ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
did_create_ptr);
if (module_sp)
return err;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h
index e1eba08f..e0142ab 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinDevice.h
@@ -26,7 +26,6 @@ public:
protected:
virtual Status GetSharedModuleWithLocalCache(
const ModuleSpec &module_spec, lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr);
struct SDKDirectoryInfo {
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
index 07c5a52..04e87b9d 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp
@@ -719,7 +719,6 @@ void PlatformDarwinKernel::UpdateKextandKernelsLocalScan() {
Status PlatformDarwinKernel::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
Status error;
module_sp.reset();
@@ -734,14 +733,12 @@ Status PlatformDarwinKernel::GetSharedModule(
// UUID search can get here with no name - and it may be a kernel.
if (kext_bundle_id == "mach_kernel" || kext_bundle_id.empty()) {
error = GetSharedModuleKernel(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
if (error.Success() && module_sp) {
return error;
}
} else {
- return GetSharedModuleKext(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
+ return GetSharedModuleKext(module_spec, process, module_sp, old_modules,
did_create_ptr);
}
}
@@ -749,13 +746,11 @@ Status PlatformDarwinKernel::GetSharedModule(
// Give the generic methods, including possibly calling into DebugSymbols
// framework on macOS systems, a chance.
return PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
}
Status PlatformDarwinKernel::GetSharedModuleKext(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
Status error;
module_sp.reset();
@@ -782,8 +777,7 @@ Status PlatformDarwinKernel::GetSharedModuleKext(
// Give the generic methods, including possibly calling into DebugSymbols
// framework on macOS systems, a chance.
error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
if (error.Success() && module_sp.get()) {
return error;
}
@@ -793,7 +787,6 @@ Status PlatformDarwinKernel::GetSharedModuleKext(
Status PlatformDarwinKernel::GetSharedModuleKernel(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
assert(module_sp.get() == nullptr);
UpdateKextandKernelsLocalScan();
@@ -848,8 +841,7 @@ Status PlatformDarwinKernel::GetSharedModuleKernel(
// Give the generic methods, including possibly calling into DebugSymbols
// framework on macOS systems, a chance.
return PlatformDarwin::GetSharedModule(module_spec, process, module_sp,
- module_search_paths_ptr, old_modules,
- did_create_ptr);
+ old_modules, did_create_ptr);
}
std::vector<lldb_private::FileSpec>
@@ -888,8 +880,8 @@ Status PlatformDarwinKernel::ExamineKextForMatchingUUID(
ModuleSP module_sp(new Module(exe_spec));
if (module_sp && module_sp->GetObjectFile() &&
module_sp->MatchesModuleSpec(exe_spec)) {
- Status error = ModuleList::GetSharedModule(exe_spec, exe_module_sp,
- NULL, NULL, NULL);
+ Status error =
+ ModuleList::GetSharedModule(exe_spec, exe_module_sp, NULL, NULL);
if (exe_module_sp && exe_module_sp->GetObjectFile()) {
return error;
}
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h
index 9db9c00..b5cf701 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h
@@ -60,7 +60,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
@@ -142,14 +141,14 @@ protected:
Status GetSharedModuleKext(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr);
- Status GetSharedModuleKernel(
- const ModuleSpec &module_spec, Process *process,
- lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr,
- llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr);
+ Status
+ GetSharedModuleKernel(const ModuleSpec &module_spec, Process *process,
+ lldb::ModuleSP &module_sp,
+ llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
+ bool *did_create_ptr);
Status ExamineKextForMatchingUUID(const FileSpec &kext_bundle_path,
const UUID &uuid, const ArchSpec &arch,
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
index dad6dcd..e6ea75a 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp
@@ -182,10 +182,8 @@ PlatformMacOSX::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
lldb_private::Status PlatformMacOSX::GetSharedModule(
const lldb_private::ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const lldb_private::FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
Status error = GetSharedModuleWithLocalCache(module_spec, module_sp,
- module_search_paths_ptr,
old_modules, did_create_ptr);
if (module_sp) {
@@ -199,9 +197,9 @@ lldb_private::Status PlatformMacOSX::GetSharedModule(
lldb::ModuleSP x86_64_module_sp;
llvm::SmallVector<lldb::ModuleSP, 1> old_x86_64_modules;
bool did_create = false;
- Status x86_64_error = GetSharedModuleWithLocalCache(
- module_spec_x86_64, x86_64_module_sp, module_search_paths_ptr,
- &old_x86_64_modules, &did_create);
+ Status x86_64_error =
+ GetSharedModuleWithLocalCache(module_spec_x86_64, x86_64_module_sp,
+ &old_x86_64_modules, &did_create);
if (x86_64_module_sp && x86_64_module_sp->GetObjectFile()) {
module_sp = x86_64_module_sp;
if (old_modules)
@@ -217,7 +215,6 @@ lldb_private::Status PlatformMacOSX::GetSharedModule(
if (!module_sp) {
error = FindBundleBinaryInExecSearchPaths(module_spec, process, module_sp,
- module_search_paths_ptr,
old_modules, did_create_ptr);
}
return error;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
index be84485..9555b16 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h
@@ -48,7 +48,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
index b83d07b..53fab93 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp
@@ -53,7 +53,7 @@ void PlatformRemoteDarwinDevice::GetStatus(Stream &strm) {
if (sdk_directory)
strm.Printf(" SDK Path: \"%s\"\n", sdk_directory);
else
- strm.PutCString(" SDK Path: error: unable to locate SDK\n");
+ strm.PutCString(" SDK Path: <unable to locate SDK>\n");
const uint32_t num_sdk_infos = m_sdk_directory_infos.size();
for (uint32_t i = 0; i < num_sdk_infos; ++i) {
@@ -158,7 +158,6 @@ Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file,
Status PlatformRemoteDarwinDevice::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) {
// For iOS, the SDK files are all cached locally on the host system. So first
// we ask for the file in the cached SDK, then we attempt to get a shared
@@ -185,7 +184,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
if (GetFileInSDK(platform_file_path, connected_sdk_idx,
platform_module_spec.GetFileSpec())) {
module_sp.reset();
- error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
if (module_sp) {
m_last_module_sdk_idx = connected_sdk_idx;
error.Clear();
@@ -202,7 +201,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
if (GetFileInSDK(platform_file_path, m_last_module_sdk_idx,
platform_module_spec.GetFileSpec())) {
module_sp.reset();
- error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
if (module_sp) {
error.Clear();
return error;
@@ -224,7 +223,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
if (GetFileInSDK(platform_file_path, current_sdk_idx,
platform_module_spec.GetFileSpec())) {
module_sp.reset();
- error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
if (module_sp) {
m_last_module_sdk_idx = current_sdk_idx;
error.Clear();
@@ -245,7 +244,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
platform_module_spec.GetFileSpec())) {
// printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str());
- error = ResolveExecutable(platform_module_spec, module_sp, nullptr);
+ error = ResolveExecutable(platform_module_spec, module_sp);
if (module_sp) {
// Remember the index of the last SDK that we found a file in in case
// the wrong SDK was selected.
@@ -261,8 +260,7 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
// This may not be an SDK-related module. Try whether we can bring in the
// thing to our local cache.
- error = GetSharedModuleWithLocalCache(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ error = GetSharedModuleWithLocalCache(module_spec, module_sp, old_modules,
did_create_ptr);
if (error.Success())
return error;
@@ -271,15 +269,13 @@ Status PlatformRemoteDarwinDevice::GetSharedModule(
// directories.
if (!module_sp)
error = PlatformDarwin::FindBundleBinaryInExecSearchPaths(
- module_spec, process, module_sp, module_search_paths_ptr, old_modules,
- did_create_ptr);
+ module_spec, process, module_sp, old_modules, did_create_ptr);
if (error.Success())
return error;
const bool always_create = false;
- error = ModuleList::GetSharedModule(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ error = ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
did_create_ptr, always_create);
if (module_sp)
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
index 557f487..4abd74e 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h
@@ -47,7 +47,6 @@ public:
Status GetSharedModule(const ModuleSpec &module_spec, Process *process,
lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules,
bool *did_create_ptr) override;
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index 0fecefe..4cc39f9 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -79,8 +79,10 @@ namespace lldb_private {
ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
- const FileSpec *,
+ const FileSpec *crash_file_path,
bool can_connect) {
+ if (crash_file_path)
+ return nullptr; // Cannot create a Windows process from a crash_file.
return ProcessSP(new ProcessWindows(target_sp, listener_sp));
}
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index b7029fb..f8e33ea 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -84,8 +84,9 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
// For now we are just making sure the file exists for a given module
if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) {
ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture());
+ core_module_spec.SetTarget(target_sp);
Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
- nullptr, nullptr, nullptr));
+ nullptr, nullptr));
if (m_core_module_sp) {
ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 3c4d9a1..cde68b5 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -210,11 +210,9 @@ void ProcessGDBRemote::Terminate() {
lldb::ProcessSP ProcessGDBRemote::CreateInstance(
lldb::TargetSP target_sp, ListenerSP listener_sp,
const FileSpec *crash_file_path, bool can_connect) {
- lldb::ProcessSP process_sp;
- if (crash_file_path == nullptr)
- process_sp = std::shared_ptr<ProcessGDBRemote>(
- new ProcessGDBRemote(target_sp, listener_sp));
- return process_sp;
+ if (crash_file_path)
+ return nullptr; // Cannot create a GDBRemote process from a crash_file.
+ return lldb::ProcessSP(new ProcessGDBRemote(target_sp, listener_sp));
}
void ProcessGDBRemote::DumpPluginHistory(Stream &s) {
@@ -441,8 +439,16 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
if (!arch_to_use.IsValid())
arch_to_use = target_arch;
- if (GetGDBServerRegisterInfo(arch_to_use))
+ llvm::Error register_info_err = GetGDBServerRegisterInfo(arch_to_use);
+ if (!register_info_err) {
+ // We got the registers from target XML.
return;
+ }
+
+ Log *log = GetLog(GDBRLog::Process);
+ LLDB_LOG_ERROR(log, std::move(register_info_err),
+ "Failed to read register information from target XML: {0}");
+ LLDB_LOG(log, "Now trying to use qRegisterInfo instead.");
char packet[128];
std::vector<DynamicRegisterInfo::Register> registers;
@@ -541,7 +547,23 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
assert(reg_info.byte_size != 0);
registers.push_back(reg_info);
} else {
- break; // ensure exit before reg_num is incremented
+ // Only warn if we were offered Target XML and could not use it, and
+ // the qRegisterInfo fallback failed. This is something a user could
+ // take action on by getting an lldb with libxml2.
+ //
+ // It's possible we weren't offered Target XML and qRegisterInfo failed,
+ // but there's no much a user can do about that. It may be the intended
+ // way the debug stub works, so we do not warn for that case.
+ if (response_type == StringExtractorGDBRemote::eUnsupported &&
+ m_gdb_comm.GetQXferFeaturesReadSupported() &&
+ !XMLDocument::XMLEnabled()) {
+ Debugger::ReportWarning(
+ "the debug server supports Target Description XML but LLDB does "
+ "not have XML parsing enabled. Using \"qRegisterInfo\" was also "
+ "not possible. Register information may be incorrect or missing.",
+ GetTarget().GetDebugger().GetID());
+ }
+ break;
}
} else {
break;
@@ -5137,14 +5159,19 @@ void ProcessGDBRemote::AddRemoteRegisters(
// query the target of gdb-remote for extended target information returns
// true on success (got register definitions), false on failure (did not).
-bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
- // Make sure LLDB has an XML parser it can use first
- if (!XMLDocument::XMLEnabled())
- return false;
-
- // check that we have extended feature read support
+llvm::Error ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
+ // If the remote does not offer XML, does not matter if we would have been
+ // able to parse it.
if (!m_gdb_comm.GetQXferFeaturesReadSupported())
- return false;
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "the debug server does not support \"qXfer:features:read\"");
+
+ if (!XMLDocument::XMLEnabled())
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "the debug server supports \"qXfer:features:read\", but LLDB does not "
+ "have XML parsing enabled (check LLLDB_ENABLE_LIBXML2)");
// These hold register type information for the whole of target.xml.
// target.xml may include further documents that
@@ -5161,7 +5188,11 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
!registers.empty())
AddRemoteRegisters(registers, arch_to_use);
- return m_register_info_sp->GetNumRegisters() > 0;
+ return m_register_info_sp->GetNumRegisters() > 0
+ ? llvm::ErrorSuccess()
+ : llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "the debug server did not describe any registers");
}
llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index eb33b52..b7e8777 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -416,7 +416,7 @@ protected:
void AddRemoteRegisters(std::vector<DynamicRegisterInfo::Register> &registers,
const ArchSpec &arch_to_use);
// Query remote GDBServer for register information
- bool GetGDBServerRegisterInfo(ArchSpec &arch);
+ llvm::Error GetGDBServerRegisterInfo(ArchSpec &arch);
lldb::ModuleSP LoadModuleAtAddress(const FileSpec &file,
lldb::addr_t link_map,
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index a780b3f..83d684e 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -95,8 +95,9 @@ bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp,
// header but we should still try to use it -
// ModuleSpecList::FindMatchingModuleSpec enforces a strict arch mach.
ModuleSpec core_module_spec(m_core_file);
+ core_module_spec.SetTarget(target_sp);
Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
- nullptr, nullptr, nullptr));
+ nullptr, nullptr));
if (m_core_module_sp) {
ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
index 6519df9..70ce101 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
@@ -7,42 +7,77 @@
//===----------------------------------------------------------------------===//
#include "ScriptedFrame.h"
-
+#include "Plugins/Process/Utility/RegisterContextMemory.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedThreadInterface.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
+char ScriptedFrame::ID;
+
void ScriptedFrame::CheckInterpreterAndScriptObject() const {
lldbassert(m_script_object_sp && "Invalid Script Object.");
lldbassert(GetInterface() && "Invalid Scripted Frame Interface.");
}
llvm::Expected<std::shared_ptr<ScriptedFrame>>
-ScriptedFrame::Create(ScriptedThread &thread,
+ScriptedFrame::Create(ThreadSP thread_sp,
+ ScriptedThreadInterfaceSP scripted_thread_interface_sp,
StructuredData::DictionarySP args_sp,
StructuredData::Generic *script_object) {
- if (!thread.IsValid())
- return llvm::createStringError("Invalid scripted thread.");
+ if (!thread_sp || !thread_sp->IsValid())
+ return llvm::createStringError("invalid thread");
+
+ ProcessSP process_sp = thread_sp->GetProcess();
+ if (!process_sp || !process_sp->IsValid())
+ return llvm::createStringError("invalid process");
- thread.CheckInterpreterAndScriptObject();
+ ScriptInterpreter *script_interp =
+ process_sp->GetTarget().GetDebugger().GetScriptInterpreter();
+ if (!script_interp)
+ return llvm::createStringError("no script interpreter");
- auto scripted_frame_interface =
- thread.GetInterface()->CreateScriptedFrameInterface();
+ auto scripted_frame_interface = script_interp->CreateScriptedFrameInterface();
if (!scripted_frame_interface)
return llvm::createStringError("failed to create scripted frame interface");
llvm::StringRef frame_class_name;
if (!script_object) {
- std::optional<std::string> class_name =
- thread.GetInterface()->GetScriptedFramePluginName();
- if (!class_name || class_name->empty())
+ // If no script object is provided and we have a scripted thread interface,
+ // try to get the frame class name from it.
+ if (scripted_thread_interface_sp) {
+ std::optional<std::string> class_name =
+ scripted_thread_interface_sp->GetScriptedFramePluginName();
+ if (!class_name || class_name->empty())
+ return llvm::createStringError(
+ "failed to get scripted frame class name");
+ frame_class_name = *class_name;
+ } else {
return llvm::createStringError(
- "failed to get scripted thread class name");
- frame_class_name = *class_name;
+ "no script object provided and no scripted thread interface");
+ }
}
- ExecutionContext exe_ctx(thread);
+ ExecutionContext exe_ctx(thread_sp);
auto obj_or_err = scripted_frame_interface->CreatePluginObject(
frame_class_name, exe_ctx, args_sp, script_object);
@@ -62,66 +97,43 @@ ScriptedFrame::Create(ScriptedThread &thread,
SymbolContext sc;
Address symbol_addr;
if (pc != LLDB_INVALID_ADDRESS) {
- symbol_addr.SetLoadAddress(pc, &thread.GetProcess()->GetTarget());
+ symbol_addr.SetLoadAddress(pc, &process_sp->GetTarget());
symbol_addr.CalculateSymbolContext(&sc);
}
std::optional<SymbolContext> maybe_sym_ctx =
scripted_frame_interface->GetSymbolContext();
- if (maybe_sym_ctx) {
+ if (maybe_sym_ctx)
sc = *maybe_sym_ctx;
- }
-
- StructuredData::DictionarySP reg_info =
- scripted_frame_interface->GetRegisterInfo();
-
- if (!reg_info)
- return llvm::createStringError(
- "failed to get scripted thread registers info");
-
- std::shared_ptr<DynamicRegisterInfo> register_info_sp =
- DynamicRegisterInfo::Create(
- *reg_info, thread.GetProcess()->GetTarget().GetArchitecture());
lldb::RegisterContextSP reg_ctx_sp;
-
- std::optional<std::string> reg_data =
- scripted_frame_interface->GetRegisterContext();
- if (reg_data) {
- DataBufferSP data_sp(
- std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
-
- if (!data_sp->GetByteSize())
- return llvm::createStringError("failed to copy raw registers data");
-
- std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
- std::make_shared<RegisterContextMemory>(
- thread, frame_id, *register_info_sp, LLDB_INVALID_ADDRESS);
- if (!reg_ctx_memory)
- return llvm::createStringError("failed to create a register context.");
-
- reg_ctx_memory->SetAllRegisterData(data_sp);
- reg_ctx_sp = reg_ctx_memory;
- }
-
- return std::make_shared<ScriptedFrame>(
- thread, scripted_frame_interface, frame_id, pc, sc, reg_ctx_sp,
- register_info_sp, owned_script_object_sp);
+ auto regs_or_err =
+ CreateRegisterContext(*scripted_frame_interface, *thread_sp, frame_id);
+ if (!regs_or_err)
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), regs_or_err.takeError(), "{0}");
+ else
+ reg_ctx_sp = *regs_or_err;
+
+ return std::make_shared<ScriptedFrame>(thread_sp, scripted_frame_interface,
+ frame_id, pc, sc, reg_ctx_sp,
+ owned_script_object_sp);
}
-ScriptedFrame::ScriptedFrame(ScriptedThread &thread,
+ScriptedFrame::ScriptedFrame(ThreadSP thread_sp,
ScriptedFrameInterfaceSP interface_sp,
lldb::user_id_t id, lldb::addr_t pc,
SymbolContext &sym_ctx,
lldb::RegisterContextSP reg_ctx_sp,
- std::shared_ptr<DynamicRegisterInfo> reg_info_sp,
StructuredData::GenericSP script_object_sp)
- : StackFrame(thread.shared_from_this(), /*frame_idx=*/id,
+ : StackFrame(thread_sp, /*frame_idx=*/id,
/*concrete_frame_idx=*/id, /*reg_context_sp=*/reg_ctx_sp,
/*cfa=*/0, /*pc=*/pc,
/*behaves_like_zeroth_frame=*/!id, /*symbol_ctx=*/&sym_ctx),
m_scripted_frame_interface_sp(interface_sp),
- m_script_object_sp(script_object_sp), m_register_info_sp(reg_info_sp) {}
+ m_script_object_sp(script_object_sp) {
+ // FIXME: This should be part of the base class constructor.
+ m_stack_frame_kind = StackFrame::Kind::Synthetic;
+}
ScriptedFrame::~ScriptedFrame() {}
@@ -129,7 +141,7 @@ const char *ScriptedFrame::GetFunctionName() {
CheckInterpreterAndScriptObject();
std::optional<std::string> function_name = GetInterface()->GetFunctionName();
if (!function_name)
- return nullptr;
+ return StackFrame::GetFunctionName();
return ConstString(function_name->c_str()).AsCString();
}
@@ -138,7 +150,7 @@ const char *ScriptedFrame::GetDisplayFunctionName() {
std::optional<std::string> function_name =
GetInterface()->GetDisplayFunctionName();
if (!function_name)
- return nullptr;
+ return StackFrame::GetDisplayFunctionName();
return ConstString(function_name->c_str()).AsCString();
}
@@ -157,35 +169,99 @@ lldb::ScriptedFrameInterfaceSP ScriptedFrame::GetInterface() const {
std::shared_ptr<DynamicRegisterInfo> ScriptedFrame::GetDynamicRegisterInfo() {
CheckInterpreterAndScriptObject();
- if (!m_register_info_sp) {
- StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
+ StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
+
+ Status error;
+ if (!reg_info)
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION, "failed to get scripted frame registers info",
+ error, LLDBLog::Thread);
+
+ ThreadSP thread_sp = m_thread_wp.lock();
+ if (!thread_sp || !thread_sp->IsValid())
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION,
+ "failed to get scripted frame registers info: invalid thread", error,
+ LLDBLog::Thread);
+
+ ProcessSP process_sp = thread_sp->GetProcess();
+ if (!process_sp || !process_sp->IsValid())
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION,
+ "failed to get scripted frame registers info: invalid process", error,
+ LLDBLog::Thread);
+
+ return DynamicRegisterInfo::Create(*reg_info,
+ process_sp->GetTarget().GetArchitecture());
+}
+
+llvm::Expected<lldb::RegisterContextSP>
+ScriptedFrame::CreateRegisterContext(ScriptedFrameInterface &interface,
+ Thread &thread, lldb::user_id_t frame_id) {
+ StructuredData::DictionarySP reg_info = interface.GetRegisterInfo();
+ if (!reg_info)
+ return llvm::createStringError(
+ "failed to get scripted frame registers info");
+
+ std::shared_ptr<DynamicRegisterInfo> register_info_sp =
+ DynamicRegisterInfo::Create(
+ *reg_info, thread.GetProcess()->GetTarget().GetArchitecture());
+
+ lldb::RegisterContextSP reg_ctx_sp;
+
+ std::optional<std::string> reg_data = interface.GetRegisterContext();
+ if (!reg_data)
+ return llvm::createStringError(
+ "failed to get scripted frame registers data");
+
+ DataBufferSP data_sp(
+ std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
+
+ if (!data_sp->GetByteSize())
+ return llvm::createStringError("failed to copy raw registers data");
+
+ std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
+ std::make_shared<RegisterContextMemory>(
+ thread, frame_id, *register_info_sp, LLDB_INVALID_ADDRESS);
+
+ reg_ctx_memory->SetAllRegisterData(data_sp);
+ reg_ctx_sp = reg_ctx_memory;
+
+ return reg_ctx_sp;
+}
+
+lldb::RegisterContextSP ScriptedFrame::GetRegisterContext() {
+ if (!m_reg_context_sp) {
Status error;
- if (!reg_info)
- return ScriptedInterface::ErrorWithMessage<
- std::shared_ptr<DynamicRegisterInfo>>(
- LLVM_PRETTY_FUNCTION, "Failed to get scripted frame registers info.",
+ if (!m_scripted_frame_interface_sp)
+ return ScriptedInterface::ErrorWithMessage<RegisterContextSP>(
+ LLVM_PRETTY_FUNCTION,
+ "failed to get scripted frame registers context: invalid interface",
error, LLDBLog::Thread);
- ThreadSP thread_sp = m_thread_wp.lock();
- if (!thread_sp || !thread_sp->IsValid())
- return ScriptedInterface::ErrorWithMessage<
- std::shared_ptr<DynamicRegisterInfo>>(
+ ThreadSP thread_sp = GetThread();
+ if (!thread_sp)
+ return ScriptedInterface::ErrorWithMessage<RegisterContextSP>(
LLVM_PRETTY_FUNCTION,
- "Failed to get scripted frame registers info: invalid thread.", error,
- LLDBLog::Thread);
+ "failed to get scripted frame registers context: invalid thread",
+ error, LLDBLog::Thread);
- ProcessSP process_sp = thread_sp->GetProcess();
- if (!process_sp || !process_sp->IsValid())
- return ScriptedInterface::ErrorWithMessage<
- std::shared_ptr<DynamicRegisterInfo>>(
+ auto regs_or_err = CreateRegisterContext(*m_scripted_frame_interface_sp,
+ *thread_sp, GetFrameIndex());
+ if (!regs_or_err) {
+ error = Status::FromError(regs_or_err.takeError());
+ return ScriptedInterface::ErrorWithMessage<RegisterContextSP>(
LLVM_PRETTY_FUNCTION,
- "Failed to get scripted frame registers info: invalid process.",
- error, LLDBLog::Thread);
+ "failed to get scripted frame registers context", error,
+ LLDBLog::Thread);
+ }
- m_register_info_sp = DynamicRegisterInfo::Create(
- *reg_info, process_sp->GetTarget().GetArchitecture());
+ m_reg_context_sp = *regs_or_err;
}
- return m_register_info_sp;
+ return m_reg_context_sp;
}
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.h b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
index 6e01e2f..0545548 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
@@ -9,33 +9,50 @@
#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
#define LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
-#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "ScriptedThread.h"
-#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/DynamicRegisterInfo.h"
#include "lldb/Target/StackFrame.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/Support/Error.h"
+#include <memory>
#include <string>
namespace lldb_private {
-class ScriptedThread;
-}
-
-namespace lldb_private {
class ScriptedFrame : public lldb_private::StackFrame {
public:
- ScriptedFrame(ScriptedThread &thread,
+ ScriptedFrame(lldb::ThreadSP thread_sp,
lldb::ScriptedFrameInterfaceSP interface_sp,
lldb::user_id_t frame_idx, lldb::addr_t pc,
SymbolContext &sym_ctx, lldb::RegisterContextSP reg_ctx_sp,
- std::shared_ptr<DynamicRegisterInfo> reg_info_sp,
StructuredData::GenericSP script_object_sp = nullptr);
~ScriptedFrame() override;
+ /// Create a ScriptedFrame from a object instanciated in the script
+ /// interpreter.
+ ///
+ /// \param[in] thread_sp
+ /// The thread this frame belongs to.
+ ///
+ /// \param[in] scripted_thread_interface_sp
+ /// The scripted thread interface (needed for ScriptedThread
+ /// compatibility). Can be nullptr for frames on real threads.
+ ///
+ /// \param[in] args_sp
+ /// Arguments to pass to the frame creation.
+ ///
+ /// \param[in] script_object
+ /// The optional script object representing this frame.
+ ///
+ /// \return
+ /// An Expected containing the ScriptedFrame shared pointer if successful,
+ /// otherwise an error.
static llvm::Expected<std::shared_ptr<ScriptedFrame>>
- Create(ScriptedThread &thread, StructuredData::DictionarySP args_sp,
+ Create(lldb::ThreadSP thread_sp,
+ lldb::ScriptedThreadInterfaceSP scripted_thread_interface_sp,
+ StructuredData::DictionarySP args_sp,
StructuredData::Generic *script_object = nullptr);
bool IsInlined() override;
@@ -44,9 +61,19 @@ public:
const char *GetFunctionName() override;
const char *GetDisplayFunctionName() override;
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || StackFrame::isA(ClassID);
+ }
+ static bool classof(const StackFrame *obj) { return obj->isA(&ID); }
+
private:
void CheckInterpreterAndScriptObject() const;
lldb::ScriptedFrameInterfaceSP GetInterface() const;
+ static llvm::Expected<lldb::RegisterContextSP>
+ CreateRegisterContext(ScriptedFrameInterface &interface, Thread &thread,
+ lldb::user_id_t frame_id);
ScriptedFrame(const ScriptedFrame &) = delete;
const ScriptedFrame &operator=(const ScriptedFrame &) = delete;
@@ -55,7 +82,8 @@ private:
lldb::ScriptedFrameInterfaceSP m_scripted_frame_interface_sp;
lldb_private::StructuredData::GenericSP m_script_object_sp;
- std::shared_ptr<DynamicRegisterInfo> m_register_info_sp;
+
+ static char ID;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
index 491efac..1dd9c48 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -210,7 +210,7 @@ bool ScriptedThread::LoadArtificialStackFrames() {
SymbolContext sc;
symbol_addr.CalculateSymbolContext(&sc);
- return std::make_shared<StackFrame>(this->shared_from_this(), idx, idx, cfa,
+ return std::make_shared<StackFrame>(shared_from_this(), idx, idx, cfa,
cfa_is_valid, pc,
StackFrame::Kind::Synthetic, artificial,
behaves_like_zeroth_frame, &sc);
@@ -231,8 +231,8 @@ bool ScriptedThread::LoadArtificialStackFrames() {
return error.ToError();
}
- auto frame_or_error =
- ScriptedFrame::Create(*this, nullptr, object_sp->GetAsGeneric());
+ auto frame_or_error = ScriptedFrame::Create(
+ shared_from_this(), GetInterface(), nullptr, object_sp->GetAsGeneric());
if (!frame_or_error) {
ScriptedInterface::ErrorWithMessage<bool>(
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
index 0910357..50569cd 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
@@ -23,6 +23,7 @@ add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces PLUGIN
OperatingSystemPythonInterface.cpp
ScriptInterpreterPythonInterfaces.cpp
ScriptedFramePythonInterface.cpp
+ ScriptedFrameProviderPythonInterface.cpp
ScriptedPlatformPythonInterface.cpp
ScriptedProcessPythonInterface.cpp
ScriptedPythonInterface.cpp
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
index d43036d..f6c707b 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp
@@ -31,6 +31,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() {
ScriptedStopHookPythonInterface::Initialize();
ScriptedBreakpointPythonInterface::Initialize();
ScriptedThreadPlanPythonInterface::Initialize();
+ ScriptedFrameProviderPythonInterface::Initialize();
}
void ScriptInterpreterPythonInterfaces::Terminate() {
@@ -40,6 +41,7 @@ void ScriptInterpreterPythonInterfaces::Terminate() {
ScriptedStopHookPythonInterface::Terminate();
ScriptedBreakpointPythonInterface::Terminate();
ScriptedThreadPlanPythonInterface::Terminate();
+ ScriptedFrameProviderPythonInterface::Terminate();
}
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
index 3814f46..b2a3479 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
@@ -17,6 +17,7 @@
#include "OperatingSystemPythonInterface.h"
#include "ScriptedBreakpointPythonInterface.h"
+#include "ScriptedFrameProviderPythonInterface.h"
#include "ScriptedFramePythonInterface.h"
#include "ScriptedPlatformPythonInterface.h"
#include "ScriptedProcessPythonInterface.h"
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp
new file mode 100644
index 0000000..3dde503
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp
@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "lldb/Core/PluginManager.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/lldb-enumerations.h"
+
+#if LLDB_ENABLE_PYTHON
+
+// LLDB Python header must be included first
+#include "../lldb-python.h"
+
+#include "../SWIGPythonBridge.h"
+#include "../ScriptInterpreterPythonImpl.h"
+#include "ScriptedFrameProviderPythonInterface.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ScriptedFrameProviderPythonInterface::ScriptedFrameProviderPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedFrameProviderInterface(), ScriptedPythonInterface(interpreter) {}
+
+bool ScriptedFrameProviderPythonInterface::AppliesToThread(
+ llvm::StringRef class_name, lldb::ThreadSP thread_sp) {
+ // If there is any issue with this method, we will just assume it also applies
+ // to this thread which is the default behavior.
+ constexpr bool fail_value = true;
+ Status error;
+ StructuredData::ObjectSP obj =
+ CallStaticMethod(class_name, "applies_to_thread", error, thread_sp);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return fail_value;
+
+ return obj->GetBooleanValue(fail_value);
+}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedFrameProviderPythonInterface::CreatePluginObject(
+ const llvm::StringRef class_name, lldb::StackFrameListSP input_frames,
+ StructuredData::DictionarySP args_sp) {
+ if (!input_frames)
+ return llvm::createStringError("invalid frame list");
+
+ StructuredDataImpl sd_impl(args_sp);
+ return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr,
+ input_frames, sd_impl);
+}
+
+std::string ScriptedFrameProviderPythonInterface::GetDescription(
+ llvm::StringRef class_name) {
+ Status error;
+ StructuredData::ObjectSP obj =
+ CallStaticMethod(class_name, "get_description", error);
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetStringValue().str();
+}
+
+StructuredData::ObjectSP
+ScriptedFrameProviderPythonInterface::GetFrameAtIndex(uint32_t index) {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_frame_at_index", error, index);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj;
+}
+
+bool ScriptedFrameProviderPythonInterface::CreateInstance(
+ lldb::ScriptLanguage language, ScriptedInterfaceUsages usages) {
+ if (language != eScriptLanguagePython)
+ return false;
+
+ return true;
+}
+
+void ScriptedFrameProviderPythonInterface::Initialize() {
+ const std::vector<llvm::StringRef> ci_usages = {
+ "target frame-provider register -C <script-name> [-k key -v value ...]",
+ "target frame-provider list",
+ "target frame-provider remove <provider-name>",
+ "target frame-provider clear"};
+ const std::vector<llvm::StringRef> api_usages = {
+ "SBTarget.RegisterScriptedFrameProvider",
+ "SBTarget.RemoveScriptedFrameProvider",
+ "SBTarget.ClearScriptedFrameProvider"};
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(),
+ llvm::StringRef("Provide scripted stack frames for threads"),
+ CreateInstance, eScriptLanguagePython, {ci_usages, api_usages});
+}
+
+void ScriptedFrameProviderPythonInterface::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.h
new file mode 100644
index 0000000..97a5cc7
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.h
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPROVIDERPYTHONINTERFACE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPROVIDERPYTHONINTERFACE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "ScriptedPythonInterface.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
+#include <optional>
+
+namespace lldb_private {
+class ScriptedFrameProviderPythonInterface
+ : public ScriptedFrameProviderInterface,
+ public ScriptedPythonInterface,
+ public PluginInterface {
+public:
+ ScriptedFrameProviderPythonInterface(
+ ScriptInterpreterPythonImpl &interpreter);
+
+ bool AppliesToThread(llvm::StringRef class_name,
+ lldb::ThreadSP thread_sp) override;
+
+ llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name,
+ lldb::StackFrameListSP input_frames,
+ StructuredData::DictionarySP args_sp) override;
+
+ llvm::SmallVector<AbstractMethodRequirement>
+ GetAbstractMethodRequirements() const override {
+ return llvm::SmallVector<AbstractMethodRequirement>(
+ {{"get_description"}, {"get_frame_at_index"}});
+ }
+
+ std::string GetDescription(llvm::StringRef class_name) override;
+
+ StructuredData::ObjectSP GetFrameAtIndex(uint32_t index) override;
+
+ static void Initialize();
+ static void Terminate();
+
+ static bool CreateInstance(lldb::ScriptLanguage language,
+ ScriptedInterfaceUsages usages);
+
+ static llvm::StringRef GetPluginNameStatic() {
+ return "ScriptedFrameProviderPythonInterface";
+ }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPROVIDERPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index 4fdf2b1..ba4473c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -94,6 +94,19 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>(
}
template <>
+lldb::ThreadSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ThreadSP>(
+ python::PythonObject &p, Status &error) {
+ if (lldb::SBThread *sb_thread = reinterpret_cast<lldb::SBThread *>(
+ python::LLDBSWIGPython_CastPyObjectToSBThread(p.get())))
+ return m_interpreter.GetOpaqueTypeFromSBThread(*sb_thread);
+ error = Status::FromErrorString(
+ "Couldn't cast lldb::SBThread to lldb_private::Thread.");
+
+ return nullptr;
+}
+
+template <>
SymbolContext
ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>(
python::PythonObject &p, Status &error) {
@@ -243,4 +256,21 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>(
return static_cast<lldb::DescriptionLevel>(unsigned_val);
}
+template <>
+lldb::StackFrameListSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameListSP>(
+ python::PythonObject &p, Status &error) {
+
+ lldb::SBFrameList *sb_frame_list = reinterpret_cast<lldb::SBFrameList *>(
+ python::LLDBSWIGPython_CastPyObjectToSBFrameList(p.get()));
+
+ if (!sb_frame_list) {
+ error = Status::FromErrorStringWithFormat(
+ "couldn't cast lldb::SBFrameList to lldb::StackFrameListSP.");
+ return {};
+ }
+
+ return m_interpreter.GetOpaqueTypeFromSBFrameList(*sb_frame_list);
+}
+
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index 2335b2e..b737f94 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -41,7 +41,7 @@ public:
eValid
};
- struct AbstrackMethodCheckerPayload {
+ struct AbstractMethodCheckerPayload {
struct InvalidArgumentCountPayload {
InvalidArgumentCountPayload(size_t required, size_t actual)
@@ -55,13 +55,69 @@ public:
std::variant<std::monostate, InvalidArgumentCountPayload> payload;
};
- llvm::Expected<std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload>>
+ llvm::Expected<FileSpec> GetScriptedModulePath() override {
+ using namespace python;
+ using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ if (!m_object_instance_sp)
+ return llvm::createStringError("scripted Interface has invalid object");
+
+ PythonObject py_obj =
+ PythonObject(PyRefType::Borrowed,
+ static_cast<PyObject *>(m_object_instance_sp->GetValue()));
+
+ if (!py_obj.IsAllocated())
+ return llvm::createStringError(
+ "scripted Interface has invalid python object");
+
+ PythonObject py_obj_class = py_obj.GetAttributeValue("__class__");
+ if (!py_obj_class.IsValid())
+ return llvm::createStringError(
+ "scripted Interface python object is missing '__class__' attribute");
+
+ PythonObject py_obj_module = py_obj_class.GetAttributeValue("__module__");
+ if (!py_obj_module.IsValid())
+ return llvm::createStringError(
+ "scripted Interface python object '__class__' is missing "
+ "'__module__' attribute");
+
+ PythonString py_obj_module_str = py_obj_module.Str();
+ if (!py_obj_module_str.IsValid())
+ return llvm::createStringError(
+ "scripted Interface python object '__class__.__module__' attribute "
+ "is not a string");
+
+ llvm::StringRef py_obj_module_str_ref = py_obj_module_str.GetString();
+ PythonModule py_module = PythonModule::AddModule(py_obj_module_str_ref);
+ if (!py_module.IsValid())
+ return llvm::createStringError("failed to import '%s' module",
+ py_obj_module_str_ref.data());
+
+ PythonObject py_module_file = py_module.GetAttributeValue("__file__");
+ if (!py_module_file.IsValid())
+ return llvm::createStringError(
+ "module '%s' is missing '__file__' attribute",
+ py_obj_module_str_ref.data());
+
+ PythonString py_module_file_str = py_module_file.Str();
+ if (!py_module_file_str.IsValid())
+ return llvm::createStringError(
+ "module '%s.__file__' attribute is not a string",
+ py_obj_module_str_ref.data());
+
+ return FileSpec(py_module_file_str.GetString());
+ }
+
+ llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerPayload>>
CheckAbstractMethodImplementation(
const python::PythonDictionary &class_dict) const {
using namespace python;
- std::map<llvm::StringLiteral, AbstrackMethodCheckerPayload> checker;
+ std::map<llvm::StringLiteral, AbstractMethodCheckerPayload> checker;
#define SET_CASE_AND_CONTINUE(method_name, case) \
{ \
checker[method_name] = {case, {}}; \
@@ -74,7 +130,8 @@ public:
if (!class_dict.HasKey(method_name))
SET_CASE_AND_CONTINUE(method_name,
AbstractMethodCheckerCases::eNotImplemented)
- auto callable_or_err = class_dict.GetItem(method_name);
+ llvm::Expected<PythonObject> callable_or_err =
+ class_dict.GetItem(method_name);
if (!callable_or_err) {
llvm::consumeError(callable_or_err.takeError());
SET_CASE_AND_CONTINUE(method_name,
@@ -102,7 +159,7 @@ public:
} else {
checker[method_name] = {
AbstractMethodCheckerCases::eInvalidArgumentCount,
- AbstrackMethodCheckerPayload::InvalidArgumentCountPayload(
+ AbstractMethodCheckerPayload::InvalidArgumentCountPayload(
requirement.min_arg_count, arg_info.max_positional_args)};
}
}
@@ -188,8 +245,13 @@ public:
// This addresses the cases where the embedded interpreter session
// dictionary is passed to the extension initializer which is not used
// most of the time.
+ // Note, though none of our API's suggest defining the interfaces with
+ // varargs, we have some extant clients that were doing that. To keep
+ // from breaking them, we just say putting a varargs in these signatures
+ // turns off argument checking.
size_t num_args = sizeof...(Args);
- if (num_args != arg_info->max_positional_args) {
+ if (arg_info->max_positional_args != PythonCallable::ArgInfo::UNBOUNDED &&
+ num_args != arg_info->max_positional_args) {
if (num_args != arg_info->max_positional_args - 1)
return create_error("Passed arguments ({0}) doesn't match the number "
"of expected arguments ({1}).",
@@ -286,7 +348,7 @@ public:
case AbstractMethodCheckerCases::eInvalidArgumentCount: {
auto &payload_variant = method_checker.second.payload;
if (!std::holds_alternative<
- AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
+ AbstractMethodCheckerPayload::InvalidArgumentCountPayload>(
payload_variant)) {
abstract_method_errors = llvm::joinErrors(
std::move(abstract_method_errors),
@@ -295,7 +357,7 @@ public:
obj_class_name.GetString(), method_checker.first)));
} else {
auto payload = std::get<
- AbstrackMethodCheckerPayload::InvalidArgumentCountPayload>(
+ AbstractMethodCheckerPayload::InvalidArgumentCountPayload>(
payload_variant);
abstract_method_errors = llvm::joinErrors(
std::move(abstract_method_errors),
@@ -325,6 +387,112 @@ public:
return m_object_instance_sp;
}
+ /// Call a static method on a Python class without creating an instance.
+ ///
+ /// This method resolves a Python class by name and calls a static method
+ /// on it, returning the result. This is useful for calling class-level
+ /// methods that don't require an instance.
+ ///
+ /// \param class_name The fully-qualified name of the Python class.
+ /// \param method_name The name of the static method to call.
+ /// \param error Output parameter to receive error information if the call
+ /// fails.
+ /// \param args Arguments to pass to the static method.
+ ///
+ /// \return The return value of the static method call, or an error value.
+ template <typename T = StructuredData::ObjectSP, typename... Args>
+ T CallStaticMethod(llvm::StringRef class_name, llvm::StringRef method_name,
+ Status &error, Args &&...args) {
+ using namespace python;
+ using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ std::string caller_signature =
+ llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +
+ llvm::Twine(class_name) + llvm::Twine(".") +
+ llvm::Twine(method_name) + llvm::Twine(")"))
+ .str();
+
+ if (class_name.empty())
+ return ErrorWithMessage<T>(caller_signature, "missing script class name",
+ error);
+
+ Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
+ Locker::FreeLock);
+
+ // Get the interpreter dictionary.
+ auto dict =
+ PythonModule::MainModule().ResolveName<python::PythonDictionary>(
+ m_interpreter.GetDictionaryName());
+ if (!dict.IsAllocated())
+ return ErrorWithMessage<T>(
+ caller_signature,
+ llvm::formatv("could not find interpreter dictionary: {0}",
+ m_interpreter.GetDictionaryName())
+ .str(),
+ error);
+
+ // Resolve the class.
+ auto class_obj =
+ PythonObject::ResolveNameWithDictionary<python::PythonCallable>(
+ class_name, dict);
+ if (!class_obj.IsAllocated())
+ return ErrorWithMessage<T>(
+ caller_signature,
+ llvm::formatv("could not find script class: {0}", class_name).str(),
+ error);
+
+ // Get the static method from the class.
+ if (!class_obj.HasAttribute(method_name))
+ return ErrorWithMessage<T>(
+ caller_signature,
+ llvm::formatv("class {0} does not have method {1}", class_name,
+ method_name)
+ .str(),
+ error);
+
+ PythonCallable method =
+ class_obj.GetAttributeValue(method_name).AsType<PythonCallable>();
+ if (!method.IsAllocated())
+ return ErrorWithMessage<T>(caller_signature,
+ llvm::formatv("method {0}.{1} is not callable",
+ class_name, method_name)
+ .str(),
+ error);
+
+ // Transform the arguments.
+ std::tuple<Args...> original_args = std::forward_as_tuple(args...);
+ auto transformed_args = TransformArgs(original_args);
+
+ // Call the static method.
+ llvm::Expected<PythonObject> expected_return_object =
+ llvm::make_error<llvm::StringError>("Not initialized.",
+ llvm::inconvertibleErrorCode());
+ std::apply(
+ [&method, &expected_return_object](auto &&...args) {
+ llvm::consumeError(expected_return_object.takeError());
+ expected_return_object = method(args...);
+ },
+ transformed_args);
+
+ if (llvm::Error e = expected_return_object.takeError()) {
+ error = Status::FromError(std::move(e));
+ return ErrorWithMessage<T>(
+ caller_signature, "python static method could not be called", error);
+ }
+
+ PythonObject py_return = std::move(expected_return_object.get());
+
+ // Re-assign reference and pointer arguments if needed.
+ if (sizeof...(Args) > 0)
+ if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
+ return ErrorWithMessage<T>(
+ caller_signature,
+ "couldn't re-assign reference and pointer arguments", error);
+
+ // Extract value from Python object (handles unallocated case).
+ return ExtractValueFromPythonObject<T>(py_return, error);
+ }
+
protected:
template <typename T = StructuredData::ObjectSP>
T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {
@@ -341,7 +509,7 @@ protected:
llvm::Twine(method_name) + llvm::Twine(")"))
.str();
if (!m_object_instance_sp)
- return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",
+ return ErrorWithMessage<T>(caller_signature, "python object ill-formed",
error);
Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,
@@ -353,7 +521,7 @@ protected:
if (!implementor.IsAllocated())
return llvm::is_contained(GetAbstractMethods(), method_name)
? ErrorWithMessage<T>(caller_signature,
- "Python implementor not allocated.",
+ "python implementor not allocated",
error)
: T{};
@@ -374,20 +542,20 @@ protected:
if (llvm::Error e = expected_return_object.takeError()) {
error = Status::FromError(std::move(e));
return ErrorWithMessage<T>(caller_signature,
- "Python method could not be called.", error);
+ "python method could not be called", error);
}
PythonObject py_return = std::move(expected_return_object.get());
// Now that we called the python method with the transformed arguments,
- // we need to interate again over both the original and transformed
+ // we need to iterate again over both the original and transformed
// parameter pack, and transform back the parameter that were passed in
// the original parameter pack as references or pointers.
if (sizeof...(Args) > 0)
if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))
return ErrorWithMessage<T>(
caller_signature,
- "Couldn't re-assign reference and pointer arguments.", error);
+ "couldn't re-assign reference and pointer arguments", error);
if (!py_return.IsAllocated())
return {};
@@ -444,6 +612,14 @@ protected:
return python::SWIGBridge::ToSWIGWrapper(arg);
}
+ python::PythonObject Transform(lldb::ThreadSP arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
+ python::PythonObject Transform(lldb::StackFrameListSP arg) {
+ return python::SWIGBridge::ToSWIGWrapper(arg);
+ }
+
python::PythonObject Transform(lldb::ThreadPlanSP arg) {
return python::SWIGBridge::ToSWIGWrapper(arg);
}
@@ -586,6 +762,11 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
python::PythonObject &p, Status &error);
template <>
+lldb::ThreadSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::ThreadSP>(
+ python::PythonObject &p, Status &error);
+
+template <>
lldb::StackFrameSP
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>(
python::PythonObject &p, Status &error);
@@ -628,6 +809,11 @@ lldb::DescriptionLevel
ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>(
python::PythonObject &p, Status &error);
+template <>
+lldb::StackFrameListSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameListSP>(
+ python::PythonObject &p, Status &error);
+
} // namespace lldb_private
#endif // LLDB_ENABLE_PYTHON
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index a2a287a..d2f795c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -810,6 +810,17 @@ bool PythonCallable::Check(PyObject *py_obj) {
if (!py_obj)
return false;
+ PythonObject python_obj(PyRefType::Borrowed, py_obj);
+
+ // Handle staticmethod/classmethod descriptors by extracting the
+ // `__func__` attribute.
+ if (python_obj.HasAttribute("__func__")) {
+ PythonObject function_obj = python_obj.GetAttributeValue("__func__");
+ if (!function_obj.IsAllocated())
+ return false;
+ return PyCallable_Check(function_obj.release());
+ }
+
return PyCallable_Check(py_obj);
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 27f5d2e..32948ff 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -93,6 +93,7 @@ public:
static PythonObject ToSWIGWrapper(const StructuredDataImpl &data_impl);
static PythonObject ToSWIGWrapper(lldb::ThreadSP thread_sp);
static PythonObject ToSWIGWrapper(lldb::StackFrameSP frame_sp);
+ static PythonObject ToSWIGWrapper(lldb::StackFrameListSP frames_sp);
static PythonObject ToSWIGWrapper(lldb::DebuggerSP debugger_sp);
static PythonObject ToSWIGWrapper(lldb::WatchpointSP watchpoint_sp);
static PythonObject ToSWIGWrapper(lldb::BreakpointLocationSP bp_loc_sp);
@@ -264,11 +265,13 @@ void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBThread(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBFrame(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBSymbolContext(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data);
void *LLDBSWIGPython_CastPyObjectToSBExecutionContext(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBFrameList(PyObject *data);
} // namespace python
} // namespace lldb_private
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index d257a08..35a772c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -272,6 +272,7 @@ void ScriptInterpreterPython::SharedLibraryDirectoryHelper(
// does.
if (this_file.GetFileNameExtension() == ".pyd") {
this_file.RemoveLastPathComponent(); // _lldb.pyd or _lldb_d.pyd
+ this_file.RemoveLastPathComponent(); // native
this_file.RemoveLastPathComponent(); // lldb
llvm::StringRef libdir = LLDB_PYTHON_RELATIVE_LIBDIR;
for (auto it = llvm::sys::path::begin(libdir),
@@ -1526,6 +1527,11 @@ ScriptInterpreterPythonImpl::CreateScriptedFrameInterface() {
return std::make_shared<ScriptedFramePythonInterface>(*this);
}
+ScriptedFrameProviderInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedFrameProviderInterface() {
+ return std::make_shared<ScriptedFrameProviderPythonInterface>(*this);
+}
+
ScriptedThreadPlanInterfaceSP
ScriptInterpreterPythonImpl::CreateScriptedThreadPlanInterface() {
return std::make_shared<ScriptedThreadPlanPythonInterface>(*this);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index 00ae59c..ad2ddd2 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -101,6 +101,9 @@ public:
lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
+ lldb::ScriptedFrameProviderInterfaceSP
+ CreateScriptedFrameProviderInterface() override;
+
lldb::ScriptedThreadPlanInterfaceSP
CreateScriptedThreadPlanInterface() override;
diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
index ce2ba69..14932e9 100644
--- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
+++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -437,7 +437,7 @@ void SymbolFileBreakpad::FindFunctions(
sc.comp_unit = cu_sp.get();
sc.function = func_sp.get();
sc.module_sp = func_sp->CalculateSymbolContextModule();
- sc_list.Append(sc);
+ sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/true);
}
}
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 63b2dc4..d65aa40 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -623,6 +623,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc,
switch (tag) {
case DW_TAG_typedef:
+ case DW_TAG_template_alias:
case DW_TAG_base_type:
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
@@ -748,7 +749,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
TypeSP type_sp;
CompilerType clang_type;
- if (tag == DW_TAG_typedef) {
+ if (tag == DW_TAG_typedef || tag == DW_TAG_template_alias) {
// DeclContext will be populated when the clang type is materialized in
// Type::ResolveCompilerType.
PrepareContextToReceiveMembers(
@@ -836,6 +837,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc,
encoding_data_type = Type::eEncodingIsRValueReferenceUID;
break;
case DW_TAG_typedef:
+ case DW_TAG_template_alias:
encoding_data_type = Type::eEncodingIsTypedefUID;
break;
case DW_TAG_const_type:
@@ -1705,8 +1707,11 @@ void DWARFASTParserClang::GetUniqueTypeNameAndDeclaration(
// For C++, we rely solely upon the one definition rule that says
// only one thing can exist at a given decl context. We ignore the
// file and line that things are declared on.
- if (!die.IsValid() || !Language::LanguageIsCPlusPlus(language) ||
- unique_typename.IsEmpty())
+ // FIXME: Rust pretends to be C++ for now, so use C++ name qualification rules
+ if (!Language::LanguageIsCPlusPlus(language) &&
+ language != lldb::eLanguageTypeRust)
+ return;
+ if (!die.IsValid() || unique_typename.IsEmpty())
return;
decl_declaration.Clear();
std::string qualified_name;
@@ -3704,12 +3709,10 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes(
}
}
- DWARFASTParserClang *src_dwarf_ast_parser =
- static_cast<DWARFASTParserClang *>(
- SymbolFileDWARF::GetDWARFParser(*src_class_die.GetCU()));
- DWARFASTParserClang *dst_dwarf_ast_parser =
- static_cast<DWARFASTParserClang *>(
- SymbolFileDWARF::GetDWARFParser(*dst_class_die.GetCU()));
+ auto *src_dwarf_ast_parser = llvm::cast<DWARFASTParserClang>(
+ SymbolFileDWARF::GetDWARFParser(*src_class_die.GetCU()));
+ auto *dst_dwarf_ast_parser = llvm::cast<DWARFASTParserClang>(
+ SymbolFileDWARF::GetDWARFParser(*dst_class_die.GetCU()));
auto link = [&](DWARFDIE src, DWARFDIE dst) {
auto &die_to_type = dst_class_die.GetDWARF()->GetDIEToType();
clang::DeclContext *dst_decl_ctx =
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index f5f7071..6eb2b6b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -47,6 +47,11 @@ public:
~DWARFASTParserClang() override;
+ // LLVM RTTI support
+ static bool classof(const DWARFASTParser *Parser) {
+ return Parser->GetKind() == Kind::DWARFASTParserClang;
+ }
+
// DWARFASTParser interface.
lldb::TypeSP
ParseTypeFromDWARF(const lldb_private::SymbolContext &sc,
@@ -264,10 +269,6 @@ protected:
lldb::ModuleSP
GetModuleForType(const lldb_private::plugin::dwarf::DWARFDIE &die);
- static bool classof(const DWARFASTParser *Parser) {
- return Parser->GetKind() == Kind::DWARFASTParserClang;
- }
-
private:
struct FieldInfo {
/// Size in bits that this field occupies. Can but
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
index 64a8005..c4efc06 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
@@ -173,6 +173,14 @@ void DWARFIndex::GetNamespacesWithParents(
});
}
+void DWARFIndex::GetFunctions(
+ const std::vector<Module::LookupInfo> &lookup_infos, SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
+ for (auto &lookup_info : lookup_infos)
+ GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
+}
+
IterationAction DWARFIndex::ProcessNamespaceDieMatchParents(
const CompilerDeclContext &parent_decl_ctx, DWARFDIE die,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
index be73255..eaf1da1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
@@ -86,6 +86,11 @@ public:
const CompilerDeclContext &parent_decl_ctx,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) = 0;
virtual void
+ GetFunctions(const std::vector<Module::LookupInfo> &lookup_infos,
+ SymbolFileDWARF &dwarf,
+ const CompilerDeclContext &parent_decl_ctx,
+ llvm::function_ref<IterationAction(DWARFDIE die)> callback);
+ virtual void
GetFunctions(const RegularExpression &regex,
llvm::function_ref<IterationAction(DWARFDIE die)> callback) = 0;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index 94fc2e83..b78e6ce8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -348,6 +348,10 @@ void DWARFUnit::ExtractDIEsRWLocked() {
void DWARFUnit::SetDwoStrOffsetsBase() {
lldb::offset_t baseOffset = 0;
+ // Size of offset for .debug_str_offsets is same as DWARF offset byte size
+ // of the DWARFUnit as a default. We might override this if below if needed.
+ m_str_offset_size = m_header.getDwarfOffsetByteSize();
+
if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) {
if (const auto *contribution =
entry->getContribution(llvm::DW_SECT_STR_OFFSETS))
@@ -357,14 +361,17 @@ void DWARFUnit::SetDwoStrOffsetsBase() {
}
if (GetVersion() >= 5) {
- const DWARFDataExtractor &strOffsets =
- GetSymbolFileDWARF().GetDWARFContext().getOrLoadStrOffsetsData();
- uint64_t length = strOffsets.GetU32(&baseOffset);
- if (length == 0xffffffff)
- length = strOffsets.GetU64(&baseOffset);
-
+ const llvm::DWARFDataExtractor &strOffsets = GetSymbolFileDWARF()
+ .GetDWARFContext()
+ .getOrLoadStrOffsetsData()
+ .GetAsLLVMDWARF();
+
+ uint64_t length;
+ llvm::dwarf::DwarfFormat format;
+ std::tie(length, format) = strOffsets.getInitialLength(&baseOffset);
+ m_str_offset_size = format == llvm::dwarf::DwarfFormat::DWARF64 ? 8 : 4;
// Check version.
- if (strOffsets.GetU16(&baseOffset) < 5)
+ if (strOffsets.getU16(&baseOffset) < 5)
return;
// Skip padding.
@@ -409,7 +416,16 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
SetRangesBase(form_value.Unsigned());
break;
case DW_AT_str_offsets_base:
+ // When we have a DW_AT_str_offsets_base attribute, it points us to the
+ // first string offset for this DWARFUnit which is after the string
+ // offsets table header. In this case we use the DWARF32/DWARF64 of the
+ // DWARFUnit to determine the string offset byte size. DWO files do not
+ // use this attribute and they point to the start of the string offsets
+ // table header which can be used to determine the DWARF32/DWARF64 status
+ // of the string table. See SetDwoStrOffsetsBase() for now it figures out
+ // the m_str_offset_size value that should be used.
SetStrOffsetsBase(form_value.Unsigned());
+ m_str_offset_size = m_header.getDwarfOffsetByteSize();
break;
case DW_AT_low_pc:
SetBaseAddress(form_value.Address());
@@ -1079,10 +1095,9 @@ uint32_t DWARFUnit::GetHeaderByteSize() const { return m_header.getSize(); }
std::optional<uint64_t>
DWARFUnit::GetStringOffsetSectionItem(uint32_t index) const {
- lldb::offset_t offset =
- GetStrOffsetsBase() + index * m_header.getDwarfOffsetByteSize();
+ lldb::offset_t offset = GetStrOffsetsBase() + index * m_str_offset_size;
return m_dwarf.GetDWARFContext().getOrLoadStrOffsetsData().GetMaxU64(
- &offset, m_header.getDwarfOffsetByteSize());
+ &offset, m_str_offset_size);
}
llvm::Expected<llvm::DWARFAddressRangesVector>
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index 91a6938..b5199a8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -364,6 +364,7 @@ protected:
dw_offset_t m_line_table_offset = DW_INVALID_OFFSET;
dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base.
+ dw_offset_t m_str_offset_size = 4; // Size in bytes of a string offset.
std::optional<llvm::DWARFDebugRnglistTable> m_rnglist_table;
bool m_rnglist_table_done = false;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 881268b..b755f3a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -794,12 +794,12 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) {
} else {
ModuleSP module_sp(m_objfile_sp->GetModule());
if (module_sp) {
- auto initialize_cu = [&](lldb::SupportFileSP support_file_sp,
+ auto initialize_cu = [&](SupportFileNSP support_file_nsp,
LanguageType cu_language,
SupportFileList &&support_files = {}) {
BuildCuTranslationTable();
cu_sp = std::make_shared<CompileUnit>(
- module_sp, &dwarf_cu, support_file_sp,
+ module_sp, &dwarf_cu, support_file_nsp,
*GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language,
eLazyBoolCalculate, std::move(support_files));
@@ -1560,8 +1560,8 @@ bool SymbolFileDWARF::HasForwardDeclForCompilerType(
auto clang_type_system = compiler_type.GetTypeSystem<TypeSystemClang>();
if (!clang_type_system)
return false;
- DWARFASTParserClang *ast_parser =
- static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser());
+ auto *ast_parser =
+ llvm::cast<DWARFASTParserClang>(clang_type_system->GetDWARFParser());
return ast_parser->GetClangASTImporter().CanImport(compiler_type);
}
@@ -1569,8 +1569,8 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
auto clang_type_system = compiler_type.GetTypeSystem<TypeSystemClang>();
if (clang_type_system) {
- DWARFASTParserClang *ast_parser =
- static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser());
+ auto *ast_parser =
+ llvm::cast<DWARFASTParserClang>(clang_type_system->GetDWARFParser());
if (ast_parser &&
ast_parser->GetClangASTImporter().CanImport(compiler_type))
return ast_parser->GetClangASTImporter().CompleteType(compiler_type);
@@ -1614,8 +1614,7 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
if (decl_die != def_die) {
GetDIEToType()[def_die.GetDIE()] = type;
- DWARFASTParserClang *ast_parser =
- static_cast<DWARFASTParserClang *>(dwarf_ast);
+ auto *ast_parser = llvm::cast<DWARFASTParserClang>(dwarf_ast);
ast_parser->MapDeclDIEToDefDIE(decl_die, def_die);
}
@@ -2018,7 +2017,7 @@ void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
}
Status error = ModuleList::GetSharedModule(dwo_module_spec, module_sp,
- nullptr, nullptr, nullptr);
+ nullptr, nullptr);
if (!module_sp) {
// ReportWarning also rate-limits based on the warning string,
// but in a -gmodules build, each object file has a similar DAG
@@ -2341,7 +2340,7 @@ void SymbolFileDWARF::FindGlobalVariables(
bool name_is_mangled = Mangled::GetManglingScheme(name.GetStringRef()) !=
Mangled::eManglingSchemeNone;
- if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name.GetCString(),
+ if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name.GetStringRef(),
context, basename))
basename = name.GetStringRef();
@@ -2482,7 +2481,7 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
sc.block = function_block.FindBlockByID(inlined_die.GetOffset());
}
- sc_list.Append(sc);
+ sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/true);
return true;
}
@@ -2550,11 +2549,11 @@ SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label,
const DWARFDIE &declaration) {
auto do_lookup = [this](llvm::StringRef lookup_name) -> DWARFDIE {
DWARFDIE found;
- Module::LookupInfo info(ConstString(lookup_name),
- lldb::eFunctionNameTypeFull,
- lldb::eLanguageTypeUnknown);
+ auto lookup_infos = Module::LookupInfo::MakeLookupInfos(
+ ConstString(lookup_name), lldb::eFunctionNameTypeFull,
+ lldb::eLanguageTypeUnknown);
- m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+ m_index->GetFunctions(lookup_infos, *this, {}, [&](DWARFDIE entry) {
if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
return IterationAction::Continue;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index aaec160..3bf113a 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -86,6 +86,40 @@ static lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
}
}
+static std::optional<std::string>
+findMatchingPDBFilePath(llvm::StringRef original_pdb_path,
+ llvm::StringRef exe_path) {
+ const FileSystem &fs = FileSystem::Instance();
+
+ if (fs.Exists(original_pdb_path))
+ return std::string(original_pdb_path);
+
+ const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent();
+ // While the exe_path uses the native style, the exe might be compiled on a
+ // different OS, so try to guess the style used.
+ const FileSpec original_pdb_spec(original_pdb_path,
+ FileSpec::GuessPathStyle(original_pdb_path)
+ .value_or(FileSpec::Style::native));
+ const llvm::StringRef pdb_filename = original_pdb_spec.GetFilename();
+
+ // If the file doesn't exist, perhaps the path specified at build time
+ // doesn't match the PDB's current location, so check the location of the
+ // executable.
+ const FileSpec local_pdb = exe_dir.CopyByAppendingPathComponent(pdb_filename);
+ if (fs.Exists(local_pdb))
+ return local_pdb.GetPath();
+
+ // Otherwise, search for one in target.debug-file-search-paths
+ FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
+ for (const FileSpec &search_dir : search_paths) {
+ FileSpec pdb_path = search_dir.CopyByAppendingPathComponent(pdb_filename);
+ if (fs.Exists(pdb_path))
+ return pdb_path.GetPath();
+ }
+
+ return std::nullopt;
+}
+
static std::unique_ptr<PDBFile>
loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
// Try to find a matching PDB for an EXE.
@@ -113,17 +147,14 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
return nullptr;
}
- // If the file doesn't exist, perhaps the path specified at build time
- // doesn't match the PDB's current location, so check the location of the
- // executable.
- if (!FileSystem::Instance().Exists(pdb_file)) {
- const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent();
- const auto pdb_name = FileSpec(pdb_file).GetFilename().GetCString();
- pdb_file = exe_dir.CopyByAppendingPathComponent(pdb_name).GetPathAsConstString().GetStringRef();
- }
+ std::optional<std::string> resolved_pdb_path =
+ findMatchingPDBFilePath(pdb_file, exe_path);
+ if (!resolved_pdb_path)
+ return nullptr;
// If the file is not a PDB or if it doesn't have a matching GUID, fail.
- auto pdb = ObjectFilePDB::loadPDBFile(std::string(pdb_file), allocator);
+ auto pdb =
+ ObjectFilePDB::loadPDBFile(*std::move(resolved_pdb_path), allocator);
if (!pdb)
return nullptr;
@@ -137,6 +168,9 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
if (expected_info->getGuid() != guid)
return nullptr;
+
+ LLDB_LOG(GetLog(LLDBLog::Symbols), "Loading {0} for {1}", pdb->getFilePath(),
+ exe_path);
return pdb;
}
@@ -1126,7 +1160,8 @@ lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) {
}
void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {
- auto *section_list = m_objfile_sp->GetSectionList();
+ auto *section_list =
+ m_objfile_sp->GetModule()->GetObjectFile()->GetSectionList();
if (!section_list)
return;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 1c575e9..46cf9b8 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -442,6 +442,10 @@ void UdtRecordCompleter::Record::ConstructRecord() {
// The end offset to a vector of field/struct that ends at the offset.
std::map<uint64_t, std::vector<Member *>> end_offset_map;
+ auto is_last_end_offset = [&](auto it) {
+ return it != end_offset_map.end() && ++it == end_offset_map.end();
+ };
+
for (auto &pair : fields_map) {
uint64_t offset = pair.first;
auto &fields = pair.second;
@@ -462,8 +466,23 @@ void UdtRecordCompleter::Record::ConstructRecord() {
}
if (iter->second.empty())
continue;
- parent = iter->second.back();
- iter->second.pop_back();
+
+ // If the new fields come after the already added ones
+ // without overlap, go back to the root.
+ if (iter->first <= offset && is_last_end_offset(iter)) {
+ if (record.kind == Member::Struct) {
+ parent = &record;
+ } else {
+ assert(record.kind == Member::Union &&
+ "Current record must be a union");
+ assert(!record.fields.empty());
+ // For unions, append the field to the last struct
+ parent = record.fields.back().get();
+ }
+ } else {
+ parent = iter->second.back();
+ iter->second.pop_back();
+ }
}
// If it's a field, then the field is inside a union, so we can safely
// increase its size by converting it to a struct to hold multiple fields.
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index 0ccb1804..97c995fc 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -287,8 +287,10 @@ uint32_t SymbolFilePDB::CalculateAbilities() {
}
void SymbolFilePDB::InitializeObject() {
- lldb::addr_t obj_load_address =
- m_objfile_sp->GetBaseAddress().GetFileAddress();
+ lldb::addr_t obj_load_address = m_objfile_sp->GetModule()
+ ->GetObjectFile()
+ ->GetBaseAddress()
+ .GetFileAddress();
lldbassert(obj_load_address && obj_load_address != LLDB_INVALID_ADDRESS);
m_session_up->setLoadAddress(obj_load_address);
if (!m_global_scope_up)
@@ -1479,7 +1481,8 @@ void SymbolFilePDB::AddSymbols(lldb_private::Symtab &symtab) {
if (!results)
return;
- auto section_list = m_objfile_sp->GetSectionList();
+ auto section_list =
+ m_objfile_sp->GetModule()->GetObjectFile()->GetSectionList();
if (!section_list)
return;
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/CMakeLists.txt b/lldb/source/Plugins/SyntheticFrameProvider/CMakeLists.txt
new file mode 100644
index 0000000..85b405e
--- /dev/null
+++ b/lldb/source/Plugins/SyntheticFrameProvider/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(ScriptedFrameProvider)
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/CMakeLists.txt b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/CMakeLists.txt
new file mode 100644
index 0000000..fe67d39
--- /dev/null
+++ b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_lldb_library(lldbPluginScriptedFrameProvider PLUGIN
+ ScriptedFrameProvider.cpp
+
+ LINK_COMPONENTS
+ Support
+
+ LINK_LIBS
+ lldbCore
+ lldbInterpreter
+ lldbTarget
+ lldbUtility
+ )
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp
new file mode 100644
index 0000000..739963e
--- /dev/null
+++ b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp
@@ -0,0 +1,221 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "ScriptedFrameProvider.h"
+#include "Plugins/Process/scripted/ScriptedFrame.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/BorrowedStackFrame.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ScriptedMetadata.h"
+#include "lldb/Utility/Status.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+
+using namespace lldb;
+using namespace lldb_private;
+
+void ScriptedFrameProvider::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ "Provides synthetic frames via scripting",
+ nullptr, ScriptedFrameProvider::CreateInstance);
+}
+
+void ScriptedFrameProvider::Terminate() {
+ PluginManager::UnregisterPlugin(ScriptedFrameProvider::CreateInstance);
+}
+
+llvm::Expected<lldb::SyntheticFrameProviderSP>
+ScriptedFrameProvider::CreateInstance(
+ lldb::StackFrameListSP input_frames,
+ const ScriptedFrameProviderDescriptor &descriptor) {
+ if (!input_frames)
+ return llvm::createStringError(
+ "failed to create scripted frame provider: invalid input frames");
+
+ Thread &thread = input_frames->GetThread();
+ ProcessSP process_sp = thread.GetProcess();
+ if (!process_sp)
+ return nullptr;
+
+ if (!descriptor.IsValid())
+ return llvm::createStringError(
+ "failed to create scripted frame provider: invalid scripted metadata");
+
+ if (!descriptor.AppliesToThread(thread))
+ return nullptr;
+
+ ScriptInterpreter *script_interp =
+ process_sp->GetTarget().GetDebugger().GetScriptInterpreter();
+ if (!script_interp)
+ return llvm::createStringError("cannot create scripted frame provider: No "
+ "script interpreter installed");
+
+ ScriptedFrameProviderInterfaceSP interface_sp =
+ script_interp->CreateScriptedFrameProviderInterface();
+ if (!interface_sp)
+ return llvm::createStringError(
+ "cannot create scripted frame provider: script interpreter couldn't "
+ "create Scripted Frame Provider Interface");
+
+ const ScriptedMetadataSP scripted_metadata = descriptor.scripted_metadata_sp;
+
+ // If we shouldn't attach a frame provider to this thread, just exit early.
+ if (!interface_sp->AppliesToThread(scripted_metadata->GetClassName(),
+ thread.shared_from_this()))
+ return nullptr;
+
+ auto obj_or_err = interface_sp->CreatePluginObject(
+ scripted_metadata->GetClassName(), input_frames,
+ scripted_metadata->GetArgsSP());
+ if (!obj_or_err)
+ return obj_or_err.takeError();
+
+ StructuredData::ObjectSP object_sp = *obj_or_err;
+ if (!object_sp || !object_sp->IsValid())
+ return llvm::createStringError(
+ "cannot create scripted frame provider: failed to create valid scripted"
+ "frame provider object");
+
+ return std::make_shared<ScriptedFrameProvider>(input_frames, interface_sp,
+ descriptor);
+}
+
+ScriptedFrameProvider::ScriptedFrameProvider(
+ StackFrameListSP input_frames,
+ lldb::ScriptedFrameProviderInterfaceSP interface_sp,
+ const ScriptedFrameProviderDescriptor &descriptor)
+ : SyntheticFrameProvider(input_frames), m_interface_sp(interface_sp),
+ m_descriptor(descriptor) {}
+
+ScriptedFrameProvider::~ScriptedFrameProvider() = default;
+
+std::string ScriptedFrameProvider::GetDescription() const {
+ if (!m_interface_sp)
+ return {};
+
+ return m_interface_sp->GetDescription(m_descriptor.GetName());
+}
+
+llvm::Expected<StackFrameSP>
+ScriptedFrameProvider::GetFrameAtIndex(uint32_t idx) {
+ if (!m_interface_sp)
+ return llvm::createStringError(
+ "cannot get stack frame: scripted frame provider not initialized");
+
+ auto create_frame_from_dict =
+ [this](StructuredData::Dictionary *dict,
+ uint32_t index) -> llvm::Expected<StackFrameSP> {
+ lldb::addr_t pc;
+ if (!dict->GetValueForKeyAsInteger("pc", pc))
+ return llvm::createStringError(
+ "missing 'pc' key from scripted frame dictionary");
+
+ Address symbol_addr;
+ symbol_addr.SetLoadAddress(pc, &GetThread().GetProcess()->GetTarget());
+
+ const lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
+ const bool cfa_is_valid = false;
+ const bool artificial = false;
+ const bool behaves_like_zeroth_frame = false;
+ SymbolContext sc;
+ symbol_addr.CalculateSymbolContext(&sc);
+
+ ThreadSP thread_sp = GetThread().shared_from_this();
+ return std::make_shared<StackFrame>(thread_sp, index, index, cfa,
+ cfa_is_valid, pc,
+ StackFrame::Kind::Synthetic, artificial,
+ behaves_like_zeroth_frame, &sc);
+ };
+
+ auto create_frame_from_script_object =
+ [this](
+ StructuredData::ObjectSP object_sp) -> llvm::Expected<StackFrameSP> {
+ Status error;
+ if (!object_sp || !object_sp->GetAsGeneric())
+ return llvm::createStringError("invalid script object");
+
+ ThreadSP thread_sp = GetThread().shared_from_this();
+ auto frame_or_error = ScriptedFrame::Create(thread_sp, nullptr, nullptr,
+ object_sp->GetAsGeneric());
+
+ if (!frame_or_error) {
+ ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
+ return error.ToError();
+ }
+
+ return *frame_or_error;
+ };
+
+ StructuredData::ObjectSP obj_sp = m_interface_sp->GetFrameAtIndex(idx);
+
+ // None/null means no more frames or error.
+ if (!obj_sp || !obj_sp->IsValid())
+ return llvm::createStringError("invalid script object returned for frame " +
+ llvm::Twine(idx));
+
+ StackFrameSP synth_frame_sp = nullptr;
+ if (StructuredData::UnsignedInteger *int_obj =
+ obj_sp->GetAsUnsignedInteger()) {
+ uint32_t real_frame_index = int_obj->GetValue();
+ if (real_frame_index < m_input_frames->GetNumFrames()) {
+ StackFrameSP real_frame_sp =
+ m_input_frames->GetFrameAtIndex(real_frame_index);
+ synth_frame_sp =
+ (real_frame_index == idx)
+ ? real_frame_sp
+ : std::make_shared<BorrowedStackFrame>(real_frame_sp, idx);
+ }
+ } else if (StructuredData::Dictionary *dict = obj_sp->GetAsDictionary()) {
+ // Check if it's a dictionary describing a frame.
+ auto frame_from_dict_or_err = create_frame_from_dict(dict, idx);
+ if (!frame_from_dict_or_err) {
+ return llvm::createStringError(llvm::Twine(
+ "couldn't create frame from dictionary at index " + llvm::Twine(idx) +
+ ": " + toString(frame_from_dict_or_err.takeError())));
+ }
+ synth_frame_sp = *frame_from_dict_or_err;
+ } else if (obj_sp->GetAsGeneric()) {
+ // It's a ScriptedFrame object.
+ auto frame_from_script_obj_or_err = create_frame_from_script_object(obj_sp);
+ if (!frame_from_script_obj_or_err) {
+ return llvm::createStringError(
+ llvm::Twine("couldn't create frame from script object at index " +
+ llvm::Twine(idx) + ": " +
+ toString(frame_from_script_obj_or_err.takeError())));
+ }
+ synth_frame_sp = *frame_from_script_obj_or_err;
+ } else {
+ return llvm::createStringError(
+ llvm::Twine("invalid return type from get_frame_at_index at index " +
+ llvm::Twine(idx)));
+ }
+
+ if (!synth_frame_sp)
+ return llvm::createStringError(
+ llvm::Twine("failed to create frame at index " + llvm::Twine(idx)));
+
+ synth_frame_sp->SetFrameIndex(idx);
+
+ return synth_frame_sp;
+}
+
+namespace lldb_private {
+void lldb_initialize_ScriptedFrameProvider() {
+ ScriptedFrameProvider::Initialize();
+}
+
+void lldb_terminate_ScriptedFrameProvider() {
+ ScriptedFrameProvider::Terminate();
+}
+} // namespace lldb_private
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.h b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.h
new file mode 100644
index 0000000..3434bf2
--- /dev/null
+++ b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.h
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYNTHETICFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_H
+#define LLDB_PLUGINS_SYNTHETICFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_H
+
+#include "lldb/Target/SyntheticFrameProvider.h"
+#include "lldb/Utility/ScriptedMetadata.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/Support/Error.h"
+
+namespace lldb_private {
+
+class ScriptedFrameProvider : public SyntheticFrameProvider {
+public:
+ static llvm::StringRef GetPluginNameStatic() {
+ return "ScriptedFrameProvider";
+ }
+
+ static llvm::Expected<lldb::SyntheticFrameProviderSP>
+ CreateInstance(lldb::StackFrameListSP input_frames,
+ const ScriptedFrameProviderDescriptor &descriptor);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ ScriptedFrameProvider(lldb::StackFrameListSP input_frames,
+ lldb::ScriptedFrameProviderInterfaceSP interface_sp,
+ const ScriptedFrameProviderDescriptor &descriptor);
+ ~ScriptedFrameProvider() override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ std::string GetDescription() const override;
+
+ /// Get a single stack frame at the specified index.
+ llvm::Expected<lldb::StackFrameSP> GetFrameAtIndex(uint32_t idx) override;
+
+private:
+ lldb::ScriptedFrameProviderInterfaceSP m_interface_sp;
+ const ScriptedFrameProviderDescriptor &m_descriptor;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_PLUGINS_SYNTHETICFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_SCRIPTEDFRAMEPROVIDER_H
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 51cb883..625d0e5 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2149,7 +2149,8 @@ PrintingPolicy TypeSystemClang::GetTypePrintingPolicy() {
printing_policy.SuppressTagKeyword = true;
// Inline namespaces are important for some type formatters (e.g., libc++
// and libstdc++ are differentiated by their inline namespaces).
- printing_policy.SuppressInlineNamespace = false;
+ printing_policy.SuppressInlineNamespace =
+ llvm::to_underlying(PrintingPolicy::SuppressInlineNamespaceMode::None);
printing_policy.SuppressUnwrittenScope = false;
// Default arguments are also always important for type formatters. Otherwise
// we would need to always specify two type names for the setups where we do
@@ -3870,7 +3871,8 @@ TypeSystemClang::GetDisplayTypeName(lldb::opaque_compiler_type_t type) {
printing_policy.SuppressTagKeyword = true;
printing_policy.SuppressScope = false;
printing_policy.SuppressUnwrittenScope = true;
- printing_policy.SuppressInlineNamespace = true;
+ printing_policy.SuppressInlineNamespace =
+ llvm::to_underlying(PrintingPolicy::SuppressInlineNamespaceMode::All);
return ConstString(qual_type.getAsString(printing_policy));
}
@@ -7346,6 +7348,102 @@ CompilerType TypeSystemClang::GetTypeForFormatters(void *type) {
return CompilerType();
}
+bool TypeSystemClang::IsPromotableIntegerType(
+ lldb::opaque_compiler_type_t type) {
+ // Unscoped enums are always considered as promotable, even if their
+ // underlying type does not need to be promoted (e.g. "int").
+ bool is_signed = false;
+ bool isUnscopedEnumerationType =
+ IsEnumerationType(type, is_signed) && !IsScopedEnumerationType(type);
+ if (isUnscopedEnumerationType)
+ return true;
+
+ switch (GetBasicTypeEnumeration(type)) {
+ case lldb::eBasicTypeBool:
+ case lldb::eBasicTypeChar:
+ case lldb::eBasicTypeSignedChar:
+ case lldb::eBasicTypeUnsignedChar:
+ case lldb::eBasicTypeShort:
+ case lldb::eBasicTypeUnsignedShort:
+ case lldb::eBasicTypeWChar:
+ case lldb::eBasicTypeSignedWChar:
+ case lldb::eBasicTypeUnsignedWChar:
+ case lldb::eBasicTypeChar16:
+ case lldb::eBasicTypeChar32:
+ return true;
+
+ default:
+ return false;
+ }
+
+ llvm_unreachable("All cases handled above.");
+}
+
+llvm::Expected<CompilerType>
+TypeSystemClang::DoIntegralPromotion(CompilerType from,
+ ExecutionContextScope *exe_scope) {
+ if (!from.IsInteger() && !from.IsUnscopedEnumerationType())
+ return from;
+
+ if (!from.IsPromotableIntegerType())
+ return from;
+
+ if (from.IsUnscopedEnumerationType()) {
+ EnumDecl *enum_decl = GetAsEnumDecl(from);
+ CompilerType promotion_type = GetType(enum_decl->getPromotionType());
+ return DoIntegralPromotion(promotion_type, exe_scope);
+ }
+
+ lldb::BasicType builtin_type =
+ from.GetCanonicalType().GetBasicTypeEnumeration();
+ uint64_t from_size = 0;
+ if (builtin_type == lldb::eBasicTypeWChar ||
+ builtin_type == lldb::eBasicTypeSignedWChar ||
+ builtin_type == lldb::eBasicTypeUnsignedWChar ||
+ builtin_type == lldb::eBasicTypeChar16 ||
+ builtin_type == lldb::eBasicTypeChar32) {
+ // Find the type that can hold the entire range of values for our type.
+ bool is_signed = from.IsSigned();
+ llvm::Expected<uint64_t> from_size = from.GetByteSize(exe_scope);
+ if (!from_size)
+ return from_size.takeError();
+ CompilerType promote_types[] = {
+ GetBasicTypeFromAST(lldb::eBasicTypeInt),
+ GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt),
+ GetBasicTypeFromAST(lldb::eBasicTypeLong),
+ GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLong),
+ GetBasicTypeFromAST(lldb::eBasicTypeLongLong),
+ GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLongLong),
+ };
+ for (CompilerType &type : promote_types) {
+ llvm::Expected<uint64_t> byte_size = type.GetByteSize(exe_scope);
+ if (!byte_size)
+ return byte_size.takeError();
+ if (*from_size < *byte_size ||
+ (*from_size == *byte_size && is_signed == type.IsSigned())) {
+ return type;
+ }
+ }
+ llvm_unreachable("char type should fit into long long");
+ }
+
+ // Here we can promote only to "int" or "unsigned int".
+ CompilerType int_type = GetBasicTypeFromAST(lldb::eBasicTypeInt);
+ llvm::Expected<uint64_t> int_byte_size = int_type.GetByteSize(exe_scope);
+ if (!int_byte_size)
+ return int_byte_size.takeError();
+
+ // Signed integer types can be safely promoted to "int".
+ if (from.IsSigned()) {
+ return int_type;
+ }
+ // Unsigned integer types are promoted to "unsigned int" if "int" cannot hold
+ // their entire value range.
+ return (from_size == *int_byte_size)
+ ? GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt)
+ : int_type;
+}
+
clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) {
const clang::EnumType *enutype =
llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type));
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 375891b..67d206e 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -938,6 +938,14 @@ public:
CompilerType GetTypeForFormatters(void *type) override;
+ // DIL
+
+ bool IsPromotableIntegerType(lldb::opaque_compiler_type_t type) override;
+
+ llvm::Expected<CompilerType>
+ DoIntegralPromotion(CompilerType from,
+ ExecutionContextScope *exe_scope) override;
+
#define LLDB_INVALID_DECL_LEVEL UINT32_MAX
// LLDB_INVALID_DECL_LEVEL is returned by CountDeclLevels if child_decl_ctx
// could not be found in decl_ctx.
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index 397c693..19ae1cf 100644
--- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -25,6 +25,8 @@
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
+#include "llvm/ADT/SmallSet.h"
+#include <deque>
using namespace lldb;
using namespace lldb_private;
@@ -50,6 +52,33 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
range, function_text.data(), function_text.size(), unwind_plan);
}
+static void DumpUnwindRowsToLog(Log *log, AddressRange range,
+ const UnwindPlan &unwind_plan) {
+ if (!log || !log->GetVerbose())
+ return;
+ StreamString strm;
+ lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
+ strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
+ base_addr, base_addr + range.GetByteSize());
+ unwind_plan.Dump(strm, nullptr, base_addr);
+ log->PutString(strm.GetString());
+}
+
+static void DumpInstToLog(Log *log, Instruction &inst,
+ const InstructionList &inst_list) {
+ if (!log || !log->GetVerbose())
+ return;
+ const bool show_address = true;
+ const bool show_bytes = true;
+ const bool show_control_flow_kind = false;
+ StreamString strm;
+ lldb_private::FormatEntity::Entry format;
+ FormatEntity::Parse("${frame.pc}: ", format);
+ inst.Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address, show_bytes,
+ show_control_flow_kind, nullptr, nullptr, nullptr, &format, 0);
+ log->PutString(strm.GetString());
+}
+
bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
AddressRange &range, uint8_t *opcode_data, size_t opcode_size,
UnwindPlan &unwind_plan) {
@@ -82,11 +111,6 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
m_range_ptr = &range;
m_unwind_plan_ptr = &unwind_plan;
- const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
- const bool show_address = true;
- const bool show_bytes = true;
- const bool show_control_flow_kind = false;
-
m_state.cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(
unwind_plan.GetRegisterKind(), unwind_plan.GetInitialCFARegister());
m_state.fp_is_cfa = false;
@@ -94,134 +118,142 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
m_pushed_regs.clear();
- // Initialize the CFA with a known value. In the 32 bit case it will be
- // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the address
- // byte size to be safe for any future address sizes
- m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
RegisterValue cfa_reg_value;
- cfa_reg_value.SetUInt(m_initial_sp, m_state.cfa_reg_info.byte_size);
+ cfa_reg_value.SetUInt(m_initial_cfa, m_state.cfa_reg_info.byte_size);
SetRegisterValue(m_state.cfa_reg_info, cfa_reg_value);
- const InstructionList &inst_list = disasm_sp->GetInstructionList();
- const size_t num_instructions = inst_list.GetSize();
-
- if (num_instructions > 0) {
- Instruction *inst = inst_list.GetInstructionAtIndex(0).get();
- const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
-
- // Map for storing the unwind state at a given offset. When we see a forward
- // branch we add a new entry to this map with the actual unwind plan row and
- // register context for the target address of the branch as the current data
- // have to be valid for the target address of the branch too if we are in
- // the same function.
- std::map<lldb::addr_t, UnwindState> saved_unwind_states;
-
- // Make a copy of the current instruction Row and save it in m_state so
- // we can add updates as we process the instructions.
- m_state.row = *unwind_plan.GetLastRow();
-
- // Add the initial state to the save list with offset 0.
- auto condition_block_start_state =
- saved_unwind_states.emplace(0, m_state).first;
-
- // The architecture dependent condition code of the last processed
- // instruction.
- EmulateInstruction::InstructionCondition last_condition =
- EmulateInstruction::UnconditionalCondition;
-
- for (size_t idx = 0; idx < num_instructions; ++idx) {
- m_curr_row_modified = false;
- m_forward_branch_offset = 0;
-
- inst = inst_list.GetInstructionAtIndex(idx).get();
- if (!inst)
- continue;
-
- lldb::addr_t current_offset =
- inst->GetAddress().GetFileAddress() - base_addr;
- auto it = saved_unwind_states.upper_bound(current_offset);
- assert(it != saved_unwind_states.begin() &&
- "Unwind row for the function entry missing");
- --it; // Move it to the row corresponding to the current offset
-
- // If the offset of m_curr_row don't match with the offset we see in
- // saved_unwind_states then we have to update current unwind state to
- // the saved values. It is happening after we processed an epilogue and a
- // return to caller instruction.
- if (it->second.row.GetOffset() != m_state.row.GetOffset())
- m_state = it->second;
-
- m_inst_emulator_up->SetInstruction(inst->GetOpcode(), inst->GetAddress(),
- nullptr);
-
- if (last_condition != m_inst_emulator_up->GetInstructionCondition()) {
- // If the last instruction was conditional with a different condition
- // than the current condition then restore the state.
- if (last_condition != EmulateInstruction::UnconditionalCondition) {
- m_state = condition_block_start_state->second;
- m_state.row.SetOffset(current_offset);
- // The last instruction might already created a row for this offset
- // and we want to overwrite it.
- saved_unwind_states.insert_or_assign(current_offset, m_state);
- }
+ InstructionList inst_list = disasm_sp->GetInstructionList();
- // We are starting a new conditional block at the actual offset
- condition_block_start_state = it;
- }
+ if (inst_list.GetSize() == 0) {
+ DumpUnwindRowsToLog(log, range, unwind_plan);
+ return unwind_plan.GetRowCount() > 0;
+ }
- if (log && log->GetVerbose()) {
- StreamString strm;
- lldb_private::FormatEntity::Entry format;
- FormatEntity::Parse("${frame.pc}: ", format);
- inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
- show_bytes, show_control_flow_kind, nullptr, nullptr,
- nullptr, &format, 0);
- log->PutString(strm.GetString());
- }
+ Instruction &first_inst = *inst_list.GetInstructionAtIndex(0);
+ const lldb::addr_t base_addr = first_inst.GetAddress().GetFileAddress();
+
+ // Map for storing the unwind state at a given offset. When we see a forward
+ // branch we add a new entry to this map with the actual unwind plan row and
+ // register context for the target address of the branch as the current data
+ // have to be valid for the target address of the branch too if we are in
+ // the same function.
+ std::map<lldb::addr_t, UnwindState> saved_unwind_states;
- last_condition = m_inst_emulator_up->GetInstructionCondition();
+ // Make a copy of the current instruction Row and save it in m_state so
+ // we can add updates as we process the instructions.
+ m_state.row = *unwind_plan.GetLastRow();
- m_inst_emulator_up->EvaluateInstruction(
- eEmulateInstructionOptionIgnoreConditions);
+ // Add the initial state to the save list with offset 0.
+ auto condition_block_start_state =
+ saved_unwind_states.emplace(0, m_state).first;
- // If the current instruction is a branch forward then save the current
- // CFI information for the offset where we are branching.
- if (m_forward_branch_offset != 0 &&
- range.ContainsFileAddress(inst->GetAddress().GetFileAddress() +
- m_forward_branch_offset)) {
- if (auto [it, inserted] = saved_unwind_states.emplace(
- current_offset + m_forward_branch_offset, m_state);
- inserted)
- it->second.row.SetOffset(current_offset + m_forward_branch_offset);
+ // The architecture dependent condition code of the last processed
+ // instruction.
+ EmulateInstruction::InstructionCondition last_condition =
+ EmulateInstruction::UnconditionalCondition;
+
+ std::deque<std::size_t> to_visit = {0};
+ llvm::SmallSet<std::size_t, 0> enqueued = {0};
+
+ // Instructions reachable through jumps are inserted on the front.
+ // The next instruction is inserted on the back.
+ // Pop from the back to ensure non-branching instructions are visited
+ // sequentially.
+ while (!to_visit.empty()) {
+ const std::size_t current_index = to_visit.back();
+ Instruction &inst = *inst_list.GetInstructionAtIndex(current_index);
+ to_visit.pop_back();
+ DumpInstToLog(log, inst, inst_list);
+
+ m_curr_row_modified = false;
+ m_branch_offset = 0;
+
+ lldb::addr_t current_offset =
+ inst.GetAddress().GetFileAddress() - base_addr;
+ auto it = saved_unwind_states.upper_bound(current_offset);
+ assert(it != saved_unwind_states.begin() &&
+ "Unwind row for the function entry missing");
+ --it; // Move it to the row corresponding to the current offset
+
+ // When state is forwarded through a branch, the offset of m_state.row is
+ // different from the offset available in saved_unwind_states. Use the
+ // forwarded state in this case, as the previous instruction may have been
+ // an unconditional jump.
+ // FIXME: this assignment can always be done unconditionally.
+ if (it->second.row.GetOffset() != m_state.row.GetOffset())
+ m_state = it->second;
+
+ m_inst_emulator_up->SetInstruction(inst.GetOpcode(), inst.GetAddress(),
+ nullptr);
+ const EmulateInstruction::InstructionCondition new_condition =
+ m_inst_emulator_up->GetInstructionCondition();
+
+ if (last_condition != new_condition) {
+ // If the last instruction was conditional with a different condition
+ // than the current condition then restore the state.
+ if (last_condition != EmulateInstruction::UnconditionalCondition) {
+ m_state = condition_block_start_state->second;
+ m_state.row.SetOffset(current_offset);
+ // The last instruction might already created a row for this offset
+ // and we want to overwrite it.
+ saved_unwind_states.insert_or_assign(current_offset, m_state);
}
- // Were there any changes to the CFI while evaluating this instruction?
- if (m_curr_row_modified) {
- // Save the modified row if we don't already have a CFI row in the
- // current address
- if (saved_unwind_states.count(current_offset +
- inst->GetOpcode().GetByteSize()) == 0) {
- m_state.row.SetOffset(current_offset +
- inst->GetOpcode().GetByteSize());
- saved_unwind_states.emplace(
- current_offset + inst->GetOpcode().GetByteSize(), m_state);
+ // We are starting a new conditional block at the actual offset
+ condition_block_start_state = it;
+ }
+
+ last_condition = new_condition;
+
+ m_inst_emulator_up->EvaluateInstruction(
+ eEmulateInstructionOptionIgnoreConditions);
+
+ // If the current instruction is a branch forward then save the current
+ // CFI information for the offset where we are branching.
+ Address branch_address = inst.GetAddress();
+ branch_address.Slide(m_branch_offset);
+ if (m_branch_offset != 0 &&
+ range.ContainsFileAddress(branch_address.GetFileAddress())) {
+ if (auto [it, inserted] = saved_unwind_states.emplace(
+ current_offset + m_branch_offset, m_state);
+ inserted) {
+ it->second.row.SetOffset(current_offset + m_branch_offset);
+ if (std::size_t dest_instr_index =
+ inst_list.GetIndexOfInstructionAtAddress(branch_address);
+ dest_instr_index < inst_list.GetSize()) {
+ to_visit.push_front(dest_instr_index);
+ enqueued.insert(dest_instr_index);
}
}
}
- for (auto &[_, state] : saved_unwind_states) {
- unwind_plan.InsertRow(std::move(state.row),
- /*replace_existing=*/true);
+
+ // If inst is a barrier, do not propagate state to the next instruction.
+ if (inst.IsBarrier())
+ continue;
+
+ // Were there any changes to the CFI while evaluating this instruction?
+ if (m_curr_row_modified) {
+ // Save the modified row if we don't already have a CFI row in the
+ // current address
+ const lldb::addr_t next_inst_offset =
+ current_offset + inst.GetOpcode().GetByteSize();
+ if (saved_unwind_states.count(next_inst_offset) == 0) {
+ m_state.row.SetOffset(next_inst_offset);
+ saved_unwind_states.emplace(next_inst_offset, m_state);
+ }
}
- }
- if (log && log->GetVerbose()) {
- StreamString strm;
- lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();
- strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",
- base_addr, base_addr + range.GetByteSize());
- unwind_plan.Dump(strm, nullptr, base_addr);
- log->PutString(strm.GetString());
+ const size_t next_idx = current_index + 1;
+ const bool never_enqueued = enqueued.insert(next_idx).second;
+ if (never_enqueued && next_idx < inst_list.GetSize())
+ to_visit.push_back(next_idx);
}
+
+ for (auto &[_, state] : saved_unwind_states)
+ unwind_plan.InsertRow(std::move(state.row),
+ /*replace_existing=*/true);
+
+ DumpUnwindRowsToLog(log, range, unwind_plan);
return unwind_plan.GetRowCount() > 0;
}
@@ -382,7 +414,7 @@ size_t UnwindAssemblyInstEmulation::WriteMemory(
if (reg_num != LLDB_INVALID_REGNUM &&
generic_regnum != LLDB_REGNUM_GENERIC_SP) {
if (m_pushed_regs.try_emplace(reg_num, addr).second) {
- const int32_t offset = addr - m_initial_sp;
+ const int32_t offset = addr - m_initial_cfa;
m_state.row.SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,
/*can_replace=*/true);
m_curr_row_modified = true;
@@ -502,21 +534,20 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
case EmulateInstruction::eContextAbsoluteBranchRegister:
case EmulateInstruction::eContextRelativeBranchImmediate: {
if (context.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate &&
- context.info.ISAAndImmediate.unsigned_data32 > 0) {
- m_forward_branch_offset =
- context.info.ISAAndImmediateSigned.signed_data32;
+ context.info.ISAAndImmediate.unsigned_data32 != 0) {
+ m_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
} else if (context.GetInfoType() ==
EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
- context.info.ISAAndImmediateSigned.signed_data32 > 0) {
- m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
+ context.info.ISAAndImmediateSigned.signed_data32 != 0) {
+ m_branch_offset = context.info.ISAAndImmediateSigned.signed_data32;
} else if (context.GetInfoType() ==
EmulateInstruction::eInfoTypeImmediate &&
- context.info.unsigned_immediate > 0) {
- m_forward_branch_offset = context.info.unsigned_immediate;
+ context.info.unsigned_immediate != 0) {
+ m_branch_offset = context.info.unsigned_immediate;
} else if (context.GetInfoType() ==
EmulateInstruction::eInfoTypeImmediateSigned &&
- context.info.signed_immediate > 0) {
- m_forward_branch_offset = context.info.signed_immediate;
+ context.info.signed_immediate != 0) {
+ m_branch_offset = context.info.signed_immediate;
}
} break;
@@ -549,7 +580,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
sp_reg_info.kinds[m_unwind_plan_ptr->GetRegisterKind()];
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
- cfa_reg_num, m_initial_sp - sp_reg_val.GetAsUInt64());
+ cfa_reg_num, m_initial_cfa - sp_reg_val.GetAsUInt64());
}
}
}
@@ -580,7 +611,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
- cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
+ cfa_reg_num, m_initial_cfa - reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
@@ -593,7 +624,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
- cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
+ cfa_reg_num, m_initial_cfa - reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
@@ -604,7 +635,7 @@ bool UnwindAssemblyInstEmulation::WriteRegister(
if (!m_state.fp_is_cfa) {
m_state.row.GetCFAValue().SetIsRegisterPlusOffset(
m_state.row.GetCFAValue().GetRegisterNumber(),
- m_initial_sp - reg_value.GetAsUInt64());
+ m_initial_cfa - reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
index 96a0881..43daf1c 100644
--- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
+++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -63,13 +63,17 @@ private:
UnwindAssemblyInstEmulation(const lldb_private::ArchSpec &arch,
lldb_private::EmulateInstruction *inst_emulator)
: UnwindAssembly(arch), m_inst_emulator_up(inst_emulator),
- m_range_ptr(nullptr), m_unwind_plan_ptr(nullptr), m_initial_sp(0),
- m_curr_row_modified(false), m_forward_branch_offset(0) {
+ m_range_ptr(nullptr), m_unwind_plan_ptr(nullptr),
+ m_curr_row_modified(false) {
if (m_inst_emulator_up) {
m_inst_emulator_up->SetBaton(this);
m_inst_emulator_up->SetCallbacks(ReadMemory, WriteMemory, ReadRegister,
WriteRegister);
}
+ // Initialize the CFA with a known value. In the 32 bit case it will be
+ // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the address
+ // byte size to be safe for any future address sizes
+ m_initial_cfa = (1ull << ((m_arch.GetAddressByteSize() * 8) - 1));
}
static size_t
@@ -134,8 +138,8 @@ private:
lldb_private::AddressRange *m_range_ptr;
lldb_private::UnwindPlan *m_unwind_plan_ptr;
UnwindState m_state;
+ uint64_t m_initial_cfa;
typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap;
- uint64_t m_initial_sp;
PushedRegisterToAddrMap m_pushed_regs;
// While processing the instruction stream, we need to communicate some state
@@ -148,7 +152,7 @@ private:
bool m_curr_row_modified;
// The instruction is branching forward with the given offset. 0 value means
// no branching.
- uint32_t m_forward_branch_offset;
+ int64_t m_branch_offset = 0;
};
#endif // LLDB_SOURCE_PLUGINS_UNWINDASSEMBLY_INSTEMULATION_UNWINDASSEMBLYINSTEMULATION_H
diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp
index 166f111..703ef13 100644
--- a/lldb/source/Symbol/CompileUnit.cpp
+++ b/lldb/source/Symbol/CompileUnit.cpp
@@ -27,14 +27,14 @@ CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
language, is_optimized) {}
CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
- lldb::SupportFileSP support_file_sp,
+ SupportFileNSP support_file_nsp,
const lldb::user_id_t cu_sym_id,
lldb::LanguageType language,
lldb_private::LazyBool is_optimized,
SupportFileList &&support_files)
: ModuleChild(module_sp), UserID(cu_sym_id), m_user_data(user_data),
m_language(language), m_flags(0),
- m_primary_support_file_sp(support_file_sp),
+ m_primary_support_file_nsp(support_file_nsp),
m_support_files(std::move(support_files)), m_is_optimized(is_optimized) {
if (language != eLanguageTypeUnknown)
m_flags.Set(flagsParsedLanguage);
diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp
index c999ab2..1a39ea9 100644
--- a/lldb/source/Symbol/CompilerType.cpp
+++ b/lldb/source/Symbol/CompilerType.cpp
@@ -370,30 +370,10 @@ bool CompilerType::IsScalarOrUnscopedEnumerationType() const {
}
bool CompilerType::IsPromotableIntegerType() const {
- // Unscoped enums are always considered as promotable, even if their
- // underlying type does not need to be promoted (e.g. "int").
- if (IsUnscopedEnumerationType())
- return true;
-
- switch (GetBasicTypeEnumeration()) {
- case lldb::eBasicTypeBool:
- case lldb::eBasicTypeChar:
- case lldb::eBasicTypeSignedChar:
- case lldb::eBasicTypeUnsignedChar:
- case lldb::eBasicTypeShort:
- case lldb::eBasicTypeUnsignedShort:
- case lldb::eBasicTypeWChar:
- case lldb::eBasicTypeSignedWChar:
- case lldb::eBasicTypeUnsignedWChar:
- case lldb::eBasicTypeChar16:
- case lldb::eBasicTypeChar32:
- return true;
-
- default:
- return false;
- }
-
- llvm_unreachable("All cases handled above.");
+ if (IsValid())
+ if (auto type_system_sp = GetTypeSystem())
+ return type_system_sp->IsPromotableIntegerType(m_type);
+ return false;
}
bool CompilerType::IsPointerToVoid() const {
diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp
index 2be1e389..11b823c 100644
--- a/lldb/source/Symbol/Function.cpp
+++ b/lldb/source/Symbol/Function.cpp
@@ -272,7 +272,7 @@ Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid,
Function::~Function() = default;
-void Function::GetStartLineSourceInfo(SupportFileSP &source_file_sp,
+void Function::GetStartLineSourceInfo(SupportFileNSP &source_file_sp,
uint32_t &line_no) {
line_no = 0;
source_file_sp = std::make_shared<SupportFile>();
@@ -300,9 +300,9 @@ void Function::GetStartLineSourceInfo(SupportFileSP &source_file_sp,
}
}
-llvm::Expected<std::pair<SupportFileSP, Function::SourceRange>>
+llvm::Expected<std::pair<SupportFileNSP, Function::SourceRange>>
Function::GetSourceInfo() {
- SupportFileSP source_file_sp;
+ SupportFileNSP source_file_sp = std::make_shared<SupportFile>();
uint32_t start_line;
GetStartLineSourceInfo(source_file_sp, start_line);
LineTable *line_table = m_comp_unit->GetLineTable();
diff --git a/lldb/source/Symbol/LineEntry.cpp b/lldb/source/Symbol/LineEntry.cpp
index c941a69..dcfbac8 100644
--- a/lldb/source/Symbol/LineEntry.cpp
+++ b/lldb/source/Symbol/LineEntry.cpp
@@ -14,7 +14,7 @@
using namespace lldb_private;
LineEntry::LineEntry()
- : range(), file_sp(std::make_shared<SupportFile>()),
+ : range(), synthetic(false), file_sp(std::make_shared<SupportFile>()),
original_file_sp(std::make_shared<SupportFile>()),
is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0),
is_epilogue_begin(0), is_terminal_entry(0) {}
@@ -33,7 +33,8 @@ void LineEntry::Clear() {
}
bool LineEntry::IsValid() const {
- return range.GetBaseAddress().IsValid() && line != LLDB_INVALID_LINE_NUMBER;
+ return (range.GetBaseAddress().IsValid() || synthetic) &&
+ line != LLDB_INVALID_LINE_NUMBER;
}
bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const {
diff --git a/lldb/source/Symbol/LineTable.cpp b/lldb/source/Symbol/LineTable.cpp
index ca3accd..ae2abf5 100644
--- a/lldb/source/Symbol/LineTable.cpp
+++ b/lldb/source/Symbol/LineTable.cpp
@@ -327,7 +327,7 @@ void LineTable::Dump(Stream *s, Target *target, Address::DumpStyle style,
Address::DumpStyle fallback_style, bool show_line_ranges) {
const size_t count = m_entries.size();
LineEntry line_entry;
- SupportFileSP prev_file;
+ SupportFileNSP prev_file = std::make_shared<SupportFile>();
for (size_t idx = 0; idx < count; ++idx) {
ConvertEntryAtIndexToLineEntry(idx, line_entry);
line_entry.Dump(s, target, !prev_file->Equal(*line_entry.original_file_sp),
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
index 6f5348c..ab28c17 100644
--- a/lldb/source/Symbol/ObjectFile.cpp
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -254,13 +254,14 @@ ObjectFile::ObjectFile(const lldb::ModuleSP &module_sp,
: ModuleChild(module_sp),
m_file(), // This file could be different from the original module's file
m_type(eTypeInvalid), m_strata(eStrataInvalid),
- m_file_offset(file_offset), m_length(length), m_data(), m_process_wp(),
+ m_file_offset(file_offset), m_length(length),
+ m_data_nsp(std::make_shared<DataExtractor>()), m_process_wp(),
m_memory_addr(LLDB_INVALID_ADDRESS), m_sections_up(), m_symtab_up(),
m_symtab_once_up(new llvm::once_flag()) {
if (file_spec_ptr)
m_file = *file_spec_ptr;
if (data_sp)
- m_data.SetData(data_sp, data_offset, length);
+ m_data_nsp->SetData(data_sp, data_offset, length);
Log *log = GetLog(LLDBLog::Object);
LLDB_LOGF(log,
"%p ObjectFile::ObjectFile() module = %p (%s), file = %s, "
@@ -275,11 +276,12 @@ ObjectFile::ObjectFile(const lldb::ModuleSP &module_sp,
const ProcessSP &process_sp, lldb::addr_t header_addr,
DataBufferSP header_data_sp)
: ModuleChild(module_sp), m_file(), m_type(eTypeInvalid),
- m_strata(eStrataInvalid), m_file_offset(0), m_length(0), m_data(),
- m_process_wp(process_sp), m_memory_addr(header_addr), m_sections_up(),
- m_symtab_up(), m_symtab_once_up(new llvm::once_flag()) {
+ m_strata(eStrataInvalid), m_file_offset(0), m_length(0),
+ m_data_nsp(std::make_shared<DataExtractor>()), m_process_wp(process_sp),
+ m_memory_addr(header_addr), m_sections_up(), m_symtab_up(),
+ m_symtab_once_up(new llvm::once_flag()) {
if (header_data_sp)
- m_data.SetData(header_data_sp, 0, header_data_sp->GetByteSize());
+ m_data_nsp->SetData(header_data_sp, 0, header_data_sp->GetByteSize());
Log *log = GetLog(LLDBLog::Object);
LLDB_LOGF(log,
"%p ObjectFile::ObjectFile() module = %p (%s), process = %p, "
@@ -474,16 +476,16 @@ WritableDataBufferSP ObjectFile::ReadMemory(const ProcessSP &process_sp,
size_t ObjectFile::GetData(lldb::offset_t offset, size_t length,
DataExtractor &data) const {
- // The entire file has already been mmap'ed into m_data, so just copy from
+ // The entire file has already been mmap'ed into m_data_nsp, so just copy from
// there as the back mmap buffer will be shared with shared pointers.
- return data.SetData(m_data, offset, length);
+ return data.SetData(*m_data_nsp.get(), offset, length);
}
size_t ObjectFile::CopyData(lldb::offset_t offset, size_t length,
void *dst) const {
- // The entire file has already been mmap'ed into m_data, so just copy from
+ // The entire file has already been mmap'ed into m_data_nsp, so just copy from
// there Note that the data remains in target byte order.
- return m_data.CopyData(offset, length, dst);
+ return m_data_nsp->CopyData(offset, length, dst);
}
size_t ObjectFile::ReadSectionData(Section *section,
diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp
index 3bbd1ef..ead924a 100644
--- a/lldb/source/Symbol/SymbolContext.cpp
+++ b/lldb/source/Symbol/SymbolContext.cpp
@@ -324,12 +324,32 @@ uint32_t SymbolContext::GetResolvedMask() const {
bool lldb_private::operator==(const SymbolContext &lhs,
const SymbolContext &rhs) {
- return lhs.function == rhs.function && lhs.symbol == rhs.symbol &&
+ return SymbolContext::CompareWithoutSymbol(lhs, rhs) &&
+ lhs.symbol == rhs.symbol;
+}
+
+bool SymbolContext::CompareConsideringPossiblyNullSymbol(
+ const SymbolContext &lhs, const SymbolContext &rhs) {
+ if (!CompareWithoutSymbol(lhs, rhs))
+ return false;
+
+ // If one (or both) of the symbol context's symbol is empty, consider them
+ // equal.
+ if (!lhs.symbol || !rhs.symbol)
+ return true;
+
+ // If both symbols are present, make sure they're the same.
+ return lhs.symbol == rhs.symbol;
+}
+
+bool SymbolContext::CompareWithoutSymbol(const SymbolContext &lhs,
+ const SymbolContext &rhs) {
+ return lhs.function == rhs.function &&
lhs.module_sp.get() == rhs.module_sp.get() &&
lhs.comp_unit == rhs.comp_unit &&
lhs.target_sp.get() == rhs.target_sp.get() &&
LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0 &&
- lhs.variable == rhs.variable;
+ lhs.variable == rhs.variable && lhs.block == rhs.block;
}
bool lldb_private::operator!=(const SymbolContext &lhs,
@@ -1200,7 +1220,10 @@ bool SymbolContextList::AppendIfUnique(const SymbolContext &sc,
bool merge_symbol_into_function) {
collection::iterator pos, end = m_symbol_contexts.end();
for (pos = m_symbol_contexts.begin(); pos != end; ++pos) {
- if (*pos == sc)
+ // Because symbol contexts might first be built without the symbol,
+ // which is then appended later on, compare the symbol contexts taking into
+ // accout that one (or either) of them might not have a symbol yet.
+ if (SymbolContext::CompareConsideringPossiblyNullSymbol(*pos, sc))
return false;
}
if (merge_symbol_into_function && sc.symbol != nullptr &&
diff --git a/lldb/source/Symbol/SymbolFile.cpp b/lldb/source/Symbol/SymbolFile.cpp
index 870d778d..bfc6300 100644
--- a/lldb/source/Symbol/SymbolFile.cpp
+++ b/lldb/source/Symbol/SymbolFile.cpp
@@ -126,6 +126,14 @@ void SymbolFile::FindFunctions(const Module::LookupInfo &lookup_info,
bool include_inlines,
SymbolContextList &sc_list) {}
+void SymbolFile::FindFunctions(llvm::ArrayRef<Module::LookupInfo> lookup_infos,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines,
+ SymbolContextList &sc_list) {
+ for (const auto &lookup_info : lookup_infos)
+ FindFunctions(lookup_info, parent_decl_ctx, include_inlines, sc_list);
+}
+
void SymbolFile::FindFunctions(const RegularExpression &regex,
bool include_inlines,
SymbolContextList &sc_list) {}
diff --git a/lldb/source/Symbol/Symtab.cpp b/lldb/source/Symbol/Symtab.cpp
index 6080703..9964ae4 100644
--- a/lldb/source/Symbol/Symtab.cpp
+++ b/lldb/source/Symbol/Symtab.cpp
@@ -722,15 +722,11 @@ Symtab::AppendSymbolIndexesWithNameAndType(ConstString symbol_name,
std::vector<uint32_t> &indexes) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (AppendSymbolIndexesWithName(symbol_name, indexes) > 0) {
- std::vector<uint32_t>::iterator pos = indexes.begin();
- while (pos != indexes.end()) {
- if (symbol_type == eSymbolTypeAny ||
- m_symbols[*pos].GetType() == symbol_type)
- ++pos;
- else
- pos = indexes.erase(pos);
- }
+ if (AppendSymbolIndexesWithName(symbol_name, indexes) > 0 &&
+ symbol_type != eSymbolTypeAny) {
+ llvm::erase_if(indexes, [this, symbol_type](uint32_t index) {
+ return m_symbols[index].GetType() != symbol_type;
+ });
}
return indexes.size();
}
@@ -742,15 +738,11 @@ uint32_t Symtab::AppendSymbolIndexesWithNameAndType(
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (AppendSymbolIndexesWithName(symbol_name, symbol_debug_type,
- symbol_visibility, indexes) > 0) {
- std::vector<uint32_t>::iterator pos = indexes.begin();
- while (pos != indexes.end()) {
- if (symbol_type == eSymbolTypeAny ||
- m_symbols[*pos].GetType() == symbol_type)
- ++pos;
- else
- pos = indexes.erase(pos);
- }
+ symbol_visibility, indexes) > 0 &&
+ symbol_type != eSymbolTypeAny) {
+ llvm::erase_if(indexes, [this, symbol_type](uint32_t index) {
+ return m_symbols[index].GetType() != symbol_type;
+ });
}
return indexes.size();
}
diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp
index f7d634f..8712142 100644
--- a/lldb/source/Symbol/TypeSystem.cpp
+++ b/lldb/source/Symbol/TypeSystem.cpp
@@ -123,6 +123,17 @@ CompilerType TypeSystem::GetTypeForFormatters(void *type) {
return CompilerType(weak_from_this(), type);
}
+bool TypeSystem::IsPromotableIntegerType(lldb::opaque_compiler_type_t type) {
+ return false;
+}
+
+llvm::Expected<CompilerType>
+TypeSystem::DoIntegralPromotion(CompilerType from,
+ ExecutionContextScope *exe_scope) {
+ return llvm::createStringError(
+ "Integral promotion is not implemented for this TypeSystem");
+}
+
bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) {
return false;
}
diff --git a/lldb/source/Target/BorrowedStackFrame.cpp b/lldb/source/Target/BorrowedStackFrame.cpp
new file mode 100644
index 0000000..5afadf2
--- /dev/null
+++ b/lldb/source/Target/BorrowedStackFrame.cpp
@@ -0,0 +1,187 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "lldb/Target/BorrowedStackFrame.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+char BorrowedStackFrame::ID;
+
+BorrowedStackFrame::BorrowedStackFrame(
+ StackFrameSP borrowed_frame_sp, uint32_t new_frame_index,
+ std::optional<uint32_t> new_concrete_frame_index)
+ : StackFrame(
+ borrowed_frame_sp->GetThread(), new_frame_index,
+ borrowed_frame_sp->GetConcreteFrameIndex(),
+ borrowed_frame_sp->GetRegisterContextSP(),
+ borrowed_frame_sp->GetStackID().GetPC(),
+ borrowed_frame_sp->GetStackID().GetCallFrameAddressWithoutMetadata(),
+ borrowed_frame_sp->m_behaves_like_zeroth_frame,
+ &borrowed_frame_sp->GetSymbolContext(eSymbolContextEverything)),
+ m_borrowed_frame_sp(borrowed_frame_sp),
+ m_new_frame_index(new_frame_index) {
+ if (new_concrete_frame_index)
+ m_new_concrete_frame_index = *new_concrete_frame_index;
+ else
+ m_new_concrete_frame_index =
+ IsInlined() ? LLDB_INVALID_FRAME_ID : new_frame_index;
+}
+
+uint32_t BorrowedStackFrame::GetFrameIndex() const { return m_new_frame_index; }
+
+void BorrowedStackFrame::SetFrameIndex(uint32_t index) {
+ m_new_frame_index = index;
+}
+
+uint32_t BorrowedStackFrame::GetConcreteFrameIndex() {
+ // FIXME: We need to find where the concrete frame into which this frame was
+ // inlined landed in the new stack frame list as that is the correct concrete
+ // frame index in this
+ // stack frame.
+ return m_new_concrete_frame_index;
+}
+
+StackID &BorrowedStackFrame::GetStackID() {
+ return m_borrowed_frame_sp->GetStackID();
+}
+
+const Address &BorrowedStackFrame::GetFrameCodeAddress() {
+ return m_borrowed_frame_sp->GetFrameCodeAddress();
+}
+
+Address BorrowedStackFrame::GetFrameCodeAddressForSymbolication() {
+ return m_borrowed_frame_sp->GetFrameCodeAddressForSymbolication();
+}
+
+bool BorrowedStackFrame::ChangePC(addr_t pc) {
+ return m_borrowed_frame_sp->ChangePC(pc);
+}
+
+const SymbolContext &
+BorrowedStackFrame::GetSymbolContext(SymbolContextItem resolve_scope) {
+ return m_borrowed_frame_sp->GetSymbolContext(resolve_scope);
+}
+
+llvm::Error BorrowedStackFrame::GetFrameBaseValue(Scalar &value) {
+ return m_borrowed_frame_sp->GetFrameBaseValue(value);
+}
+
+DWARFExpressionList *
+BorrowedStackFrame::GetFrameBaseExpression(Status *error_ptr) {
+ return m_borrowed_frame_sp->GetFrameBaseExpression(error_ptr);
+}
+
+Block *BorrowedStackFrame::GetFrameBlock() {
+ return m_borrowed_frame_sp->GetFrameBlock();
+}
+
+RegisterContextSP BorrowedStackFrame::GetRegisterContext() {
+ return m_borrowed_frame_sp->GetRegisterContext();
+}
+
+VariableList *BorrowedStackFrame::GetVariableList(bool get_file_globals,
+ Status *error_ptr) {
+ return m_borrowed_frame_sp->GetVariableList(get_file_globals, error_ptr);
+}
+
+VariableListSP
+BorrowedStackFrame::GetInScopeVariableList(bool get_file_globals,
+ bool must_have_valid_location) {
+ return m_borrowed_frame_sp->GetInScopeVariableList(get_file_globals,
+ must_have_valid_location);
+}
+
+ValueObjectSP BorrowedStackFrame::GetValueForVariableExpressionPath(
+ llvm::StringRef var_expr, DynamicValueType use_dynamic, uint32_t options,
+ VariableSP &var_sp, Status &error) {
+ return m_borrowed_frame_sp->GetValueForVariableExpressionPath(
+ var_expr, use_dynamic, options, var_sp, error);
+}
+
+bool BorrowedStackFrame::HasDebugInformation() {
+ return m_borrowed_frame_sp->HasDebugInformation();
+}
+
+const char *BorrowedStackFrame::Disassemble() {
+ return m_borrowed_frame_sp->Disassemble();
+}
+
+ValueObjectSP BorrowedStackFrame::GetValueObjectForFrameVariable(
+ const VariableSP &variable_sp, DynamicValueType use_dynamic) {
+ return m_borrowed_frame_sp->GetValueObjectForFrameVariable(variable_sp,
+ use_dynamic);
+}
+
+bool BorrowedStackFrame::IsInlined() {
+ return m_borrowed_frame_sp->IsInlined();
+}
+
+bool BorrowedStackFrame::IsSynthetic() const {
+ return m_borrowed_frame_sp->IsSynthetic();
+}
+
+bool BorrowedStackFrame::IsHistorical() const {
+ return m_borrowed_frame_sp->IsHistorical();
+}
+
+bool BorrowedStackFrame::IsArtificial() const {
+ return m_borrowed_frame_sp->IsArtificial();
+}
+
+bool BorrowedStackFrame::IsHidden() { return m_borrowed_frame_sp->IsHidden(); }
+
+const char *BorrowedStackFrame::GetFunctionName() {
+ return m_borrowed_frame_sp->GetFunctionName();
+}
+
+const char *BorrowedStackFrame::GetDisplayFunctionName() {
+ return m_borrowed_frame_sp->GetDisplayFunctionName();
+}
+
+ValueObjectSP BorrowedStackFrame::FindVariable(ConstString name) {
+ return m_borrowed_frame_sp->FindVariable(name);
+}
+
+SourceLanguage BorrowedStackFrame::GetLanguage() {
+ return m_borrowed_frame_sp->GetLanguage();
+}
+
+SourceLanguage BorrowedStackFrame::GuessLanguage() {
+ return m_borrowed_frame_sp->GuessLanguage();
+}
+
+ValueObjectSP BorrowedStackFrame::GuessValueForAddress(addr_t addr) {
+ return m_borrowed_frame_sp->GuessValueForAddress(addr);
+}
+
+ValueObjectSP
+BorrowedStackFrame::GuessValueForRegisterAndOffset(ConstString reg,
+ int64_t offset) {
+ return m_borrowed_frame_sp->GuessValueForRegisterAndOffset(reg, offset);
+}
+
+StructuredData::ObjectSP BorrowedStackFrame::GetLanguageSpecificData() {
+ return m_borrowed_frame_sp->GetLanguageSpecificData();
+}
+
+RecognizedStackFrameSP BorrowedStackFrame::GetRecognizedFrame() {
+ return m_borrowed_frame_sp->GetRecognizedFrame();
+}
+
+StackFrameSP BorrowedStackFrame::GetBorrowedFrame() const {
+ return m_borrowed_frame_sp;
+}
+
+bool BorrowedStackFrame::isA(const void *ClassID) const {
+ return ClassID == &ID || StackFrame::isA(ClassID);
+}
+
+bool BorrowedStackFrame::classof(const StackFrame *obj) {
+ return obj->isA(&ID);
+}
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index b7788e8..df2ee03 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -38,8 +38,10 @@ add_lldb_library(lldbTarget
RegisterNumber.cpp
RemoteAwarePlatform.cpp
ScriptedThreadPlan.cpp
+ SyntheticFrameProvider.cpp
SectionLoadHistory.cpp
SectionLoadList.cpp
+ BorrowedStackFrame.cpp
StackFrame.cpp
StackFrameList.cpp
StackFrameRecognizer.cpp
@@ -80,7 +82,6 @@ add_lldb_library(lldbTarget
UnixSignals.cpp
UnwindAssembly.cpp
UnwindLLDB.cpp
- VerboseTrapFrameRecognizer.cpp
ADDITIONAL_HEADER_DIRS
${LLDB_INCLUDE_DIR}/lldb/Target
diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp
index a795913..b16ff26 100644
--- a/lldb/source/Target/ExecutionContext.cpp
+++ b/lldb/source/Target/ExecutionContext.cpp
@@ -466,10 +466,13 @@ operator=(const ExecutionContext &exe_ctx) {
else
m_tid = LLDB_INVALID_THREAD_ID;
lldb::StackFrameSP frame_sp(exe_ctx.GetFrameSP());
- if (frame_sp)
+ if (frame_sp) {
m_stack_id = frame_sp->GetStackID();
- else
+ m_frame_list_wp = frame_sp->GetContainingStackFrameList();
+ } else {
m_stack_id.Clear();
+ m_frame_list_wp.reset();
+ }
return *this;
}
@@ -511,6 +514,7 @@ void ExecutionContextRef::SetThreadSP(const lldb::ThreadSP &thread_sp) {
void ExecutionContextRef::SetFrameSP(const lldb::StackFrameSP &frame_sp) {
if (frame_sp) {
m_stack_id = frame_sp->GetStackID();
+ m_frame_list_wp = frame_sp->GetContainingStackFrameList();
SetThreadSP(frame_sp->GetThread());
} else {
ClearFrame();
@@ -638,6 +642,15 @@ lldb::ThreadSP ExecutionContextRef::GetThreadSP() const {
lldb::StackFrameSP ExecutionContextRef::GetFrameSP() const {
if (m_stack_id.IsValid()) {
+ // Try the remembered frame list first to avoid circular dependencies
+ // during frame provider initialization.
+ if (auto frame_list_sp = m_frame_list_wp.lock()) {
+ if (auto frame_sp = frame_list_sp->GetFrameWithStackID(m_stack_id))
+ return frame_sp;
+ }
+
+ // Fallback: ask the thread, which might re-trigger the frame provider
+ // initialization.
lldb::ThreadSP thread_sp(GetThreadSP());
if (thread_sp)
return thread_sp->GetFrameWithStackID(m_stack_id);
diff --git a/lldb/source/Target/InstrumentationRuntime.cpp b/lldb/source/Target/InstrumentationRuntime.cpp
index 7e58e8b..d9800a8 100644
--- a/lldb/source/Target/InstrumentationRuntime.cpp
+++ b/lldb/source/Target/InstrumentationRuntime.cpp
@@ -55,7 +55,8 @@ void InstrumentationRuntime::ModulesDidLoad(
return IterationAction::Continue;
const RegularExpression &runtime_regex = GetPatternForRuntimeLibrary();
- if (runtime_regex.Execute(file_spec.GetFilename().GetCString()) ||
+ if (MatchAllModules() ||
+ runtime_regex.Execute(file_spec.GetFilename().GetCString()) ||
module_sp->IsExecutable()) {
if (CheckIfRuntimeIsValid(module_sp)) {
SetRuntimeModuleSP(module_sp);
diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp
index 8268d4a..c8b09c3 100644
--- a/lldb/source/Target/Language.cpp
+++ b/lldb/source/Target/Language.cpp
@@ -159,6 +159,48 @@ void Language::ForEach(
}
}
+llvm::Expected<LanguageType>
+Language::GetExceptionLanguageForLanguage(llvm::StringRef lang_name) {
+ LanguageType language = Language::GetLanguageTypeFromString(lang_name);
+ LanguageType exception_language = eLanguageTypeUnknown;
+
+ llvm::StringRef error_context;
+ switch (language) {
+ case eLanguageTypeC89:
+ case eLanguageTypeC:
+ case eLanguageTypeC99:
+ case eLanguageTypeC11:
+ exception_language = eLanguageTypeC;
+ break;
+ case eLanguageTypeC_plus_plus:
+ case eLanguageTypeC_plus_plus_03:
+ case eLanguageTypeC_plus_plus_11:
+ case eLanguageTypeC_plus_plus_14:
+ exception_language = eLanguageTypeC_plus_plus;
+ break;
+ case eLanguageTypeObjC_plus_plus:
+ error_context =
+ "Set exception breakpoints separately for c++ and objective-c";
+ break;
+ case eLanguageTypeUnknown:
+ error_context = "Unknown language type for exception breakpoint";
+ break;
+ default:
+ if (Language *languagePlugin = Language::FindPlugin(language)) {
+ if (languagePlugin->SupportsExceptionBreakpointsOnThrow() ||
+ languagePlugin->SupportsExceptionBreakpointsOnCatch()) {
+ exception_language = language;
+ break;
+ }
+ }
+ error_context = "Unsupported language type for exception breakpoint";
+ }
+ if (!error_context.empty())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ error_context);
+ return exception_language;
+}
+
bool Language::IsTopLevelFunction(Function &function) { return false; }
lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; }
diff --git a/lldb/source/Target/ModuleCache.cpp b/lldb/source/Target/ModuleCache.cpp
index f737836..9978946 100644
--- a/lldb/source/Target/ModuleCache.cpp
+++ b/lldb/source/Target/ModuleCache.cpp
@@ -255,7 +255,7 @@ Status ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();
error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp,
- nullptr, nullptr, did_create_ptr, false);
+ nullptr, did_create_ptr, false);
if (error.Fail())
return error;
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 8681ada..5b0930c 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -163,11 +163,12 @@ Platform::LocateExecutableScriptingResources(Target *target, Module &module,
Status Platform::GetSharedModule(
const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr,
llvm::SmallVectorImpl<lldb::ModuleSP> *old_modules, bool *did_create_ptr) {
if (IsHost())
- return ModuleList::GetSharedModule(module_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ // Note: module_search_paths_ptr functionality is now handled internally
+ // by getting target from module_spec and calling
+ // target->GetExecutableSearchPaths()
+ return ModuleList::GetSharedModule(module_spec, module_sp, old_modules,
did_create_ptr, false);
// Module resolver lambda.
@@ -180,16 +181,14 @@ Status Platform::GetSharedModule(
resolved_spec = spec;
resolved_spec.GetFileSpec().PrependPathComponent(m_sdk_sysroot);
// Try to get shared module with resolved spec.
- error = ModuleList::GetSharedModule(resolved_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ error = ModuleList::GetSharedModule(resolved_spec, module_sp, old_modules,
did_create_ptr, false);
}
// If we don't have sysroot or it didn't work then
// try original module spec.
if (!error.Success()) {
resolved_spec = spec;
- error = ModuleList::GetSharedModule(resolved_spec, module_sp,
- module_search_paths_ptr, old_modules,
+ error = ModuleList::GetSharedModule(resolved_spec, module_sp, old_modules,
did_create_ptr, false);
}
if (error.Success() && module_sp)
@@ -731,10 +730,8 @@ bool Platform::SetOSVersion(llvm::VersionTuple version) {
return false;
}
-Status
-Platform::ResolveExecutable(const ModuleSpec &module_spec,
- lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) {
+Status Platform::ResolveExecutable(const ModuleSpec &module_spec,
+ lldb::ModuleSP &exe_module_sp) {
// We may connect to a process and use the provided executable (Don't use
// local $PATH).
@@ -750,9 +747,8 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec,
if (resolved_module_spec.GetArchitecture().IsValid() ||
resolved_module_spec.GetUUID().IsValid()) {
- Status error =
- ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, nullptr, nullptr);
+ Status error = ModuleList::GetSharedModule(resolved_module_spec,
+ exe_module_sp, nullptr, nullptr);
if (exe_module_sp && exe_module_sp->GetObjectFile())
return error;
@@ -767,9 +763,9 @@ Platform::ResolveExecutable(const ModuleSpec &module_spec,
Status error;
for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) {
resolved_module_spec.GetArchitecture() = arch;
- error =
- ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr, nullptr, nullptr);
+
+ error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
+ nullptr, nullptr);
if (error.Success()) {
if (exe_module_sp && exe_module_sp->GetObjectFile())
break;
@@ -1446,16 +1442,13 @@ const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() {
return m_trap_handlers;
}
-Status
-Platform::GetCachedExecutable(ModuleSpec &module_spec,
- lldb::ModuleSP &module_sp,
- const FileSpecList *module_search_paths_ptr) {
+Status Platform::GetCachedExecutable(ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp) {
FileSpec platform_spec = module_spec.GetFileSpec();
Status error = GetRemoteSharedModule(
module_spec, nullptr, module_sp,
[&](const ModuleSpec &spec) {
- return Platform::ResolveExecutable(spec, module_sp,
- module_search_paths_ptr);
+ return Platform::ResolveExecutable(spec, module_sp);
},
nullptr);
if (error.Success()) {
@@ -1497,7 +1490,7 @@ Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec,
for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) {
arch_module_spec.GetArchitecture() = arch;
error = ModuleList::GetSharedModule(arch_module_spec, module_sp, nullptr,
- nullptr, nullptr);
+ nullptr);
// Did we find an executable using one of the
if (error.Success() && module_sp)
break;
@@ -1673,11 +1666,12 @@ void Platform::CallLocateModuleCallbackIfSet(const ModuleSpec &module_spec,
cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5
// content hash instead of real UUID.
cached_module_spec.GetFileSpec() = module_file_spec;
+ cached_module_spec.GetSymbolFileSpec() = symbol_file_spec;
cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();
cached_module_spec.SetObjectOffset(0);
error = ModuleList::GetSharedModule(cached_module_spec, module_sp, nullptr,
- nullptr, did_create_ptr, false);
+ did_create_ptr, false, false);
if (error.Success() && module_sp) {
// Succeeded to load the module file.
LLDB_LOGF(log, "%s: locate module callback succeeded: module=%s symbol=%s",
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index fb9e7eb..9c8e8fa7 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -65,7 +65,6 @@
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Target/ThreadPlanStack.h"
#include "lldb/Target/UnixSignals.h"
-#include "lldb/Target/VerboseTrapFrameRecognizer.h"
#include "lldb/Utility/AddressableBits.h"
#include "lldb/Utility/Event.h"
#include "lldb/Utility/LLDBLog.h"
@@ -513,7 +512,6 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
// We should have a plugin do the registration instead, for example, a
// common C LanguageRuntime plugin.
RegisterAssertFrameRecognizer(this);
- RegisterVerboseTrapFrameRecognizer(*this);
}
Process::~Process() {
@@ -2454,8 +2452,10 @@ size_t Process::ReadScalarIntegerFromMemory(addr_t addr, uint32_t byte_size,
scalar = data.GetMaxU32(&offset, byte_size);
else
scalar = data.GetMaxU64(&offset, byte_size);
- if (is_signed)
+ if (is_signed) {
+ scalar.MakeSigned();
scalar.SignExtend(byte_size * 8);
+ }
return bytes_read;
}
} else {
@@ -3258,6 +3258,7 @@ Status Process::ConnectRemote(llvm::StringRef remote_url) {
if (state == eStateStopped || state == eStateCrashed) {
// If we attached and actually have a process on the other end, then
// this ended up being the equivalent of an attach.
+ SetShouldDetach(true);
CompleteAttach();
// This delays passing the stopped event to listeners till
@@ -6546,7 +6547,7 @@ Status Process::WriteMemoryTags(lldb::addr_t addr, size_t len,
// Create a CoreFileMemoryRange from a MemoryRegionInfo
static CoreFileMemoryRange
-CreateCoreFileMemoryRange(const MemoryRegionInfo &region) {
+CreateCoreFileMemoryRange(const lldb_private::MemoryRegionInfo &region) {
const addr_t addr = region.GetRange().GetRangeBase();
llvm::AddressRange range(addr, addr + region.GetRange().GetByteSize());
return {range, region.GetLLDBPermissions()};
@@ -6555,7 +6556,7 @@ CreateCoreFileMemoryRange(const MemoryRegionInfo &region) {
// Add dirty pages to the core file ranges and return true if dirty pages
// were added. Return false if the dirty page information is not valid or in
// the region.
-static bool AddDirtyPages(const MemoryRegionInfo &region,
+static bool AddDirtyPages(const lldb_private::MemoryRegionInfo &region,
CoreFileMemoryRanges &ranges) {
const auto &dirty_page_list = region.GetDirtyPageList();
if (!dirty_page_list)
@@ -6594,8 +6595,8 @@ static bool AddDirtyPages(const MemoryRegionInfo &region,
// given region. If the region has dirty page information, only dirty pages
// will be added to \a ranges, else the entire range will be added to \a
// ranges.
-static void AddRegion(const MemoryRegionInfo &region, bool try_dirty_pages,
- CoreFileMemoryRanges &ranges) {
+static void AddRegion(const lldb_private::MemoryRegionInfo &region,
+ bool try_dirty_pages, CoreFileMemoryRanges &ranges) {
// Don't add empty ranges.
if (region.GetRange().GetByteSize() == 0)
return;
@@ -6618,7 +6619,7 @@ static void SaveDynamicLoaderSections(Process &process,
if (!dyld)
return;
- std::vector<MemoryRegionInfo> dynamic_loader_mem_regions;
+ std::vector<lldb_private::MemoryRegionInfo> dynamic_loader_mem_regions;
std::function<bool(const lldb_private::Thread &)> save_thread_predicate =
[&](const lldb_private::Thread &t) -> bool {
return options.ShouldThreadBeSaved(t.GetID());
@@ -6743,10 +6744,11 @@ static void GetCoreFileSaveRangesStackOnly(Process &process,
// TODO: We should refactor CoreFileMemoryRanges to use the lldb range type, and
// then add an intersect method on it, or MemoryRegionInfo.
-static MemoryRegionInfo Intersect(const MemoryRegionInfo &lhs,
- const MemoryRegionInfo::RangeType &rhs) {
+static lldb_private::MemoryRegionInfo
+Intersect(const lldb_private::MemoryRegionInfo &lhs,
+ const lldb_private::MemoryRegionInfo::RangeType &rhs) {
- MemoryRegionInfo region_info;
+ lldb_private::MemoryRegionInfo region_info;
region_info.SetLLDBPermissions(lhs.GetLLDBPermissions());
region_info.GetRange() = lhs.GetRange().Intersect(rhs);
diff --git a/lldb/source/Target/RemoteAwarePlatform.cpp b/lldb/source/Target/RemoteAwarePlatform.cpp
index cac738e..89b946b 100644
--- a/lldb/source/Target/RemoteAwarePlatform.cpp
+++ b/lldb/source/Target/RemoteAwarePlatform.cpp
@@ -29,9 +29,8 @@ bool RemoteAwarePlatform::GetModuleSpec(const FileSpec &module_file_spec,
return false;
}
-Status RemoteAwarePlatform::ResolveExecutable(
- const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
- const FileSpecList *module_search_paths_ptr) {
+Status RemoteAwarePlatform::ResolveExecutable(const ModuleSpec &module_spec,
+ lldb::ModuleSP &exe_module_sp) {
ModuleSpec resolved_module_spec(module_spec);
// The host platform can resolve the path more aggressively.
@@ -47,12 +46,10 @@ Status RemoteAwarePlatform::ResolveExecutable(
if (!FileSystem::Instance().Exists(resolved_file_spec))
FileSystem::Instance().ResolveExecutableLocation(resolved_file_spec);
} else if (m_remote_platform_sp) {
- return GetCachedExecutable(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr);
+ return GetCachedExecutable(resolved_module_spec, exe_module_sp);
}
- return Platform::ResolveExecutable(resolved_module_spec, exe_module_sp,
- module_search_paths_ptr);
+ return Platform::ResolveExecutable(resolved_module_spec, exe_module_sp);
}
Status RemoteAwarePlatform::RunShellCommand(
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 2ed58c53..3bbb851 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -45,6 +45,9 @@
using namespace lldb;
using namespace lldb_private;
+// LLVM RTTI support.
+char StackFrame::ID;
+
// The first bits in the flags are reserved for the SymbolContext::Scope bits
// so we know if we have tried to look up information in our internal symbol
// context (m_sc) already.
@@ -328,6 +331,13 @@ StackFrame::GetSymbolContext(SymbolContextItem resolve_scope) {
// following the function call instruction...
Address lookup_addr(GetFrameCodeAddressForSymbolication());
+ // For PC-less frames (e.g., scripted frames), skip PC-based symbol
+ // resolution and preserve any already-populated SymbolContext fields.
+ if (!lookup_addr.IsValid()) {
+ m_flags.Set(resolve_scope | resolved);
+ return m_sc;
+ }
+
if (m_sc.module_sp) {
// We have something in our stack frame symbol context, lets check if we
// haven't already tried to lookup one of those things. If we haven't
@@ -1344,18 +1354,18 @@ const char *StackFrame::GetDisplayFunctionName() {
SourceLanguage StackFrame::GetLanguage() {
CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit;
if (cu)
- return cu->GetLanguage();
+ return SourceLanguage{cu->GetLanguage()};
return {};
}
SourceLanguage StackFrame::GuessLanguage() {
SourceLanguage lang_type = GetLanguage();
- if (lang_type == eLanguageTypeUnknown) {
+ if (!lang_type) {
SymbolContext sc =
GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol);
if (sc.function)
- lang_type = LanguageType(sc.function->GetMangled().GuessLanguage());
+ lang_type = SourceLanguage(sc.function->GetMangled().GuessLanguage());
else if (sc.symbol)
lang_type = SourceLanguage(sc.symbol->GetMangled().GuessLanguage());
}
@@ -2054,10 +2064,10 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
disasm_display = debugger.GetStopDisassemblyDisplay();
GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry);
- if (m_sc.comp_unit && m_sc.line_entry.IsValid()) {
+ if (m_sc.comp_unit || m_sc.line_entry.IsValid()) {
have_debuginfo = true;
if (source_lines_before > 0 || source_lines_after > 0) {
- SupportFileSP source_file_sp = m_sc.line_entry.file_sp;
+ SupportFileNSP source_file_sp = m_sc.line_entry.file_sp;
uint32_t start_line = m_sc.line_entry.line;
if (!start_line && m_sc.function) {
m_sc.function->GetStartLineSourceInfo(source_file_sp, start_line);
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp
index ccf874f..896a760 100644
--- a/lldb/source/Target/StackFrameList.cpp
+++ b/lldb/source/Target/StackFrameList.cpp
@@ -20,6 +20,7 @@
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/StackFrameRecognizer.h"
#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/SyntheticFrameProvider.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Unwind.h"
@@ -55,6 +56,49 @@ StackFrameList::~StackFrameList() {
Clear();
}
+SyntheticStackFrameList::SyntheticStackFrameList(
+ Thread &thread, lldb::StackFrameListSP input_frames,
+ const lldb::StackFrameListSP &prev_frames_sp, bool show_inline_frames)
+ : StackFrameList(thread, prev_frames_sp, show_inline_frames),
+ m_input_frames(std::move(input_frames)) {}
+
+bool SyntheticStackFrameList::FetchFramesUpTo(
+ uint32_t end_idx, InterruptionControl allow_interrupt) {
+
+ size_t num_synthetic_frames = 0;
+ // Check if the thread has a synthetic frame provider.
+ if (auto provider_sp = m_thread.GetFrameProvider()) {
+ // Use the synthetic frame provider to generate frames lazily.
+ // Keep fetching until we reach end_idx or the provider returns an error.
+ for (uint32_t idx = m_frames.size(); idx <= end_idx; idx++) {
+ if (allow_interrupt &&
+ m_thread.GetProcess()->GetTarget().GetDebugger().InterruptRequested())
+ return true;
+ auto frame_or_err = provider_sp->GetFrameAtIndex(idx);
+ if (!frame_or_err) {
+ // Provider returned error - we've reached the end.
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), frame_or_err.takeError(),
+ "Frame provider reached end at index {0}: {1}", idx);
+ SetAllFramesFetched();
+ break;
+ }
+ StackFrameSP frame_sp = *frame_or_err;
+ if (frame_sp->IsSynthetic())
+ frame_sp->GetStackID().SetCFA(num_synthetic_frames++,
+ GetThread().GetProcess().get());
+ // Set the frame list weak pointer so ExecutionContextRef can resolve
+ // the frame without calling Thread::GetStackFrameList().
+ frame_sp->m_frame_list_wp = shared_from_this();
+ m_frames.push_back(frame_sp);
+ }
+
+ return false; // Not interrupted.
+ }
+
+ // If no provider, fall back to the base implementation.
+ return StackFrameList::FetchFramesUpTo(end_idx, allow_interrupt);
+}
+
void StackFrameList::CalculateCurrentInlinedDepth() {
uint32_t cur_inlined_depth = GetCurrentInlinedDepth();
if (cur_inlined_depth == UINT32_MAX) {
@@ -330,6 +374,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa,
cfa_is_valid, pc, StackFrame::Kind::Regular, artificial,
behaves_like_zeroth_frame, &sc);
+ synth_frame->m_frame_list_wp = shared_from_this();
m_frames.push_back(synth_frame);
LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);
}
@@ -445,6 +490,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
unwind_frame_sp = std::make_shared<StackFrame>(
m_thread.shared_from_this(), m_frames.size(), idx, reg_ctx_sp,
cfa, pc, behaves_like_zeroth_frame, nullptr);
+ unwind_frame_sp->m_frame_list_wp = shared_from_this();
m_frames.push_back(unwind_frame_sp);
}
} else {
@@ -479,6 +525,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
// although its concrete index will stay the same.
SynthesizeTailCallFrames(*unwind_frame_sp.get());
+ unwind_frame_sp->m_frame_list_wp = shared_from_this();
m_frames.push_back(unwind_frame_sp);
}
@@ -503,6 +550,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
unwind_frame_sp->GetRegisterContextSP(), cfa, next_frame_address,
behaves_like_zeroth_frame, &next_frame_sc));
+ frame_sp->m_frame_list_wp = shared_from_this();
m_frames.push_back(frame_sp);
unwind_sc = next_frame_sc;
curr_frame_address = next_frame_address;
@@ -559,6 +607,7 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
prev_frame->UpdatePreviousFrameFromCurrentFrame(*curr_frame);
// Now copy the fixed up previous frame into the current frames so the
// pointer doesn't change.
+ prev_frame_sp->m_frame_list_wp = shared_from_this();
m_frames[curr_frame_idx] = prev_frame_sp;
#if defined(DEBUG_STACK_FRAMES)
diff --git a/lldb/source/Target/SyntheticFrameProvider.cpp b/lldb/source/Target/SyntheticFrameProvider.cpp
new file mode 100644
index 0000000..97ff42d
--- /dev/null
+++ b/lldb/source/Target/SyntheticFrameProvider.cpp
@@ -0,0 +1,121 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "lldb/Target/SyntheticFrameProvider.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SyntheticFrameProvider::SyntheticFrameProvider(StackFrameListSP input_frames)
+ : m_input_frames(std::move(input_frames)) {}
+
+SyntheticFrameProvider::~SyntheticFrameProvider() = default;
+
+void ScriptedFrameProviderDescriptor::Dump(Stream *s) const {
+ if (!s)
+ return;
+
+ s->Format(" ID: {0:x}\n", GetID());
+ s->Printf(" Name: %s\n", GetName().str().c_str());
+
+ std::string description = GetDescription();
+ if (!description.empty())
+ s->Printf(" Description: %s\n", description.c_str());
+
+ // Show thread filter information.
+ if (thread_specs.empty()) {
+ s->PutCString(" Thread Filter: (applies to all threads)\n");
+ } else {
+ s->Printf(" Thread Filter: %zu specification(s)\n", thread_specs.size());
+ for (size_t i = 0; i < thread_specs.size(); ++i) {
+ const ThreadSpec &spec = thread_specs[i];
+ s->Printf(" [%zu] ", i);
+ spec.GetDescription(s, lldb::eDescriptionLevelVerbose);
+ s->PutChar('\n');
+ }
+ }
+}
+
+uint32_t ScriptedFrameProviderDescriptor::GetID() const {
+ if (!scripted_metadata_sp)
+ return 0;
+
+ return scripted_metadata_sp->GetID();
+}
+
+std::string ScriptedFrameProviderDescriptor::GetDescription() const {
+ // If we have an interface, call get_description() to fetch it.
+ if (interface_sp && scripted_metadata_sp)
+ return interface_sp->GetDescription(scripted_metadata_sp->GetClassName());
+ return {};
+}
+
+llvm::Expected<SyntheticFrameProviderSP> SyntheticFrameProvider::CreateInstance(
+ StackFrameListSP input_frames,
+ const ScriptedFrameProviderDescriptor &descriptor) {
+ if (!input_frames)
+ return llvm::createStringError(
+ "cannot create synthetic frame provider: invalid input frames");
+
+ // Iterate through all registered ScriptedFrameProvider plugins.
+ ScriptedFrameProviderCreateInstance create_callback = nullptr;
+ for (uint32_t idx = 0;
+ (create_callback =
+ PluginManager::GetScriptedFrameProviderCreateCallbackAtIndex(
+ idx)) != nullptr;
+ ++idx) {
+ auto provider_or_err = create_callback(input_frames, descriptor);
+ if (!provider_or_err) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Target), provider_or_err.takeError(),
+ "Failed to create synthetic frame provider: {0}");
+ continue;
+ }
+
+ if (auto frame_provider_up = std::move(*provider_or_err))
+ return std::move(frame_provider_up);
+ }
+
+ return llvm::createStringError(
+ "cannot create synthetic frame provider: no suitable plugin found");
+}
+
+llvm::Expected<SyntheticFrameProviderSP> SyntheticFrameProvider::CreateInstance(
+ StackFrameListSP input_frames, llvm::StringRef plugin_name,
+ const std::vector<ThreadSpec> &thread_specs) {
+ if (!input_frames)
+ return llvm::createStringError(
+ "cannot create synthetic frame provider: invalid input frames");
+
+ // Look up the specific C++ plugin by name.
+ SyntheticFrameProviderCreateInstance create_callback =
+ PluginManager::GetSyntheticFrameProviderCreateCallbackForPluginName(
+ plugin_name);
+
+ if (!create_callback)
+ return llvm::createStringError(
+ "cannot create synthetic frame provider: C++ plugin '%s' not found",
+ plugin_name.str().c_str());
+
+ auto provider_or_err = create_callback(input_frames, thread_specs);
+ if (!provider_or_err)
+ return provider_or_err.takeError();
+
+ if (auto frame_provider_sp = std::move(*provider_or_err))
+ return std::move(frame_provider_sp);
+
+ return llvm::createStringError(
+ "cannot create synthetic frame provider: C++ plugin '%s' returned null",
+ plugin_name.str().c_str());
+}
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 1e43094..2305f10 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -156,8 +156,6 @@ static Status installExecutable(const Installer &installer) {
return Status();
}
-constexpr std::chrono::milliseconds EvaluateExpressionOptions::default_timeout;
-
Target::Arch::Arch(const ArchSpec &spec)
: m_spec(spec),
m_plugin_up(PluginManager::CreateArchitectureInstance(spec)) {}
@@ -187,6 +185,8 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch,
m_internal_stop_hooks(), m_latest_stop_hook_id(0), m_valid(true),
m_suppress_stop_hooks(false), m_is_dummy_target(is_dummy_target),
m_target_unique_id(g_target_unique_id++),
+ m_target_session_name(
+ llvm::formatv("Session {0}", m_target_unique_id).str()),
m_frame_recognizer_manager_up(
std::make_unique<StackFrameRecognizerManager>()) {
SetEventName(eBroadcastBitBreakpointChanged, "breakpoint-changed");
@@ -194,6 +194,7 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch,
SetEventName(eBroadcastBitModulesUnloaded, "modules-unloaded");
SetEventName(eBroadcastBitWatchpointChanged, "watchpoint-changed");
SetEventName(eBroadcastBitSymbolsLoaded, "symbols-loaded");
+ SetEventName(eBroadcastBitNewTargetCreated, "new-target-created");
CheckInWithManager();
@@ -1779,9 +1780,9 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform,
arch_spec.GetArchitectureName(),
arch_spec.GetTriple().getTriple().c_str());
ModuleSpec module_spec(executable_sp->GetFileSpec(), other);
- FileSpecList search_paths = GetExecutableSearchPaths();
+ module_spec.SetTarget(shared_from_this());
Status error = ModuleList::GetSharedModule(module_spec, executable_sp,
- &search_paths, nullptr, nullptr);
+ nullptr, nullptr);
if (!error.Fail() && executable_sp) {
SetExecutableModule(executable_sp, eLoadDependentsYes);
@@ -1855,6 +1856,9 @@ void Target::NotifyModulesRemoved(lldb_private::ModuleList &module_list) {
}
void Target::ModulesDidLoad(ModuleList &module_list) {
+ if (GetPreloadSymbols())
+ module_list.PreloadSymbols(GetParallelModuleLoad());
+
const size_t num_images = module_list.GetSize();
if (m_valid && num_images) {
for (size_t idx = 0; idx < num_images; ++idx) {
@@ -2279,8 +2283,10 @@ size_t Target::ReadScalarIntegerFromMemory(const Address &addr, uint32_t byte_si
else
scalar = data.GetMaxU64(&offset, byte_size);
- if (is_signed)
+ if (is_signed) {
+ scalar.MakeSigned();
scalar.SignExtend(byte_size * 8);
+ }
return bytes_read;
}
} else {
@@ -2295,7 +2301,7 @@ int64_t Target::ReadSignedIntegerFromMemory(const Address &addr,
int64_t fail_value, Status &error,
bool force_live_memory) {
Scalar scalar;
- if (ReadScalarIntegerFromMemory(addr, integer_byte_size, false, scalar, error,
+ if (ReadScalarIntegerFromMemory(addr, integer_byte_size, true, scalar, error,
force_live_memory))
return scalar.SLongLong(fail_value);
return fail_value;
@@ -2350,6 +2356,7 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
// Apply any remappings specified in target.object-map:
ModuleSpec module_spec(orig_module_spec);
+ module_spec.SetTarget(shared_from_this());
PathMappingList &obj_mapping = GetObjectPathMap();
if (std::optional<FileSpec> remapped_obj_file =
obj_mapping.RemapPath(orig_module_spec.GetFileSpec().GetPath(),
@@ -2408,9 +2415,9 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
transformed_spec.GetFileSpec().SetDirectory(transformed_dir);
transformed_spec.GetFileSpec().SetFilename(
module_spec.GetFileSpec().GetFilename());
+ transformed_spec.SetTarget(shared_from_this());
error = ModuleList::GetSharedModule(transformed_spec, module_sp,
- &search_paths, &old_modules,
- &did_create_module);
+ &old_modules, &did_create_module);
}
}
}
@@ -2426,9 +2433,8 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
// cache.
if (module_spec.GetUUID().IsValid()) {
// We have a UUID, it is OK to check the global module list...
- error =
- ModuleList::GetSharedModule(module_spec, module_sp, &search_paths,
- &old_modules, &did_create_module);
+ error = ModuleList::GetSharedModule(module_spec, module_sp,
+ &old_modules, &did_create_module);
}
if (!module_sp) {
@@ -2436,8 +2442,8 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
// module in the shared module cache.
if (m_platform_sp) {
error = m_platform_sp->GetSharedModule(
- module_spec, m_process_sp.get(), module_sp, &search_paths,
- &old_modules, &did_create_module);
+ module_spec, m_process_sp.get(), module_sp, &old_modules,
+ &did_create_module);
} else {
error = Status::FromErrorString("no platform is currently set");
}
@@ -2509,10 +2515,6 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
if (symbol_file_spec)
module_sp->SetSymbolFileFileSpec(symbol_file_spec);
- // Preload symbols outside of any lock, so hopefully we can do this for
- // each library in parallel.
- if (GetPreloadSymbols())
- module_sp->PreloadSymbols();
llvm::SmallVector<ModuleSP, 1> replaced_modules;
for (ModuleSP &old_module_sp : old_modules) {
if (m_images.GetIndexForModule(old_module_sp.get()) !=
@@ -3207,6 +3209,11 @@ bool Target::RunStopHooks(bool at_initial_stop) {
bool should_stop = false;
bool requested_continue = false;
+ // A stop hook might get deleted while running stop hooks.
+ // We have to decide what that means. We will follow the rule that deleting
+ // a stop hook while processing these stop hooks will delete it for FUTURE
+ // stops but not this stop. Fortunately, copying the m_stop_hooks to the
+ // active_hooks list before iterating over the hooks has this effect.
for (auto cur_hook_sp : active_hooks) {
bool any_thread_matched = false;
for (auto exc_ctx : exc_ctx_with_reasons) {
@@ -3713,6 +3720,61 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) {
return error;
}
+llvm::Expected<uint32_t> Target::AddScriptedFrameProviderDescriptor(
+ const ScriptedFrameProviderDescriptor &descriptor) {
+ if (!descriptor.IsValid())
+ return llvm::createStringError("invalid frame provider descriptor");
+
+ llvm::StringRef name = descriptor.GetName();
+ if (name.empty())
+ return llvm::createStringError(
+ "frame provider descriptor has no class name");
+
+ std::lock_guard<std::recursive_mutex> guard(
+ m_frame_provider_descriptors_mutex);
+
+ uint32_t descriptor_id = descriptor.GetID();
+ m_frame_provider_descriptors[descriptor_id] = descriptor;
+
+ // Clear frame providers on existing threads so they reload with new config.
+ if (ProcessSP process_sp = GetProcessSP())
+ for (ThreadSP thread_sp : process_sp->Threads())
+ thread_sp->ClearScriptedFrameProvider();
+
+ return descriptor_id;
+}
+
+bool Target::RemoveScriptedFrameProviderDescriptor(uint32_t id) {
+ std::lock_guard<std::recursive_mutex> guard(
+ m_frame_provider_descriptors_mutex);
+ bool removed = m_frame_provider_descriptors.erase(id);
+
+ if (removed)
+ if (ProcessSP process_sp = GetProcessSP())
+ for (ThreadSP thread_sp : process_sp->Threads())
+ thread_sp->ClearScriptedFrameProvider();
+
+ return removed;
+}
+
+void Target::ClearScriptedFrameProviderDescriptors() {
+ std::lock_guard<std::recursive_mutex> guard(
+ m_frame_provider_descriptors_mutex);
+
+ m_frame_provider_descriptors.clear();
+
+ if (ProcessSP process_sp = GetProcessSP())
+ for (ThreadSP thread_sp : process_sp->Threads())
+ thread_sp->ClearScriptedFrameProvider();
+}
+
+const llvm::DenseMap<uint32_t, ScriptedFrameProviderDescriptor> &
+Target::GetScriptedFrameProviderDescriptors() const {
+ std::lock_guard<std::recursive_mutex> guard(
+ m_frame_provider_descriptors_mutex);
+ return m_frame_provider_descriptors;
+}
+
void Target::FinalizeFileActions(ProcessLaunchInfo &info) {
Log *log = GetLog(LLDBLog::Process);
@@ -3962,9 +4024,7 @@ void Target::StopHook::GetDescription(Stream &s,
return;
}
- unsigned indent_level = s.GetIndentLevel();
-
- s.SetIndentLevel(indent_level + 2);
+ auto indent_scope = s.MakeIndentScope();
s.Printf("Hook: %" PRIu64 "\n", GetID());
if (m_active)
@@ -3978,19 +4038,17 @@ void Target::StopHook::GetDescription(Stream &s,
if (m_specifier_sp) {
s.Indent();
s.PutCString("Specifier:\n");
- s.SetIndentLevel(indent_level + 4);
+ auto indent_scope = s.MakeIndentScope();
m_specifier_sp->GetDescription(&s, level);
- s.SetIndentLevel(indent_level + 2);
}
if (m_thread_spec_up) {
StreamString tmp;
s.Indent("Thread:\n");
m_thread_spec_up->GetDescription(&tmp, level);
- s.SetIndentLevel(indent_level + 4);
+ auto indent_scope = s.MakeIndentScope();
s.Indent(tmp.GetString());
s.PutCString("\n");
- s.SetIndentLevel(indent_level + 2);
}
GetSubclassDescription(s, level);
}
@@ -4003,14 +4061,13 @@ void Target::StopHookCommandLine::GetSubclassDescription(
s.PutCString(m_commands.GetStringAtIndex(0));
return;
}
- s.Indent("Commands: \n");
- s.SetIndentLevel(s.GetIndentLevel() + 4);
+ s.Indent("Commands:\n");
+ auto indent_scope = s.MakeIndentScope(4);
uint32_t num_commands = m_commands.GetSize();
for (uint32_t i = 0; i < num_commands; i++) {
s.Indent(m_commands.GetStringAtIndex(i));
s.PutCString("\n");
}
- s.SetIndentLevel(s.GetIndentLevel() - 4);
}
// Target::StopHookCommandLine
@@ -4145,7 +4202,7 @@ void Target::StopHookScripted::GetSubclassDescription(
return;
s.Indent("Args:\n");
- s.SetIndentLevel(s.GetIndentLevel() + 4);
+ auto indent_scope = s.MakeIndentScope(4);
auto print_one_element = [&s](llvm::StringRef key,
StructuredData::Object *object) {
@@ -4155,8 +4212,6 @@ void Target::StopHookScripted::GetSubclassDescription(
};
as_dict->ForEach(print_one_element);
-
- s.SetIndentLevel(s.GetIndentLevel() - 4);
}
static constexpr OptionEnumValueElement g_dynamic_value_types[] = {
@@ -4952,7 +5007,7 @@ void TargetProperties::SetStandardErrorPath(llvm::StringRef path) {
SourceLanguage TargetProperties::GetLanguage() const {
const uint32_t idx = ePropertyLanguage;
- return {GetPropertyAtIndexAs<LanguageType>(idx, {})};
+ return SourceLanguage{GetPropertyAtIndexAs<LanguageType>(idx, {})};
}
llvm::StringRef TargetProperties::GetExpressionPrefixContents() {
@@ -5090,17 +5145,17 @@ void TargetProperties::SetProcessLaunchInfo(
const FileAction *input_file_action =
launch_info.GetFileActionForFD(STDIN_FILENO);
if (input_file_action) {
- SetStandardInputPath(input_file_action->GetPath());
+ SetStandardInputPath(input_file_action->GetFileSpec().GetPath());
}
const FileAction *output_file_action =
launch_info.GetFileActionForFD(STDOUT_FILENO);
if (output_file_action) {
- SetStandardOutputPath(output_file_action->GetPath());
+ SetStandardOutputPath(output_file_action->GetFileSpec().GetPath());
}
const FileAction *error_file_action =
launch_info.GetFileActionForFD(STDERR_FILENO);
if (error_file_action) {
- SetStandardErrorPath(error_file_action->GetPath());
+ SetStandardErrorPath(error_file_action->GetFileSpec().GetPath());
}
SetDetachOnError(launch_info.GetFlags().Test(lldb::eLaunchFlagDetachOnError));
SetDisableASLR(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableASLR));
@@ -5203,6 +5258,11 @@ Target::TargetEventData::TargetEventData(const lldb::TargetSP &target_sp,
const ModuleList &module_list)
: EventData(), m_target_sp(target_sp), m_module_list(module_list) {}
+Target::TargetEventData::TargetEventData(
+ const lldb::TargetSP &target_sp, const lldb::TargetSP &created_target_sp)
+ : EventData(), m_target_sp(target_sp),
+ m_created_target_sp(created_target_sp), m_module_list() {}
+
Target::TargetEventData::~TargetEventData() = default;
llvm::StringRef Target::TargetEventData::GetFlavorString() {
@@ -5237,6 +5297,15 @@ TargetSP Target::TargetEventData::GetTargetFromEvent(const Event *event_ptr) {
return target_sp;
}
+TargetSP
+Target::TargetEventData::GetCreatedTargetFromEvent(const Event *event_ptr) {
+ TargetSP created_target_sp;
+ const TargetEventData *event_data = GetEventDataFromEvent(event_ptr);
+ if (event_data)
+ created_target_sp = event_data->m_created_target_sp;
+ return created_target_sp;
+}
+
ModuleList
Target::TargetEventData::GetModuleListFromEvent(const Event *event_ptr) {
ModuleList module_list;
diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp
index 188c250..ce04e9c 100644
--- a/lldb/source/Target/TargetList.cpp
+++ b/lldb/source/Target/TargetList.cpp
@@ -48,7 +48,7 @@ Status TargetList::CreateTarget(Debugger &debugger,
LoadDependentFiles load_dependent_files,
const OptionGroupPlatform *platform_options,
TargetSP &target_sp) {
- std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
+
auto result = TargetList::CreateTargetInternal(
debugger, user_exe_path, triple_str, load_dependent_files,
platform_options, target_sp);
@@ -63,7 +63,7 @@ Status TargetList::CreateTarget(Debugger &debugger,
const ArchSpec &specified_arch,
LoadDependentFiles load_dependent_files,
PlatformSP &platform_sp, TargetSP &target_sp) {
- std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
+
auto result = TargetList::CreateTargetInternal(
debugger, user_exe_path, specified_arch, load_dependent_files,
platform_sp, target_sp);
@@ -304,13 +304,9 @@ Status TargetList::CreateTargetInternal(Debugger &debugger,
ModuleSP exe_module_sp;
if (platform_sp) {
- FileSpecList executable_search_paths(
- Target::GetDefaultExecutableSearchPaths());
ModuleSpec module_spec(file, arch);
- error = platform_sp->ResolveExecutable(module_spec, exe_module_sp,
- executable_search_paths.GetSize()
- ? &executable_search_paths
- : nullptr);
+ module_spec.SetTarget(target_sp);
+ error = platform_sp->ResolveExecutable(module_spec, exe_module_sp);
}
if (error.Success() && exe_module_sp) {
@@ -525,6 +521,7 @@ uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const {
}
void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) {
+ std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex);
lldbassert(!llvm::is_contained(m_target_list, target_sp) &&
"target already exists it the list");
UnregisterInProcessTarget(target_sp);
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index 8c3e197..b40e753 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -13,9 +13,12 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
#include "lldb/Interpreter/OptionValueFileSpecList.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Interpreter/Property.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
@@ -26,6 +29,7 @@
#include "lldb/Target/ScriptedThreadPlan.h"
#include "lldb/Target/StackFrameRecognizer.h"
#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/SyntheticFrameProvider.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlan.h"
@@ -45,6 +49,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/ScriptedMetadata.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
@@ -257,6 +262,7 @@ void Thread::DestroyThread() {
std::lock_guard<std::recursive_mutex> guard(m_frame_mutex);
m_curr_frames_sp.reset();
m_prev_frames_sp.reset();
+ m_frame_provider_sp.reset();
m_prev_framezero_pc.reset();
}
@@ -1439,13 +1445,76 @@ void Thread::CalculateExecutionContext(ExecutionContext &exe_ctx) {
StackFrameListSP Thread::GetStackFrameList() {
std::lock_guard<std::recursive_mutex> guard(m_frame_mutex);
- if (!m_curr_frames_sp)
+ if (m_curr_frames_sp)
+ return m_curr_frames_sp;
+
+ // First, try to load a frame provider if we don't have one yet.
+ if (!m_frame_provider_sp) {
+ ProcessSP process_sp = GetProcess();
+ if (process_sp) {
+ Target &target = process_sp->GetTarget();
+ const auto &descriptors = target.GetScriptedFrameProviderDescriptors();
+
+ // Find first descriptor that applies to this thread.
+ for (const auto &entry : descriptors) {
+ const ScriptedFrameProviderDescriptor &descriptor = entry.second;
+ if (descriptor.IsValid() && descriptor.AppliesToThread(*this)) {
+ if (llvm::Error error = LoadScriptedFrameProvider(descriptor)) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(error),
+ "Failed to load scripted frame provider: {0}");
+ }
+ break; // Use first matching descriptor (success or failure).
+ }
+ }
+ }
+ }
+
+ // Create the frame list based on whether we have a provider.
+ if (m_frame_provider_sp) {
+ // We have a provider - create synthetic frame list.
+ StackFrameListSP input_frames = m_frame_provider_sp->GetInputFrames();
+ m_curr_frames_sp = std::make_shared<SyntheticStackFrameList>(
+ *this, input_frames, m_prev_frames_sp, true);
+ } else {
+ // No provider - use normal unwinder frames.
m_curr_frames_sp =
std::make_shared<StackFrameList>(*this, m_prev_frames_sp, true);
+ }
return m_curr_frames_sp;
}
+llvm::Error Thread::LoadScriptedFrameProvider(
+ const ScriptedFrameProviderDescriptor &descriptor) {
+ std::lock_guard<std::recursive_mutex> guard(m_frame_mutex);
+
+ // Note: We don't create input_frames here - it will be created lazily
+ // by SyntheticStackFrameList when frames are first fetched.
+ // Creating them too early can cause crashes during thread initialization.
+
+ // Create a temporary StackFrameList just to get the thread reference for the
+ // provider. The provider won't actually use this - it will get real input
+ // frames from SyntheticStackFrameList later.
+ StackFrameListSP temp_frames =
+ std::make_shared<StackFrameList>(*this, m_prev_frames_sp, true);
+
+ auto provider_or_err =
+ SyntheticFrameProvider::CreateInstance(temp_frames, descriptor);
+ if (!provider_or_err)
+ return provider_or_err.takeError();
+
+ ClearScriptedFrameProvider();
+ m_frame_provider_sp = *provider_or_err;
+ return llvm::Error::success();
+}
+
+void Thread::ClearScriptedFrameProvider() {
+ std::lock_guard<std::recursive_mutex> guard(m_frame_mutex);
+ m_frame_provider_sp.reset();
+ m_curr_frames_sp.reset();
+ m_prev_frames_sp.reset();
+}
+
std::optional<addr_t> Thread::GetPreviousFrameZeroPC() {
return m_prev_framezero_pc;
}
@@ -1466,6 +1535,7 @@ void Thread::ClearStackFrames() {
m_prev_frames_sp.swap(m_curr_frames_sp);
m_curr_frames_sp.reset();
+ m_frame_provider_sp.reset();
m_extended_info.reset();
m_extended_info_fetched = false;
}
diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp
index d49a01b..0307b38 100644
--- a/lldb/source/Target/ThreadPlanStepOut.cpp
+++ b/lldb/source/Target/ThreadPlanStepOut.cpp
@@ -356,13 +356,10 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
}
}
- // If there was only one owner, then we're done. But if we also hit
- // some user breakpoint on our way out, we should mark ourselves as
- // done, but also not claim to explain the stop, since it is more
- // important to report the user breakpoint than the step out
- // completion.
-
- if (site_sp->GetNumberOfConstituents() == 1)
+ // If the thread also hit a user breakpoint on its way out, the plan is
+ // done but should not claim to explain the stop. It is more important
+ // to report the user breakpoint than the step out completion.
+ if (!site_sp->ContainsUserBreakpointForThread(GetThread()))
return true;
}
return false;
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
index dca96cc..3a9deb6 100644
--- a/lldb/source/Target/ThreadPlanStepRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -431,10 +431,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
top_most_line_entry.original_file_sp =
std::make_shared<SupportFile>(call_site_file_spec);
top_most_line_entry.range = range;
- top_most_line_entry.file_sp.reset();
+ top_most_line_entry.file_sp = std::make_shared<SupportFile>();
top_most_line_entry.ApplyFileMappings(
GetThread().CalculateTarget());
- if (!top_most_line_entry.file_sp)
+ if (!top_most_line_entry.file_sp->GetSpecOnly())
top_most_line_entry.file_sp =
top_most_line_entry.original_file_sp;
}
diff --git a/lldb/source/Target/ThreadSpec.cpp b/lldb/source/Target/ThreadSpec.cpp
index ba4c3aa..624f64e 100644
--- a/lldb/source/Target/ThreadSpec.cpp
+++ b/lldb/source/Target/ThreadSpec.cpp
@@ -19,6 +19,10 @@ const char *ThreadSpec::g_option_names[static_cast<uint32_t>(
ThreadSpec::ThreadSpec() : m_name(), m_queue_name() {}
+ThreadSpec::ThreadSpec(Thread &thread)
+ : m_index(thread.GetIndexID()), m_tid(thread.GetID()),
+ m_name(thread.GetName()), m_queue_name(thread.GetQueueName()) {}
+
std::unique_ptr<ThreadSpec> ThreadSpec::CreateFromStructuredData(
const StructuredData::Dictionary &spec_dict, Status &error) {
uint32_t index = UINT32_MAX;
diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp
index 6113c66..881431f 100644
--- a/lldb/source/Target/UnixSignals.cpp
+++ b/lldb/source/Target/UnixSignals.cpp
@@ -137,6 +137,13 @@ llvm::StringRef UnixSignals::GetSignalAsStringRef(int32_t signo) const {
return pos->second.m_name;
}
+llvm::StringRef UnixSignals::GetSignalNumberDescription(int32_t signo) const {
+ const auto pos = m_signals.find(signo);
+ if (pos == m_signals.end())
+ return {};
+ return pos->second.m_description;
+}
+
std::string UnixSignals::GetSignalDescription(
int32_t signo, std::optional<int32_t> code,
std::optional<lldb::addr_t> addr, std::optional<lldb::addr_t> lower,
diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt
index 1dd4d63..80b53f8 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -38,7 +38,6 @@ add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES
DataEncoder.cpp
DataExtractor.cpp
Diagnostics.cpp
- DiagnosticsRendering.cpp
Environment.cpp
ErrorMessages.cpp
Event.cpp
@@ -78,6 +77,7 @@ add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES
UserIDResolver.cpp
VASprintf.cpp
VMRange.cpp
+ VirtualDataExtractor.cpp
XcodeSDK.cpp
ZipFile.cpp
diff --git a/lldb/source/Utility/DataExtractor.cpp b/lldb/source/Utility/DataExtractor.cpp
index e9be0cb..a9aea16 100644
--- a/lldb/source/Utility/DataExtractor.cpp
+++ b/lldb/source/Utility/DataExtractor.cpp
@@ -662,10 +662,6 @@ size_t DataExtractor::ExtractBytes(offset_t offset, offset_t length,
const uint8_t *src = PeekData(offset, length);
if (src) {
if (dst_byte_order != GetByteOrder()) {
- // Validate that only a word- or register-sized dst is byte swapped
- assert(length == 1 || length == 2 || length == 4 || length == 8 ||
- length == 10 || length == 16 || length == 32);
-
for (uint32_t i = 0; i < length; ++i)
(static_cast<uint8_t *>(dst))[i] = src[length - i - 1];
} else
diff --git a/lldb/source/Utility/FileSpecList.cpp b/lldb/source/Utility/FileSpecList.cpp
index 5852367..8aa0820 100644
--- a/lldb/source/Utility/FileSpecList.cpp
+++ b/lldb/source/Utility/FileSpecList.cpp
@@ -45,10 +45,9 @@ bool FileSpecList::AppendIfUnique(const FileSpec &file_spec) {
// FIXME: Replace this with a DenseSet at the call site. It is inefficient.
bool SupportFileList::AppendIfUnique(const FileSpec &file_spec) {
collection::iterator end = m_files.end();
- if (find_if(m_files.begin(), end,
- [&](const std::shared_ptr<SupportFile> &support_file) {
- return support_file->GetSpecOnly() == file_spec;
- }) == end) {
+ if (find_if(m_files.begin(), end, [&](const SupportFileNSP &support_file) {
+ return support_file->GetSpecOnly() == file_spec;
+ }) == end) {
Append(file_spec);
return true;
}
@@ -214,11 +213,10 @@ const FileSpec &SupportFileList::GetFileSpecAtIndex(size_t idx) const {
return g_empty_file_spec;
}
-std::shared_ptr<SupportFile>
-SupportFileList::GetSupportFileAtIndex(size_t idx) const {
+SupportFileNSP SupportFileList::GetSupportFileAtIndex(size_t idx) const {
if (idx < m_files.size())
return m_files[idx];
- return {};
+ return std::make_shared<SupportFile>();
}
// Return the size in bytes that this object takes in memory. This returns the
diff --git a/lldb/source/Utility/LLDBLog.cpp b/lldb/source/Utility/LLDBLog.cpp
index 613dae4..a08764d 100644
--- a/lldb/source/Utility/LLDBLog.cpp
+++ b/lldb/source/Utility/LLDBLog.cpp
@@ -67,6 +67,9 @@ static constexpr Log::Category g_categories[] = {
{{"disassembler"},
{"log disassembler related activities"},
LLDBLog::Disassembler},
+ {{"instrumentation-runtime"},
+ {"log instrumentation runtime plugin related activities"},
+ LLDBLog::InstrumentationRuntime},
};
static Log::Channel g_log_channel(g_categories,
diff --git a/lldb/source/Utility/RegisterValue.cpp b/lldb/source/Utility/RegisterValue.cpp
index 12c349a..4d762dc 100644
--- a/lldb/source/Utility/RegisterValue.cpp
+++ b/lldb/source/Utility/RegisterValue.cpp
@@ -127,7 +127,7 @@ bool RegisterValue::GetScalarValue(Scalar &scalar) const {
case eTypeUInt16:
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -180,8 +180,6 @@ Status RegisterValue::SetValueFromData(const RegisterInfo &reg_info,
if (src_len > reg_info.byte_size)
src_len = reg_info.byte_size;
- type128 int128;
-
m_type = eTypeInvalid;
switch (reg_info.encoding) {
case eEncodingInvalid:
@@ -196,17 +194,13 @@ Status RegisterValue::SetValueFromData(const RegisterInfo &reg_info,
SetUInt32(src.GetMaxU32(&src_offset, src_len));
else if (reg_info.byte_size <= 8)
SetUInt64(src.GetMaxU64(&src_offset, src_len));
- else if (reg_info.byte_size <= 16) {
- uint64_t data1 = src.GetU64(&src_offset);
- uint64_t data2 = src.GetU64(&src_offset);
- if (src.GetByteOrder() == eByteOrderLittle) {
- int128.x[0] = data1;
- int128.x[1] = data2;
- } else {
- int128.x[0] = data2;
- int128.x[1] = data1;
- }
- SetUInt128(llvm::APInt(128, 2, int128.x));
+ else {
+ std::vector<uint8_t> native_endian_src(src_len, 0);
+ src.ExtractBytes(src_offset, src_len, endian::InlHostByteOrder(),
+ native_endian_src.data());
+ llvm::APInt uint = llvm::APInt::getZero(src_len * 8);
+ llvm::LoadIntFromMemory(uint, native_endian_src.data(), src_len);
+ SetUIntN(uint);
}
break;
case eEncodingIEEE754:
@@ -442,7 +436,7 @@ bool RegisterValue::SignExtend(uint32_t sign_bitpos) {
case eTypeUInt16:
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
return m_scalar.SignExtend(sign_bitpos);
case eTypeFloat:
case eTypeDouble:
@@ -465,7 +459,7 @@ bool RegisterValue::CopyValue(const RegisterValue &rhs) {
case eTypeUInt16:
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -581,7 +575,7 @@ llvm::APInt RegisterValue::GetAsUInt128(const llvm::APInt &fail_value,
case eTypeUInt16:
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -596,8 +590,10 @@ llvm::APInt RegisterValue::GetAsUInt128(const llvm::APInt &fail_value,
case 8:
case 16:
return llvm::APInt(
- BITWIDTH_INT128, NUM_OF_WORDS_INT128,
- (reinterpret_cast<const type128 *>(buffer.bytes.data()))->x);
+ BITWIDTH_INT128,
+ llvm::ArrayRef(
+ (reinterpret_cast<const type128 *>(buffer.bytes.data()))->x,
+ NUM_OF_WORDS_INT128));
}
} break;
}
@@ -614,7 +610,7 @@ float RegisterValue::GetAsFloat(float fail_value, bool *success_ptr) const {
break;
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -634,7 +630,7 @@ double RegisterValue::GetAsDouble(double fail_value, bool *success_ptr) const {
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -655,7 +651,7 @@ long double RegisterValue::GetAsLongDouble(long double fail_value,
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -674,7 +670,7 @@ const void *RegisterValue::GetBytes() const {
case eTypeUInt16:
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -696,7 +692,7 @@ uint32_t RegisterValue::GetByteSize() const {
return 2;
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -719,7 +715,7 @@ bool RegisterValue::SetUInt(uint64_t uint, uint32_t byte_size) {
} else if (byte_size <= 8) {
SetUInt64(uint);
} else if (byte_size <= 16) {
- SetUInt128(llvm::APInt(128, uint));
+ SetUIntN(llvm::APInt(128, uint));
} else
return false;
return true;
@@ -747,7 +743,7 @@ bool RegisterValue::operator==(const RegisterValue &rhs) const {
case eTypeUInt16:
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
case eTypeFloat:
case eTypeDouble:
case eTypeLongDouble:
@@ -772,7 +768,7 @@ bool RegisterValue::ClearBit(uint32_t bit) {
case eTypeUInt16:
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
if (bit < (GetByteSize() * 8)) {
return m_scalar.ClearBit(bit);
}
@@ -812,7 +808,7 @@ bool RegisterValue::SetBit(uint32_t bit) {
case eTypeUInt16:
case eTypeUInt32:
case eTypeUInt64:
- case eTypeUInt128:
+ case eTypeUIntN:
if (bit < (GetByteSize() * 8)) {
return m_scalar.SetBit(bit);
}
diff --git a/lldb/source/Utility/Stream.cpp b/lldb/source/Utility/Stream.cpp
index 89dce9f..e9632c3 100644
--- a/lldb/source/Utility/Stream.cpp
+++ b/lldb/source/Utility/Stream.cpp
@@ -202,6 +202,14 @@ void Stream::IndentLess(unsigned amount) {
m_indent_level = 0;
}
+// Create an indentation scope that restores the original indent level when the
+// object goes out of scope (RAII).
+Stream::IndentScope Stream::MakeIndentScope(unsigned indent_amount) {
+ IndentScope indent_scope(*this);
+ IndentMore(indent_amount);
+ return indent_scope;
+}
+
// Get the address size in bytes
uint32_t Stream::GetAddressByteSize() const { return m_addr_size; }
diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp
index 010149a..40b5d03 100644
--- a/lldb/source/Utility/StringExtractorGDBRemote.cpp
+++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp
@@ -12,9 +12,6 @@
#include <cstring>
#include <optional>
-constexpr lldb::pid_t StringExtractorGDBRemote::AllProcesses;
-constexpr lldb::tid_t StringExtractorGDBRemote::AllThreads;
-
StringExtractorGDBRemote::ResponseType
StringExtractorGDBRemote::GetResponseType() const {
if (m_packet.empty())
diff --git a/lldb/source/Utility/VirtualDataExtractor.cpp b/lldb/source/Utility/VirtualDataExtractor.cpp
new file mode 100644
index 0000000..a23e43b
--- /dev/null
+++ b/lldb/source/Utility/VirtualDataExtractor.cpp
@@ -0,0 +1,139 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "lldb/Utility/VirtualDataExtractor.h"
+#include <cassert>
+
+using namespace lldb;
+using namespace lldb_private;
+
+VirtualDataExtractor::VirtualDataExtractor(const void *data,
+ offset_t data_length,
+ ByteOrder byte_order,
+ uint32_t addr_size,
+ LookupTable lookup_table)
+ : DataExtractor(data, data_length, byte_order, addr_size),
+ m_lookup_table(std::move(lookup_table)) {
+ m_lookup_table.Sort();
+}
+
+VirtualDataExtractor::VirtualDataExtractor(const DataBufferSP &data_sp,
+ ByteOrder byte_order,
+ uint32_t addr_size,
+ LookupTable lookup_table)
+ : DataExtractor(data_sp, byte_order, addr_size),
+ m_lookup_table(std::move(lookup_table)) {
+ m_lookup_table.Sort();
+}
+
+const VirtualDataExtractor::LookupTable::Entry *
+VirtualDataExtractor::FindEntry(offset_t virtual_addr) const {
+ // Use RangeDataVector's binary search instead of linear search.
+ return m_lookup_table.FindEntryThatContains(virtual_addr);
+}
+
+bool VirtualDataExtractor::ValidateVirtualRead(offset_t virtual_addr,
+ offset_t length) const {
+ const LookupTable::Entry *entry = FindEntry(virtual_addr);
+ if (!entry)
+ return false;
+
+ // Assert that the read does not cross entry boundaries.
+ // RangeData.Contains() checks if a range is fully contained.
+ assert(entry->Contains(LookupTable::Range(virtual_addr, length)) &&
+ "Read crosses lookup table entry boundary");
+
+ // Also validate that the physical offset is within the data buffer.
+ // RangeData.data contains the physical offset.
+ offset_t physical_offset = entry->data + (virtual_addr - entry->base);
+ return ValidOffsetForDataOfSize(physical_offset, length);
+}
+
+const void *VirtualDataExtractor::GetData(offset_t *offset_ptr,
+ offset_t length) const {
+ // Override to treat offset as virtual address.
+ if (!offset_ptr)
+ return nullptr;
+
+ offset_t virtual_addr = *offset_ptr;
+
+ if (!ValidateVirtualRead(virtual_addr, length))
+ return nullptr;
+
+ const LookupTable::Entry *entry = FindEntry(virtual_addr);
+ assert(entry && "ValidateVirtualRead should have found an entry");
+
+ offset_t physical_offset = entry->data + (virtual_addr - entry->base);
+ // Use base class PeekData directly to avoid recursion.
+ const void *result = DataExtractor::PeekData(physical_offset, length);
+
+ if (result) {
+ // Advance the virtual offset pointer.
+ *offset_ptr += length;
+ }
+
+ return result;
+}
+
+const uint8_t *VirtualDataExtractor::PeekData(offset_t offset,
+ offset_t length) const {
+ // Override to treat offset as virtual address.
+ if (!ValidateVirtualRead(offset, length))
+ return nullptr;
+
+ const LookupTable::Entry *entry = FindEntry(offset);
+ assert(entry && "ValidateVirtualRead should have found an entry");
+
+ offset_t physical_offset = entry->data + (offset - entry->base);
+ // Use the base class PeekData with the physical offset.
+ return DataExtractor::PeekData(physical_offset, length);
+}
+
+uint8_t VirtualDataExtractor::GetU8_unchecked(offset_t *offset_ptr) const {
+ offset_t virtual_addr = *offset_ptr;
+ const LookupTable::Entry *entry = FindEntry(virtual_addr);
+ assert(entry && "Unchecked methods require valid virtual address");
+
+ offset_t physical_offset = entry->data + (virtual_addr - entry->base);
+ uint8_t result = DataExtractor::GetU8_unchecked(&physical_offset);
+ *offset_ptr += 1;
+ return result;
+}
+
+uint16_t VirtualDataExtractor::GetU16_unchecked(offset_t *offset_ptr) const {
+ offset_t virtual_addr = *offset_ptr;
+ const LookupTable::Entry *entry = FindEntry(virtual_addr);
+ assert(entry && "Unchecked methods require valid virtual address");
+
+ offset_t physical_offset = entry->data + (virtual_addr - entry->base);
+ uint16_t result = DataExtractor::GetU16_unchecked(&physical_offset);
+ *offset_ptr += 2;
+ return result;
+}
+
+uint32_t VirtualDataExtractor::GetU32_unchecked(offset_t *offset_ptr) const {
+ offset_t virtual_addr = *offset_ptr;
+ const LookupTable::Entry *entry = FindEntry(virtual_addr);
+ assert(entry && "Unchecked methods require valid virtual address");
+
+ offset_t physical_offset = entry->data + (virtual_addr - entry->base);
+ uint32_t result = DataExtractor::GetU32_unchecked(&physical_offset);
+ *offset_ptr += 4;
+ return result;
+}
+
+uint64_t VirtualDataExtractor::GetU64_unchecked(offset_t *offset_ptr) const {
+ offset_t virtual_addr = *offset_ptr;
+ const LookupTable::Entry *entry = FindEntry(virtual_addr);
+ assert(entry && "Unchecked methods require valid virtual address");
+
+ offset_t physical_offset = entry->data + (virtual_addr - entry->base);
+ uint64_t result = DataExtractor::GetU64_unchecked(&physical_offset);
+ *offset_ptr += 8;
+ return result;
+}
diff --git a/lldb/source/ValueObject/CMakeLists.txt b/lldb/source/ValueObject/CMakeLists.txt
index 2a61407..f0fe7f3 100644
--- a/lldb/source/ValueObject/CMakeLists.txt
+++ b/lldb/source/ValueObject/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_lldb_library(lldbValueObject
+add_lldb_library(lldbValueObject NO_PLUGIN_DEPENDENCIES
DILAST.cpp
DILEval.cpp
DILLexer.cpp
@@ -34,6 +34,4 @@ add_lldb_library(lldbValueObject
lldbSymbol
lldbTarget
lldbUtility
- lldbPluginCPlusPlusLanguage
- lldbPluginObjCLanguage
)
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index 7ed34db..0b9e1f4 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -51,4 +51,8 @@ BooleanLiteralNode::Accept(Visitor *v) const {
return v->Visit(this);
}
+llvm::Expected<lldb::ValueObjectSP> CastNode::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 a9dbfad..dc0d93d 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -21,6 +21,101 @@
namespace lldb_private::dil {
+static llvm::Expected<lldb::TypeSystemSP>
+GetTypeSystemFromCU(std::shared_ptr<ExecutionContextScope> ctx) {
+ auto stack_frame = ctx->CalculateStackFrame();
+ if (!stack_frame)
+ return llvm::createStringError("no stack frame in this context");
+ SymbolContext symbol_context =
+ stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit);
+ lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
+
+ symbol_context = stack_frame->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();
+}
+
+static lldb::ValueObjectSP
+ArrayToPointerConversion(ValueObject &valobj, ExecutionContextScope &ctx) {
+ uint64_t addr = valobj.GetLoadAddress();
+ ExecutionContext exe_ctx;
+ ctx.CalculateExecutionContext(exe_ctx);
+ return ValueObject::CreateValueObjectFromAddress(
+ "result", addr, exe_ctx,
+ valobj.GetCompilerType().GetArrayElementType(&ctx).GetPointerType(),
+ /* do_deref */ false);
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location) {
+ if (!valobj)
+ return llvm::make_error<DILDiagnosticError>(m_expr, "invalid value object",
+ location);
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_exe_ctx_scope);
+ if (!type_system)
+ return type_system.takeError();
+
+ CompilerType in_type = valobj->GetCompilerType();
+ if (valobj->IsBitfield()) {
+ // Promote bitfields. If `int` can represent the bitfield value, it is
+ // converted to `int`. Otherwise, if `unsigned int` can represent it, it
+ // is converted to `unsigned int`. Otherwise, it is treated as its
+ // underlying type.
+ uint32_t bitfield_size = valobj->GetBitfieldBitSize();
+ // Some bitfields have undefined size (e.g. result of ternary operation).
+ // The AST's `bitfield_size` of those is 0, and no promotion takes place.
+ if (bitfield_size > 0 && in_type.IsInteger()) {
+ CompilerType int_type = GetBasicType(*type_system, lldb::eBasicTypeInt);
+ CompilerType uint_type =
+ GetBasicType(*type_system, lldb::eBasicTypeUnsignedInt);
+ llvm::Expected<uint64_t> int_bit_size =
+ int_type.GetBitSize(m_exe_ctx_scope.get());
+ if (!int_bit_size)
+ return int_bit_size.takeError();
+ llvm::Expected<uint64_t> uint_bit_size =
+ uint_type.GetBitSize(m_exe_ctx_scope.get());
+ if (!uint_bit_size)
+ return int_bit_size.takeError();
+ if (bitfield_size < *int_bit_size ||
+ (in_type.IsSigned() && bitfield_size == *int_bit_size))
+ return valobj->CastToBasicType(int_type);
+ if (bitfield_size <= *uint_bit_size)
+ return valobj->CastToBasicType(uint_type);
+ // Re-create as a const value with the same underlying type
+ Scalar scalar;
+ bool resolved = valobj->ResolveValue(scalar);
+ if (!resolved)
+ return llvm::createStringError("invalid scalar value");
+ return ValueObject::CreateValueObjectFromScalar(m_target, scalar, in_type,
+ "result");
+ }
+ }
+
+ if (in_type.IsArrayType())
+ valobj = ArrayToPointerConversion(*valobj, *m_exe_ctx_scope);
+
+ if (valobj->GetCompilerType().IsInteger() ||
+ valobj->GetCompilerType().IsUnscopedEnumerationType()) {
+ llvm::Expected<CompilerType> promoted_type =
+ type_system.get()->DoIntegralPromotion(valobj->GetCompilerType(),
+ m_exe_ctx_scope.get());
+ if (!promoted_type)
+ return promoted_type.takeError();
+ if (!promoted_type->CompareTypes(valobj->GetCompilerType()))
+ return valobj->CastToBasicType(*promoted_type);
+ }
+
+ return valobj;
+}
+
static lldb::VariableSP DILFindVariable(ConstString name,
VariableList &variable_list) {
lldb::VariableSP exact_match;
@@ -147,6 +242,10 @@ Interpreter::Interpreter(lldb::TargetSP target, llvm::StringRef expr,
llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) {
// Evaluate an AST.
auto value_or_error = node->Accept(this);
+ // Convert SP with a nullptr to an error.
+ if (value_or_error && !*value_or_error)
+ return llvm::make_error<DILDiagnosticError>(m_expr, "invalid value object",
+ node->GetLocation());
// Return the computed value-or-error. The caller is responsible for
// checking if an error occured during the evaluation.
return value_or_error;
@@ -175,21 +274,21 @@ Interpreter::Visit(const IdentifierNode *node) {
llvm::Expected<lldb::ValueObjectSP>
Interpreter::Visit(const UnaryOpNode *node) {
Status error;
- auto rhs_or_err = Evaluate(node->GetOperand());
- if (!rhs_or_err)
- return rhs_or_err;
+ auto op_or_err = Evaluate(node->GetOperand());
+ if (!op_or_err)
+ return op_or_err;
- lldb::ValueObjectSP rhs = *rhs_or_err;
+ lldb::ValueObjectSP operand = *op_or_err;
switch (node->GetKind()) {
case UnaryOpKind::Deref: {
- lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(m_use_dynamic);
- if (dynamic_rhs)
- rhs = dynamic_rhs;
+ lldb::ValueObjectSP dynamic_op = operand->GetDynamicValue(m_use_dynamic);
+ if (dynamic_op)
+ operand = dynamic_op;
- lldb::ValueObjectSP child_sp = rhs->Dereference(error);
+ lldb::ValueObjectSP child_sp = operand->Dereference(error);
if (!child_sp && m_use_synthetic) {
- if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) {
+ if (lldb::ValueObjectSP synth_obj_sp = operand->GetSyntheticValue()) {
error.Clear();
child_sp = synth_obj_sp->Dereference(error);
}
@@ -202,18 +301,69 @@ Interpreter::Visit(const UnaryOpNode *node) {
}
case UnaryOpKind::AddrOf: {
Status error;
- lldb::ValueObjectSP value = rhs->AddressOf(error);
+ lldb::ValueObjectSP value = operand->AddressOf(error);
if (error.Fail())
return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),
node->GetLocation());
return value;
}
+ case UnaryOpKind::Minus: {
+ if (operand->GetCompilerType().IsReferenceType()) {
+ operand = operand->Dereference(error);
+ if (error.Fail())
+ return error.ToError();
+ }
+ llvm::Expected<lldb::ValueObjectSP> conv_op =
+ UnaryConversion(operand, node->GetOperand()->GetLocation());
+ if (!conv_op)
+ return conv_op;
+ operand = *conv_op;
+ CompilerType operand_type = operand->GetCompilerType();
+ if (!operand_type.IsScalarType()) {
+ std::string errMsg =
+ llvm::formatv("invalid argument type '{0}' to unary expression",
+ operand_type.GetTypeName());
+ return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
+ node->GetLocation());
+ }
+ Scalar scalar;
+ bool resolved = operand->ResolveValue(scalar);
+ if (!resolved)
+ break;
+
+ bool negated = scalar.UnaryNegate();
+ if (negated)
+ return ValueObject::CreateValueObjectFromScalar(
+ m_target, scalar, operand->GetCompilerType(), "result");
+ break;
}
-
- // Unsupported/invalid operation.
- return llvm::make_error<DILDiagnosticError>(
- m_expr, "invalid ast: unexpected binary operator", node->GetLocation());
+ case UnaryOpKind::Plus: {
+ if (operand->GetCompilerType().IsReferenceType()) {
+ operand = operand->Dereference(error);
+ if (error.Fail())
+ return error.ToError();
+ }
+ llvm::Expected<lldb::ValueObjectSP> conv_op =
+ UnaryConversion(operand, node->GetOperand()->GetLocation());
+ if (!conv_op)
+ return conv_op;
+ operand = *conv_op;
+ CompilerType operand_type = operand->GetCompilerType();
+ if (!operand_type.IsScalarType() &&
+ // Unary plus is allowed for pointers.
+ !operand_type.IsPointerType()) {
+ std::string errMsg =
+ llvm::formatv("invalid argument type '{0}' to unary expression",
+ operand_type.GetTypeName());
+ return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
+ node->GetLocation());
+ }
+ return operand;
+ }
+ }
+ return llvm::make_error<DILDiagnosticError>(m_expr, "invalid unary operation",
+ node->GetLocation());
}
llvm::Expected<lldb::ValueObjectSP>
@@ -499,24 +649,6 @@ 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,
@@ -608,4 +740,16 @@ Interpreter::Visit(const BooleanLiteralNode *node) {
return ValueObject::CreateValueObjectFromBool(m_target, value, "result");
}
+llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const CastNode *node) {
+ auto operand_or_err = Evaluate(node->GetOperand());
+ if (!operand_or_err)
+ return operand_or_err;
+
+ lldb::ValueObjectSP operand = *operand_or_err;
+ // Don't actually do the cast for now -- that code will be added later.
+ // For now just return an error message.
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "Type casting is not supported here.", node->GetLocation());
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index 566bcaf..e94ce31 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -12,8 +12,10 @@
//===----------------------------------------------------------------------===//
#include "lldb/ValueObject/DILParser.h"
+#include "lldb/Host/common/DiagnosticsRendering.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/ExecutionContextScope.h"
-#include "lldb/Utility/DiagnosticsRendering.h"
+#include "lldb/Target/LanguageRuntime.h"
#include "lldb/ValueObject/DILAST.h"
#include "lldb/ValueObject/DILEval.h"
#include "llvm/ADT/StringRef.h"
@@ -80,26 +82,77 @@ ASTNodeUP DILParser::Run() {
// Parse an expression.
//
// expression:
-// unary_expression
+// cast_expression
//
-ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); }
+ASTNodeUP DILParser::ParseExpression() { return ParseCastExpression(); }
+
+// Parse a cast_expression.
+//
+// cast_expression:
+// unary_expression
+// "(" type_id ")" cast_expression
+
+ASTNodeUP DILParser::ParseCastExpression() {
+ if (!CurToken().Is(Token::l_paren))
+ return ParseUnaryExpression();
+
+ // This could be a type cast, try parsing the contents as a type declaration.
+ Token token = CurToken();
+ uint32_t loc = token.GetLocation();
+
+ // Enable lexer backtracking, so that we can rollback in case it's not
+ // actually a type declaration.
+
+ // Start tentative parsing (save token location/idx, for possible rollback).
+ uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx();
+
+ // Consume the token only after enabling the backtracking.
+ m_dil_lexer.Advance();
+
+ // Try parsing the type declaration. If the returned value is not valid,
+ // then we should rollback and try parsing the expression.
+ auto type_id = ParseTypeId();
+ if (type_id) {
+ // Successfully parsed the type declaration. Commit the backtracked
+ // tokens and parse the cast_expression.
+
+ if (!type_id.value().IsValid())
+ return std::make_unique<ErrorNode>();
+
+ Expect(Token::r_paren);
+ m_dil_lexer.Advance();
+ auto rhs = ParseCastExpression();
+
+ return std::make_unique<CastNode>(loc, type_id.value(), std::move(rhs),
+ CastKind::eNone);
+ }
+
+ // Failed to parse the contents of the parentheses as a type declaration.
+ // Rollback the lexer and try parsing it as unary_expression.
+ TentativeParsingRollback(save_token_idx);
+
+ return ParseUnaryExpression();
+}
// Parse an unary_expression.
//
// unary_expression:
// postfix_expression
-// unary_operator expression
+// unary_operator cast_expression
//
// unary_operator:
// "&"
// "*"
+// "+"
+// "-"
//
ASTNodeUP DILParser::ParseUnaryExpression() {
- if (CurToken().IsOneOf({Token::amp, Token::star})) {
+ if (CurToken().IsOneOf(
+ {Token::amp, Token::star, Token::minus, Token::plus})) {
Token token = CurToken();
uint32_t loc = token.GetLocation();
m_dil_lexer.Advance();
- auto rhs = ParseExpression();
+ auto rhs = ParseCastExpression();
switch (token.GetKind()) {
case Token::star:
return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Deref,
@@ -107,7 +160,12 @@ ASTNodeUP DILParser::ParseUnaryExpression() {
case Token::amp:
return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::AddrOf,
std::move(rhs));
-
+ case Token::minus:
+ return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Minus,
+ std::move(rhs));
+ case Token::plus:
+ return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Plus,
+ std::move(rhs));
default:
llvm_unreachable("invalid token kind");
}
@@ -274,6 +332,81 @@ std::string DILParser::ParseNestedNameSpecifier() {
}
}
+// Parse a type_id.
+//
+// type_id:
+// type_specifier_seq [abstract_declarator]
+//
+// type_specifier_seq:
+// type_specifier [type_specifier]
+//
+// type_specifier:
+// ["::"] [nested_name_specifier] type_name // not handled for now!
+// builtin_typename
+//
+std::optional<CompilerType> DILParser::ParseTypeId() {
+ CompilerType type;
+ // For now only allow builtin types -- will expand add to this later.
+ auto maybe_builtin_type = ParseBuiltinType();
+ if (maybe_builtin_type) {
+ type = *maybe_builtin_type;
+ } else
+ return {};
+
+ //
+ // abstract_declarator:
+ // ptr_operator [abstract_declarator]
+ //
+ std::vector<Token> ptr_operators;
+ while (CurToken().IsOneOf({Token::star, Token::amp})) {
+ Token tok = CurToken();
+ ptr_operators.push_back(std::move(tok));
+ m_dil_lexer.Advance();
+ }
+ type = ResolveTypeDeclarators(type, ptr_operators);
+
+ return type;
+}
+
+// Parse a built-in type
+//
+// builtin_typename:
+// identifer_seq
+//
+// identifier_seq
+// identifer [identifier_seq]
+//
+// A built-in type can be a single identifier or a space-separated
+// list of identifiers (e.g. "short" or "long long").
+std::optional<CompilerType> DILParser::ParseBuiltinType() {
+ std::string type_name = "";
+ uint32_t save_token_idx = m_dil_lexer.GetCurrentTokenIdx();
+ bool first_word = true;
+ while (CurToken().GetKind() == Token::identifier) {
+ if (CurToken().GetSpelling() == "const" ||
+ CurToken().GetSpelling() == "volatile")
+ continue;
+ if (!first_word)
+ type_name.push_back(' ');
+ else
+ first_word = false;
+ type_name.append(CurToken().GetSpelling());
+ m_dil_lexer.Advance();
+ }
+
+ if (type_name.size() > 0) {
+ lldb::TargetSP target_sp = m_ctx_scope->CalculateTarget();
+ ConstString const_type_name(type_name.c_str());
+ for (auto type_system_sp : target_sp->GetScratchTypeSystems())
+ if (auto compiler_type =
+ type_system_sp->GetBuiltinTypeByName(const_type_name))
+ return compiler_type;
+ }
+
+ TentativeParsingRollback(save_token_idx);
+ return {};
+}
+
// Parse an id_expression.
//
// id_expression:
@@ -339,6 +472,40 @@ std::string DILParser::ParseUnqualifiedId() {
return identifier;
}
+CompilerType
+DILParser::ResolveTypeDeclarators(CompilerType type,
+ const std::vector<Token> &ptr_operators) {
+ // Resolve pointers/references.
+ for (Token tk : ptr_operators) {
+ uint32_t loc = tk.GetLocation();
+ if (tk.GetKind() == Token::star) {
+ // Pointers to reference types are forbidden.
+ if (type.IsReferenceType()) {
+ BailOut(llvm::formatv("'type name' declared as a pointer to a "
+ "reference of type {0}",
+ type.TypeDescription()),
+ loc, CurToken().GetSpelling().length());
+ return {};
+ }
+ // Get pointer type for the base type: e.g. int* -> int**.
+ type = type.GetPointerType();
+
+ } else if (tk.GetKind() == Token::amp) {
+ // References to references are forbidden.
+ // FIXME: In future we may want to allow rvalue references (i.e. &&).
+ if (type.IsReferenceType()) {
+ BailOut("type name declared as a reference to a reference", loc,
+ CurToken().GetSpelling().length());
+ return {};
+ }
+ // Get reference type for the base type: e.g. int -> int&.
+ type = type.GetLValueReferenceType();
+ }
+ }
+
+ return type;
+}
+
// Parse an boolean_literal.
//
// boolean_literal:
diff --git a/lldb/source/ValueObject/ValueObjectSynthetic.cpp b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
index f673c51..44e53bd 100644
--- a/lldb/source/ValueObject/ValueObjectSynthetic.cpp
+++ b/lldb/source/ValueObject/ValueObjectSynthetic.cpp
@@ -443,3 +443,18 @@ void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
else
this->ValueObject::SetLanguageFlags(flags);
}
+
+void ValueObjectSynthetic::GetExpressionPath(Stream &stream,
+ GetExpressionPathFormat epformat) {
+ // A synthetic ValueObject may wrap an underlying Register or RegisterSet
+ // ValueObject, which requires a different approach to generating the
+ // expression path. In such cases, delegate to the non-synthetic value object.
+ if (const lldb::ValueType obj_value_type = GetValueType();
+ IsSynthetic() && (obj_value_type == lldb::eValueTypeRegister ||
+ obj_value_type == lldb::eValueTypeRegisterSet)) {
+
+ if (const lldb::ValueObjectSP raw_value = GetNonSyntheticValue())
+ return raw_value->GetExpressionPath(stream, epformat);
+ }
+ return ValueObject::GetExpressionPath(stream, epformat);
+}
diff --git a/lldb/source/Version/CMakeLists.txt b/lldb/source/Version/CMakeLists.txt
index 8b0acb9..d179805 100644
--- a/lldb/source/Version/CMakeLists.txt
+++ b/lldb/source/Version/CMakeLists.txt
@@ -40,4 +40,7 @@ add_lldb_library(lldbVersion NO_PLUGIN_DEPENDENCIES
ADDITIONAL_HEADERS
${version_inc}
${vcs_version_inc}
+
+ CLANG_LIBS
+ clangBasic
)