summaryrefslogtreecommitdiff
path: root/lldb/source
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/API/SBCommandInterpreter.cpp2
-rw-r--r--lldb/source/API/SBFrame.cpp16
-rw-r--r--lldb/source/API/SBFunction.cpp9
-rw-r--r--lldb/source/API/SBHostOS.cpp10
-rw-r--r--lldb/source/API/SBSymbol.cpp9
-rw-r--r--lldb/source/API/SBThread.cpp107
-rw-r--r--lldb/source/Commands/CommandObjectBreakpoint.cpp36
-rw-r--r--lldb/source/Commands/CommandObjectCommands.cpp4
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.cpp11
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.h1
-rw-r--r--lldb/source/Commands/CommandObjectFrame.cpp11
-rw-r--r--lldb/source/Commands/CommandObjectLog.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectMemory.cpp7
-rw-r--r--lldb/source/Commands/CommandObjectMultiword.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectProcess.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectProtocolServer.cpp15
-rw-r--r--lldb/source/Commands/CommandObjectSource.cpp6
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp9
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp2
-rw-r--r--lldb/source/Commands/CommandObjectWatchpoint.cpp24
-rw-r--r--lldb/source/Commands/CommandObjectWatchpointCommand.cpp6
-rw-r--r--lldb/source/Commands/Options.td3240
-rw-r--r--lldb/source/Core/CoreProperties.td4
-rw-r--r--lldb/source/Core/Disassembler.cpp156
-rw-r--r--lldb/source/Core/FormatEntity.cpp16
-rw-r--r--lldb/source/Core/Mangled.cpp15
-rw-r--r--lldb/source/Core/ModuleList.cpp15
-rw-r--r--lldb/source/Core/ProtocolServer.cpp34
-rw-r--r--lldb/source/Expression/DWARFExpression.cpp10
-rw-r--r--lldb/source/Expression/DWARFExpressionList.cpp2
-rw-r--r--lldb/source/Expression/Expression.cpp29
-rw-r--r--lldb/source/Expression/IRExecutionUnit.cpp59
-rw-r--r--lldb/source/Expression/IRMemoryMap.cpp13
-rw-r--r--lldb/source/Host/common/Editline.cpp30
-rw-r--r--lldb/source/Host/common/File.cpp34
-rw-r--r--lldb/source/Host/common/HostInfoBase.cpp38
-rw-r--r--lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm12
-rw-r--r--lldb/source/Host/windows/Host.cpp46
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp37
-rw-r--r--lldb/source/Interpreter/CommandObject.cpp12
-rw-r--r--lldb/source/Interpreter/Options.cpp38
-rw-r--r--lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp7
-rw-r--r--lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp186
-rw-r--r--lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h5
-rw-r--r--lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp12
-rw-r--r--lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h3
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp22
-rw-r--r--lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp19
-rw-r--r--lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp8
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp372
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h70
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp24
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp67
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.h17
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp29
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp59
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp22
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp10
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp41
-rw-r--r--lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp35
-rw-r--r--lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h3
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp122
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp329
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h13
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp557
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h53
-rw-r--r--lldb/source/Plugins/Process/Utility/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp11
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h11
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp117
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h42
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h14
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp46
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.h14
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp27
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h1
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterUtilities.h5
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp2
-rw-r--r--lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp17
-rw-r--r--lldb/source/Plugins/Process/scripted/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp191
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedFrame.h63
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedThread.cpp82
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedThread.h5
-rw-r--r--lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp129
-rw-r--r--lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h24
-rw-r--r--lldb/source/Plugins/Protocol/MCP/Resource.cpp15
-rw-r--r--lldb/source/Plugins/Protocol/MCP/Resource.h15
-rw-r--r--lldb/source/Plugins/Protocol/MCP/Tool.cpp12
-rw-r--r--lldb/source/Plugins/Protocol/MCP/Tool.h8
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h1
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp157
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h59
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp3
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp17
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h5
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp5
-rw-r--r--lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp18
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp185
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h15
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp1
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp110
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h8
-rw-r--r--lldb/source/Protocol/MCP/CMakeLists.txt2
-rw-r--r--lldb/source/Protocol/MCP/Protocol.cpp203
-rw-r--r--lldb/source/Protocol/MCP/Server.cpp291
-rw-r--r--lldb/source/Protocol/MCP/Transport.cpp23
-rw-r--r--lldb/source/Symbol/ObjectFile.cpp2
-rw-r--r--lldb/source/Target/ABI.cpp4
-rw-r--r--lldb/source/Target/InstrumentationRuntimeStopInfo.cpp42
-rw-r--r--lldb/source/Target/Process.cpp8
-rw-r--r--lldb/source/Target/RegisterContextUnwind.cpp44
-rw-r--r--lldb/source/Target/StackFrame.cpp40
-rw-r--r--lldb/source/Target/StackFrameList.cpp8
-rw-r--r--lldb/source/Target/StackID.cpp11
-rw-r--r--lldb/source/Target/Statistics.cpp20
-rw-r--r--lldb/source/Target/StopInfo.cpp105
-rw-r--r--lldb/source/Utility/ArchSpec.cpp163
-rw-r--r--lldb/source/ValueObject/DILAST.cpp9
-rw-r--r--lldb/source/ValueObject/DILEval.cpp254
-rw-r--r--lldb/source/ValueObject/DILLexer.cpp57
-rw-r--r--lldb/source/ValueObject/DILParser.cpp67
127 files changed, 5806 insertions, 3211 deletions
diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp
index 4ea79d336e08..34323bc5a2c3 100644
--- a/lldb/source/API/SBCommandInterpreter.cpp
+++ b/lldb/source/API/SBCommandInterpreter.cpp
@@ -208,7 +208,7 @@ void SBCommandInterpreter::HandleCommandsFromFile(
LLDB_INSTRUMENT_VA(this, file, override_context, options, result);
if (!IsValid()) {
- result->AppendError("SBCommandInterpreter is not valid.");
+ result->AppendError("SBCommandInterpreter is not valid");
return;
}
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
index b12cfceacd75..b6724bb0c411 100644
--- a/lldb/source/API/SBFrame.cpp
+++ b/lldb/source/API/SBFrame.cpp
@@ -1118,6 +1118,22 @@ bool SBFrame::IsArtificial() const {
return false;
}
+bool SBFrame::IsSynthetic() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ llvm::Expected<StoppedExecutionContext> exe_ctx =
+ GetStoppedExecutionContext(m_opaque_sp);
+ if (!exe_ctx) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
+ return false;
+ }
+
+ if (StackFrame *frame = exe_ctx->GetFramePtr())
+ return frame->IsSynthetic();
+
+ return false;
+}
+
bool SBFrame::IsHidden() const {
LLDB_INSTRUMENT_VA(this);
diff --git a/lldb/source/API/SBFunction.cpp b/lldb/source/API/SBFunction.cpp
index 19861f6af364..65b02d6b309c 100644
--- a/lldb/source/API/SBFunction.cpp
+++ b/lldb/source/API/SBFunction.cpp
@@ -79,6 +79,15 @@ const char *SBFunction::GetMangledName() const {
return nullptr;
}
+const char *SBFunction::GetBaseName() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (!m_opaque_ptr)
+ return nullptr;
+
+ return m_opaque_ptr->GetMangled().GetBaseName().AsCString();
+}
+
bool SBFunction::operator==(const SBFunction &rhs) const {
LLDB_INSTRUMENT_VA(this, rhs);
diff --git a/lldb/source/API/SBHostOS.cpp b/lldb/source/API/SBHostOS.cpp
index a77a703bba37..cd9b8571df3e 100644
--- a/lldb/source/API/SBHostOS.cpp
+++ b/lldb/source/API/SBHostOS.cpp
@@ -86,15 +86,7 @@ SBFileSpec SBHostOS::GetLLDBPath(lldb::PathType path_type) {
SBFileSpec SBHostOS::GetUserHomeDirectory() {
LLDB_INSTRUMENT();
-
- FileSpec homedir;
- FileSystem::Instance().GetHomeDirectory(homedir);
- FileSystem::Instance().Resolve(homedir);
-
- SBFileSpec sb_fspec;
- sb_fspec.SetFileSpec(homedir);
-
- return sb_fspec;
+ return HostInfo::GetUserHomeDir();
}
lldb::thread_t SBHostOS::ThreadCreate(const char *name,
diff --git a/lldb/source/API/SBSymbol.cpp b/lldb/source/API/SBSymbol.cpp
index 3b59119494f3..3030c8329212 100644
--- a/lldb/source/API/SBSymbol.cpp
+++ b/lldb/source/API/SBSymbol.cpp
@@ -79,6 +79,15 @@ const char *SBSymbol::GetMangledName() const {
return name;
}
+const char *SBSymbol::GetBaseName() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (!m_opaque_ptr)
+ return nullptr;
+
+ return m_opaque_ptr->GetMangled().GetBaseName().AsCString();
+}
+
bool SBSymbol::operator==(const SBSymbol &rhs) const {
LLDB_INSTRUMENT_VA(this, rhs);
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index ec68b2a4b6f3..4e4aa48bc9a2 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -157,52 +157,8 @@ size_t SBThread::GetStopReasonDataCount() {
if (exe_ctx) {
if (exe_ctx->HasThreadScope()) {
StopInfoSP stop_info_sp = exe_ctx->GetThreadPtr()->GetStopInfo();
- if (stop_info_sp) {
- StopReason reason = stop_info_sp->GetStopReason();
- switch (reason) {
- case eStopReasonInvalid:
- case eStopReasonNone:
- case eStopReasonTrace:
- case eStopReasonExec:
- case eStopReasonPlanComplete:
- case eStopReasonThreadExiting:
- case eStopReasonInstrumentation:
- case eStopReasonProcessorTrace:
- case eStopReasonVForkDone:
- case eStopReasonHistoryBoundary:
- // There is no data for these stop reasons.
- return 0;
-
- case eStopReasonBreakpoint: {
- break_id_t site_id = stop_info_sp->GetValue();
- lldb::BreakpointSiteSP bp_site_sp(
- exe_ctx->GetProcessPtr()->GetBreakpointSiteList().FindByID(
- site_id));
- if (bp_site_sp)
- return bp_site_sp->GetNumberOfConstituents() * 2;
- else
- return 0; // Breakpoint must have cleared itself...
- } break;
-
- case eStopReasonWatchpoint:
- return 1;
-
- case eStopReasonSignal:
- return 1;
-
- case eStopReasonInterrupt:
- return 1;
-
- case eStopReasonException:
- return 1;
-
- case eStopReasonFork:
- return 1;
-
- case eStopReasonVFork:
- return 1;
- }
- }
+ if (stop_info_sp)
+ return stop_info_sp->GetStopReasonDataCount();
}
} else {
LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
@@ -220,63 +176,8 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
if (exe_ctx->HasThreadScope()) {
Thread *thread = exe_ctx->GetThreadPtr();
StopInfoSP stop_info_sp = thread->GetStopInfo();
- if (stop_info_sp) {
- StopReason reason = stop_info_sp->GetStopReason();
- switch (reason) {
- case eStopReasonInvalid:
- case eStopReasonNone:
- case eStopReasonTrace:
- case eStopReasonExec:
- case eStopReasonPlanComplete:
- case eStopReasonThreadExiting:
- case eStopReasonInstrumentation:
- case eStopReasonProcessorTrace:
- case eStopReasonVForkDone:
- case eStopReasonHistoryBoundary:
- // There is no data for these stop reasons.
- return 0;
-
- case eStopReasonBreakpoint: {
- break_id_t site_id = stop_info_sp->GetValue();
- lldb::BreakpointSiteSP bp_site_sp(
- exe_ctx->GetProcessPtr()->GetBreakpointSiteList().FindByID(
- site_id));
- if (bp_site_sp) {
- uint32_t bp_index = idx / 2;
- BreakpointLocationSP bp_loc_sp(
- bp_site_sp->GetConstituentAtIndex(bp_index));
- if (bp_loc_sp) {
- if (idx & 1) {
- // Odd idx, return the breakpoint location ID
- return bp_loc_sp->GetID();
- } else {
- // Even idx, return the breakpoint ID
- return bp_loc_sp->GetBreakpoint().GetID();
- }
- }
- }
- return LLDB_INVALID_BREAK_ID;
- } break;
-
- case eStopReasonWatchpoint:
- return stop_info_sp->GetValue();
-
- case eStopReasonSignal:
- return stop_info_sp->GetValue();
-
- case eStopReasonInterrupt:
- return stop_info_sp->GetValue();
-
- case eStopReasonException:
- return stop_info_sp->GetValue();
-
- case eStopReasonFork:
- return stop_info_sp->GetValue();
-
- case eStopReasonVFork:
- return stop_info_sp->GetValue();
- }
- }
+ if (stop_info_sp)
+ return stop_info_sp->GetStopReasonDataAtIndex(idx);
}
} else {
LLDB_LOG_ERROR(GetLog(LLDBLog::API), exe_ctx.takeError(), "{0}");
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp
index 38ec375c0307..de0a7e709341 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -609,12 +609,12 @@ protected:
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.");
+ result.AppendError("no file supplied and no default file available");
return;
}
} else if (num_files > 1) {
- result.AppendError("Only one file at a time is allowed for file and "
- "line breakpoints.");
+ result.AppendError("only one file at a time is allowed for file and "
+ "line breakpoints");
return;
} else
file = m_options.m_filenames.GetFileSpecAtIndex(0);
@@ -784,7 +784,7 @@ protected:
}
result.SetStatus(eReturnStatusSuccessFinishResult);
} else if (!bp_sp) {
- result.AppendError("Breakpoint creation failed: No breakpoint created.");
+ result.AppendError("breakpoint creation failed: no breakpoint created");
}
}
@@ -940,7 +940,7 @@ protected:
size_t num_breakpoints = breakpoints.GetSize();
if (num_breakpoints == 0) {
- result.AppendError("No breakpoints exist to be enabled.");
+ result.AppendError("no breakpoints exist to be enabled");
return;
}
@@ -1048,7 +1048,7 @@ protected:
size_t num_breakpoints = breakpoints.GetSize();
if (num_breakpoints == 0) {
- result.AppendError("No breakpoints exist to be disabled.");
+ result.AppendError("no breakpoints exist to be disabled");
return;
}
@@ -1224,7 +1224,7 @@ protected:
}
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else {
- result.AppendError("Invalid breakpoint ID.");
+ result.AppendError("invalid breakpoint ID");
}
}
}
@@ -1318,7 +1318,7 @@ protected:
// Early return if there's no breakpoint at all.
if (num_breakpoints == 0) {
- result.AppendError("Breakpoint clear: No breakpoint cleared.");
+ result.AppendError("breakpoint clear: no breakpoint cleared");
return;
}
@@ -1364,7 +1364,7 @@ protected:
output_stream.EOL();
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else {
- result.AppendError("Breakpoint clear: No breakpoint cleared.");
+ result.AppendError("breakpoint clear: no breakpoint cleared");
}
}
@@ -1459,7 +1459,7 @@ protected:
size_t num_breakpoints = breakpoints.GetSize();
if (num_breakpoints == 0) {
- result.AppendError("No breakpoints exist to be deleted.");
+ result.AppendError("no breakpoints exist to be deleted");
return;
}
@@ -1504,7 +1504,7 @@ protected:
}
}
if (valid_bp_ids.GetSize() == 0) {
- result.AppendError("No disabled breakpoints.");
+ result.AppendError("no disabled breakpoints");
return;
}
} else {
@@ -1712,7 +1712,7 @@ protected:
const size_t argc = command.GetArgumentCount();
if (argc == 0) {
- result.AppendError("No names provided.");
+ result.AppendError("no names provided");
return;
}
@@ -1799,7 +1799,7 @@ public:
protected:
void DoExecute(Args &command, CommandReturnObject &result) override {
if (!m_name_options.m_name.OptionWasSet()) {
- result.AppendError("No name option provided.");
+ result.AppendError("no name option provided");
return;
}
@@ -1813,7 +1813,7 @@ protected:
size_t num_breakpoints = breakpoints.GetSize();
if (num_breakpoints == 0) {
- result.AppendError("No breakpoints, cannot add names.");
+ result.AppendError("no breakpoints, cannot add names");
return;
}
@@ -1825,7 +1825,7 @@ protected:
if (result.Succeeded()) {
if (valid_bp_ids.GetSize() == 0) {
- result.AppendError("No breakpoints specified, cannot add names.");
+ result.AppendError("no breakpoints specified, cannot add names");
return;
}
size_t num_valid_ids = valid_bp_ids.GetSize();
@@ -1873,7 +1873,7 @@ public:
protected:
void DoExecute(Args &command, CommandReturnObject &result) override {
if (!m_name_options.m_name.OptionWasSet()) {
- result.AppendError("No name option provided.");
+ result.AppendError("no name option provided");
return;
}
@@ -1887,7 +1887,7 @@ protected:
size_t num_breakpoints = breakpoints.GetSize();
if (num_breakpoints == 0) {
- result.AppendError("No breakpoints, cannot delete names.");
+ result.AppendError("no breakpoints, cannot delete names");
return;
}
@@ -1899,7 +1899,7 @@ protected:
if (result.Succeeded()) {
if (valid_bp_ids.GetSize() == 0) {
- result.AppendError("No breakpoints specified, cannot delete names.");
+ result.AppendError("no breakpoints specified, cannot delete names");
return;
}
ConstString bp_name(m_name_options.m_name.GetCurrentValue());
diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp
index 3049eb8c20db..a3293f0f7966 100644
--- a/lldb/source/Commands/CommandObjectCommands.cpp
+++ b/lldb/source/Commands/CommandObjectCommands.cpp
@@ -418,7 +418,7 @@ protected:
if ((pos != std::string::npos) && (pos > 0))
raw_command_string = raw_command_string.substr(pos);
} else {
- result.AppendError("Error parsing command string. No alias created.");
+ result.AppendError("error parsing command string. No alias created");
return;
}
@@ -2888,7 +2888,7 @@ protected:
size_t num_args = command.GetArgumentCount();
if (num_args == 0) {
- result.AppendError("No command was specified.");
+ result.AppendError("no command was specified");
return;
}
diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp
index 70e687e19ac6..c0553d2c6c8b 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -154,6 +154,10 @@ Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
}
} break;
+ case 'v':
+ enable_variable_annotations = true;
+ break;
+
case '\x01':
force = true;
break;
@@ -180,6 +184,7 @@ void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
end_addr = LLDB_INVALID_ADDRESS;
symbol_containing_addr = LLDB_INVALID_ADDRESS;
raw = false;
+ enable_variable_annotations = false;
plugin_name.clear();
Target *target =
@@ -503,8 +508,9 @@ void CommandObjectDisassemble::DoExecute(Args &command,
"\"disassemble\" arguments are specified as options.\n");
const int terminal_width =
GetCommandInterpreter().GetDebugger().GetTerminalWidth();
+ const bool use_color = GetCommandInterpreter().GetDebugger().GetUseColor();
GetOptions()->GenerateOptionUsage(result.GetErrorStream(), *this,
- terminal_width);
+ terminal_width, use_color);
return;
}
@@ -528,6 +534,9 @@ void CommandObjectDisassemble::DoExecute(Args &command,
if (m_options.raw)
options |= Disassembler::eOptionRawOuput;
+ if (m_options.enable_variable_annotations)
+ options |= Disassembler::eOptionVariableAnnotations;
+
llvm::Expected<std::vector<AddressRange>> ranges =
GetRangesForSelectedMode(result);
if (!ranges) {
diff --git a/lldb/source/Commands/CommandObjectDisassemble.h b/lldb/source/Commands/CommandObjectDisassemble.h
index 4fbcd72d1c04..eed44adce5ff 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.h
+++ b/lldb/source/Commands/CommandObjectDisassemble.h
@@ -78,6 +78,7 @@ public:
// in SetOptionValue if anything the selects a location is set.
lldb::addr_t symbol_containing_addr = 0;
bool force = false;
+ bool enable_variable_annotations = false;
};
CommandObjectDisassemble(CommandInterpreter &interpreter);
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 56926999d167..88a02dce35b9 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -140,7 +140,7 @@ protected:
} else {
StopInfoSP stop_info_sp = thread->GetStopInfo();
if (!stop_info_sp) {
- result.AppendError("No arguments provided, and no stop info.");
+ result.AppendError("no arguments provided, and no stop info");
return;
}
@@ -148,7 +148,7 @@ protected:
}
if (!valobj_sp) {
- result.AppendError("No diagnosis available.");
+ result.AppendError("no diagnosis available");
return;
}
@@ -310,7 +310,7 @@ protected:
if (frame_idx == 0) {
// If you are already at the bottom of the stack, then just warn
// and don't reset the frame.
- result.AppendError("Already at the bottom of the stack.");
+ result.AppendError("already at the bottom of the stack");
return;
} else
frame_idx = 0;
@@ -335,7 +335,7 @@ protected:
if (frame_idx == num_frames - 1) {
// If we are already at the top of the stack, just warn and don't
// reset the frame.
- result.AppendError("Already at the top of the stack.");
+ result.AppendError("already at the top of the stack");
return;
} else
frame_idx = num_frames - 1;
@@ -349,7 +349,8 @@ protected:
command[0].c_str());
m_options.GenerateOptionUsage(
result.GetErrorStream(), *this,
- GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
+ GetCommandInterpreter().GetDebugger().GetUseColor());
return;
}
diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp
index 17efae189b05..0c01da0b5683 100644
--- a/lldb/source/Commands/CommandObjectLog.cpp
+++ b/lldb/source/Commands/CommandObjectLog.cpp
@@ -547,7 +547,7 @@ protected:
Timer::SetQuiet(!increment);
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else
- result.AppendError("Could not convert increment value to boolean.");
+ result.AppendError("could not convert increment value to boolean");
}
if (!result.Succeeded()) {
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
index af1ff3e84510..5786e757ef7e 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -365,6 +365,8 @@ protected:
return;
}
+ ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
+
CompilerType compiler_type;
Status error;
@@ -520,7 +522,7 @@ protected:
--pointer_count;
}
- auto size_or_err = compiler_type.GetByteSize(nullptr);
+ auto size_or_err = compiler_type.GetByteSize(exe_scope);
if (!size_or_err) {
result.AppendErrorWithFormat(
"unable to get the byte size of the type '%s'\n%s",
@@ -640,7 +642,7 @@ protected:
if (!m_format_options.GetFormatValue().OptionWasSet())
m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
- auto size_or_err = compiler_type.GetByteSize(nullptr);
+ auto size_or_err = compiler_type.GetByteSize(exe_scope);
if (!size_or_err) {
result.AppendError(llvm::toString(size_or_err.takeError()));
return;
@@ -800,7 +802,6 @@ protected:
output_stream_p = &result.GetOutputStream();
}
- ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
if (compiler_type.GetOpaqueQualType()) {
for (uint32_t i = 0; i < item_count; ++i) {
addr_t item_addr = addr + (i * item_byte_size);
diff --git a/lldb/source/Commands/CommandObjectMultiword.cpp b/lldb/source/Commands/CommandObjectMultiword.cpp
index c99b75ff2914..a369557cca84 100644
--- a/lldb/source/Commands/CommandObjectMultiword.cpp
+++ b/lldb/source/Commands/CommandObjectMultiword.cpp
@@ -159,7 +159,7 @@ void CommandObjectMultiword::Execute(const char *args_string,
auto sub_command = args[0].ref();
if (sub_command.empty()) {
- result.AppendError("Need to specify a non-empty subcommand.");
+ result.AppendError("need to specify a non-empty subcommand");
return;
}
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 84c576e721e7..7d326404a550 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -259,7 +259,7 @@ protected:
if (!exe_module_sp)
exe_module_sp = target->GetExecutableModule();
if (!exe_module_sp) {
- result.AppendWarning("Could not get executable module after launch.");
+ result.AppendWarning("could not get executable module after launch");
} else {
const char *archname =
diff --git a/lldb/source/Commands/CommandObjectProtocolServer.cpp b/lldb/source/Commands/CommandObjectProtocolServer.cpp
index f11e27f01c8a..c5ab9e9f05be 100644
--- a/lldb/source/Commands/CommandObjectProtocolServer.cpp
+++ b/lldb/source/Commands/CommandObjectProtocolServer.cpp
@@ -15,6 +15,7 @@
#include "lldb/Utility/UriParser.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/FormatAdapters.h"
+#include <string>
using namespace llvm;
using namespace lldb;
@@ -28,7 +29,7 @@ public:
CommandObjectProtocolServerStart(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "protocol-server start",
"start protocol server",
- "protocol-server start <protocol> <connection>") {
+ "protocol-server start <protocol> [<connection>]") {
AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain);
}
@@ -51,15 +52,13 @@ protected:
return;
}
- if (args.GetArgumentCount() < 2) {
- result.AppendError("no connection specified");
- return;
- }
- llvm::StringRef connection_uri = args.GetArgumentAtIndex(1);
+ std::string connection_uri = "listen://[localhost]:0";
+ if (args.GetArgumentCount() >= 2)
+ connection_uri = args.GetArgumentAtIndex(1);
const char *connection_error =
- "unsupported connection specifier, expected 'accept:///path' or "
- "'listen://[host]:port', got '{0}'.";
+ "unsupported connection specifier, expected 'accept:///path' "
+ "or 'listen://[host]:port', got '{0}'.";
auto uri = lldb_private::URI::Parse(connection_uri);
if (!uri) {
result.AppendErrorWithFormatv(connection_error, connection_uri);
diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp
index 7e7d3f065b62..0b4599b16ef0 100644
--- a/lldb/source/Commands/CommandObjectSource.cpp
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -513,7 +513,7 @@ protected:
"No selected frame to use to find the default source.");
return false;
} else if (!cur_frame->HasDebugInformation()) {
- result.AppendError("No debug info for the selected frame.");
+ result.AppendError("no debug info for the selected frame");
return false;
} else {
const SymbolContext &sc =
@@ -553,11 +553,11 @@ protected:
}
}
if (!m_module_list.GetSize()) {
- result.AppendError("No modules match the input.");
+ result.AppendError("no modules match the input");
return;
}
} else if (target.GetImages().GetSize() == 0) {
- result.AppendError("The target has no associated executable images.");
+ result.AppendError("the target has no associated executable images");
return;
}
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index dbebbbd38093..004542e3e6ae 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -2420,7 +2420,7 @@ protected:
result.GetErrorStream().SetAddressByteSize(addr_byte_size);
if (command.GetArgumentCount() == 0) {
- result.AppendError("file option must be specified.");
+ result.AppendError("file option must be specified");
return;
} else {
// Dump specified images (by basename or fullpath)
@@ -3565,13 +3565,13 @@ protected:
ThreadList threads(process->GetThreadList());
if (threads.GetSize() == 0) {
- result.AppendError("The process must be paused to use this command.");
+ result.AppendError("the process must be paused to use this command");
return;
}
ThreadSP thread(threads.GetThreadAtIndex(0));
if (!thread) {
- result.AppendError("The process must be paused to use this command.");
+ result.AppendError("the process must be paused to use this command");
return;
}
@@ -4075,7 +4075,8 @@ public:
default:
m_options.GenerateOptionUsage(
result.GetErrorStream(), *this,
- GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
+ GetCommandInterpreter().GetDebugger().GetUseColor());
syntax_error = true;
break;
}
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 57c23d533fb9..bbec714642ec 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -1570,7 +1570,7 @@ protected:
uint32_t frame_idx = frame_sp->GetFrameIndex();
if (frame_sp->IsInlined()) {
- result.AppendError("Don't know how to return from inlined frames.");
+ result.AppendError("don't know how to return from inlined frames");
return;
}
diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp
index e79c3b8939fa..12effed12a3c 100644
--- a/lldb/source/Commands/CommandObjectWatchpoint.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -44,7 +44,7 @@ static bool CheckTargetForWatchpointOperations(Target &target,
bool process_is_valid =
target.GetProcessSP() && target.GetProcessSP()->IsAlive();
if (!process_is_valid) {
- result.AppendError("There's no process or it is not alive.");
+ result.AppendError("there's no process or it is not alive");
return false;
}
// Target passes our checks, return true.
@@ -243,7 +243,7 @@ protected:
std::vector<uint32_t> wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
target, command, wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
@@ -298,7 +298,7 @@ protected:
size_t num_watchpoints = watchpoints.GetSize();
if (num_watchpoints == 0) {
- result.AppendError("No watchpoints exist to be enabled.");
+ result.AppendError("no watchpoints exist to be enabled");
return;
}
@@ -314,7 +314,7 @@ protected:
std::vector<uint32_t> wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
target, command, wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
@@ -366,7 +366,7 @@ protected:
size_t num_watchpoints = watchpoints.GetSize();
if (num_watchpoints == 0) {
- result.AppendError("No watchpoints exist to be disabled.");
+ result.AppendError("no watchpoints exist to be disabled");
return;
}
@@ -385,7 +385,7 @@ protected:
std::vector<uint32_t> wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
target, command, wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
@@ -476,7 +476,7 @@ protected:
size_t num_watchpoints = watchpoints.GetSize();
if (num_watchpoints == 0) {
- result.AppendError("No watchpoints exist to be deleted.");
+ result.AppendError("no watchpoints exist to be deleted");
return;
}
@@ -500,7 +500,7 @@ protected:
std::vector<uint32_t> wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
@@ -596,7 +596,7 @@ protected:
size_t num_watchpoints = watchpoints.GetSize();
if (num_watchpoints == 0) {
- result.AppendError("No watchpoints exist to be ignored.");
+ result.AppendError("no watchpoints exist to be ignored");
return;
}
@@ -611,7 +611,7 @@ protected:
std::vector<uint32_t> wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
target, command, wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
@@ -715,7 +715,7 @@ protected:
size_t num_watchpoints = watchpoints.GetSize();
if (num_watchpoints == 0) {
- result.AppendError("No watchpoints exist to be modified.");
+ result.AppendError("no watchpoints exist to be modified");
return;
}
@@ -728,7 +728,7 @@ protected:
std::vector<uint32_t> wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
target, command, wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
diff --git a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
index 32cb80b421fd..062bf75eb8ae 100644
--- a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -376,7 +376,7 @@ protected:
std::vector<uint32_t> valid_wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
valid_wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
@@ -470,7 +470,7 @@ protected:
std::vector<uint32_t> valid_wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
valid_wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
@@ -525,7 +525,7 @@ protected:
std::vector<uint32_t> valid_wp_ids;
if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
valid_wp_ids)) {
- result.AppendError("Invalid watchpoints specification.");
+ result.AppendError("invalid watchpoints specification");
return;
}
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 17d72cdcad12..595b3d08abec 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1,232 +1,354 @@
include "OptionsBase.td"
let Command = "target modules dump symtab" in {
- def tm_sort : Option<"sort", "s">, Group<1>,
- Desc<"Supply a sort order when dumping the symbol table.">,
- EnumArg<"SortOrder">;
- def tm_smn : Option<"show-mangled-names", "m">, Group<1>,
- Desc<"Do not demangle symbol names before showing them.">;
+ def tm_sort : Option<"sort", "s">,
+ Group<1>,
+ Desc<"${S}upply a sort order when dumping the symbol table.">,
+ EnumArg<"SortOrder">;
+ def tm_smn : Option<"show-mangled-names", "m">,
+ Group<1>,
+ Desc<"Do not de${m}angle symbol names before showing them.">;
}
let Command = "target modules dump separate debug info" in {
- def tm_json : Option<"json", "j">, Group<1>,
- Desc<"Output the details in JSON format.">;
- def tm_errors_only : Option<"errors-only", "e">, Group<1>,
- Desc<"Filter to show only debug info files with errors.">;
- def tm_force_load_all_debug_info : Option<"force-load-all-debug-info", "f">,
- Group<1>,
- Desc<"Load all debug info files.">;
+ def tm_json : Option<"json", "j">,
+ Group<1>,
+ Desc<"Output the details in ${J}SON format.">;
+ def tm_errors_only
+ : Option<"errors-only", "e">,
+ Group<1>,
+ Desc<"Filter to show only debug info files with ${e}rrors.">;
+ def tm_force_load_all_debug_info
+ : Option<"force-load-all-debug-info", "f">,
+ Group<1>,
+ Desc<"${F}orce load all debug info files.">;
}
let Command = "help" in {
def help_hide_aliases : Option<"hide-aliases", "a">,
- Desc<"Hide aliases in the command list.">;
+ Desc<"Hide ${a}liases in the command list.">;
def help_hide_user : Option<"hide-user-commands", "u">,
- Desc<"Hide user-defined commands from the list.">;
+ Desc<"Hide ${u}ser-defined commands from the list.">;
def help_show_hidden : Option<"show-hidden-commands", "h">,
- Desc<"Include commands prefixed with an underscore.">;
+ Desc<"Include commands prefixed with an underscore.">;
}
let Command = "settings set" in {
- def setset_global : Option<"global", "g">,
- Desc<"Apply the new value to the global default value.">;
- def setset_force : Option<"force", "f">,
- Desc<"Force an empty value to be accepted as the default.">;
- def setset_exists : Option<"exists", "e">,
- Desc<"Set the setting if it exists, but do not cause the command to raise "
- "an error if it does not exist.">;
+ def setset_global
+ : Option<"global", "g">,
+ Desc<"Apply the new value to the ${g}lobal default value.">;
+ def setset_force
+ : Option<"force", "f">,
+ Desc<"${F}orce an empty value to be accepted as the default.">;
+ def setset_exists
+ : Option<"exists", "e">,
+ Desc<"Set the setting if it ${e}xists, but do not cause the command to "
+ "raise an error if it does not exist.">;
}
let Command = "settings write" in {
- def setwrite_file : Option<"file", "f">, Required, Arg<"Filename">,
- Completion<"DiskFile">,
- Desc<"The file into which to write the settings.">;
+ def setwrite_file : Option<"file", "f">,
+ Required,
+ Arg<"Filename">,
+ Completion<"DiskFile">,
+ Desc<"The ${f}ile into which to write the settings.">;
def setwrite_append : Option<"append", "a">,
- Desc<"Append to saved settings file if it exists.">;
+ Desc<"${A}ppend to saved settings file if it exists.">;
}
let Command = "settings read" in {
- def setread_file : Option<"file", "f">, Required, Arg<"Filename">,
- Completion<"DiskFile">,
- Desc<"The file from which to read the settings.">;
+ def setread_file : Option<"file", "f">,
+ Required,
+ Arg<"Filename">,
+ Completion<"DiskFile">,
+ Desc<"The ${f}ile from which to read the settings.">;
}
let Command = "settings clear" in {
- def setclear_all : Option<"all", "a">,
- Desc<"Clear all settings.">;
+ def setclear_all : Option<"all", "a">, Desc<"Clear ${a}ll settings.">;
}
let Command = "settings show" in {
def setshow_defaults : Option<"defaults", "d">,
- Desc<"Include default values if defined.">;
+ Desc<"Include ${d}efault values if defined.">;
}
let Command = "breakpoint list" in {
// FIXME: We need to add an "internal" command, and then add this sort of
// thing to it. But I need to see it for now, and don't want to wait.
def blist_internal : Option<"internal", "i">,
- Desc<"Show debugger internal breakpoints">;
- def blist_brief : Option<"brief", "b">, Group<1>,
- Desc<"Give a brief description of the breakpoint (no location info).">;
- def blist_full : Option<"full", "f">, Group<2>,
- Desc<"Give a full description of the breakpoint and its locations.">;
- def blist_verbose : Option<"verbose", "v">, Group<3>,
- Desc<"Explain everything we know about the breakpoint (for debugging "
- "debugger bugs).">;
- def blist_dummy_bp : Option<"dummy-breakpoints", "D">,
- Desc<"List Dummy breakpoints - i.e. breakpoints set before a file is "
- "provided, which prime new targets.">;
+ Desc<"Show debugger ${i}nternal breakpoints">;
+ def blist_brief : Option<"brief", "b">,
+ Group<1>,
+ Desc<"Give a ${b}rief description of the breakpoint (no "
+ "location info).">;
+ def blist_full
+ : Option<"full", "f">,
+ Group<2>,
+ Desc<"Give a ${f}ull description of the breakpoint and its locations.">;
+ def blist_verbose : Option<"verbose", "v">,
+ Group<3>,
+ Desc<"Explain everything we know about the breakpoint "
+ "(for debugging debugger bugs).">;
+ def blist_dummy_bp
+ : Option<"dummy-breakpoints", "D">,
+ Desc<"List ${D}ummy breakpoints - i.e. breakpoints set before a file "
+ "is provided, which prime new targets.">;
}
let Command = "breakpoint modify" in {
- def breakpoint_modify_ignore_count : Option<"ignore-count", "i">, Group<1>,
- Arg<"Count">,
- Desc<"Set the number of times this breakpoint is skipped before stopping.">;
- def breakpoint_modify_one_shot : Option<"one-shot", "o">, Group<1>,
- Arg<"Boolean">,
- Desc<"The breakpoint is deleted the first time it stop causes a stop.">;
- def breakpoint_modify_thread_index : Option<"thread-index", "x">, Group<1>,
- Arg<"ThreadIndex">, Desc<"The breakpoint stops only for the thread whose "
- "index matches this argument.">;
- def breakpoint_modify_thread_id : Option<"thread-id", "t">, Group<1>,
- Arg<"ThreadID">, Desc<"The breakpoint stops only for the thread whose TID "
- "matches this argument. The token 'current' resolves to the current thread's ID.">;
- def breakpoint_modify_thread_name : Option<"thread-name", "T">, Group<1>,
- Arg<"ThreadName">, Desc<"The breakpoint stops only for the thread whose "
- "thread name matches this argument.">;
- def breakpoint_modify_queue_name : Option<"queue-name", "q">, Group<1>,
- Arg<"QueueName">, Desc<"The breakpoint stops only for threads in the queue "
- "whose name is given by this argument.">;
- def breakpoint_modify_condition : Option<"condition", "c">, Group<1>,
- Arg<"Expression">, Desc<"The breakpoint stops only if this condition "
- "expression evaluates to true.">;
+ def breakpoint_modify_ignore_count
+ : Option<"ignore-count", "i">,
+ Group<1>,
+ Arg<"Count">,
+ Desc<"Set the number of times this breakpoint is skipped before "
+ "stopping.">;
+ def breakpoint_modify_one_shot
+ : Option<"one-shot", "o">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"The breakpoint is deleted the first time it causes a stop.">;
+ def breakpoint_modify_thread_index
+ : Option<"thread-index", "x">,
+ Group<1>,
+ Arg<"ThreadIndex">,
+ Desc<"The breakpoint stops only for the thread whose inde${x} matches "
+ "this argument.">;
+ def breakpoint_modify_thread_id
+ : Option<"thread-id", "t">,
+ Group<1>,
+ Arg<"ThreadID">,
+ Desc<"The breakpoint stops only for the ${t}hread whose TID matches "
+ "this argument. The token 'current' resolves to the current "
+ "thread's ID.">;
+ def breakpoint_modify_thread_name
+ : Option<"thread-name", "T">,
+ Group<1>,
+ Arg<"ThreadName">,
+ Desc<"The breakpoint stops only for the ${t}hread whose thread name "
+ "matches this argument.">;
+ def breakpoint_modify_queue_name
+ : Option<"queue-name", "q">,
+ Group<1>,
+ Arg<"QueueName">,
+ Desc<"The breakpoint stops only for threads in the ${q}ueue whose name "
+ "is given by this argument.">;
+ def breakpoint_modify_condition
+ : Option<"condition", "c">,
+ Group<1>,
+ Arg<"Expression">,
+ Desc<"The breakpoint stops only if this ${c}ondition expression "
+ "evaluates to true.">;
def breakpoint_modify_condition_language
: Option<"condition-language", "Y">,
Group<1>,
Arg<"Language">,
Desc<"Specifies the Language to use when executing the breakpoint's "
"condition expression.">;
- def breakpoint_modify_auto_continue : Option<"auto-continue", "G">, Group<1>,
- Arg<"Boolean">,
- Desc<"The breakpoint will auto-continue after running its commands.">;
- def breakpoint_modify_enable : Option<"enable", "e">, Group<2>,
- Desc<"Enable the breakpoint.">;
- def breakpoint_modify_disable : Option<"disable", "d">, Group<3>,
- Desc<"Disable the breakpoint.">;
- def breakpoint_modify_command : Option<"command", "C">, Group<4>,
- Arg<"Command">,
- Desc<"A command to run when the breakpoint is hit, can be provided more "
- "than once, the commands will be run in left-to-right order.">;
+ def breakpoint_modify_auto_continue
+ : Option<"auto-continue", "G">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"The breakpoint will auto-continue after running its commands.">;
+ def breakpoint_modify_enable : Option<"enable", "e">,
+ Group<2>,
+ Desc<"${E}nable the breakpoint.">;
+ def breakpoint_modify_disable : Option<"disable", "d">,
+ Group<3>,
+ Desc<"${D}isable the breakpoint.">;
+ def breakpoint_modify_command
+ : Option<"command", "C">,
+ Group<4>,
+ Arg<"Command">,
+ Desc<
+ "A ${c}ommand to run when the breakpoint is hit, can be provided "
+ "more than once, the commands will be run in left-to-right order.">;
}
let Command = "breakpoint dummy" in {
- def breakpoint_dummy_options_dummy_breakpoints :
- Option<"dummy-breakpoints", "D">, Group<1>,
- Desc<"Act on Dummy breakpoints - i.e. breakpoints set before a file is "
- "provided, which prime new targets.">;
+ def breakpoint_dummy_options_dummy_breakpoints
+ : Option<"dummy-breakpoints", "D">,
+ Group<1>,
+ Desc<"Act on ${D}ummy breakpoints - i.e. breakpoints set before a file "
+ "is provided, which prime new targets.">;
}
let Command = "breakpoint set" in {
- def breakpoint_set_shlib : Option<"shlib", "s">, Arg<"ShlibName">,
- Completion<"Module">, Groups<[1,2,3,4,5,6,7,8,9,11,12]>, // *not* in group 10
- Desc<"Set the breakpoint only in this shared library. Can repeat this "
- "option multiple times to specify multiple shared libraries.">;
- def breakpoint_set_hardware : Option<"hardware", "H">,
- Desc<"Require the breakpoint to use hardware breakpoints.">;
- def breakpoint_set_file : Option<"file", "f">, Arg<"Filename">,
- Completion<"SourceFile">, Groups<[1,3,4,5,6,7,8,9,11]>,
- Desc<"Specifies the source file in which to set this breakpoint. Note, by "
- "default lldb only looks for files that are #included if they use the "
- "standard include file extensions. To set breakpoints on .c/.cpp/.m/.mm "
- "files that are #included, set target.inline-breakpoint-strategy to "
- "\"always\".">;
- def breakpoint_set_line : Option<"line", "l">, Group<1>, Arg<"LineNum">,
- Required,
- Desc<"Specifies the line number on which to set this breakpoint.">;
- def breakpoint_set_column : Option<"column", "u">, Group<1>, Arg<"ColumnNum">,
- Desc<"Specifies the column number on which to set this breakpoint.">;
- def breakpoint_set_address : Option<"address", "a">, Group<2>,
- Arg<"AddressOrExpression">, Required,
- Desc<"Set the breakpoint at the specified address. If the address maps "
- "uniquely to a particular binary, then the address will be converted to "
- "a \"file\"address, so that the breakpoint will track that binary+offset "
- "no matter where the binary eventually loads. Alternately, if you also "
- "specify the module - with the -s option - then the address will be "
- "treated as a file address in that module, and resolved accordingly. "
- "Again, this will allow lldb to track that offset on subsequent reloads. "
- "The module need not have been loaded at the time you specify this "
- "breakpoint, and will get resolved when the module is loaded.">;
- def breakpoint_set_name : Option<"name", "n">, Group<3>, Arg<"FunctionName">,
- Completion<"Symbol">, Required,
- Desc<"Set the breakpoint by function name. Can be repeated multiple times "
- "to make one breakpoint for multiple names.">;
- def breakpoint_set_source_regexp_function :
- Option<"source-regexp-function", "X">, Group<9>, Arg<"FunctionName">,
- Completion<"Symbol">,
- Desc<"When used with '-p' limits the source regex to source contained in "
- "the named functions. Can be repeated multiple times.">;
- def breakpoint_set_fullname : Option<"fullname", "F">, Group<4>,
- Arg<"FullName">, Required, Completion<"Symbol">,
- Desc<"Set the breakpoint by fully qualified function names. For C++ this "
- "means namespaces and all arguments, and for Objective-C this means a full "
- "function prototype with class and selector. Can be repeated multiple times"
- " to make one breakpoint for multiple names.">;
- def breakpoint_set_selector : Option<"selector", "S">, Group<5>,
- Arg<"Selector">, Required,
- Desc<"Set the breakpoint by Objective-C selector name. Can be repeated "
- "multiple times to make one breakpoint for multiple Selectors.">;
- def breakpoint_set_method : Option<"method", "M">, Group<6>, Arg<"Method">,
- Required, Desc<"Set the breakpoint by C++ method names. Can be repeated "
- "multiple times to make one breakpoint for multiple methods.">;
- def breakpoint_set_func_regex : Option<"func-regex", "r">, Group<7>,
- Arg<"RegularExpression">, Required, Desc<"Set the breakpoint by function "
- "name, evaluating a regular-expression to find the function name(s).">;
- def breakpoint_set_basename : Option<"basename", "b">, Group<8>,
- Arg<"FunctionName">, Required, Completion<"Symbol">,
- Desc<"Set the breakpoint by function basename (C++ namespaces and arguments"
- " will be ignored). Can be repeated multiple times to make one breakpoint "
- "for multiple symbols.">;
- def breakpoint_set_source_pattern_regexp :
- Option<"source-pattern-regexp", "p">, Group<9>, Arg<"RegularExpression">,
- Required, Desc<"Set the breakpoint by specifying a regular expression which"
- " is matched against the source text in a source file or files specified "
- "with the -f can be specified more than once. If no source files "
- "are specified, uses the current \"default source file\". If you want to "
- "match against all source files, pass the \"--all-files\" option.">;
- def breakpoint_set_all_files : Option<"all-files", "A">, Group<9>,
- Desc<"All files are searched for source pattern matches.">;
- def breakpoint_set_language_exception : Option<"language-exception", "E">,
- Group<10>, Arg<"Language">, Required,
- Desc<"Set the breakpoint on exceptions thrown by the specified language "
- "(without options, on throw but not catch.)">;
- def breakpoint_set_on_throw : Option<"on-throw", "w">, Group<10>,
- Arg<"Boolean">, Desc<"Set the breakpoint on exception throW.">;
- def breakpoint_set_on_catch : Option<"on-catch", "h">, Group<10>,
- Arg<"Boolean">, Desc<"Set the breakpoint on exception catcH.">;
- def breakpoint_set_language : Option<"language", "L">, GroupRange<3, 8>,
- Arg<"Language">,
- Desc<"Specifies the Language to use when interpreting the breakpoint's "
- "expression (note: currently only implemented for setting breakpoints on "
- "identifiers). If not set the target.language setting is used.">;
- def breakpoint_set_skip_prologue : Option<"skip-prologue", "K">,
- Arg<"Boolean">, Groups<[1,3,4,5,6,7,8,12]>,
- Desc<"Skip the prologue if the breakpoint is at the beginning of a "
- "function. If not set the target.skip-prologue setting is used.">;
- def breakpoint_set_breakpoint_name : Option<"breakpoint-name", "N">,
- Arg<"BreakpointName">,
- Desc<"Adds this to the list of names for this breakpoint.">;
- def breakpoint_set_address_slide : Option<"address-slide", "R">,
- Arg<"Address">, Groups<[1,3,4,5,6,7,8,12]>,
- 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_set_move_to_nearest_code : Option<"move-to-nearest-code", "m">,
- Groups<[1,9,12]>, Arg<"Boolean">,
- Desc<"Move breakpoints to nearest code. If not set the "
- "target.move-to-nearest-code setting is used.">;
- def breakpoint_set_file_colon_line : Option<"joint-specifier", "y">, Group<12>, Arg<"FileLineColumn">,
- Required, Completion<"SourceFile">,
- Desc<"A specifier in the form filename:line[:column] for setting file & line breakpoints.">;
+ def breakpoint_set_shlib
+ : Option<"shlib", "s">,
+ Arg<"ShlibName">,
+ Completion<"Module">,
+ Groups<[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12]>, // *not* in group 10
+ Desc<
+ "${S}et the breakpoint only in this shared library. Can repeat "
+ "this option multiple times to specify multiple shared libraries.">;
+ def breakpoint_set_hardware
+ : Option<"hardware", "H">,
+ Desc<"Require the breakpoint to use ${h}ardware breakpoints.">;
+ def breakpoint_set_file
+ : Option<"file", "f">,
+ Arg<"Filename">,
+ Completion<"SourceFile">,
+ Groups<[1, 3, 4, 5, 6, 7, 8, 9, 11]>,
+ Desc<"Specifies the source ${f}ile in which to set this breakpoint. "
+ "Note, by default lldb only looks for files that are #included if "
+ "they use the standard include file extensions. To set "
+ "breakpoints on .c/.cpp/.m/.mm files that are #included, set "
+ "target.inline-breakpoint-strategy to \"always\".">;
+ def breakpoint_set_line
+ : Option<"line", "l">,
+ Group<1>,
+ Arg<"LineNum">,
+ Required,
+ Desc<"Specifies the ${l}ine number on which to set this breakpoint.">;
+ def breakpoint_set_column
+ : Option<"column", "u">,
+ Group<1>,
+ Arg<"ColumnNum">,
+ Desc<"Specifies the col${u}mn number on which to set this breakpoint.">;
+ def breakpoint_set_address
+ : Option<"address", "a">,
+ Group<2>,
+ Arg<"AddressOrExpression">,
+ Required,
+ Desc<"Set the breakpoint at the specified ${a}ddress. If the address "
+ "maps uniquely to a particular binary, then the address will be "
+ "converted to a \"file\"address, so that the breakpoint will "
+ "track that binary+offset no matter where the binary eventually "
+ "loads. Alternately, if you also specify the module - with the "
+ "-s option - then the address will be treated as a file address "
+ "in that module, and resolved accordingly. Again, this will "
+ "allow lldb to track that offset on subsequent reloads. The "
+ "module need not have been loaded at the time you specify this "
+ "breakpoint, and will get resolved when the module is loaded.">;
+ def breakpoint_set_name
+ : Option<"name", "n">,
+ Group<3>,
+ Arg<"FunctionName">,
+ Completion<"Symbol">,
+ Required,
+ Desc<"Set the breakpoint by function ${n}ame. Can be repeated "
+ "multiple times to make one breakpoint for multiple names.">;
+ def breakpoint_set_source_regexp_function
+ : Option<"source-regexp-function", "X">,
+ Group<9>,
+ Arg<"FunctionName">,
+ Completion<"Symbol">,
+ Desc<"When used with '-p' limits the source regex to source contained "
+ "in the named functions. Can be repeated multiple times.">;
+ def breakpoint_set_fullname
+ : Option<"fullname", "F">,
+ Group<4>,
+ Arg<"FullName">,
+ Required,
+ Completion<"Symbol">,
+ Desc<"Set the breakpoint by ${f}ully qualified function names. For C++ "
+ "this means namespaces and all arguments, and for Objective-C "
+ "this means a full function prototype with class and selector. "
+ "Can be repeated multiple times to make one breakpoint for "
+ "multiple names.">;
+ def breakpoint_set_selector
+ : Option<"selector", "S">,
+ Group<5>,
+ Arg<"Selector">,
+ Required,
+ Desc<"Set the breakpoint by Objective-C ${s}elector name. Can be "
+ "repeated multiple times to make one breakpoint for multiple "
+ "Selectors.">;
+ def breakpoint_set_method
+ : Option<"method", "M">,
+ Group<6>,
+ Arg<"Method">,
+ Required,
+ Desc<"Set the breakpoint by C++ ${m}ethod names. Can be repeated "
+ "multiple times to make one breakpoint for multiple methods.">;
+ def breakpoint_set_func_regex
+ : Option<"func-regex", "r">,
+ Group<7>,
+ Arg<"RegularExpression">,
+ Required,
+ Desc<"Set the breakpoint by function name, evaluating a "
+ "${r}egular-expression to find the function name(s).">;
+ def breakpoint_set_basename
+ : Option<"basename", "b">,
+ Group<8>,
+ Arg<"FunctionName">,
+ Required,
+ Completion<"Symbol">,
+ Desc<"Set the breakpoint by function ${b}asename (C++ namespaces and "
+ "arguments will be ignored). Can be repeated multiple times to "
+ "make one breakpoint for multiple symbols.">;
+ def breakpoint_set_source_pattern_regexp
+ : Option<"source-pattern-regexp", "p">,
+ Group<9>,
+ Arg<"RegularExpression">,
+ Required,
+ Desc<"Set the breakpoint by specifying a regular expression which is "
+ "matched against the source text in a source file or files "
+ "specified with the -f can be specified more than once. If no "
+ "source files are specified, uses the current \"default source "
+ "file\". If you want to match against all source files, ${p}ass "
+ "the \"--all-files\" option.">;
+ def breakpoint_set_all_files
+ : Option<"all-files", "A">,
+ Group<9>,
+ Desc<"${A}ll files are searched for source pattern matches.">;
+ def breakpoint_set_language_exception
+ : Option<"language-exception", "E">,
+ Group<10>,
+ Arg<"Language">,
+ Required,
+ Desc<"Set the breakpoint on ${e}xceptions thrown by the specified "
+ "language (without options, on throw but not catch.)">;
+ def breakpoint_set_on_throw
+ : Option<"on-throw", "w">,
+ Group<10>,
+ Arg<"Boolean">,
+ Desc<"Set the breakpoint on exception thro${w}.">;
+ def breakpoint_set_on_catch
+ : Option<"on-catch", "h">,
+ Group<10>,
+ Arg<"Boolean">,
+ Desc<"Set the breakpoint on exception catc${h}.">;
+ def breakpoint_set_language
+ : Option<"language", "L">,
+ GroupRange<3, 8>,
+ Arg<"Language">,
+ Desc<"Specifies the ${L}anguage to use when interpreting the "
+ "breakpoint's expression (note: currently only implemented for "
+ "setting breakpoints on identifiers). If not set the "
+ "target.language setting is used.">;
+ def breakpoint_set_skip_prologue
+ : Option<"skip-prologue", "K">,
+ Arg<"Boolean">,
+ Groups<[1, 3, 4, 5, 6, 7, 8, 12]>,
+ Desc<"S${k}ip the prologue if the breakpoint is at the beginning of a "
+ "function. If not set the target.skip-prologue setting is used.">;
+ def breakpoint_set_breakpoint_name
+ : Option<"breakpoint-name", "N">,
+ Arg<"BreakpointName">,
+ Desc<"Adds this to the list of ${n}ames for this breakpoint.">;
+ def breakpoint_set_address_slide
+ : Option<"address-slide", "R">,
+ Arg<"Address">,
+ Groups<[1, 3, 4, 5, 6, 7, 8, 12]>,
+ Desc<"Add the specified offset to whatever address(es) the breakpoint "
+ "${r}esolves to. At present this applies the offset directly as "
+ "given, and doesn't try to align it to instruction boundaries.">;
+ def breakpoint_set_move_to_nearest_code
+ : Option<"move-to-nearest-code", "m">,
+ Groups<[1, 9, 12]>,
+ Arg<"Boolean">,
+ Desc<"${M}ove breakpoints to nearest code. If not set the "
+ "target.move-to-nearest-code setting is used.">;
+ def breakpoint_set_file_colon_line
+ : Option<"joint-specifier", "y">,
+ Group<12>,
+ Arg<"FileLineColumn">,
+ Required,
+ Completion<"SourceFile">,
+ Desc<"A specifier in the form filename:line[:column] for setting file "
+ "& line breakpoints.">;
/* Don't add this option till it actually does something useful...
def breakpoint_set_exception_typename : Option<"exception-typename", "O">,
Arg<"TypeName">, Desc<"The breakpoint will only stop if an "
@@ -236,465 +358,743 @@ let Command = "breakpoint set" in {
}
let Command = "breakpoint clear" in {
- def breakpoint_clear_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
- Completion<"SourceFile">,
- Desc<"Specify the breakpoint by source location in this particular file.">;
- def breakpoint_clear_line : Option<"line", "l">, Group<1>, Arg<"LineNum">,
- Required,
- Desc<"Specify the breakpoint by source location at this particular line.">;
+ def breakpoint_clear_file : Option<"file", "f">,
+ Group<1>,
+ Arg<"Filename">,
+ Completion<"SourceFile">,
+ Desc<"Specify the breakpoint by source location "
+ "in this particular ${f}ile.">;
+ def breakpoint_clear_line : Option<"line", "l">,
+ Group<1>,
+ Arg<"LineNum">,
+ Required,
+ Desc<"Specify the breakpoint by source location "
+ "at this particular ${l}ine.">;
}
let Command = "breakpoint delete" in {
- def breakpoint_delete_force : Option<"force", "f">, Group<1>,
- Desc<"Delete all breakpoints without querying for confirmation.">;
- def breakpoint_delete_dummy_breakpoints : Option<"dummy-breakpoints", "D">,
- Group<1>, Desc<"Delete Dummy breakpoints - i.e. breakpoints set before a "
- "file is provided, which prime new targets.">;
- def breakpoint_delete_disabled : Option<"disabled", "d">, Group<1>,
- Desc<"Delete all breakpoints which are currently disabled. When using the disabled option "
- "any breakpoints listed on the command line are EXCLUDED from deletion.">;
+ def breakpoint_delete_force
+ : Option<"force", "f">,
+ Group<1>,
+ Desc<"Delete all breakpoints without querying for confirmation.">;
+ def breakpoint_delete_dummy_breakpoints
+ : Option<"dummy-breakpoints", "D">,
+ Group<1>,
+ Desc<"Delete Dummy breakpoints - i.e. breakpoints set before a file is "
+ "provided, which prime new targets.">;
+ def breakpoint_delete_disabled
+ : Option<"disabled", "d">,
+ Group<1>,
+ Desc<"${D}elete all breakpoints which are currently disabled. When "
+ "using the disabled option any breakpoints listed on the command "
+ "line are EXCLUDED from deletion.">;
}
let Command = "breakpoint name" in {
- def breakpoint_name_name : Option<"name", "N">, Group<1>,
- Arg<"BreakpointName">, Desc<"Specifies a breakpoint name to use.">;
- def breakpoint_name_breakpoint_id : Option<"breakpoint-id", "B">, Group<2>,
- Arg<"BreakpointID">, Desc<"Specify a breakpoint ID to use.">;
- def breakpoint_name_dummy_breakpoints : Option<"dummy-breakpoints", "D">,
- Group<3>, Desc<"Operate on Dummy breakpoints - i.e. breakpoints set before "
- "a file is provided, which prime new targets.">;
- def breakpoint_name_help_string : Option<"help-string", "H">, Group<4>,
- Arg<"None">, Desc<"A help string describing the purpose of this name.">;
+ def breakpoint_name_name : Option<"name", "N">,
+ Group<1>,
+ Arg<"BreakpointName">,
+ Desc<"Specifies a breakpoint name to use.">;
+ def breakpoint_name_breakpoint_id : Option<"breakpoint-id", "B">,
+ Group<2>,
+ Arg<"BreakpointID">,
+ Desc<"Specify a breakpoint ID to use.">;
+ def breakpoint_name_dummy_breakpoints
+ : Option<"dummy-breakpoints", "D">,
+ Group<3>,
+ Desc<"Operate on Dummy breakpoints - i.e. breakpoints set before a "
+ "file is provided, which prime new targets.">;
+ def breakpoint_name_help_string
+ : Option<"help-string", "H">,
+ Group<4>,
+ Arg<"None">,
+ Desc<"A help string describing the purpose of this name.">;
}
let Command = "breakpoint access" in {
- def breakpoint_access_allow_list : Option<"allow-list", "L">, Group<1>,
- Arg<"Boolean">, Desc<"Determines whether the breakpoint will show up in "
- "break list if not referred to explicitly.">;
- def breakpoint_access_allow_disable : Option<"allow-disable", "A">, Group<2>,
- Arg<"Boolean">, Desc<"Determines whether the breakpoint can be disabled by "
- "name or when all breakpoints are disabled.">;
- def breakpoint_access_allow_delete : Option<"allow-delete", "D">, Group<3>,
- Arg<"Boolean">, Desc<"Determines whether the breakpoint can be deleted by "
- "name or when all breakpoints are deleted.">;
+ def breakpoint_access_allow_list
+ : Option<"allow-list", "L">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"Determines whether the breakpoint will show up in break list if "
+ "not referred to explicitly.">;
+ def breakpoint_access_allow_disable
+ : Option<"allow-disable", "A">,
+ Group<2>,
+ Arg<"Boolean">,
+ Desc<"Determines whether the breakpoint can be disabled by name or "
+ "when all breakpoints are disabled.">;
+ def breakpoint_access_allow_delete
+ : Option<"allow-delete", "D">,
+ Group<3>,
+ Arg<"Boolean">,
+ Desc<"Determines whether the breakpoint can be deleted by name or when "
+ "all breakpoints are deleted.">;
}
let Command = "breakpoint read" in {
- def breakpoint_read_file : Option<"file", "f">, Arg<"Filename">, Required,
- Completion<"DiskFile">,
- Desc<"The file from which to read the breakpoints.">;
- def breakpoint_read_breakpoint_name : Option<"breakpoint-name", "N">,
- Arg<"BreakpointName">, Desc<"Only read in breakpoints with this name.">;
+ def breakpoint_read_file
+ : Option<"file", "f">,
+ Arg<"Filename">,
+ Required,
+ Completion<"DiskFile">,
+ Desc<"The ${f}ile from which to read the breakpoints.">;
+ def breakpoint_read_breakpoint_name
+ : Option<"breakpoint-name", "N">,
+ Arg<"BreakpointName">,
+ Desc<"Only read in breakpoints with this name.">;
}
let Command = "breakpoint write" in {
- def breakpoint_write_file : Option<"file", "f">, Arg<"Filename">, Required,
- Completion<"DiskFile">,
- Desc<"The file into which to write the breakpoints.">;
- def breakpoint_write_append : Option<"append", "a">,
- Desc<"Append to saved breakpoints file if it exists.">;
+ def breakpoint_write_file
+ : Option<"file", "f">,
+ Arg<"Filename">,
+ Required,
+ Completion<"DiskFile">,
+ Desc<"The ${f}ile into which to write the breakpoints.">;
+ def breakpoint_write_append
+ : Option<"append", "a">,
+ Desc<"${A}ppend to saved breakpoints file if it exists.">;
}
let Command = "breakpoint command add" in {
- def breakpoint_add_one_liner : Option<"one-liner", "o">, Group<1>,
- Arg<"OneLiner">, Desc<"Specify a one-line breakpoint command inline. Be "
- "sure to surround it with quotes.">;
- def breakpoint_add_stop_on_error : Option<"stop-on-error", "e">,
- Arg<"Boolean">, Desc<"Specify whether breakpoint command execution should "
- "terminate on error.">;
- def breakpoint_add_script_type : Option<"script-type", "s">,
- EnumArg<"ScriptLang">,
- Desc<"Specify the language for the commands - if none is specified, the "
- "lldb command interpreter will be used.">;
- def breakpoint_add_dummy_breakpoints : Option<"dummy-breakpoints", "D">,
- Desc<"Sets Dummy breakpoints - i.e. breakpoints set before a file is "
- "provided, which prime new targets.">;
+ def breakpoint_add_one_liner
+ : Option<"one-liner", "o">,
+ Group<1>,
+ Arg<"OneLiner">,
+ Desc<"Specify a ${o}ne-line breakpoint command inline. Be sure to "
+ "surround it with quotes.">;
+ def breakpoint_add_stop_on_error
+ : Option<"stop-on-error", "e">,
+ Arg<"Boolean">,
+ Desc<"Specify whether breakpoint command execution should terminate on "
+ "error.">;
+ def breakpoint_add_script_type
+ : Option<"script-type", "s">,
+ EnumArg<"ScriptLang">,
+ Desc<"Specify the language for the commands - if none is specified, "
+ "the lldb command interpreter will be used.">;
+ def breakpoint_add_dummy_breakpoints
+ : Option<"dummy-breakpoints", "D">,
+ Desc<"Sets Dummy breakpoints - i.e. breakpoints set before a file is "
+ "provided, which prime new targets.">;
}
let Command = "breakpoint command delete" in {
- def breakpoint_command_delete_dummy_breakpoints :
- Option<"dummy-breakpoints", "D">, Group<1>,
- Desc<"Delete commands from Dummy breakpoints - i.e. breakpoints set before "
- "a file is provided, which prime new targets.">;
+ def breakpoint_command_delete_dummy_breakpoints
+ : Option<"dummy-breakpoints", "D">,
+ Group<1>,
+ Desc<"Delete commands from Dummy breakpoints - i.e. breakpoints set "
+ "before a file is provided, which prime new targets.">;
}
let Command = "disassemble" in {
- def disassemble_options_bytes : Option<"bytes", "b">,
- Desc<"Show opcode bytes when disassembling.">;
- def disassemble_options_kind : Option<"kind", "k">,
- Desc<"Show instruction control flow kind. Refer to the enum "
- "`InstructionControlFlowKind` for a list of control flow kind. "
- "As an important note, far jumps, far calls and far returns often indicate "
- "calls to and from kernel.">;
- def disassemble_options_context : Option<"context", "C">, Arg<"NumLines">,
- Desc<"Number of context lines of source to show.">;
- def disassemble_options_mixed : Option<"mixed", "m">,
- Desc<"Enable mixed source and assembly display.">;
- def disassemble_options_raw : Option<"raw", "r">,
- Desc<"Print raw disassembly with no symbol information.">;
- def disassemble_options_plugin : Option<"plugin", "P">, Arg<"Plugin">,
- Desc<"Name of the disassembler plugin you want to use.">;
- def disassemble_options_flavor : Option<"flavor", "F">,
- Arg<"DisassemblyFlavor">, Desc<"Name of the disassembly flavor you want to "
- "use. Currently the only valid options are default, and for Intel "
- "architectures, att and intel.">;
- def disassemble_options_cpu : Option<"cpu", "X">, Arg<"CPUName">,
- Desc<"Override the CPU for disassembling.">;
- def disassemble_options_features : Option<"features", "Y">, Arg<"CPUFeatures">,
- Desc<"Specify additional CPU features for disassembling.">;
- def disassemble_options_arch : Option<"arch", "A">, Arg<"Architecture">,
- Desc<"Specify the architecture to use from cross disassembly.">;
- def disassemble_options_start_address : Option<"start-address", "s">,
- Groups<[1,2]>, Arg<"AddressOrExpression">, Required,
- Desc<"Address at which to start disassembling.">;
- def disassemble_options_end_address : Option<"end-address", "e">, Group<1>,
- Arg<"AddressOrExpression">, Desc<"Address at which to end disassembling.">;
- def disassemble_options_count : Option<"count", "c">, Groups<[2,3,4,5,7]>,
- Arg<"NumLines">, Desc<"Number of instructions to display.">;
- def disassemble_options_name : Option<"name", "n">, Group<3>,
- Arg<"FunctionName">, Completion<"Symbol">,
- Desc<"Disassemble entire contents of the given function name.">;
- def disassemble_options_frame : Option<"frame", "f">, Group<4>,
- Desc<"Disassemble from the start of the current frame's function.">;
- def disassemble_options_pc : Option<"pc", "p">, Group<5>,
- Desc<"Disassemble around the current pc.">;
- def disassemble_options_line : Option<"line", "l">, Group<6>,
- Desc<"Disassemble the current frame's current source line instructions if "
- "there is debug line table information, else disassemble around the pc.">;
- def disassemble_options_address : Option<"address", "a">, Group<7>,
- Arg<"AddressOrExpression">,
- Desc<"Disassemble function containing this address.">;
- def disassemble_options_force : Option<"force", "\\x01">, Groups<[2,3,4,5,7]>,
- Desc<"Force disassembly of large functions.">;
+ def disassemble_options_bytes
+ : Option<"bytes", "b">,
+ Desc<"Show opcode ${b}ytes when disassembling.">;
+ def disassemble_options_kind
+ : Option<"kind", "k">,
+ Desc<"Show instruction control flow ${k}ind. Refer to the enum "
+ "`InstructionControlFlowKind` for a list of control flow kind. As "
+ "an important note, far jumps, far calls and far returns often "
+ "indicate calls to and from kernel.">;
+ def disassemble_options_context
+ : Option<"context", "C">,
+ Arg<"NumLines">,
+ Desc<"Number of ${c}ontext lines of source to show.">;
+ def disassemble_options_mixed
+ : Option<"mixed", "m">,
+ Desc<"Enable ${m}ixed source and assembly display.">;
+ def disassemble_options_raw
+ : Option<"raw", "r">,
+ Desc<"Print ${r}aw disassembly with no symbol information.">;
+ def disassemble_options_plugin
+ : Option<"plugin", "P">,
+ Arg<"Plugin">,
+ Desc<"Name of the disassembler ${p}lugin you want to use.">;
+ def disassemble_options_flavor
+ : Option<"flavor", "F">,
+ Arg<"DisassemblyFlavor">,
+ Desc<"Name of the disassembly ${f}lavor you want to use. Currently the "
+ "only valid options are default, and for Intel architectures, att "
+ "and intel.">;
+ def disassemble_options_cpu : Option<"cpu", "X">,
+ Arg<"CPUName">,
+ Desc<"Override the CPU for disassembling.">;
+ def disassemble_options_features
+ : Option<"features", "Y">,
+ Arg<"CPUFeatures">,
+ Desc<"Specify additional CPU features for disassembling.">;
+ def disassemble_options_arch
+ : Option<"arch", "A">,
+ Arg<"Architecture">,
+ Desc<"Specify the ${a}rchitecture to use for cross disassembly.">;
+ def disassemble_options_start_address
+ : Option<"start-address", "s">,
+ Groups<[1, 2]>,
+ Arg<"AddressOrExpression">,
+ Required,
+ Desc<"Address at which to ${s}tart disassembling.">;
+ def disassemble_options_end_address
+ : Option<"end-address", "e">,
+ Group<1>,
+ Arg<"AddressOrExpression">,
+ Desc<"Address at which to ${e}nd disassembling.">;
+ def disassemble_options_count : Option<"count", "c">,
+ Groups<[2, 3, 4, 5, 7]>,
+ Arg<"NumLines">,
+ Desc<"Number of instructions to display.">;
+ def disassemble_options_name
+ : Option<"name", "n">,
+ Group<3>,
+ Arg<"FunctionName">,
+ Completion<"Symbol">,
+ Desc<"Disassemble entire contents of the given function ${n}ame.">;
+ def disassemble_options_frame
+ : Option<"frame", "f">,
+ Group<4>,
+ Desc<"Disassemble from the start of the current frame's function.">;
+ def disassemble_options_pc : Option<"pc", "p">,
+ Group<5>,
+ Desc<"Disassemble around the current ${p}c.">;
+ def disassemble_options_line
+ : Option<"line", "l">,
+ Group<6>,
+ Desc<"Disassemble the current frame's current source ${l}ine "
+ "instructions if there is debug line table information, else "
+ "disassemble around the pc.">;
+ def disassemble_options_address
+ : Option<"address", "a">,
+ Group<7>,
+ Arg<"AddressOrExpression">,
+ Desc<"Disassemble function containing this ${a}ddress.">;
+ def disassemble_options_force : Option<"force", "\\x01">,
+ Groups<[2, 3, 4, 5, 7]>,
+ Desc<"Force disassembly of large functions.">;
+ def disassemble_options_variable
+ : Option<"variable", "v">,
+ Desc<"Enable ${v}ariable disassembly annotations for this invocation.">;
}
let Command = "diagnostics dump" in {
- def diagnostics_dump_directory : Option<"directory", "d">, Group<1>,
- Arg<"Path">, Desc<"Dump the diagnostics to the given directory.">;
+ def diagnostics_dump_directory
+ : Option<"directory", "d">,
+ Group<1>,
+ Arg<"Path">,
+ Desc<"Dump the diagnostics to the given directory.">;
}
let Command = "expression" in {
- def expression_options_all_threads : Option<"all-threads", "a">,
- Groups<[1,2]>, Arg<"Boolean">, Desc<"Should we run all threads if the "
- "execution doesn't complete on one thread.">;
- def expression_options_ignore_breakpoints : Option<"ignore-breakpoints", "i">,
- Groups<[1,2]>, Arg<"Boolean">,
- Desc<"Ignore breakpoint hits while running expressions">;
- def expression_options_timeout : Option<"timeout", "t">, Groups<[1,2]>,
- Arg<"UnsignedInteger">,
- Desc<"Timeout value (in microseconds) for running the expression.">;
- def expression_options_unwind_on_error : Option<"unwind-on-error", "u">,
- Groups<[1,2]>, Arg<"Boolean">,
- Desc<"Clean up program state if the expression causes a crash, or raises a "
- "signal. Note, unlike gdb hitting a breakpoint is controlled by another "
- "option (-i).">;
- def expression_options_debug : Option<"debug", "g">, Groups<[1,2]>,
- Desc<"When specified, debug the JIT code by setting a breakpoint on the "
- "first instruction and forcing breakpoints to not be ignored (-i0) and no "
- "unwinding to happen on error (-u0).">;
- def expression_options_language : Option<"language", "l">, Groups<[1,2,3]>,
- Arg<"Language">, Desc<"Specifies the Language to use when parsing the "
- "expression. If not set the target.language setting is used.">;
- def expression_options_apply_fixits : Option<"apply-fixits", "X">,
- Groups<[1,2]>, Arg<"Boolean">, Desc<"If true, simple fix-it hints will be "
- "automatically applied to the expression.">;
- def expression_options_description_verbosity :
- Option<"description-verbosity", "v">, Group<1>,
- OptionalEnumArg<"DescriptionVerbosity">,
- Desc<"How verbose should the output of this expression be, if the object "
- "description is asked for.">;
- def expression_options_top_level : Option<"top-level", "p">, Groups<[1,2]>,
- Desc<"Interpret the expression as a complete translation unit, without "
- "injecting it into the local context. Allows declaration of persistent, "
- "top-level entities without a $ prefix.">;
- def expression_options_allow_jit : Option<"allow-jit", "j">, Groups<[1,2]>,
- Arg<"Boolean">,
- Desc<"Controls whether the expression can fall back to being JITted if it's "
- "not supported by the interpreter (defaults to true).">;
- def persistent_result : Option<"persistent-result", "\\x01">, Groups<[1,2]>,
- Arg<"Boolean">,
- Desc<"Persist expression result in a variable for subsequent use. "
- "Expression results will be labeled with $-prefixed variables, e.g. $0, "
- "$1, etc.">;
+ def expression_options_all_threads
+ : Option<"all-threads", "a">,
+ Groups<[1, 2]>,
+ Arg<"Boolean">,
+ Desc<
+ "Should we run ${a}ll threads if the execution doesn't complete on "
+ "one thread.">;
+ def expression_options_ignore_breakpoints
+ : Option<"ignore-breakpoints", "i">,
+ Groups<[1, 2]>,
+ Arg<"Boolean">,
+ Desc<"${I}gnore breakpoint hits while running expressions">;
+ def expression_options_timeout
+ : Option<"timeout", "t">,
+ Groups<[1, 2]>,
+ Arg<"UnsignedInteger">,
+ Desc<"${T}imeout value (in microseconds) for running the expression.">;
+ def expression_options_unwind_on_error
+ : Option<"unwind-on-error", "u">,
+ Groups<[1, 2]>,
+ Arg<"Boolean">,
+ Desc<"Clean up program state if the expression causes a crash, or "
+ "raises a signal. Note, unlike gdb hitting a breakpoint is "
+ "controlled by another option (-i).">;
+ def expression_options_debug
+ : Option<"debug", "g">,
+ Groups<[1, 2]>,
+ Desc<"When specified, debug the JIT code by setting a breakpoint on "
+ "the first instruction and forcing breakpoints to not be ignored "
+ "(-i0) and no unwinding to happen on error (-u0).">;
+ def expression_options_language
+ : Option<"language", "l">,
+ Groups<[1, 2, 3]>,
+ Arg<"Language">,
+ Desc<"Specifies the Language to use when parsing the expression. If "
+ "not set the target.language setting is used.">;
+ def expression_options_apply_fixits
+ : Option<"apply-fixits", "X">,
+ Groups<[1, 2]>,
+ Arg<"Boolean">,
+ Desc<"If true, simple fix-it hints will be automatically applied to "
+ "the expression.">;
+ def expression_options_description_verbosity
+ : Option<"description-verbosity", "v">,
+ Group<1>,
+ OptionalEnumArg<"DescriptionVerbosity">,
+ Desc<"How verbose should the output of this expression be, if the "
+ "object description is asked for.">;
+ def expression_options_top_level
+ : Option<"top-level", "p">,
+ Groups<[1, 2]>,
+ Desc<"Interpret the expression as a complete translation unit, without "
+ "injecting it into the local context. Allows declaration of "
+ "persistent, top-level entities without a $ prefix.">;
+ def expression_options_allow_jit
+ : Option<"allow-jit", "j">,
+ Groups<[1, 2]>,
+ Arg<"Boolean">,
+ Desc<"Controls whether the expression can fall back to being JITted if "
+ "it's not supported by the interpreter (defaults to true).">;
+ def persistent_result
+ : Option<"persistent-result", "\\x01">,
+ Groups<[1, 2]>,
+ Arg<"Boolean">,
+ Desc<"Persist expression result in a variable for subsequent use. "
+ "Expression results will be labeled with $-prefixed variables, "
+ "e.g. $0, $1, etc.">;
}
let Command = "frame diag" in {
- def frame_diag_register : Option<"register", "r">, Group<1>,
- Arg<"RegisterName">, Desc<"A register to diagnose.">;
- def frame_diag_address : Option<"address", "a">, Group<1>, Arg<"Address">,
- Desc<"An address to diagnose.">;
- def frame_diag_offset : Option<"offset", "o">, Group<1>, Arg<"Offset">,
- Desc<"An optional offset. Requires --register.">;
+ def frame_diag_register : Option<"register", "r">,
+ Group<1>,
+ Arg<"RegisterName">,
+ Desc<"A register to diagnose.">;
+ def frame_diag_address : Option<"address", "a">,
+ Group<1>,
+ Arg<"Address">,
+ Desc<"An address to diagnose.">;
+ def frame_diag_offset : Option<"offset", "o">,
+ Group<1>,
+ Arg<"Offset">,
+ Desc<"An optional offset. Requires --register.">;
}
let Command = "frame select" in {
- def frame_select_relative : Option<"relative", "r">, Group<1>, Arg<"Offset">,
- Desc<"A relative frame index offset from the current frame index.">;
+ def frame_select_relative
+ : Option<"relative", "r">,
+ Group<1>,
+ Arg<"Offset">,
+ Desc<"A relative frame index offset from the current frame index.">;
}
let Command = "frame recognizer add" in {
- def frame_recognizer_shlib : Option<"shlib", "s">, Arg<"ShlibName">,
- Completion<"Module">,
- Desc<"Name of the module or shared library that this recognizer applies "
- "to.">;
- def frame_recognizer_function : Option<"function", "n">, Arg<"Name">,
- Completion<"Symbol">,
- Desc<"Name of the function that this recognizer applies to. "
- "Can be specified more than once except if -x|--regex is provided.">;
- def frame_recognizer_python_class : Option<"python-class", "l">, Group<2>,
- Arg<"PythonClass">,
- Desc<"Give the name of a Python class to use for this frame recognizer.">;
- def frame_recognizer_regex : Option<"regex", "x">,
- Desc<"Function name and module name are actually regular expressions.">;
- def frame_recognizer_first_instruction_only : Option<"first-instruction-only", "f">, Arg<"Boolean">,
- Desc<"If true, only apply this recognizer to frames whose PC currently points to the "
- "first instruction of the specified function. If false, the recognizer "
- "will always be applied, regardless of the current position within the specified function. The "
- "implementer should keep in mind that some features, e.g. accessing function argument "
- "values via $arg<N>, are not guaranteed to work reliably in this case, so extra care must "
- "be taken to make the recognizer operate correctly. Defaults to true.">;
+ def frame_recognizer_shlib : Option<"shlib", "s">,
+ Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"Name of the module or shared library that "
+ "this recognizer applies to.">;
+ def frame_recognizer_function
+ : Option<"function", "n">,
+ Arg<"Name">,
+ Completion<"Symbol">,
+ Desc<"Name of the function that this recognizer applies to. Can be "
+ "specified more than once except if -x|--regex is provided.">;
+ def frame_recognizer_python_class : Option<"python-class", "l">,
+ Group<2>,
+ Arg<"PythonClass">,
+ Desc<"Give the name of a Python class to "
+ "use for this frame recognizer.">;
+ def frame_recognizer_regex
+ : Option<"regex", "x">,
+ Desc<"Function name and module name are actually regular expressions.">;
+ def frame_recognizer_first_instruction_only
+ : Option<"first-instruction-only", "f">,
+ Arg<"Boolean">,
+ Desc<"If true, only apply this recognizer to frames whose PC currently "
+ "points to the first instruction of the specified function. If "
+ "false, the recognizer will always be applied, regardless of the "
+ "current position within the specified function. The implementer "
+ "should keep in mind that some features, e.g., accessing function "
+ "argument values via $arg<N>, are not guaranteed to work reliably "
+ "in this case, so extra care must be taken to make the recognizer "
+ "operate correctly. Defaults to true.">;
}
let Command = "history" in {
- def history_count : Option<"count", "c">, Group<1>, Arg<"UnsignedInteger">,
- Desc<"How many history commands to print.">;
- def history_start_index : Option<"start-index", "s">, Group<1>,
- Arg<"UnsignedInteger">, Desc<"Index at which to start printing history "
- "commands (or end to mean tail mode).">;
- def history_end_index : Option<"end-index", "e">, Group<1>,
- Arg<"UnsignedInteger">,
- Desc<"Index at which to stop printing history commands.">;
- def history_clear : Option<"clear", "C">, Group<2>,
- Desc<"Clears the current command history.">;
+ def history_count : Option<"count", "c">,
+ Group<1>,
+ Arg<"UnsignedInteger">,
+ Desc<"How many history commands to print.">;
+ def history_start_index : Option<"start-index", "s">,
+ Group<1>,
+ Arg<"UnsignedInteger">,
+ Desc<"Index at which to start printing history "
+ "commands (or end to mean tail mode).">;
+ def history_end_index
+ : Option<"end-index", "e">,
+ Group<1>,
+ Arg<"UnsignedInteger">,
+ Desc<"Index at which to stop printing history commands.">;
+ def history_clear : Option<"clear", "C">,
+ Group<2>,
+ Desc<"Clears the current command history.">;
}
let Command = "log enable" in {
- def log_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
- Desc<"Set the destination file to log to.">;
- def log_handler : Option<"log-handler", "h">, Group<1>,
- EnumArg<"LogHandler">, Desc<"Specify a log handler which determines where log messages are written.">;
- def log_buffer_size : Option<"buffer", "b">, Group<1>, Arg<"UnsignedInteger">,
- Desc<"Set the log to be buffered, using the specified buffer size, if supported by the log handler.">;
- def log_verbose : Option<"verbose", "v">, Group<1>,
- Desc<"Enable verbose logging.">;
- def log_sequence : Option<"sequence", "s">, Group<1>,
- Desc<"Prepend all log lines with an increasing integer sequence id.">;
- def log_timestamp : Option<"timestamp", "T">, Group<1>,
- Desc<"Prepend all log lines with a timestamp.">;
- def log_pid_tid : Option<"pid-tid", "p">, Group<1>,
- Desc<"Prepend all log lines with the process and thread ID that generates "
- "the log line.">;
- def log_thread_name : Option<"thread-name", "n">, Group<1>,
- Desc<"Prepend all log lines with the thread name for the thread that "
- "generates the log line.">;
-
- def log_stack : Option<"stack", "S">, Group<1>,
- Desc<"Append a stack backtrace to each log line.">;
- def log_append : Option<"append", "a">, Group<1>,
- Desc<"Append to the log file instead of overwriting.">;
- def log_file_function : Option<"file-function", "F">, Group<1>,
- Desc<"Prepend the names of files and function that generate the logs.">;
+ def log_file : Option<"file", "f">,
+ Group<1>,
+ Arg<"Filename">,
+ Desc<"Set the destination file to log to.">;
+ def log_handler : Option<"log-handler", "h">,
+ Group<1>,
+ EnumArg<"LogHandler">,
+ Desc<"Specify a log handler which determines where log "
+ "messages are written.">;
+ def log_buffer_size : Option<"buffer", "b">,
+ Group<1>,
+ Arg<"UnsignedInteger">,
+ Desc<"Set the log to be buffered, using the specified "
+ "buffer size, if supported by the log handler.">;
+ def log_verbose : Option<"verbose", "v">,
+ Group<1>,
+ Desc<"Enable verbose logging.">;
+ def log_sequence
+ : Option<"sequence", "s">,
+ Group<1>,
+ Desc<"Prepend all log lines with an increasing integer sequence id.">;
+ def log_timestamp : Option<"timestamp", "T">,
+ Group<1>,
+ Desc<"Prepend all log lines with a timestamp.">;
+ def log_pid_tid : Option<"pid-tid", "p">,
+ Group<1>,
+ Desc<"Prepend all log lines with the process and thread ID "
+ "that generates the log line.">;
+ def log_thread_name : Option<"thread-name", "n">,
+ Group<1>,
+ Desc<"Prepend all log lines with the thread name for "
+ "the thread that generates the log line.">;
+
+ def log_stack : Option<"stack", "S">,
+ Group<1>,
+ Desc<"Append a stack backtrace to each log line.">;
+ def log_append : Option<"append", "a">,
+ Group<1>,
+ Desc<"Append to the log file instead of overwriting.">;
+ def log_file_function
+ : Option<"file-function", "F">,
+ Group<1>,
+ Desc<"Prepend the names of files and function that generate the logs.">;
}
let Command = "log dump" in {
- def log_dump_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
- Desc<"Set the destination file to dump to.">;
+ def log_dump_file : Option<"file", "f">,
+ Group<1>,
+ Arg<"Filename">,
+ Desc<"Set the destination file to dump to.">;
}
let Command = "memory read" in {
- def memory_read_num_per_line : Option<"num-per-line", "l">, Group<1>,
- Arg<"NumberPerLine">, Desc<"The number of items per line to display.">;
- def memory_read_binary : Option<"binary", "b">, Group<2>,
- Desc<"If true, memory will be saved as binary. If false, the memory is "
- "saved save as an ASCII dump that uses the format, size, count and number "
- "per line settings.">;
- def memory_read_type : Option<"type", "t">, Groups<[3,4]>, Arg<"Name">,
- Required, Desc<"The name of a type to view memory as.">;
- def memory_read_language : Option<"language", "x">, Group<4>, Arg<"Language">,
- Desc<"The language of the type to view memory as.">;
- def memory_read_offset : Option<"offset", "E">, Group<3>, Arg<"Count">,
- Desc<"How many elements of the specified type to skip before starting to "
- "display data.">;
- def memory_read_force : Option<"force", "r">, Groups<[1,2,3]>,
- Desc<"Necessary if reading over target.max-memory-read-size bytes.">;
+ def memory_read_num_per_line
+ : Option<"num-per-line", "l">,
+ Group<1>,
+ Arg<"NumberPerLine">,
+ Desc<"The number of items per line to display.">;
+ def memory_read_binary
+ : Option<"binary", "b">,
+ Group<2>,
+ Desc<"If true, memory will be saved as binary. If false, the memory is "
+ "saved save as an ASCII dump that uses the format, size, count "
+ "and number per line settings.">;
+ def memory_read_type : Option<"type", "t">,
+ Groups<[3, 4]>,
+ Arg<"Name">,
+ Required,
+ Desc<"The name of a type to view memory as.">;
+ def memory_read_language
+ : Option<"language", "x">,
+ Group<4>,
+ Arg<"Language">,
+ Desc<"The language of the type to view memory as.">;
+ def memory_read_offset : Option<"offset", "E">,
+ Group<3>,
+ Arg<"Count">,
+ Desc<"How many elements of the specified type to "
+ "skip before starting to display data.">;
+ def memory_read_force
+ : Option<"force", "r">,
+ Groups<[1, 2, 3]>,
+ Desc<"Necessary if reading over target.max-memory-read-size bytes.">;
}
let Command = "memory find" in {
- def memory_find_expression : Option<"expression", "e">, Group<1>,
- Arg<"Expression">, Required,
- Desc<"Evaluate an expression to obtain a byte pattern.">;
- def memory_find_string : Option<"string", "s">, Group<2>, Arg<"Name">,
- Required, Desc<"Use text to find a byte pattern.">;
- def memory_find_count : Option<"count", "c">, Arg<"Count">,
- Desc<"How many times to perform the search.">;
- def memory_find_dump_offset : Option<"dump-offset", "o">, Arg<"Offset">,
- Desc<"When dumping memory for a match, an offset from the match location to"
- " start dumping from.">;
+ def memory_find_expression
+ : Option<"expression", "e">,
+ Group<1>,
+ Arg<"Expression">,
+ Required,
+ Desc<"Evaluate an expression to obtain a byte pattern.">;
+ def memory_find_string : Option<"string", "s">,
+ Group<2>,
+ Arg<"Name">,
+ Required,
+ Desc<"Use text to find a byte pattern.">;
+ def memory_find_count : Option<"count", "c">,
+ Arg<"Count">,
+ Desc<"How many times to perform the search.">;
+ def memory_find_dump_offset
+ : Option<"dump-offset", "o">,
+ Arg<"Offset">,
+ Desc<"When dumping memory for a match, an offset from the match "
+ "location to start dumping from.">;
}
let Command = "memory write" in {
- def memory_write_infile : Option<"infile", "i">, Group<1>, Arg<"Filename">,
- Required, Desc<"Write memory using the contents of a file.">;
- def memory_write_offset : Option<"offset", "o">, Group<1>, Arg<"Offset">,
- Desc<"Start writing bytes from an offset within the input file.">;
+ def memory_write_infile : Option<"infile", "i">,
+ Group<1>,
+ Arg<"Filename">,
+ Required,
+ Desc<"Write memory using the contents of a file.">;
+ def memory_write_offset
+ : Option<"offset", "o">,
+ Group<1>,
+ Arg<"Offset">,
+ Desc<"Start writing bytes from an offset within the input file.">;
}
let Command = "memory region" in {
- def memory_region_all : Option<"all", "a">, Group<2>, Required,
- Desc<"Show all memory regions. This is equivalent to starting from address "
- "0 and repeating the command. Unmapped areas are included.">;
+ def memory_region_all : Option<"all", "a">,
+ Group<2>,
+ Required,
+ Desc<"Show all memory regions. This is equivalent to "
+ "starting from address 0 and repeating the "
+ "command. Unmapped areas are included.">;
}
let Command = "memory tag write" in {
- def memory_write_end_addr : Option<"end-addr", "e">, Group<1>,
- Arg<"AddressOrExpression">, Desc<
- "Set tags for start address to end-addr, repeating tags as needed"
- " to cover the range. (instead of calculating the range from the"
- " number of tags given)">;
+ def memory_write_end_addr
+ : Option<"end-addr", "e">,
+ Group<1>,
+ Arg<"AddressOrExpression">,
+ Desc<"Set tags for start address to end-addr, repeating tags as needed "
+ "to cover the range. (instead of calculating the range from the "
+ "number of tags given)">;
}
let Command = "register read" in {
- def register_read_alternate : Option<"alternate", "A">,
- Desc<"Display register names using the alternate register name if there "
- "is one.">;
- def register_read_set : Option<"set", "s">, Group<1>, Arg<"Index">,
- Desc<"Specify which register sets to dump by index.">;
- def register_read_all : Option<"all", "a">, Group<2>,
- Desc<"Show all register sets.">;
+ def register_read_alternate
+ : Option<"alternate", "A">,
+ Desc<"Display register names using the alternate register name if "
+ "there is one.">;
+ def register_read_set : Option<"set", "s">,
+ Group<1>,
+ Arg<"Index">,
+ Desc<"Specify which register sets to dump by index.">;
+ def register_read_all : Option<"all", "a">,
+ Group<2>,
+ Desc<"Show all register sets.">;
}
let Command = "source" in {
- def source_stop_on_error : Option<"stop-on-error", "e">, Arg<"Boolean">,
- Desc<"If true, stop executing commands on error.">;
- def source_stop_on_continue : Option<"stop-on-continue", "c">, Arg<"Boolean">,
- Desc<"If true, stop executing commands on continue.">;
- def source_silent_run : Option<"silent-run", "s">, Arg<"Boolean">,
- Desc<"If true don't echo commands while executing.">;
- def cmd_relative_to_command_file : Option<"relative-to-command-file", "C">,
- Desc<"Resolve non-absolute paths relative to the location of the "
- "current command file. This argument can only be used when the command is "
- "being sourced from a file.">;
+ def source_stop_on_error : Option<"stop-on-error", "e">,
+ Arg<"Boolean">,
+ Desc<"If true, stop executing commands on error.">;
+ def source_stop_on_continue
+ : Option<"stop-on-continue", "c">,
+ Arg<"Boolean">,
+ Desc<"If true, stop executing commands on continue.">;
+ def source_silent_run : Option<"silent-run", "s">,
+ Arg<"Boolean">,
+ Desc<"If true don't echo commands while executing.">;
+ def cmd_relative_to_command_file
+ : Option<"relative-to-command-file", "C">,
+ Desc<"Resolve non-absolute paths relative to the location of the "
+ "current command file. This argument can only be used when the "
+ "command is being sourced from a file.">;
}
let Command = "alias" in {
- def alias_help : Option<"help", "h">, Arg<"HelpText">,
- Desc<"Help text for this command">;
- def alias_long_help : Option<"long-help", "H">, Arg<"HelpText">,
- Desc<"Long help text for this command">;
+ def alias_help : Option<"help", "h">,
+ Arg<"HelpText">,
+ Desc<"Help text for this command">;
+ def alias_long_help : Option<"long-help", "H">,
+ Arg<"HelpText">,
+ Desc<"Long help text for this command">;
}
let Command = "regex" in {
- def regex_help : Option<"help", "h">, Group<1>, Arg<"None">,
- Desc<"The help text to display for this command.">;
- def regex_syntax : Option<"syntax", "s">, Group<1>, Arg<"None">,
- Desc<"A syntax string showing the typical usage syntax.">;
+ def regex_help : Option<"help", "h">,
+ Group<1>,
+ Arg<"None">,
+ Desc<"The help text to display for this command.">;
+ def regex_syntax : Option<"syntax", "s">,
+ Group<1>,
+ Arg<"None">,
+ Desc<"A syntax string showing the typical usage syntax.">;
}
let Command = "permissions" in {
- def permissions_permissions_value : Option<"permissions-value", "v">,
- Arg<"PermissionsNumber">,
- Desc<"Give out the numeric value for permissions (e.g. 757)">;
- def permissions_permissions_string : Option<"permissions-string", "s">,
- Arg<"PermissionsString">,
- Desc<"Give out the string value for permissions (e.g. rwxr-xr--).">;
+ def permissions_permissions_value
+ : Option<"permissions-value", "v">,
+ Arg<"PermissionsNumber">,
+ Desc<"Give out the numeric value for permissions (e.g. 757)">;
+ def permissions_permissions_string
+ : Option<"permissions-string", "s">,
+ Arg<"PermissionsString">,
+ Desc<"Give out the string value for permissions (e.g. rwxr-xr--).">;
def permissions_user_read : Option<"user-read", "r">,
- Desc<"Allow user to read.">;
+ Desc<"Allow user to read.">;
def permissions_user_write : Option<"user-write", "w">,
- Desc<"Allow user to write.">;
+ Desc<"Allow user to write.">;
def permissions_user_exec : Option<"user-exec", "x">,
- Desc<"Allow user to execute.">;
+ Desc<"Allow user to execute.">;
def permissions_group_read : Option<"group-read", "R">,
- Desc<"Allow group to read.">;
+ Desc<"Allow group to read.">;
def permissions_group_write : Option<"group-write", "W">,
- Desc<"Allow group to write.">;
+ Desc<"Allow group to write.">;
def permissions_group_exec : Option<"group-exec", "X">,
- Desc<"Allow group to execute.">;
+ Desc<"Allow group to execute.">;
def permissions_world_read : Option<"world-read", "d">,
- Desc<"Allow world to read.">;
+ Desc<"Allow world to read.">;
def permissions_world_write : Option<"world-write", "t">,
- Desc<"Allow world to write.">;
+ Desc<"Allow world to write.">;
def permissions_world_exec : Option<"world-exec", "e">,
- Desc<"Allow world to execute.">;
+ Desc<"Allow world to execute.">;
}
let Command = "platform fread" in {
- def platform_fread_offset : Option<"offset", "o">, Group<1>, Arg<"Index">,
- Desc<"Offset into the file at which to start reading.">;
- def platform_fread_count : Option<"count", "c">, Group<1>, Arg<"Count">,
- Desc<"Number of bytes to read from the file.">;
+ def platform_fread_offset
+ : Option<"offset", "o">,
+ Group<1>,
+ Arg<"Index">,
+ Desc<"Offset into the file at which to start reading.">;
+ def platform_fread_count : Option<"count", "c">,
+ Group<1>,
+ Arg<"Count">,
+ Desc<"Number of bytes to read from the file.">;
}
let Command = "platform fwrite" in {
- def platform_fwrite_offset : Option<"offset", "o">, Group<1>, Arg<"Index">,
- Desc<"Offset into the file at which to start reading.">;
- def platform_fwrite_data : Option<"data", "d">, Group<1>, Arg<"Value">,
- Desc<"Text to write to the file.">;
+ def platform_fwrite_offset
+ : Option<"offset", "o">,
+ Group<1>,
+ Arg<"Index">,
+ Desc<"Offset into the file at which to start reading.">;
+ def platform_fwrite_data : Option<"data", "d">,
+ Group<1>,
+ Arg<"Value">,
+ Desc<"Text to write to the file.">;
}
let Command = "platform process list" in {
- def platform_process_list_pid : Option<"pid", "p">, Group<1>, Arg<"Pid">,
- Desc<"List the process info for a specific process ID.">;
- def platform_process_list_name : Option<"name", "n">, Group<2>,
- Arg<"ProcessName">, Required,
- Desc<"Find processes with executable basenames that match a string.">;
- def platform_process_list_ends_with : Option<"ends-with", "e">, Group<3>,
- Arg<"ProcessName">, Required,
- Desc<"Find processes with executable basenames that end with a string.">;
- def platform_process_list_starts_with : Option<"starts-with", "s">, Group<4>,
- Arg<"ProcessName">, Required,
- Desc<"Find processes with executable basenames that start with a string.">;
- def platform_process_list_contains : Option<"contains", "c">, Group<5>,
- Arg<"ProcessName">, Required,
- Desc<"Find processes with executable basenames that contain a string.">;
- def platform_process_list_regex : Option<"regex", "r">, Group<6>,
- Arg<"RegularExpression">, Required,
- Desc<"Find processes with executable basenames that match a regular "
- "expression.">;
- def platform_process_list_parent : Option<"parent", "P">, GroupRange<2, 6>,
- Arg<"Pid">, Desc<"Find processes that have a matching parent process ID.">;
- def platform_process_list_uid : Option<"uid", "u">, GroupRange<2, 6>,
- Arg<"UnsignedInteger">, Validator<"&posix_validator">,
- Desc<"Find processes that have a matching user ID.">;
- def platform_process_list_euid : Option<"euid", "U">, GroupRange<2, 6>,
- Arg<"UnsignedInteger">, Validator<"&posix_validator">,
- Desc<"Find processes that have a matching effective user ID.">;
- def platform_process_list_gid : Option<"gid", "g">, GroupRange<2, 6>,
- Arg<"UnsignedInteger">, Validator<"&posix_validator">,
- Desc<"Find processes that have a matching group ID.">;
- def platform_process_list_egid : Option<"egid", "G">, GroupRange<2, 6>,
- Arg<"UnsignedInteger">, Validator<"&posix_validator">,
- Desc<"Find processes that have a matching effective group ID.">;
- def platform_process_list_arch : Option<"arch", "a">, GroupRange<2, 6>,
- Arg<"Architecture">,
- Desc<"Find processes that have a matching architecture.">;
- def platform_process_list_show_args : Option<"show-args", "A">,
- GroupRange<1, 6>,
- Desc<"Show process arguments instead of the process executable basename.">;
- def platform_process_list_all_users: Option<"all-users", "x">,
- GroupRange<1,6>,
- Desc<"Show processes matching all user IDs.">;
- def platform_process_list_verbose : Option<"verbose", "v">, GroupRange<1, 6>,
- Desc<"Enable verbose output.">;
+ def platform_process_list_pid
+ : Option<"pid", "p">,
+ Group<1>,
+ Arg<"Pid">,
+ Desc<"List the process info for a specific process ID.">;
+ def platform_process_list_name
+ : Option<"name", "n">,
+ Group<2>,
+ Arg<"ProcessName">,
+ Required,
+ Desc<"Find processes with executable basenames that match a string.">;
+ def platform_process_list_ends_with
+ : Option<"ends-with", "e">,
+ Group<3>,
+ Arg<"ProcessName">,
+ Required,
+ Desc<
+ "Find processes with executable basenames that end with a string.">;
+ def platform_process_list_starts_with
+ : Option<"starts-with", "s">,
+ Group<4>,
+ Arg<"ProcessName">,
+ Required,
+ Desc<"Find processes with executable basenames that start with a "
+ "string.">;
+ def platform_process_list_contains
+ : Option<"contains", "c">,
+ Group<5>,
+ Arg<"ProcessName">,
+ Required,
+ Desc<"Find processes with executable basenames that contain a string.">;
+ def platform_process_list_regex
+ : Option<"regex", "r">,
+ Group<6>,
+ Arg<"RegularExpression">,
+ Required,
+ Desc<"Find processes with executable basenames that match a regular "
+ "expression.">;
+ def platform_process_list_parent
+ : Option<"parent", "P">,
+ GroupRange<2, 6>,
+ Arg<"Pid">,
+ Desc<"Find processes that have a matching parent process ID.">;
+ def platform_process_list_uid
+ : Option<"uid", "u">,
+ GroupRange<2, 6>,
+ Arg<"UnsignedInteger">,
+ Validator<"&posix_validator">,
+ Desc<"Find processes that have a matching user ID.">;
+ def platform_process_list_euid
+ : Option<"euid", "U">,
+ GroupRange<2, 6>,
+ Arg<"UnsignedInteger">,
+ Validator<"&posix_validator">,
+ Desc<"Find processes that have a matching effective user ID.">;
+ def platform_process_list_gid
+ : Option<"gid", "g">,
+ GroupRange<2, 6>,
+ Arg<"UnsignedInteger">,
+ Validator<"&posix_validator">,
+ Desc<"Find processes that have a matching group ID.">;
+ def platform_process_list_egid
+ : Option<"egid", "G">,
+ GroupRange<2, 6>,
+ Arg<"UnsignedInteger">,
+ Validator<"&posix_validator">,
+ Desc<"Find processes that have a matching effective group ID.">;
+ def platform_process_list_arch
+ : Option<"arch", "a">,
+ GroupRange<2, 6>,
+ Arg<"Architecture">,
+ Desc<"Find processes that have a matching architecture.">;
+ def platform_process_list_show_args
+ : Option<"show-args", "A">,
+ GroupRange<1, 6>,
+ Desc<"Show process arguments instead of the process executable "
+ "basename.">;
+ def platform_process_list_all_users
+ : Option<"all-users", "x">,
+ GroupRange<1, 6>,
+ Desc<"Show processes matching all user IDs.">;
+ def platform_process_list_verbose : Option<"verbose", "v">,
+ GroupRange<1, 6>,
+ Desc<"Enable verbose output.">;
}
let Command = "platform process attach" in {
- def platform_process_attach_plugin : Option<"plugin", "P">, Arg<"Plugin">,
- Desc<"Name of the process plugin you want to use.">;
- def platform_process_attach_pid : Option<"pid", "p">, Group<1>, Arg<"Pid">,
- Desc<"The process ID of an existing process to attach to.">;
- def platform_process_attach_name : Option<"name", "n">, Group<2>,
- Arg<"ProcessName">, Desc<"The name of the process to attach to.">;
- def platform_process_attach_waitfor : Option<"waitfor", "w">, Group<2>,
- Desc<"Wait for the process with <process-name> to launch.">;
+ def platform_process_attach_plugin
+ : Option<"plugin", "P">,
+ Arg<"Plugin">,
+ Desc<"Name of the process plugin you want to use.">;
+ def platform_process_attach_pid
+ : Option<"pid", "p">,
+ Group<1>,
+ Arg<"Pid">,
+ Desc<"The process ID of an existing process to attach to.">;
+ def platform_process_attach_name
+ : Option<"name", "n">,
+ Group<2>,
+ Arg<"ProcessName">,
+ Desc<"The name of the process to attach to.">;
+ def platform_process_attach_waitfor
+ : Option<"waitfor", "w">,
+ Group<2>,
+ Desc<"Wait for the process with <process-name> to launch.">;
}
let Command = "platform shell" in {
- def platform_shell_host : Option<"host", "h">,
- Desc<"Run the commands on the host shell when enabled.">;
- def platform_shell_timeout : Option<"timeout", "t">, Arg<"Value">,
- Desc<"Seconds to wait for the remote host to finish running the command.">;
- def platform_shell_interpreter : Option<"shell", "s">, Arg<"Path">,
- Desc<"Shell interpreter path. This is the binary used to run the command.">;
+ def platform_shell_host
+ : Option<"host", "h">,
+ Desc<"Run the commands on the host shell when enabled.">;
+ def platform_shell_timeout : Option<"timeout", "t">,
+ Arg<"Value">,
+ Desc<"Seconds to wait for the remote host to "
+ "finish running the command.">;
+ def platform_shell_interpreter : Option<"shell", "s">,
+ Arg<"Path">,
+ Desc<"Shell interpreter path. This is the "
+ "binary used to run the command.">;
}
let Command = "plugin list" in {
@@ -703,808 +1103,1316 @@ let Command = "plugin list" in {
}
let Command = "process launch" in {
- def process_launch_stop_at_entry : Option<"stop-at-entry", "s">,
- Desc<"Stop at the entry point of the program when launching a process.">;
- def process_launch_stop_at_user_entry : Option<"stop-at-user-entry", "m">,
- Desc<"Stop at the user entry point when launching a process. For C based "
- "languages this will be the 'main' function, but this might differ for "
- "other languages.">;
- def process_launch_disable_aslr : Option<"disable-aslr", "A">, Arg<"Boolean">,
- Desc<"Set whether to disable address space layout randomization when launching a process.">;
- def process_launch_plugin : Option<"plugin", "P">, Arg<"Plugin">,
- Desc<"Name of the process plugin you want to use.">;
- def process_launch_working_dir : Option<"working-dir", "w">, Arg<"DirectoryName">,
- Desc<"Set the current working directory to <path> when running the inferior. This option "
- "applies only to the current `process launch` invocation. If "
- "`target.launch-working-dir` is set and this option is given, the value of this "
- "option will be used instead of the setting.">;
- def process_launch_arch : Option<"arch", "a">, Arg<"Architecture">,
- Desc<"Set the architecture for the process to launch when ambiguous.">;
- def process_launch_environment : Option<"environment", "E">,
- Arg<"None">, Desc<"Specify an environment variable name/value string "
- "(--environment NAME=VALUE). Can be specified multiple times for subsequent "
- "environment entries.">;
- def process_launch_shell : Option<"shell", "c">, GroupRange<1,3>,
- OptionalArg<"Filename">, Desc<"Run the process in a shell (not supported on all platforms).">;
- def process_launch_stdin : Option<"stdin", "i">, Group<1>,
- Arg<"Filename">, Desc<"Redirect stdin for the process to <filename>.">;
- def process_launch_stdout : Option<"stdout", "o">, Group<1>,
- Arg<"Filename">, Desc<"Redirect stdout for the process to <filename>.">;
- def process_launch_stderr : Option<"stderr", "e">, Group<1>,
- Arg<"Filename">, Desc<"Redirect stderr for the process to <filename>.">;
- def process_launch_tty : Option<"tty", "t">, Group<2>,
- Desc<"Start the process in a terminal (not supported on all platforms).">;
- def process_launch_no_stdio : Option<"no-stdio", "n">, Group<3>,
- Desc<"Do not set up for terminal I/O to go to running process.">;
- def process_launch_shell_expand_args : Option<"shell-expand-args", "X">, Group<4>,
- Arg<"Boolean">, Desc<"Set whether to shell expand arguments to the process when launching.">;
+ def process_launch_stop_at_entry
+ : Option<"stop-at-entry", "s">,
+ Desc<
+ "Stop at the entry point of the program when launching a process.">;
+ def process_launch_stop_at_user_entry
+ : Option<"stop-at-user-entry", "m">,
+ Desc<"Stop at the user entry point when launching a process. For C "
+ "based languages this will be the 'main' function, but this might "
+ "differ for other languages.">;
+ def process_launch_disable_aslr
+ : Option<"disable-aslr", "A">,
+ Arg<"Boolean">,
+ Desc<"Set whether to disable address space layout randomization when "
+ "launching a process.">;
+ def process_launch_plugin
+ : Option<"plugin", "P">,
+ Arg<"Plugin">,
+ Desc<"Name of the process plugin you want to use.">;
+ def process_launch_working_dir
+ : Option<"working-dir", "w">,
+ Arg<"DirectoryName">,
+ Desc<"Set the current working directory to <path> when running the "
+ "inferior. This option applies only to the current `process "
+ "launch` invocation. If `target.launch-working-dir` is set and "
+ "this option is given, the value of this option will be used "
+ "instead of the setting.">;
+ def process_launch_arch
+ : Option<"arch", "a">,
+ Arg<"Architecture">,
+ Desc<"Set the architecture for the process to launch when ambiguous.">;
+ def process_launch_environment
+ : Option<"environment", "E">,
+ Arg<"None">,
+ Desc<"Specify an environment variable name/value string (--environment "
+ "NAME=VALUE). Can be specified multiple times for subsequent "
+ "environment entries.">;
+ def process_launch_shell
+ : Option<"shell", "c">,
+ GroupRange<1, 3>,
+ OptionalArg<"Filename">,
+ Desc<"Run the process in a shell (not supported on all platforms).">;
+ def process_launch_stdin
+ : Option<"stdin", "i">,
+ Group<1>,
+ Arg<"Filename">,
+ Desc<"Redirect stdin for the process to <filename>.">;
+ def process_launch_stdout
+ : Option<"stdout", "o">,
+ Group<1>,
+ Arg<"Filename">,
+ Desc<"Redirect stdout for the process to <filename>.">;
+ def process_launch_stderr
+ : Option<"stderr", "e">,
+ Group<1>,
+ Arg<"Filename">,
+ Desc<"Redirect stderr for the process to <filename>.">;
+ def process_launch_tty : Option<"tty", "t">,
+ Group<2>,
+ Desc<"Start the process in a terminal (not "
+ "supported on all platforms).">;
+ def process_launch_no_stdio
+ : Option<"no-stdio", "n">,
+ Group<3>,
+ Desc<"Do not set up for terminal I/O to go to running process.">;
+ def process_launch_shell_expand_args
+ : Option<"shell-expand-args", "X">,
+ Group<4>,
+ Arg<"Boolean">,
+ Desc<"Set whether to shell expand arguments to the process when "
+ "launching.">;
}
let Command = "process attach" in {
- def process_attach_continue : Option<"continue", "c">,
- Desc<"Immediately continue the process once attached.">;
- def process_attach_plugin : Option<"plugin", "P">, Arg<"Plugin">,
- Desc<"Name of the process plugin you want to use.">;
- def process_attach_pid : Option<"pid", "p">, Group<1>, Arg<"Pid">,
- Desc<"The process ID of an existing process to attach to.">;
- def process_attach_name : Option<"name", "n">, Group<2>, Arg<"ProcessName">,
- Desc<"The name of the process to attach to.">;
- def process_attach_include_existing : Option<"include-existing", "i">,
- Group<2>, Desc<"Include existing processes when doing attach -w.">;
- def process_attach_waitfor : Option<"waitfor", "w">, Group<2>,
- Desc<"Wait for the process with <process-name> to launch.">;
+ def process_attach_continue
+ : Option<"continue", "c">,
+ Desc<"Immediately ${c}ontinue the process once attached.">;
+ def process_attach_plugin
+ : Option<"plugin", "P">,
+ Arg<"Plugin">,
+ Desc<"Name of the process ${p}lugin you want to use.">;
+ def process_attach_pid
+ : Option<"pid", "p">,
+ Group<1>,
+ Arg<"Pid">,
+ Desc<"The ${p}rocess ID of an existing process to attach to.">;
+ def process_attach_name : Option<"name", "n">,
+ Group<2>,
+ Arg<"ProcessName">,
+ Desc<"The ${n}ame of the process to attach to.">;
+ def process_attach_include_existing
+ : Option<"include-existing", "i">,
+ Group<2>,
+ Desc<"${I}nclude existing processes when doing attach -w.">;
+ def process_attach_waitfor
+ : Option<"waitfor", "w">,
+ Group<2>,
+ Desc<"${W}ait for the process with <process-name> to launch.">;
}
let Command = "process continue" in {
- def process_continue_ignore_count : Option<"ignore-count", "i">, Groups<[1,2]>,
- Arg<"UnsignedInteger">, Desc<"Ignore <N> crossings of the breakpoint (if it"
- " exists) for the currently selected thread.">;
- def process_continue_run_to_bkpt : Option<"continue-to-bkpt", "b">, Groups<[3,4]>,
- Arg<"BreakpointIDRange">, Desc<"Specify a breakpoint to continue to, temporarily "
- "ignoring other breakpoints. Can be specified more than once. "
- "The continue action will be done synchronously if this option is specified.">;
- def thread_continue_forward : Option<"forward", "F">, Groups<[1,3]>,
- Desc<"Set the direction to forward before continuing.">;
- def thread_continue_reverse : Option<"reverse", "R">, Groups<[2,4]>,
- Desc<"Set the direction to reverse before continuing.">;
+ def process_continue_ignore_count
+ : Option<"ignore-count", "i">,
+ Groups<[1, 2]>,
+ Arg<"UnsignedInteger">,
+ Desc<"Ignore <N> crossings of the breakpoint (if it exists) for the "
+ "currently selected thread.">;
+ def process_continue_run_to_bkpt
+ : Option<"continue-to-bkpt", "b">,
+ Groups<[3, 4]>,
+ Arg<"BreakpointIDRange">,
+ Desc<"Specify a breakpoint to continue to, temporarily ignoring other "
+ "breakpoints. Can be specified more than once. The continue "
+ "action will be done synchronously if this option is specified.">;
+ def thread_continue_forward
+ : Option<"forward", "F">,
+ Groups<[1, 3]>,
+ Desc<"Set the direction to forward before continuing.">;
+ def thread_continue_reverse
+ : Option<"reverse", "R">,
+ Groups<[2, 4]>,
+ Desc<"Set the direction to reverse before continuing.">;
}
let Command = "process detach" in {
- def process_detach_keep_stopped : Option<"keep-stopped", "s">, Group<1>,
- Arg<"Boolean">, Desc<"Whether or not the process should be kept stopped on"
- " detach (if possible).">;
+ def process_detach_keep_stopped
+ : Option<"keep-stopped", "s">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"Whether or not the process should be kept stopped on"
+ " detach (if possible).">;
}
let Command = "process connect" in {
- def process_connect_plugin : Option<"plugin", "p">, Arg<"Plugin">,
- Desc<"Name of the process plugin you want to use.">;
+ def process_connect_plugin
+ : Option<"plugin", "p">,
+ Arg<"Plugin">,
+ Desc<"Name of the process plugin you want to use.">;
}
let Command = "process load" in {
- def process_load_install : Option<"install", "i">, OptionalArg<"Path">,
- Desc<"Install the shared library to the target. If specified without an "
- "argument then the library will installed in the current working "
- "directory.">;
+ def process_load_install
+ : Option<"install", "i">,
+ OptionalArg<"Path">,
+ Desc<
+ "Install the shared library to the target. If specified without an "
+ "argument then the library will installed in the current working "
+ "directory.">;
}
let Command = "process handle" in {
- def process_handle_clear : Option<"clear", "c">, Group<2>,
- Desc<"Removes the signals listed from the Target signal handlers">;
- def process_handle_stop : Option<"stop", "s">, Group<1>, Arg<"Boolean">,
- Desc<"Whether or not the process should be stopped if the signal is "
- "received.">;
- def process_handle_notify : Option<"notify", "n">, Group<1>, Arg<"Boolean">,
- Desc<"Whether or not the debugger should notify the user if the signal is "
- "received.">;
- def process_handle_pass : Option<"pass", "p">, Group<1>, Arg<"Boolean">,
- Desc<"Whether or not the signal should be passed to the process.">;
- def process_handle_only_target : Option<"target", "t">, Group<1>,
- Desc<"Show only the signals with behaviors modified in this target">;
- def process_handle_dummy : Option<"dummy", "d">, Group<2>,
- Desc<"Also clear the values in the dummy target so they won't be inherited by new targets.">;
+ def process_handle_clear
+ : Option<"clear", "c">,
+ Group<2>,
+ Desc<"Removes the signals listed from the Target signal handlers">;
+ def process_handle_stop
+ : Option<"stop", "s">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"Whether or not the process should be stopped if the signal is "
+ "received.">;
+ def process_handle_notify : Option<"notify", "n">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"Whether or not the debugger should notify "
+ "the user if the signal is "
+ "received.">;
+ def process_handle_pass
+ : Option<"pass", "p">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"Whether or not the signal should be passed to the process.">;
+ def process_handle_only_target
+ : Option<"target", "t">,
+ Group<1>,
+ Desc<"Show only the signals with behaviors modified in this target">;
+ def process_handle_dummy : Option<"dummy", "d">,
+ Group<2>,
+ Desc<"Also clear the values in the dummy target "
+ "so they won't be inherited by new targets.">;
}
let Command = "process status" in {
- def process_status_verbose : Option<"verbose", "v">, Group<1>,
- Desc<"Show verbose process status including extended crash information.">;
- def process_status_dump : Option<"dump-modification-id", "d">, Group<1>,
- Desc<"Dump the state of the ProcessModID of the stopped process.">;
+ def process_status_verbose : Option<"verbose", "v">,
+ Group<1>,
+ Desc<"Show verbose process status including "
+ "extended crash information.">;
+ def process_status_dump
+ : Option<"dump-modification-id", "d">,
+ Group<1>,
+ Desc<"Dump the state of the ProcessModID of the stopped process.">;
}
let Command = "process save_core" in {
- def process_save_core_style : Option<"style", "s">, Group<1>,
- EnumArg<"SaveCoreStyle">, Desc<"Request a specific style "
- "of corefile to be saved.">;
- def process_save_core_plugin_name : Option<"plugin-name", "p">,
- OptionalArg<"Plugin">, Desc<"Specify a plugin name to create the core file. "
- "This allows core files to be saved in different formats.">;
+ def process_save_core_style : Option<"style", "s">,
+ Group<1>,
+ EnumArg<"SaveCoreStyle">,
+ Desc<"Request a specific style "
+ "of corefile to be saved.">;
+ def process_save_core_plugin_name
+ : Option<"plugin-name", "p">,
+ OptionalArg<"Plugin">,
+ Desc<"Specify a plugin name to create the core file. "
+ "This allows core files to be saved in different formats.">;
}
let Command = "script import" in {
- def script_import_allow_reload : Option<"allow-reload", "r">, Group<1>,
- Desc<"Allow the script to be loaded even if it was already loaded before. "
- "This argument exists for backwards compatibility, but reloading is always "
- "allowed, whether you specify it or not.">;
- def relative_to_command_file : Option<"relative-to-command-file", "c">,
- Group<1>, Desc<"Resolve non-absolute paths relative to the location of the "
- "current command file. This argument can only be used when the command is "
- "being sourced from a file.">;
- def silent : Option<"silent", "s">, Group<1>,
- Desc<"If true don't print any script output while importing.">;
+ def script_import_allow_reload
+ : Option<"allow-reload", "r">,
+ Group<1>,
+ Desc<"Allow the script to be loaded even if it was already loaded "
+ "before. "
+ "This argument exists for backwards compatibility, but reloading "
+ "is always "
+ "allowed, whether you specify it or not.">;
+ def relative_to_command_file
+ : Option<"relative-to-command-file", "c">,
+ Group<1>,
+ Desc<"Resolve non-absolute paths relative to the location of the "
+ "current command file. This argument can only be used when the "
+ "command is "
+ "being sourced from a file.">;
+ def silent : Option<"silent", "s">,
+ Group<1>,
+ Desc<"If true don't print any script output while importing.">;
}
let Command = "script add" in {
- def script_add_function : Option<"function", "f">, Group<1>,
- Arg<"PythonFunction">,
- Desc<"Name of the Python function to bind to this command name.">;
- def script_add_class : Option<"class", "c">, Groups<[2,3]>,
- Arg<"PythonClass">,
- Desc<"Name of the Python class to bind to this command name.">;
- def script_add_help : Option<"help", "h">, Group<1>, Arg<"HelpText">,
- Desc<"The help text to display for this command.">;
- def script_add_overwrite : Option<"overwrite", "o">,
- Desc<"Overwrite an existing command at this node.">;
- def script_add_synchronicity : Option<"synchronicity", "s">,
- EnumArg<"ScriptedCommandSynchronicity">,
- Desc<"Set the synchronicity of this command's executions with regard to "
- "LLDB event system.">;
- def script_add_completion_type : Option<"completion-type", "C">,
- Groups<[1,2]>, EnumArg<"CompletionType">,
- Desc<"Specify which completion type the command should use - if none is "
- "specified, the command won't use auto-completion.">;
- def script_add_parsed_command : Option<"parsed", "p">, Group<3>,
- Desc<"Make a parsed command. The command class will provide the command "
- "definition by implementing get_options and get_arguments.">;
-
+ def script_add_function
+ : Option<"function", "f">,
+ Group<1>,
+ Arg<"PythonFunction">,
+ Desc<"Name of the Python function to bind to this command name.">;
+ def script_add_class
+ : Option<"class", "c">,
+ Groups<[2, 3]>,
+ Arg<"PythonClass">,
+ Desc<"Name of the Python class to bind to this command name.">;
+ def script_add_help : Option<"help", "h">,
+ Group<1>,
+ Arg<"HelpText">,
+ Desc<"The help text to display for this command.">;
+ def script_add_overwrite
+ : Option<"overwrite", "o">,
+ Desc<"Overwrite an existing command at this node.">;
+ def script_add_synchronicity
+ : Option<"synchronicity", "s">,
+ EnumArg<"ScriptedCommandSynchronicity">,
+ Desc<
+ "Set the synchronicity of this command's executions with regard to "
+ "LLDB event system.">;
+ def script_add_completion_type
+ : Option<"completion-type", "C">,
+ Groups<[1, 2]>,
+ EnumArg<"CompletionType">,
+ Desc<
+ "Specify which completion type the command should use - if none is "
+ "specified, the command won't use auto-completion.">;
+ def script_add_parsed_command
+ : Option<"parsed", "p">,
+ Group<3>,
+ Desc<
+ "Make a parsed command. The command class will provide the command "
+ "definition by implementing get_options and get_arguments.">;
}
let Command = "container add" in {
- def container_add_help : Option<"help", "h">, Arg<"HelpText">,
- Desc<"Help text for this command">;
- def container_add_long_help : Option<"long-help", "H">, Arg<"HelpText">,
- Desc<"Long help text for this command">;
- def container_add_overwrite : Option<"overwrite", "o">, Group<1>,
- Desc<"Overwrite an existing command at this node.">;
+ def container_add_help : Option<"help", "h">,
+ Arg<"HelpText">,
+ Desc<"Help text for this command">;
+ def container_add_long_help : Option<"long-help", "H">,
+ Arg<"HelpText">,
+ Desc<"Long help text for this command">;
+ def container_add_overwrite
+ : Option<"overwrite", "o">,
+ Group<1>,
+ Desc<"Overwrite an existing command at this node.">;
}
let Command = "scripting run" in {
def script_language : Option<"language", "l">,
- EnumArg<"ScriptLang">, Desc<"Specify the scripting "
- " language. If none is specific the default scripting language is used.">;
+ EnumArg<"ScriptLang">,
+ Desc<"Specify the scripting "
+ " language. If none is specific the default "
+ "scripting language is used.">;
}
let Command = "scripting extension list" in {
- def scripting_extension_list_language : Option<"language", "l">,
- EnumArg<"ScriptLang">, Desc<"Specify the scripting "
- " language. If none is specified the default scripting language is used.">;
+ def scripting_extension_list_language
+ : Option<"language", "l">,
+ EnumArg<"ScriptLang">,
+ Desc<"Specify the scripting "
+ " language. If none is specified the default scripting language "
+ "is used.">;
}
let Command = "source info" in {
- def source_info_count : Option<"count", "c">, Arg<"Count">,
- Desc<"The number of line entries to display.">;
- def source_info_shlib : Option<"shlib", "s">, Groups<[1,2]>, Arg<"ShlibName">,
- Completion<"Module">, Desc<"Look up the source in the given module or "
- "shared library (can be specified more than once).">;
- def source_info_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
- Completion<"SourceFile">, Desc<"The file from which to display source.">;
- def source_info_line : Option<"line", "l">, Group<1>, Arg<"LineNum">,
- Desc<"The line number at which to start the displaying lines.">;
- def source_info_end_line : Option<"end-line", "e">, Group<1>, Arg<"LineNum">,
- Desc<"The line number at which to stop displaying lines.">;
- def source_info_name : Option<"name", "n">, Group<2>, Arg<"Symbol">,
- Completion<"Symbol">,
- Desc<"The name of a function whose source to display.">;
- def source_info_address : Option<"address", "a">, Group<3>,
- Arg<"AddressOrExpression">, Desc<"Lookup the address and display the source"
- " information for the corresponding file and line.">;
+ def source_info_count : Option<"count", "c">,
+ Arg<"Count">,
+ Desc<"The number of line entries to display.">;
+ def source_info_shlib
+ : Option<"shlib", "s">,
+ Groups<[1, 2]>,
+ Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"Look up the source in the given module or "
+ "shared library (can be specified more than once).">;
+ def source_info_file : Option<"file", "f">,
+ Group<1>,
+ Arg<"Filename">,
+ Completion<"SourceFile">,
+ Desc<"The file from which to display source.">;
+ def source_info_line
+ : Option<"line", "l">,
+ Group<1>,
+ Arg<"LineNum">,
+ Desc<"The line number at which to start the displaying lines.">;
+ def source_info_end_line
+ : Option<"end-line", "e">,
+ Group<1>,
+ Arg<"LineNum">,
+ Desc<"The line number at which to stop displaying lines.">;
+ def source_info_name
+ : Option<"name", "n">,
+ Group<2>,
+ Arg<"Symbol">,
+ Completion<"Symbol">,
+ Desc<"The name of a function whose source to display.">;
+ def source_info_address
+ : Option<"address", "a">,
+ Group<3>,
+ Arg<"AddressOrExpression">,
+ Desc<"Lookup the address and display the source"
+ " information for the corresponding file and line.">;
}
let Command = "source list" in {
- def source_list_count : Option<"count", "c">, Arg<"Count">,
- Desc<"The number of source lines to display.">;
- def source_list_shlib : Option<"shlib", "s">, Groups<[1,2,5]>, Arg<"ShlibName">,
- Completion<"Module">,
- Desc<"Look up the source file in the given shared library.">;
- def source_list_show_breakpoints : Option<"show-breakpoints", "b">,
- Desc<"Show the line table locations from the debug information that "
- "indicate valid places to set source level breakpoints.">;
- def source_list_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
- Completion<"SourceFile">, Desc<"The file from which to display source.">;
- def source_list_line : Option<"line", "l">, Group<1>, Arg<"LineNum">,
- Desc<"The line number at which to start the display source.">;
- def source_list_name : Option<"name", "n">, Group<2>, Arg<"Symbol">,
- Completion<"Symbol">,
- Desc<"The name of a function whose source to display.">;
- def source_list_address : Option<"address", "a">, Group<3>,
- Arg<"AddressOrExpression">, Desc<"Lookup the address and display the source"
- " information for the corresponding file and line.">;
- def source_list_reverse : Option<"reverse", "r">, Group<4>, Desc<"Reverse the"
- " listing to look backwards from the last displayed block of source.">;
- def source_list_file_colon_line : Option<"joint-specifier", "y">, Group<5>,
- Arg<"FileLineColumn">, Completion<"SourceFile">,
- Desc<"A specifier in the form filename:line[:column] from which to display"
- " source.">;
+ def source_list_count : Option<"count", "c">,
+ Arg<"Count">,
+ Desc<"The number of source lines to display.">;
+ def source_list_shlib
+ : Option<"shlib", "s">,
+ Groups<[1, 2, 5]>,
+ Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"Look up the source file in the given shared library.">;
+ def source_list_show_breakpoints
+ : Option<"show-breakpoints", "b">,
+ Desc<"Show the line table locations from the debug information that "
+ "indicate valid places to set source level breakpoints.">;
+ def source_list_file : Option<"file", "f">,
+ Group<1>,
+ Arg<"Filename">,
+ Completion<"SourceFile">,
+ Desc<"The file from which to display source.">;
+ def source_list_line
+ : Option<"line", "l">,
+ Group<1>,
+ Arg<"LineNum">,
+ Desc<"The line number at which to start displaying source.">;
+ def source_list_name
+ : Option<"name", "n">,
+ Group<2>,
+ Arg<"Symbol">,
+ Completion<"Symbol">,
+ Desc<"The name of a function whose source to display.">;
+ def source_list_address
+ : Option<"address", "a">,
+ Group<3>,
+ Arg<"AddressOrExpression">,
+ Desc<"Lookup the address and display the source information for the "
+ "corresponding file and line.">;
+ def source_list_reverse : Option<"reverse", "r">,
+ Group<4>,
+ Desc<"Reverse the listing to look backwards from "
+ "the last displayed block of source.">;
+ def source_list_file_colon_line
+ : Option<"joint-specifier", "y">,
+ Group<5>,
+ Arg<"FileLineColumn">,
+ Completion<"SourceFile">,
+ Desc<"A specifier in the form filename:line[:column] from which to "
+ "display source.">;
}
let Command = "target dependents" in {
- def dependents_no_dependents : Option<"no-dependents", "d">, Group<1>,
- OptionalEnumArg<"Value">,
- Desc<"Whether or not to load dependents when creating a target. If the "
- "option is not specified, the value is implicitly 'default'. If the "
- "option is specified but without a value, the value is implicitly "
- "'true'.">;
+ def dependents_no_dependents
+ : Option<"no-dependents", "d">,
+ Group<1>,
+ OptionalEnumArg<"Value">,
+ Desc<"Whether or not to load dependents when creating a target. If the "
+ "option is not specified, the value is implicitly 'default'. If "
+ "the "
+ "option is specified but without a value, the value is implicitly "
+ "'true'.">;
}
let Command = "target modules dump" in {
def target_modules_dump_verbose : Option<"verbose", "v">,
- Desc<"Enable verbose dump.">;
+ Desc<"Enable verbose dump.">;
}
let Command = "target modules list" in {
- def target_modules_list_address : Option<"address", "a">, Group<1>,
- Arg<"AddressOrExpression">, Desc<"Display the image at this address.">;
- def target_modules_list_arch : Option<"arch", "A">, Group<1>,
- OptionalArg<"Width">, Desc<"Display the architecture when listing images.">;
- def target_modules_list_triple : Option<"triple", "t">, Group<1>,
- OptionalArg<"Width">, Desc<"Display the triple when listing images.">;
- def target_modules_list_header : Option<"header", "h">, Group<1>,
- Desc<"Display the image base address as a load address if debugging, a file"
- " address otherwise.">;
- def target_modules_list_offset : Option<"offset", "o">, Group<1>,
- Desc<"Display the image load address offset from the base file address "
- "(the slide amount).">;
- def target_modules_list_uuid : Option<"uuid", "u">, Group<1>,
- Desc<"Display the UUID when listing images.">;
- def target_modules_list_fullpath : Option<"fullpath", "f">, Group<1>,
- OptionalArg<"Width">,
- Desc<"Display the fullpath to the image object file.">;
- def target_modules_list_directory : Option<"directory", "d">, Group<1>,
- OptionalArg<"Width">, Desc<"Display the directory with optional width for "
- "the image object file.">;
- def target_modules_list_basename : Option<"basename", "b">, Group<1>,
- OptionalArg<"Width">, Desc<"Display the basename with optional width for "
- "the image object file.">;
- def target_modules_list_symfile : Option<"symfile", "s">, Group<1>,
- OptionalArg<"Width">, Desc<"Display the fullpath to the image symbol file "
- "with optional width.">;
- def target_modules_list_symfile_unique : Option<"symfile-unique", "S">,
- Group<1>, OptionalArg<"Width">, Desc<"Display the symbol file with optional"
- " width only if it is different from the executable object file.">;
- def target_modules_list_mod_time : Option<"mod-time", "m">, Group<1>,
- OptionalArg<"Width">, Desc<"Display the modification time with optional "
- "width of the module.">;
- def target_modules_list_ref_count : Option<"ref-count", "r">, Group<1>,
- OptionalArg<"Width">, Desc<"Display whether the module is still in the "
- "the shared module cache (Y/N), and its shared pointer use_count.">;
- def target_modules_list_pointer : Option<"pointer", "p">, Group<1>,
- OptionalArg<"None">, Desc<"Display the module pointer.">;
- def target_modules_list_global : Option<"global", "g">, Group<1>,
- Desc<"Display the modules from the global module list, not just the "
- "current target.">;
+ def target_modules_list_address : Option<"address", "a">,
+ Group<1>,
+ Arg<"AddressOrExpression">,
+ Desc<"Display the image at this address.">;
+ def target_modules_list_arch
+ : Option<"arch", "A">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<"Display the architecture when listing images.">;
+ def target_modules_list_triple
+ : Option<"triple", "t">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<"Display the triple when listing images.">;
+ def target_modules_list_header : Option<"header", "h">,
+ Group<1>,
+ Desc<"Display the image base address as a "
+ "load address if debugging, a file"
+ " address otherwise.">;
+ def target_modules_list_offset
+ : Option<"offset", "o">,
+ Group<1>,
+ Desc<"Display the image load address offset from the base file address "
+ "(the slide amount).">;
+ def target_modules_list_uuid : Option<"uuid", "u">,
+ Group<1>,
+ Desc<"Display the UUID when listing images.">;
+ def target_modules_list_fullpath
+ : Option<"fullpath", "f">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<"Display the fullpath to the image object file.">;
+ def target_modules_list_directory
+ : Option<"directory", "d">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<"Display the directory with optional width for "
+ "the image object file.">;
+ def target_modules_list_basename
+ : Option<"basename", "b">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<"Display the basename with optional width for "
+ "the image object file.">;
+ def target_modules_list_symfile
+ : Option<"symfile", "s">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<"Display the fullpath to the image symbol file "
+ "with optional width.">;
+ def target_modules_list_symfile_unique
+ : Option<"symfile-unique", "S">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<"Display the symbol file with optional"
+ " width only if it is different from the executable object file.">;
+ def target_modules_list_mod_time
+ : Option<"mod-time", "m">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<"Display the modification time with optional "
+ "width of the module.">;
+ def target_modules_list_ref_count
+ : Option<"ref-count", "r">,
+ Group<1>,
+ OptionalArg<"Width">,
+ Desc<
+ "Display whether the module is still in the "
+ "the shared module cache (Y/N), and its shared pointer use_count.">;
+ def target_modules_list_pointer : Option<"pointer", "p">,
+ Group<1>,
+ OptionalArg<"None">,
+ Desc<"Display the module pointer.">;
+ def target_modules_list_global
+ : Option<"global", "g">,
+ Group<1>,
+ Desc<"Display the modules from the global module list, not just the "
+ "current target.">;
}
let Command = "target modules show unwind" in {
- def target_modules_show_unwind_name : Option<"name", "n">, Group<1>,
- Arg<"FunctionName">,
- Desc<"Show unwind instructions for a function or symbol name.">;
- def target_modules_show_unwind_address : Option<"address", "a">, Group<2>,
- Arg<"AddressOrExpression">, Desc<"Show unwind instructions for a function "
- "or symbol containing an address">;
- def target_modules_show_unwind_cached : Option<"cached", "c">,
- Arg<"Boolean">, Desc<"Show cached unwind information">;
+ def target_modules_show_unwind_name
+ : Option<"name", "n">,
+ Group<1>,
+ Arg<"FunctionName">,
+ Desc<"Show unwind instructions for a function or symbol name.">;
+ def target_modules_show_unwind_address
+ : Option<"address", "a">,
+ Group<2>,
+ Arg<"AddressOrExpression">,
+ Desc<"Show unwind instructions for a function "
+ "or symbol containing an address">;
+ def target_modules_show_unwind_cached
+ : Option<"cached", "c">,
+ Arg<"Boolean">,
+ Desc<"Show cached unwind information">;
}
let Command = "target modules lookup" in {
- def target_modules_lookup_address : Option<"address", "a">, Group<1>,
- Arg<"AddressOrExpression">, Required, Desc<"Lookup an address in one or "
- "more target modules.">;
- def target_modules_lookup_offset : Option<"offset", "o">, Group<1>,
- Arg<"Offset">, Desc<"When looking up an address subtract <offset> from any "
- "addresses before doing the lookup.">;
+ def target_modules_lookup_address : Option<"address", "a">,
+ Group<1>,
+ Arg<"AddressOrExpression">,
+ Required,
+ Desc<"Lookup an address in one or "
+ "more target modules.">;
+ def target_modules_lookup_offset
+ : Option<"offset", "o">,
+ Group<1>,
+ Arg<"Offset">,
+ Desc<"When looking up an address subtract <offset> from any "
+ "addresses before doing the lookup.">;
// FIXME: re-enable regex for types when the LookupTypeInModule actually uses
// the regex option by adding to group 6.
- def target_modules_lookup_regex : Option<"regex", "r">, Groups<[2,4,5]>,
- Desc<"The <name> argument for name lookups are regular expressions.">;
- def target_modules_lookup_symbol : Option<"symbol", "s">, Group<2>,
- Arg<"Symbol">, Required, Desc<"Lookup a symbol by name in the symbol tables"
- " in one or more target modules.">;
- def target_modules_lookup_file : Option<"file", "f">, Group<3>,
- Arg<"Filename">, Required, Desc<"Lookup a file by fullpath or basename in "
- "one or more target modules.">;
- def target_modules_lookup_line : Option<"line", "l">, Group<3>,
- Arg<"LineNum">, Desc<"Lookup a line number in a file (must be used in "
- "conjunction with --file).">;
- def target_modules_lookup_no_inlines : Option<"no-inlines", "i">,
- GroupRange<3,5>,
- Desc<"Ignore inline entries (must be used in conjunction with --file or "
- "--function).">;
- def target_modules_lookup_function : Option<"function", "F">, Group<4>,
- Arg<"FunctionName">, Required, Desc<"Lookup a function by name in the debug"
- " symbols in one or more target modules.">;
- def target_modules_lookup_name : Option<"name", "n">, Group<5>,
- Arg<"FunctionOrSymbol">, Required, Desc<"Lookup a function or symbol by "
- "name in one or more target modules.">;
- def target_modules_lookup_type : Option<"type", "t">, Group<6>, Arg<"Name">,
- Required, Desc<"Lookup a type by name in the debug symbols in one or more "
- "target modules.">;
- def target_modules_lookup_variables_ranges : Option<"show-variable-ranges",
- "\\x01">, GroupRange<1, 6>, Desc<"Dump valid ranges of variables (must be "
- "used in conjunction with --verbose">;
- def target_modules_lookup_verbose : Option<"verbose", "v">,
- Desc<"Enable verbose lookup information.">;
- def target_modules_lookup_all : Option<"all", "A">, Desc<"Print all matches, "
- "not just the best match, if a best match is available.">;
+ def target_modules_lookup_regex
+ : Option<"regex", "r">,
+ Groups<[2, 4, 5]>,
+ Desc<"The <name> argument for name lookups are regular expressions.">;
+ def target_modules_lookup_symbol
+ : Option<"symbol", "s">,
+ Group<2>,
+ Arg<"Symbol">,
+ Required,
+ Desc<"Lookup a symbol by name in the symbol tables"
+ " in one or more target modules.">;
+ def target_modules_lookup_file
+ : Option<"file", "f">,
+ Group<3>,
+ Arg<"Filename">,
+ Required,
+ Desc<"Lookup a file by fullpath or basename in "
+ "one or more target modules.">;
+ def target_modules_lookup_line
+ : Option<"line", "l">,
+ Group<3>,
+ Arg<"LineNum">,
+ Desc<"Lookup a line number in a file (must be used in "
+ "conjunction with --file).">;
+ def target_modules_lookup_no_inlines
+ : Option<"no-inlines", "i">,
+ GroupRange<3, 5>,
+ Desc<
+ "Ignore inline entries (must be used in conjunction with --file or "
+ "--function).">;
+ def target_modules_lookup_function
+ : Option<"function", "F">,
+ Group<4>,
+ Arg<"FunctionName">,
+ Required,
+ Desc<"Lookup a function by name in the debug"
+ " symbols in one or more target modules.">;
+ def target_modules_lookup_name : Option<"name", "n">,
+ Group<5>,
+ Arg<"FunctionOrSymbol">,
+ Required,
+ Desc<"Lookup a function or symbol by "
+ "name in one or more target modules.">;
+ def target_modules_lookup_type
+ : Option<"type", "t">,
+ Group<6>,
+ Arg<"Name">,
+ Required,
+ Desc<"Lookup a type by name in the debug symbols in one or more "
+ "target modules.">;
+ def target_modules_lookup_variables_ranges
+ : Option<"show-variable-ranges", "\\x01">,
+ GroupRange<1, 6>,
+ Desc<"Dump valid ranges of variables (must be used in conjunction with "
+ "--verbose">;
+ def target_modules_lookup_verbose
+ : Option<"verbose", "v">,
+ Desc<"Enable verbose lookup information.">;
+ def target_modules_lookup_all : Option<"all", "A">,
+ Desc<"Print all matches, not just the best "
+ "match, if a best match is available.">;
}
let Command = "target stop hook add" in {
- def target_stop_hook_add_one_liner : Option<"one-liner", "o">, GroupRange<1,3>,
- Arg<"OneLiner">, Desc<"Add a command for the stop hook. Can be specified "
- "more than once, and commands will be run in the order they appear.">;
- def target_stop_hook_add_shlib : Option<"shlib", "s">, Arg<"ShlibName">,
- Completion<"Module">,
- Desc<"Set the module within which the stop-hook is to be run.">;
- def target_stop_hook_add_thread_index : Option<"thread-index", "x">,
- Arg<"ThreadIndex">, Desc<"The stop hook is run only for the thread whose "
- "index matches this argument.">;
- def target_stop_hook_add_thread_id : Option<"thread-id", "t">,
- Arg<"ThreadID">, Desc<"The stop hook is run only for the thread whose TID "
- "matches this argument.">;
- def target_stop_hook_add_thread_name : Option<"thread-name", "T">,
- Arg<"ThreadName">, Desc<"The stop hook is run only for the thread whose "
- "thread name matches this argument.">;
- def target_stop_hook_add_queue_name : Option<"queue-name", "q">,
- Arg<"QueueName">, Desc<"The stop hook is run only for threads in the queue "
- "whose name is given by this argument.">;
- def target_stop_hook_add_file : Option<"file", "f">, Groups<[1,4]>,
- Arg<"Filename">, Desc<"Specify the source file within which the stop-hook "
- "is to be run.">, Completion<"SourceFile">;
- def target_stop_hook_add_start_line : Option<"start-line", "l">, Groups<[1,4]>,
- Arg<"LineNum">, Desc<"Set the start of the line range for which the "
- "stop-hook is to be run.">;
- def target_stop_hook_add_end_line : Option<"end-line", "e">, Groups<[1,4]>,
- Arg<"LineNum">, Desc<"Set the end of the line range for which the stop-hook"
- " is to be run.">;
- def target_stop_hook_add_classname : Option<"classname", "c">, Groups<[2,5]>,
- Arg<"ClassName">,
- Desc<"Specify the class within which the stop-hook is to be run.">;
- def target_stop_hook_add_name : Option<"name", "n">, Groups<[3,6]>,
- Arg<"FunctionName">, Desc<"Set the function name within which the stop hook"
- " will be run.">, Completion<"Symbol">;
- def target_stop_hook_add_auto_continue : Option<"auto-continue", "G">,
- Arg<"Boolean">, Desc<"The stop-hook will auto-continue after running its"
- " commands.">;
- def target_stop_hook_add_at_initial_stop : Option<"at-initial-stop", "I">,
- Arg<"Boolean">, Desc<"Whether the stop-hook will trigger when lldb "
- "initially gains control of the process. For a process launch, this "
- "initial stop may happen very early on - before the loader has run. You "
- "can use this option if you do not want some stop-hooks to run then. "
- "Defaults to true.">;
+ def target_stop_hook_add_one_liner
+ : Option<"one-liner", "o">,
+ GroupRange<1, 3>,
+ Arg<"OneLiner">,
+ Desc<"Add a command for the stop hook. Can be specified more than "
+ "once, and commands will be run in the order they appear.">;
+ def target_stop_hook_add_shlib
+ : Option<"shlib", "s">,
+ Arg<"ShlibName">,
+ Completion<"Module">,
+ Desc<"Set the module within which the stop-hook is to be run.">;
+ def target_stop_hook_add_thread_index
+ : Option<"thread-index", "x">,
+ Arg<"ThreadIndex">,
+ Desc<"The stop hook is run only for the thread whose index matches "
+ "this argument.">;
+ def target_stop_hook_add_thread_id
+ : Option<"thread-id", "t">,
+ Arg<"ThreadID">,
+ Desc<"The stop hook is run only for the thread whose TID matches this "
+ "argument.">;
+ def target_stop_hook_add_thread_name
+ : Option<"thread-name", "T">,
+ Arg<"ThreadName">,
+ Desc<"The stop hook is run only for the thread whose thread name "
+ "matches this argument.">;
+ def target_stop_hook_add_queue_name
+ : Option<"queue-name", "q">,
+ Arg<"QueueName">,
+ Desc<"The stop hook is run only for threads in the ${q}ueue whose name "
+ "is given by this argument.">;
+ def target_stop_hook_add_file : Option<"file", "f">,
+ Groups<[1, 4]>,
+ Arg<"Filename">,
+ Desc<"Specify the source ${f}ile within "
+ "which the stop-hook is to be run.">,
+ Completion<"SourceFile">;
+ def target_stop_hook_add_start_line
+ : Option<"start-line", "l">,
+ Groups<[1, 4]>,
+ Arg<"LineNum">,
+ Desc<"Set the start of the ${l}ine range for which the "
+ "stop-hook is to be run.">;
+ def target_stop_hook_add_end_line
+ : Option<"end-line", "e">,
+ Groups<[1, 4]>,
+ Arg<"LineNum">,
+ Desc<"Set the ${e}nd of the line range for which the stop-hook is to "
+ "be run.">;
+ def target_stop_hook_add_classname
+ : Option<"classname", "c">,
+ Groups<[2, 5]>,
+ Arg<"ClassName">,
+ Desc<"Specify the ${c}lass within which the stop-hook is to be run.">;
+ def target_stop_hook_add_name
+ : Option<"name", "n">,
+ Groups<[3, 6]>,
+ Arg<"FunctionName">,
+ Desc<
+ "Set the ${f}unction name within which the stop hook will be run.">,
+ Completion<"Symbol">;
+ def target_stop_hook_add_auto_continue
+ : Option<"auto-continue", "G">,
+ Arg<"Boolean">,
+ Desc<"The stop-hook will auto-continue after running its commands.">;
+ def target_stop_hook_add_at_initial_stop
+ : Option<"at-initial-stop", "I">,
+ Arg<"Boolean">,
+ Desc<"Whether the stop-hook will trigger when lldb ${i}nitially gains "
+ "control of the process. For a process launch, this initial stop "
+ "may happen very early on - before the loader has run. You can "
+ "use this option if you do not want some stop-hooks to run then. "
+ "Defaults to true.">;
}
let Command = "thread backtrace" in {
- def thread_backtrace_count : Option<"count", "c">, Group<1>, Arg<"Count">,
- Desc<"How many frames to display (0 for all)">;
- def thread_backtrace_start : Option<"start", "s">, Group<1>,
- Arg<"FrameIndex">, Desc<"Frame in which to start the backtrace">;
- def thread_backtrace_extended : Option<"extended", "e">, Group<1>,
- Arg<"Boolean">, Desc<"Show the extended backtrace, if available">;
- def thread_backtrace_unfiltered : Option<"unfiltered", "u">, Group<1>,
- Desc<"Do not filter out frames according to installed frame recognizers">;
+ def thread_backtrace_count : Option<"count", "c">,
+ Group<1>,
+ Arg<"Count">,
+ Desc<"How many frames to display (0 for all)">;
+ def thread_backtrace_start : Option<"start", "s">,
+ Group<1>,
+ Arg<"FrameIndex">,
+ Desc<"Frame in which to ${s}tart the backtrace">;
+ def thread_backtrace_extended
+ : Option<"extended", "e">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"Show the ${e}xtended backtrace, if available">;
+ def thread_backtrace_unfiltered : Option<"unfiltered", "u">,
+ Group<1>,
+ Desc<"Do not filter out frames according "
+ "to installed frame recognizers">;
}
let Command = "thread step scope" in {
- def thread_step_scope_step_in_avoids_no_debug :
- Option<"step-in-avoids-no-debug", "a">, Group<1>, Arg<"Boolean">,
- Desc<"A boolean value that sets whether stepping into functions will step "
- "over functions with no debug information.">;
- def thread_step_scope_step_out_avoids_no_debug :
- Option<"step-out-avoids-no-debug", "A">, Group<1>, Arg<"Boolean">,
- Desc<"A boolean value, if true stepping out of functions will continue to"
- " step out till it hits a function with debug information.">;
- def thread_step_scope_count : Option<"count", "c">, Group<1>, Arg<"Count">,
- Desc<"How many times to perform the stepping operation - currently only "
- "supported for step-inst and next-inst.">;
- def thread_step_scope_end_linenumber : Option<"end-linenumber", "e">,
- Group<1>, Arg<"LineNum">, Desc<"The line at which to stop stepping - "
- "defaults to the next line and only supported for step-in and step-over."
- " You can also pass the string 'block' to step to the end of the current"
- " block. This is particularly use in conjunction with --step-target to"
- " step through a complex calling sequence.">;
- def thread_step_scope_run_mode : Option<"run-mode", "m">, Group<1>,
- EnumArg<"RunMode">, Desc<"Determine how to run other "
- "threads while stepping the current thread.">;
- def thread_step_scope_step_over_regexp : Option<"step-over-regexp", "r">,
- Group<1>, Arg<"RegularExpression">, Desc<"A regular expression that defines "
- "function names to not to stop at when stepping in.">;
- def thread_step_scope_step_in_target : Option<"step-in-target", "t">,
- Group<1>, Arg<"FunctionName">, Desc<"The name of the directly called "
- "function step in should stop at when stepping into.">;
+ def thread_step_scope_step_in_avoids_no_debug
+ : Option<"step-in-avoids-no-debug", "a">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"A boolean value that sets whether stepping into functions will "
+ "step over functions with no debug information.">;
+ def thread_step_scope_step_out_avoids_no_debug
+ : Option<"step-out-avoids-no-debug", "A">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"A boolean value, if true stepping out of functions will continue "
+ "to step out till it hits a function with debug information.">;
+ def thread_step_scope_count
+ : Option<"count", "c">,
+ Group<1>,
+ Arg<"Count">,
+ Desc<"How many times to perform the stepping operation - currently "
+ "only supported for step-inst and next-inst.">;
+ def thread_step_scope_end_linenumber
+ : Option<"end-linenumber", "e">,
+ Group<1>,
+ Arg<"LineNum">,
+ Desc<"The line at which to stop stepping - defaults to the next line "
+ "and only supported for step-in and step-over. You can also pass "
+ "the string 'block' to step to the end of the current block. This "
+ "is particularly useful in conjunction with --step-target to step "
+ "through a complex calling sequence.">;
+ def thread_step_scope_run_mode : Option<"run-mode", "m">,
+ Group<1>,
+ EnumArg<"RunMode">,
+ Desc<"Determine how to run other threads "
+ "while stepping the current thread.">;
+ def thread_step_scope_step_over_regexp
+ : Option<"step-over-regexp", "r">,
+ Group<1>,
+ Arg<"RegularExpression">,
+ Desc<"A ${r}egular expression that defines function names to not to "
+ "stop at when stepping in.">;
+ def thread_step_scope_step_in_target
+ : Option<"step-in-target", "t">,
+ Group<1>,
+ Arg<"FunctionName">,
+ Desc<"The name of the directly called function step in should stop at "
+ "when stepping into.">;
}
let Command = "thread until" in {
- def thread_until_frame : Option<"frame", "f">, Group<1>, Arg<"FrameIndex">,
- Desc<"Frame index for until operation - defaults to 0">;
- def thread_until_thread : Option<"thread", "t">, Group<1>, Arg<"ThreadIndex">,
- Desc<"Thread index for the thread for until operation">;
- def thread_until_run_mode : Option<"run-mode", "m">, Group<1>,
- EnumArg<"RunMode">, Desc<"Determine how to run other "
- "threads while stepping this one">;
- def thread_until_address : Option<"address", "a">, Group<1>,
- Arg<"AddressOrExpression">, Desc<"Run until we reach the specified address, "
- "or leave the function - can be specified multiple times.">;
+ def thread_until_frame
+ : Option<"frame", "f">,
+ Group<1>,
+ Arg<"FrameIndex">,
+ Desc<"Frame index for until operation - defaults to 0">;
+ def thread_until_thread
+ : Option<"thread", "t">,
+ Group<1>,
+ Arg<"ThreadIndex">,
+ Desc<"Thread index for the thread for until operation">;
+ def thread_until_run_mode : Option<"run-mode", "m">,
+ Group<1>,
+ EnumArg<"RunMode">,
+ Desc<"Determine how to run other "
+ "threads while stepping this one">;
+ def thread_until_address
+ : Option<"address", "a">,
+ Group<1>,
+ Arg<"AddressOrExpression">,
+ Desc<"Run until we reach the specified address, "
+ "or leave the function - can be specified multiple times.">;
}
let Command = "thread info" in {
- def thread_info_json : Option<"json", "j">, Desc<"Display the thread info in"
- " JSON format.">;
- def thread_info_stop_info : Option<"stop-info", "s">, Desc<"Display the "
- "extended stop info in JSON format.">;
+ def thread_info_json : Option<"json", "j">,
+ Desc<"Display the thread info in"
+ " JSON format.">;
+ def thread_info_stop_info : Option<"stop-info", "s">,
+ Desc<"Display the "
+ "extended stop info in JSON format.">;
def thread_info_backing_thread : Option<"backing-thread", "b">,
- Desc<"If this is an OS plugin thread, query the backing thread instead; has"
- " no effect otherwise.">;
+ Desc<"If this is an OS plugin thread, query "
+ "the backing thread instead; has"
+ " no effect otherwise.">;
}
let Command = "thread return" in {
- def thread_return_from_expression : Option<"from-expression", "x">,
- Desc<"Return from the innermost expression evaluation.">;
+ def thread_return_from_expression
+ : Option<"from-expression", "x">,
+ Desc<"Return from the innermost expression evaluation.">;
}
let Command = "thread jump" in {
- def thread_jump_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
- Completion<"SourceFile">, Desc<"Specifies the source file to jump to.">;
- def thread_jump_line : Option<"line", "l">, Group<1>, Arg<"LineNum">,
- Required, Desc<"Specifies the line number to jump to.">;
- def thread_jump_by : Option<"by", "b">, Group<2>, Arg<"Offset">, Required,
- Desc<"Jumps by a relative line offset from the current line,"
- "can be a positive or negative offset">;
- def thread_jump_address : Option<"address", "a">, Group<3>,
- Arg<"AddressOrExpression">, Required, Desc<"Jumps to a specific address.">;
- def thread_jump_force : Option<"force", "r">, Groups<[1,2,3]>,
- Desc<"Allows the PC to leave the current function.">;
+ def thread_jump_file : Option<"file", "f">,
+ Group<1>,
+ Arg<"Filename">,
+ Completion<"SourceFile">,
+ Desc<"Specifies the source file to jump to.">;
+ def thread_jump_line : Option<"line", "l">,
+ Group<1>,
+ Arg<"LineNum">,
+ Required,
+ Desc<"Specifies the line number to jump to.">;
+ def thread_jump_by
+ : Option<"by", "b">,
+ Group<2>,
+ Arg<"Offset">,
+ Required,
+ Desc<"Jumps by a relative line offset from the current line, "
+ "can be a positive or negative offset.">;
+ def thread_jump_address : Option<"address", "a">,
+ Group<3>,
+ Arg<"AddressOrExpression">,
+ Required,
+ Desc<"Jumps to a specific address.">;
+ def thread_jump_force : Option<"force", "r">,
+ Groups<[1, 2, 3]>,
+ Desc<"Allows the PC to leave the current function.">;
}
let Command = "thread plan list" in {
- def thread_plan_list_verbose : Option<"verbose", "v">, Group<1>,
- Desc<"Display more information about the thread plans">;
- def thread_plan_list_internal : Option<"internal", "i">, Group<1>,
- Desc<"Display internal as well as user thread plans">;
- def thread_plan_list_thread_id : Option<"thread-id", "t">, Group<1>,
- Arg<"ThreadID">, Desc<"List the thread plans for this TID, can be "
- "specified more than once.">;
- def thread_plan_list_unreported : Option<"unreported", "u">, Group<1>,
- Desc<"Display thread plans for unreported threads">;
+ def thread_plan_list_verbose
+ : Option<"verbose", "v">,
+ Group<1>,
+ Desc<"Display more information about the thread plans">;
+ def thread_plan_list_internal
+ : Option<"internal", "i">,
+ Group<1>,
+ Desc<"Display internal as well as user thread plans">;
+ def thread_plan_list_thread_id
+ : Option<"thread-id", "t">,
+ Group<1>,
+ Arg<"ThreadID">,
+ Desc<"List the thread plans for this TID, can be "
+ "specified more than once.">;
+ def thread_plan_list_unreported
+ : Option<"unreported", "u">,
+ Group<1>,
+ Desc<"Display thread plans for unreported threads">;
}
let Command = "thread select" in {
- def thread_select_thread_id : Option<"thread-id", "t">, Group<2>,
- Arg<"ThreadID">, Completion<"ThreadID">,
- Desc<"Provide a thread ID instead of a thread index.">;
+ def thread_select_thread_id
+ : Option<"thread-id", "t">,
+ Group<2>,
+ Arg<"ThreadID">,
+ Completion<"ThreadID">,
+ Desc<"Provide a thread ID instead of a thread index.">;
}
let Command = "thread trace dump function calls" in {
- def thread_trace_dump_function_calls_file : Option<"file", "F">, Group<1>,
- Arg<"Filename">,
- Desc<"Dump the function calls to a file instead of the standard output.">;
- def thread_trace_dump_function_calls_json: Option<"json", "j">,
- Group<1>,
- Desc<"Dump in simple JSON format.">;
- def thread_trace_dump_function_calls_pretty_json: Option<"pretty-json", "J">,
- Group<1>,
- Desc<"Dump in JSON format but pretty printing the output for easier "
- "readability.">;
+ def thread_trace_dump_function_calls_file
+ : Option<"file", "F">,
+ Group<1>,
+ Arg<"Filename">,
+ Desc<"Dump the function calls to a file instead of the standard "
+ "output.">;
+ def thread_trace_dump_function_calls_json
+ : Option<"json", "j">,
+ Group<1>,
+ Desc<"Dump in simple JSON format.">;
+ def thread_trace_dump_function_calls_pretty_json
+ : Option<"pretty-json", "J">,
+ Group<1>,
+ Desc<"Dump in JSON format but pretty printing the output for easier "
+ "readability.">;
}
let Command = "thread trace dump instructions" in {
- def thread_trace_dump_instructions_forwards: Option<"forwards", "f">,
- Group<1>,
- Desc<"If specified, the trace is traversed forwards chronologically "
- "starting at the oldest instruction. Otherwise, it starts at the most "
- "recent one and the traversal is backwards.">;
- def thread_trace_dump_instructions_count : Option<"count", "c">, Group<1>,
- Arg<"Count">,
- Desc<"The number of instructions to display starting at the most recent "
- "instruction, or the oldest if --forwards is provided.">;
- def thread_trace_dump_instructions_all : Option<"all", "a">, Group<1>,
- Desc<"From the starting point of the trace, dump all instructions "
- "available.">;
- def thread_trace_dump_instructions_id: Option<"id", "i">, Group<1>,
- Arg<"Index">,
- Desc<"Custom starting instruction id from where to start traversing. This "
- "id can be provided in decimal or hexadecimal representation.">;
- def thread_trace_dump_instructions_skip: Option<"skip", "s">, Group<1>,
- Arg<"Index">,
- Desc<"How many trace items (instructions, errors and events) to skip from "
- "the starting position of the trace before starting the traversal.">;
- def thread_trace_dump_instructions_raw : Option<"raw", "r">, Group<1>,
- Desc<"Dump only instruction address without disassembly nor symbol "
- "information.">;
- def thread_trace_dump_instructions_file : Option<"file", "F">, Group<1>,
- Arg<"Filename">,
- Desc<"Dump the instruction to a file instead of the standard output.">;
- def thread_trace_dump_instructions_json: Option<"json", "j">,
- Group<1>,
- Desc<"Dump in simple JSON format.">;
- def thread_trace_dump_instructions_pretty_print: Option<"pretty-json", "J">,
- Group<1>,
- Desc<"Dump in JSON format but pretty printing the output for easier "
- "readability.">;
- def thread_trace_dump_instructions_show_kind : Option<"kind", "k">, Group<1>,
- Desc<"Show instruction control flow kind. Refer to the enum "
- "`InstructionControlFlowKind` for a list of control flow kind. "
- "As an important note, far jumps, far calls and far returns often indicate "
- "calls to and from kernel.">;
- def thread_trace_dump_instructions_show_timestamps: Option<"time", "t">,
- Group<1>,
- Desc<"For each trace item, print the corresponding wall clock timestamp "
- "if available.">;
- def thread_trace_dump_instructions_show_events : Option<"events", "e">,
- Group<1>,
- Desc<"Dump the events that happened during the execution of the target.">;
- def thread_trace_dump_instruction_only_events : Option<"only-events", "E">,
- Group<1>,
- Desc<"Dump only the events that happened during the execution of the "
- "target. No instructions are dumped.">;
- def thread_trace_dump_instructions_continue: Option<"continue", "C">,
- Group<1>,
- Desc<"Continue dumping instructions right where the previous invocation of "
- "this command was left, or from the beginning if this is the first "
- "invocation. The --skip argument is discarded and the other arguments are "
- "preserved from the previous invocation when possible.">;
+ def thread_trace_dump_instructions_forwards
+ : Option<"forwards", "f">,
+ Group<1>,
+ Desc<"If specified, the trace is traversed forwards chronologically "
+ "starting at the oldest instruction. Otherwise, it starts at the "
+ "most "
+ "recent one and the traversal is backwards.">;
+ def thread_trace_dump_instructions_count
+ : Option<"count", "c">,
+ Group<1>,
+ Arg<"Count">,
+ Desc<
+ "The number of instructions to display starting at the most recent "
+ "instruction, or the oldest if --forwards is provided.">;
+ def thread_trace_dump_instructions_all
+ : Option<"all", "a">,
+ Group<1>,
+ Desc<"From the starting point of the trace, dump all instructions "
+ "available.">;
+ def thread_trace_dump_instructions_id
+ : Option<"id", "i">,
+ Group<1>,
+ Arg<"Index">,
+ Desc<"Custom starting instruction id from where to start traversing. "
+ "This "
+ "id can be provided in decimal or hexadecimal representation.">;
+ def thread_trace_dump_instructions_skip
+ : Option<"skip", "s">,
+ Group<1>,
+ Arg<"Index">,
+ Desc<"How many trace items (instructions, errors and events) to skip "
+ "from "
+ "the starting position of the trace before starting the "
+ "traversal.">;
+ def thread_trace_dump_instructions_raw
+ : Option<"raw", "r">,
+ Group<1>,
+ Desc<"Dump only instruction address without disassembly nor symbol "
+ "information.">;
+ def thread_trace_dump_instructions_file
+ : Option<"file", "F">,
+ Group<1>,
+ Arg<"Filename">,
+ Desc<"Dump the instruction to a file instead of the standard output.">;
+ def thread_trace_dump_instructions_json : Option<"json", "j">,
+ Group<1>,
+ Desc<"Dump in simple JSON format.">;
+ def thread_trace_dump_instructions_pretty_print
+ : Option<"pretty-json", "J">,
+ Group<1>,
+ Desc<"Dump in JSON format but pretty printing the output for easier "
+ "readability.">;
+ def thread_trace_dump_instructions_show_kind
+ : Option<"kind", "k">,
+ Group<1>,
+ Desc<"Show instruction control flow kind. Refer to the enum "
+ "`InstructionControlFlowKind` for a list of control flow kind. "
+ "As an important note, far jumps, far calls and far returns often "
+ "indicate "
+ "calls to and from kernel.">;
+ def thread_trace_dump_instructions_show_timestamps
+ : Option<"time", "t">,
+ Group<1>,
+ Desc<
+ "For each trace item, print the corresponding wall clock timestamp "
+ "if available.">;
+ def thread_trace_dump_instructions_show_events
+ : Option<"events", "e">,
+ Group<1>,
+ Desc<"Dump the events that happened during the execution of the "
+ "target.">;
+ def thread_trace_dump_instruction_only_events
+ : Option<"only-events", "E">,
+ Group<1>,
+ Desc<"Dump only the events that happened during the execution of the "
+ "target. No instructions are dumped.">;
+ def thread_trace_dump_instructions_continue
+ : Option<"continue", "C">,
+ Group<1>,
+ Desc<
+ "Continue dumping instructions right where the previous invocation "
+ "of "
+ "this command was left, or from the beginning if this is the first "
+ "invocation. The --skip argument is discarded and the other "
+ "arguments are "
+ "preserved from the previous invocation when possible.">;
}
let Command = "thread trace dump info" in {
- def thread_trace_dump_info_verbose : Option<"verbose", "v">, Group<1>,
- Desc<"show verbose thread trace dump info">;
- def thread_trace_dump_info_json: Option<"json", "j">, Group<1>,
- Desc<"Dump in JSON format.">;
+ def thread_trace_dump_info_verbose
+ : Option<"verbose", "v">,
+ Group<1>,
+ Desc<"show verbose thread trace dump info">;
+ def thread_trace_dump_info_json : Option<"json", "j">,
+ Group<1>,
+ Desc<"Dump in JSON format.">;
}
let Command = "type summary add" in {
- def type_summary_add_category : Option<"category", "w">, Arg<"Name">,
- Desc<"Add this to the given category instead of the default one.">;
- def type_summary_add_cascade : Option<"cascade", "C">, Arg<"Boolean">,
- Desc<"If true, cascade through typedef chains.">;
- def type_summary_add_no_value : Option<"no-value", "v">,
- Desc<"Don't show the value, just show the summary, for this type.">;
- def type_summary_add_skip_pointers : Option<"skip-pointers", "p">,
- Desc<"Don't use this format for pointers-to-type objects.">;
- def type_summary_add_pointer_match_depth : Option<"pointer-match-depth", "d">,
- Arg<"UnsignedInteger">,
- Desc<"Specify the maximum pointer depth that this format can be apply to "
- "(default to 1). It's only effective when --skip-pointers is not set.">;
- def type_summary_add_skip_references : Option<"skip-references", "r">,
- Desc<"Don't use this format for references-to-type objects.">;
- def type_summary_add_regex : Option<"regex", "x">,
- Desc<"Type names are actually regular expressions.">;
- def type_summary_add_recognizer_function :
- Option<"recognizer-function", "\\x01">,
- Desc<"The names in the argument list are actually the names of python "
- "functions that decide whether to use this summary for any given type. "
- "Cannot be specified at the same time as --regex (-x).">;
- def type_summary_add_inline_children : Option<"inline-children", "c">,
- Group<1>, Required,
- Desc<"If true, inline all child values into summary string.">;
- def type_summary_add_omit_names : Option<"omit-names", "O">, Group<1>,
- Desc<"If true, omit value names in the summary display.">;
- def type_summary_add_summary_string : Option<"summary-string", "s">, Group<2>,
- Arg<"SummaryString">, Required,
- Desc<"Summary string used to display text and object contents.">;
- def type_summary_add_python_script : Option<"python-script", "o">, Group<3>,
- Arg<"PythonScript">,
- Desc<"Give a one-liner Python script as part of the command.">;
- def type_summary_add_python_function : Option<"python-function", "F">,
- Group<3>, Arg<"PythonFunction">,
- Desc<"Give the name of a Python function to use for this type.">;
- def type_summary_add_input_python : Option<"input-python", "P">, Group<3>,
- Desc<"Input Python code to use for this type manually.">;
- def type_summary_add_expand : Option<"expand", "e">, Groups<[2,3]>,
- Desc<"Expand aggregate data types to show children on separate lines.">;
- def type_summary_add_hide_empty : Option<"hide-empty", "h">, Groups<[2,3]>,
- Desc<"Do not expand aggregate data types with no children.">;
- def type_summary_add_name : Option<"name", "n">, Groups<[2,3]>, Arg<"Name">,
- Desc<"A name for this summary string.">;
+ def type_summary_add_category
+ : Option<"category", "w">,
+ Arg<"Name">,
+ Desc<"Add this to the given category instead of the default one.">;
+ def type_summary_add_cascade
+ : Option<"cascade", "C">,
+ Arg<"Boolean">,
+ Desc<"If true, cascade through typedef chains.">;
+ def type_summary_add_no_value
+ : Option<"no-value", "v">,
+ Desc<"Don't show the value, just show the summary, for this type.">;
+ def type_summary_add_skip_pointers
+ : Option<"skip-pointers", "p">,
+ Desc<"Don't use this format for pointers-to-type objects.">;
+ def type_summary_add_pointer_match_depth
+ : Option<"pointer-match-depth", "d">,
+ Arg<"UnsignedInteger">,
+ Desc<"Specify the maximum pointer depth that this format can be apply "
+ "to "
+ "(default to 1). It's only effective when --skip-pointers is not "
+ "set.">;
+ def type_summary_add_skip_references
+ : Option<"skip-references", "r">,
+ Desc<"Don't use this format for references-to-type objects.">;
+ def type_summary_add_regex
+ : Option<"regex", "x">,
+ Desc<"Type names are actually regular expressions.">;
+ def type_summary_add_recognizer_function
+ : Option<"recognizer-function", "\\x01">,
+ Desc<"The names in the argument list are actually the names of python "
+ "functions that decide whether to use this summary for any given "
+ "type. "
+ "Cannot be specified at the same time as --regex (-x).">;
+ def type_summary_add_inline_children
+ : Option<"inline-children", "c">,
+ Group<1>,
+ Required,
+ Desc<"If true, inline all child values into summary string.">;
+ def type_summary_add_omit_names
+ : Option<"omit-names", "O">,
+ Group<1>,
+ Desc<"If true, omit value names in the summary display.">;
+ def type_summary_add_summary_string
+ : Option<"summary-string", "s">,
+ Group<2>,
+ Arg<"SummaryString">,
+ Required,
+ Desc<"Summary string used to display text and object contents.">;
+ def type_summary_add_python_script
+ : Option<"python-script", "o">,
+ Group<3>,
+ Arg<"PythonScript">,
+ Desc<"Give a one-liner Python script as part of the command.">;
+ def type_summary_add_python_function
+ : Option<"python-function", "F">,
+ Group<3>,
+ Arg<"PythonFunction">,
+ Desc<"Give the name of a Python function to use for this type.">;
+ def type_summary_add_input_python
+ : Option<"input-python", "P">,
+ Group<3>,
+ Desc<"Input Python code to use for this type manually.">;
+ def type_summary_add_expand
+ : Option<"expand", "e">,
+ Groups<[2, 3]>,
+ Desc<"Expand aggregate data types to show children on separate lines.">;
+ def type_summary_add_hide_empty
+ : Option<"hide-empty", "h">,
+ Groups<[2, 3]>,
+ Desc<"Do not expand aggregate data types with no children.">;
+ def type_summary_add_name : Option<"name", "n">,
+ Groups<[2, 3]>,
+ Arg<"Name">,
+ Desc<"A name for this summary string.">;
}
let Command = "type synth add" in {
- def type_synth_add_cascade : Option<"cascade", "C">, Arg<"Boolean">,
- Desc<"If true, cascade through typedef chains.">;
- def type_synth_add_skip_pointers : Option<"skip-pointers", "p">,
- Desc<"Don't use this format for pointers-to-type objects.">;
- def type_synth_add_skip_references : Option<"skip-references", "r">,
- Desc<"Don't use this format for references-to-type objects.">;
- def type_synth_add_category : Option<"category", "w">, Arg<"Name">,
- Desc<"Add this to the given category instead of the default one.">;
- def type_synth_add_python_class : Option<"python-class", "l">, Group<2>,
- Arg<"PythonClass">,
- Desc<"Use this Python class to produce synthetic children.">;
- def type_synth_add_input_python : Option<"input-python", "P">, Group<3>,
- Desc<"Type Python code to generate a class that provides synthetic "
- "children.">;
- def type_synth_add_regex : Option<"regex", "x">,
- Desc<"Type names are actually regular expressions.">;
- def type_synth_add_recognizer_function :
- Option<"recognizer-function", "\\x01">,
- Desc<"The names in the argument list are actually the names of python "
- "functions that decide whether to use this summary for any given type. "
- "Cannot be specified at the same time as --regex (-x).">;
+ def type_synth_add_cascade : Option<"cascade", "C">,
+ Arg<"Boolean">,
+ Desc<"If true, cascade through typedef chains.">;
+ def type_synth_add_skip_pointers
+ : Option<"skip-pointers", "p">,
+ Desc<"Don't use this format for pointers-to-type objects.">;
+ def type_synth_add_skip_references
+ : Option<"skip-references", "r">,
+ Desc<"Don't use this format for references-to-type objects.">;
+ def type_synth_add_category
+ : Option<"category", "w">,
+ Arg<"Name">,
+ Desc<"Add this to the given category instead of the default one.">;
+ def type_synth_add_python_class
+ : Option<"python-class", "l">,
+ Group<2>,
+ Arg<"PythonClass">,
+ Desc<"Use this Python class to produce synthetic children.">;
+ def type_synth_add_input_python
+ : Option<"input-python", "P">,
+ Group<3>,
+ Desc<"Type Python code to generate a class that provides synthetic "
+ "children.">;
+ def type_synth_add_regex
+ : Option<"regex", "x">,
+ Desc<"Type names are actually regular expressions.">;
+ def type_synth_add_recognizer_function
+ : Option<"recognizer-function", "\\x01">,
+ Desc<"The names in the argument list are actually the names of python "
+ "functions that decide whether to use this summary for any given "
+ "type. "
+ "Cannot be specified at the same time as --regex (-x).">;
}
let Command = "type format add" in {
- def type_format_add_category : Option<"category", "w">, Arg<"Name">,
- Desc<"Add this to the given category instead of the default one.">;
- def type_format_add_cascade : Option<"cascade", "C">, Arg<"Boolean">,
- Desc<"If true, cascade through typedef chains.">;
- def type_format_add_skip_pointers : Option<"skip-pointers", "p">,
- Desc<"Don't use this format for pointers-to-type objects.">;
- def type_format_add_skip_references : Option<"skip-references", "r">,
- Desc<"Don't use this format for references-to-type objects.">;
- def type_format_add_regex : Option<"regex", "x">,
- Desc<"Type names are actually regular expressions.">;
- def type_format_add_type : Option<"type", "t">, Group<2>, Arg<"Name">,
- Desc<"Format variables as if they were of this type.">;
+ def type_format_add_category
+ : Option<"category", "w">,
+ Arg<"Name">,
+ Desc<"Add this to the given category instead of the default one.">;
+ def type_format_add_cascade
+ : Option<"cascade", "C">,
+ Arg<"Boolean">,
+ Desc<"If true, cascade through typedef chains.">;
+ def type_format_add_skip_pointers
+ : Option<"skip-pointers", "p">,
+ Desc<"Don't use this format for pointers-to-type objects.">;
+ def type_format_add_skip_references
+ : Option<"skip-references", "r">,
+ Desc<"Don't use this format for references-to-type objects.">;
+ def type_format_add_regex
+ : Option<"regex", "x">,
+ Desc<"Type names are actually regular expressions.">;
+ def type_format_add_type
+ : Option<"type", "t">,
+ Group<2>,
+ Arg<"Name">,
+ Desc<"Format variables as if they were of this type.">;
}
let Command = "type formatter delete" in {
- def type_formatter_delete_all : Option<"all", "a">, Group<1>,
- Desc<"Delete from every category.">;
- def type_formatter_delete_category : Option<"category", "w">, Group<2>,
- Arg<"Name">, Desc<"Delete from given category.">;
- def type_formatter_delete_language : Option<"language", "l">, Group<3>,
- Arg<"Language">, Desc<"Delete from given language's category.">;
+ def type_formatter_delete_all : Option<"all", "a">,
+ Group<1>,
+ Desc<"Delete from every category.">;
+ def type_formatter_delete_category : Option<"category", "w">,
+ Group<2>,
+ Arg<"Name">,
+ Desc<"Delete from given category.">;
+ def type_formatter_delete_language
+ : Option<"language", "l">,
+ Group<3>,
+ Arg<"Language">,
+ Desc<"Delete from given language's category.">;
}
let Command = "type formatter clear" in {
def type_formatter_clear_all : Option<"all", "a">,
- Desc<"Clear every category.">;
+ Desc<"Clear every category.">;
}
let Command = "type formatter list" in {
- def type_formatter_list_category_regex : Option<"category-regex", "w">,
- Group<1>, Arg<"Name">, Desc<"Only show categories matching this filter.">;
- def type_formatter_list_language : Option<"language", "l">, Group<2>,
- Arg<"Language">, Desc<"Only show the category for a specific language.">;
+ def type_formatter_list_category_regex
+ : Option<"category-regex", "w">,
+ Group<1>,
+ Arg<"Name">,
+ Desc<"Only show categories matching this filter.">;
+ def type_formatter_list_language
+ : Option<"language", "l">,
+ Group<2>,
+ Arg<"Language">,
+ Desc<"Only show the category for a specific language.">;
}
let Command = "type category define" in {
- def type_category_define_enabled : Option<"enabled", "e">,
- Desc<"If specified, this category will be created enabled.">;
- def type_category_define_language : Option<"language", "l">, Arg<"Language">,
- Desc<"Specify the language that this category is supported for.">;
+ def type_category_define_enabled
+ : Option<"enabled", "e">,
+ Desc<"If specified, this category will be created enabled.">;
+ def type_category_define_language
+ : Option<"language", "l">,
+ Arg<"Language">,
+ Desc<"Specify the language that this category is supported for.">;
}
let Command = "type category enable" in {
- def type_category_enable_language : Option<"language", "l">, Arg<"Language">,
- Desc<"Enable the category for this language.">;
+ def type_category_enable_language
+ : Option<"language", "l">,
+ Arg<"Language">,
+ Desc<"Enable the category for this language.">;
}
let Command = "type category disable" in {
- def type_category_disable_language : Option<"language", "l">, Arg<"Language">,
- Desc<"Enable the category for this language.">;
+ def type_category_disable_language
+ : Option<"language", "l">,
+ Arg<"Language">,
+ Desc<"Disable the category for this language.">;
}
let Command = "type filter add" in {
- def type_filter_add_cascade : Option<"cascade", "C">, Arg<"Boolean">,
- Desc<"If true, cascade through typedef chains.">;
- def type_filter_add_skip_pointers : Option<"skip-pointers", "p">,
- Desc<"Don't use this format for pointers-to-type objects.">;
- def type_filter_add_skip_references : Option<"skip-references", "r">,
- Desc<"Don't use this format for references-to-type objects.">;
- def type_filter_add_category : Option<"category", "w">, Arg<"Name">,
- Desc<"Add this to the given category instead of the default one.">;
- def type_filter_add_child : Option<"child", "c">, Arg<"ExpressionPath">,
- Desc<"Include this expression path in the synthetic view.">;
- def type_filter_add_regex : Option<"regex", "x">,
- Desc<"Type names are actually regular expressions.">;
+ def type_filter_add_cascade
+ : Option<"cascade", "C">,
+ Arg<"Boolean">,
+ Desc<"If true, cascade through typedef chains.">;
+ def type_filter_add_skip_pointers
+ : Option<"skip-pointers", "p">,
+ Desc<"Don't use this format for pointers-to-type objects.">;
+ def type_filter_add_skip_references
+ : Option<"skip-references", "r">,
+ Desc<"Don't use this format for references-to-type objects.">;
+ def type_filter_add_category
+ : Option<"category", "w">,
+ Arg<"Name">,
+ Desc<"Add this to the given category instead of the default one.">;
+ def type_filter_add_child
+ : Option<"child", "c">,
+ Arg<"ExpressionPath">,
+ Desc<"Include this expression path in the synthetic view.">;
+ def type_filter_add_regex
+ : Option<"regex", "x">,
+ Desc<"Type names are actually regular expressions.">;
}
let Command = "type lookup" in {
def type_lookup_show_help : Option<"show-help", "h">,
- Desc<"Display available help for types">;
- def type_lookup_language : Option<"language", "l">, Arg<"Language">,
- Desc<"Which language's types should the search scope be">;
+ Desc<"Display available help for types">;
+ def type_lookup_language
+ : Option<"language", "l">,
+ Arg<"Language">,
+ Desc<"Which language's types should the search scope be">;
}
let Command = "watchpoint list" in {
- def watchpoint_list_brief : Option<"brief", "b">, Group<1>, Desc<"Give a "
- "brief description of the watchpoint (no location info).">;
- def watchpoint_list_full : Option<"full", "f">, Group<2>, Desc<"Give a full "
- "description of the watchpoint and its locations.">;
- def watchpoint_list_verbose : Option<"verbose", "v">, Group<3>, Desc<"Explain "
- "everything we know about the watchpoint (for debugging debugger bugs).">;
+ def watchpoint_list_brief
+ : Option<"brief", "b">,
+ Group<1>,
+ Desc<"Give a "
+ "brief description of the watchpoint (no location info).">;
+ def watchpoint_list_full
+ : Option<"full", "f">,
+ Group<2>,
+ Desc<"Give a full "
+ "description of the watchpoint and its locations.">;
+ def watchpoint_list_verbose : Option<"verbose", "v">,
+ Group<3>,
+ Desc<"Explain "
+ "everything we know about the watchpoint "
+ "(for debugging debugger bugs).">;
}
let Command = "watchpoint ignore" in {
- def watchpoint_ignore_ignore_count : Option<"ignore-count", "i">,
- Arg<"Count">, Required, Desc<"Set the number of times this watchpoint is"
- " skipped before stopping.">;
+ def watchpoint_ignore_ignore_count
+ : Option<"ignore-count", "i">,
+ Arg<"Count">,
+ Required,
+ Desc<"Set the number of times this watchpoint is"
+ " skipped before stopping.">;
}
let Command = "watchpoint modify" in {
- def watchpoint_modify_condition : Option<"condition", "c">, Arg<"Expression">,
- Desc<"The watchpoint stops only if this condition expression evaluates "
- "to true.">;
+ def watchpoint_modify_condition
+ : Option<"condition", "c">,
+ Arg<"Expression">,
+ Desc<"The watchpoint stops only if this condition expression evaluates "
+ "to true.">;
}
let Command = "watchpoint command add" in {
- def watchpoint_command_add_one_liner : Option<"one-liner", "o">, Group<1>,
- Arg<"OneLiner">, Desc<"Specify a one-line watchpoint command inline. Be "
- "sure to surround it with quotes.">;
- def watchpoint_command_add_stop_on_error : Option<"stop-on-error", "e">,
- Arg<"Boolean">, Desc<"Specify whether watchpoint command execution should "
- "terminate on error.">;
- def watchpoint_command_add_script_type : Option<"script-type", "s">,
- EnumArg<"ScriptLang">, Desc<"Specify the language for the"
- " commands - if none is specified, the lldb command interpreter will be "
- "used.">;
- def watchpoint_command_add_python_function : Option<"python-function", "F">,
- Group<2>, Arg<"PythonFunction">, Desc<"Give the name of a Python function "
- "to run as command for this watchpoint. Be sure to give a module name if "
- "appropriate.">;
+ def watchpoint_command_add_one_liner
+ : Option<"one-liner", "o">,
+ Group<1>,
+ Arg<"OneLiner">,
+ Desc<"Specify a one-line watchpoint command inline. Be "
+ "sure to surround it with quotes.">;
+ def watchpoint_command_add_stop_on_error
+ : Option<"stop-on-error", "e">,
+ Arg<"Boolean">,
+ Desc<"Specify whether watchpoint command execution should "
+ "terminate on error.">;
+ def watchpoint_command_add_script_type
+ : Option<"script-type", "s">,
+ EnumArg<"ScriptLang">,
+ Desc<"Specify the language for the"
+ " commands - if none is specified, the lldb command interpreter "
+ "will be "
+ "used.">;
+ def watchpoint_command_add_python_function
+ : Option<"python-function", "F">,
+ Group<2>,
+ Arg<"PythonFunction">,
+ Desc<"Give the name of a Python function "
+ "to run as command for this watchpoint. Be sure to give a module "
+ "name if "
+ "appropriate.">;
}
let Command = "watchpoint delete" in {
- def watchpoint_delete_force : Option<"force", "f">, Group<1>,
- Desc<"Delete all watchpoints without querying for confirmation.">;
+ def watchpoint_delete_force
+ : Option<"force", "f">,
+ Group<1>,
+ Desc<"Delete all watchpoints without querying for confirmation.">;
}
let Command = "trace load" in {
- def trace_load_verbose : Option<"verbose", "v">, Group<1>,
- Desc<"Show verbose trace load logging for debugging the plug-in "
- "implementation.">;
+ def trace_load_verbose
+ : Option<"verbose", "v">,
+ Group<1>,
+ Desc<"Show verbose trace load logging for debugging the plug-in "
+ "implementation.">;
}
let Command = "trace save" in {
- def trace_save_compact: Option<"compact", "c">,
- Group<1>,
- Desc<"Try not to save to disk information irrelevant to the traced "
- "processes. Each trace plug-in implements this in a different "
- "fashion.">;
+ def trace_save_compact
+ : Option<"compact", "c">,
+ Group<1>,
+ Desc<"Try not to save to disk information irrelevant to the traced "
+ "processes. Each trace plug-in implements this in a different "
+ "fashion.">;
}
let Command = "trace dump" in {
- def trace_dump_verbose : Option<"verbose", "v">, Group<1>,
- Desc<"Show verbose trace information.">;
+ def trace_dump_verbose : Option<"verbose", "v">,
+ Group<1>,
+ Desc<"Show verbose trace information.">;
}
let Command = "trace schema" in {
- def trace_schema_verbose : Option<"verbose", "v">, Group<1>,
- Desc<"Show verbose trace schema logging for debugging the plug-in.">;
+ def trace_schema_verbose
+ : Option<"verbose", "v">,
+ Group<1>,
+ Desc<"Show verbose trace schema logging for debugging the plug-in.">;
}
let Command = "statistics dump" in {
- def statistics_dump_all: Option<"all-targets", "a">, Group<1>,
- Desc<"Include statistics for all targets.">;
- def statistics_dump_summary: Option<"summary", "s">, Group<1>,
- Desc<"Dump only high-level summary statistics. "
- "Exclude targets, modules, breakpoints etc... details.">;
- def statistics_dump_force: Option<"load-all-debug-info", "f">, Group<1>,
- Desc<"Dump the total possible debug info statistics. "
- "Force loading all the debug information if not yet loaded, and collect "
- "statistics with those.">;
- def statistics_dump_targets: Option<"targets", "r">, Group<1>,
- Arg<"Boolean">,
- Desc<"Dump statistics for the targets, including breakpoints, expression "
- "evaluations, frame variables, etc. "
- "Defaults to true in both default mode and summary mode. "
- "In default mode, if both '--targets' and '--modules' are 'true', a list "
- "of module identifiers will be added to the 'targets' section.">;
- def statistics_dump_modules: Option<"modules", "m">, Group<1>,
- Arg<"Boolean">,
- Desc<"Dump statistics for the modules, including time and size of various "
- "aspects of the module and debug information, type system, path, etc. "
- "Defaults to true, unless the '--summary' mode is enabled, in which case "
- "this is turned off unless specified. "
- "In default mode, if both '--targets' and '--modules' are 'true', a list "
- "of module identifiers will be added to the 'targets' section.">;
+ def statistics_dump_all : Option<"all-targets", "a">,
+ Group<1>,
+ Desc<"Include statistics for all targets.">;
+ def statistics_dump_summary
+ : Option<"summary", "s">,
+ Group<1>,
+ Desc<"Dump only high-level summary statistics. Exclude targets, "
+ "modules, breakpoints etc... details.">;
+ def statistics_dump_force
+ : Option<"load-all-debug-info", "f">,
+ Group<1>,
+ Desc<"Dump the total possible debug info statistics. Force loading all "
+ "the debug information if not yet loaded, and collect statistics "
+ "with those.">;
+ def statistics_dump_targets
+ : Option<"targets", "r">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"Dump statistics for the targets, including breakpoints, "
+ "expression evaluations, frame variables, etc. Defaults to true "
+ "in both default mode and summary mode. In default mode, if both "
+ "'--targets' and '--modules' are 'true', a list of module "
+ "identifiers will be added to the 'targets' section.">;
+ def statistics_dump_modules
+ : Option<"modules", "m">,
+ Group<1>,
+ Arg<"Boolean">,
+ Desc<"Dump statistics for the modules, including time and size of "
+ "various aspects of the module and debug information, type "
+ "system, path, etc. Defaults to true, unless the '--summary' mode "
+ "is enabled, in which case this is turned off unless specified. "
+ "In default mode, if both '--targets' and '--modules' are 'true', "
+ "a list of module identifiers will be added to the 'targets' "
+ "section.">;
def statistics_dump_transcript
: Option<"transcript", "t">,
Group<1>,
Arg<"Boolean">,
Desc<"If the setting interpreter.save-transcript is enabled and this "
"option is 'true', include a JSON array with all commands the "
- "user and/or "
- "scripts executed during a debug session. "
- "Defaults to false. ">;
+ "user and/or scripts executed during a debug session. Defaults to "
+ "false. ">;
def statistics_dump_plugins
: Option<"plugins", "p">,
Group<1>,
diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td
index 53dd333f045c..fda34a8ad263 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}}}{${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,
@@ -233,7 +233,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}}}{${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/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
index e0a7d6934570..f2ed1f739534 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -26,7 +26,11 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
@@ -41,6 +45,8 @@
#include "lldb/lldb-private-enumerations.h"
#include "lldb/lldb-private-interfaces.h"
#include "lldb/lldb-private-types.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/TargetParser/Triple.h"
@@ -280,6 +286,127 @@ bool Disassembler::ElideMixedSourceAndDisassemblyLine(
return false;
}
+// For each instruction, this block attempts to resolve in-scope variables
+// and determine if the current PC falls within their
+// DWARF location entry. If so, it prints a simplified annotation using the
+// variable name and its resolved location (e.g., "var = reg; " ).
+//
+// Annotations are only included if the variable has a valid DWARF location
+// entry, and the location string is non-empty after filtering. Decoding
+// errors and DWARF opcodes are intentionally omitted to keep the output
+// concise and user-friendly.
+//
+// The goal is to give users helpful live variable hints alongside the
+// disassembled instruction stream, similar to how debug information
+// enhances source-level debugging.
+std::vector<std::string>
+VariableAnnotator::annotate(Instruction &inst, Target &target,
+ const lldb::ModuleSP &module_sp) {
+ std::vector<std::string> events;
+
+ // If we lost module context, everything becomes <undef>.
+ if (!module_sp) {
+ for (const auto &KV : Live_)
+ events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
+ Live_.clear();
+ return events;
+ }
+
+ // Resolve function/block at this *file* address.
+ SymbolContext sc;
+ const Address &iaddr = inst.GetAddress();
+ const auto mask = eSymbolContextFunction | eSymbolContextBlock;
+ if (!module_sp->ResolveSymbolContextForAddress(iaddr, mask, sc) ||
+ !sc.function) {
+ // No function context: everything dies here.
+ for (const auto &KV : Live_)
+ events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
+ Live_.clear();
+ return events;
+ }
+
+ // Collect in-scope variables for this instruction into Current.
+ VariableList var_list;
+ // Innermost block containing iaddr.
+ if (Block *B = sc.block) {
+ auto filter = [](Variable *v) -> bool { return v && !v->IsArtificial(); };
+ B->AppendVariables(/*can_create*/ true,
+ /*get_parent_variables*/ true,
+ /*stop_if_block_is_inlined_function*/ false,
+ /*filter*/ filter,
+ /*variable_list*/ &var_list);
+ }
+
+ const lldb::addr_t pc_file = iaddr.GetFileAddress();
+ const lldb::addr_t func_file = sc.function->GetAddress().GetFileAddress();
+
+ // ABI from Target (pretty reg names if plugin exists). Safe to be null.
+ lldb::ABISP abi_sp = ABI::FindPlugin(nullptr, target.GetArchitecture());
+ ABI *abi = abi_sp.get();
+
+ llvm::DIDumpOptions opts;
+ opts.ShowAddresses = false;
+ // Prefer "register-only" output when we have an ABI.
+ opts.PrintRegisterOnly = static_cast<bool>(abi_sp);
+
+ llvm::DenseMap<lldb::user_id_t, VarState> Current;
+
+ for (size_t i = 0, e = var_list.GetSize(); i != e; ++i) {
+ lldb::VariableSP v = var_list.GetVariableAtIndex(i);
+ if (!v || v->IsArtificial())
+ continue;
+
+ const char *nm = v->GetName().AsCString();
+ llvm::StringRef name = nm ? nm : "<anon>";
+
+ DWARFExpressionList &exprs = v->LocationExpressionList();
+ if (!exprs.IsValid())
+ continue;
+
+ auto entry_or_err = exprs.GetExpressionEntryAtAddress(func_file, pc_file);
+ if (!entry_or_err)
+ continue;
+
+ auto entry = *entry_or_err;
+
+ StreamString loc_ss;
+ entry.expr->DumpLocation(&loc_ss, eDescriptionLevelBrief, abi, opts);
+
+ llvm::StringRef loc = llvm::StringRef(loc_ss.GetString()).trim();
+ if (loc.empty())
+ continue;
+
+ Current.try_emplace(v->GetID(),
+ VarState{std::string(name), std::string(loc)});
+ }
+
+ // Diff Live_ → Current.
+
+ // 1) Starts/changes: iterate Current and compare with Live_.
+ for (const auto &KV : Current) {
+ auto it = Live_.find(KV.first);
+ if (it == Live_.end()) {
+ // Newly live.
+ events.emplace_back(
+ llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());
+ } else if (it->second.last_loc != KV.second.last_loc) {
+ // Location changed.
+ events.emplace_back(
+ llvm::formatv("{0} = {1}", KV.second.name, KV.second.last_loc).str());
+ }
+ }
+
+ // 2) Ends: anything that was live but is not in Current becomes <undef>.
+ for (const auto &KV : Live_) {
+ if (!Current.count(KV.first))
+ events.emplace_back(llvm::formatv("{0} = <undef>", KV.second.name).str());
+ }
+
+ // Commit new state.
+ Live_ = std::move(Current);
+ return events;
+}
+
void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
const ExecutionContext &exe_ctx,
bool mixed_source_and_assembly,
@@ -376,6 +503,7 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
}
}
+ VariableAnnotator annot;
previous_symbol = nullptr;
SourceLine previous_line;
for (size_t i = 0; i < num_instructions_found; ++i) {
@@ -540,10 +668,26 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
const bool show_bytes = (options & eOptionShowBytes) != 0;
const bool show_control_flow_kind =
(options & eOptionShowControlFlowKind) != 0;
- inst->Dump(&strm, max_opcode_byte_size, true, show_bytes,
+
+ StreamString inst_line;
+
+ inst->Dump(&inst_line, max_opcode_byte_size, true, show_bytes,
show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
address_text_size);
+
+ if ((options & eOptionVariableAnnotations) && target_sp) {
+ auto annotations = annot.annotate(*inst, *target_sp, module_sp);
+ if (!annotations.empty()) {
+ const size_t annotation_column = 100;
+ inst_line.FillLastLineToColumn(annotation_column, ' ');
+ inst_line.PutCString("; ");
+ inst_line.PutCString(llvm::join(annotations, ", "));
+ }
+ }
+
+ strm.PutCString(inst_line.GetString());
strm.EOL();
+
} else {
break;
}
@@ -724,9 +868,7 @@ bool Instruction::DumpEmulation(const ArchSpec &arch) {
return false;
}
-bool Instruction::CanSetBreakpoint () {
- return !HasDelaySlot();
-}
+bool Instruction::CanSetBreakpoint() { return !HasDelaySlot(); }
bool Instruction::HasDelaySlot() {
// Default is false.
@@ -1073,10 +1215,8 @@ void InstructionList::Append(lldb::InstructionSP &inst_sp) {
m_instructions.push_back(inst_sp);
}
-uint32_t
-InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
- bool ignore_calls,
- bool *found_calls) const {
+uint32_t InstructionList::GetIndexOfNextBranchInstruction(
+ uint32_t start, bool ignore_calls, bool *found_calls) const {
size_t num_instructions = m_instructions.size();
uint32_t next_branch = UINT32_MAX;
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 5d3c8b421d5d..491f5c6320d9 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -108,6 +108,7 @@ constexpr Definition g_frame_child_entries[] = {
Entry::DefinitionWithChildren("reg", EntryType::FrameRegisterByName,
g_string_entry),
Definition("is-artificial", EntryType::FrameIsArtificial),
+ Definition("kind", EntryType::FrameKind),
};
constexpr Definition g_function_child_entries[] = {
@@ -380,6 +381,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) {
ENUM_TO_CSTR(FrameRegisterFlags);
ENUM_TO_CSTR(FrameRegisterByName);
ENUM_TO_CSTR(FrameIsArtificial);
+ ENUM_TO_CSTR(FrameKind);
ENUM_TO_CSTR(ScriptFrame);
ENUM_TO_CSTR(FunctionID);
ENUM_TO_CSTR(FunctionDidChange);
@@ -1679,7 +1681,7 @@ 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()) {
+ if (pc_addr.IsValid() || frame->IsSynthetic()) {
if (DumpAddressAndContent(s, sc, exe_ctx, pc_addr, false))
return true;
}
@@ -1747,6 +1749,18 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
return false;
}
+ case Entry::Type::FrameKind: {
+ if (exe_ctx)
+ if (StackFrame *frame = exe_ctx->GetFramePtr()) {
+ if (frame->IsSynthetic())
+ s.PutCString(" [synthetic]");
+ else if (frame->IsHistorical())
+ s.PutCString(" [history]");
+ return true;
+ }
+ return false;
+ }
+
case Entry::Type::ScriptFrame:
if (exe_ctx) {
StackFrame *frame = exe_ctx->GetFramePtr();
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index ce4db4e0daa8..91b9c0007617 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -556,3 +556,18 @@ void Mangled::Encode(DataEncoder &file, ConstStringTable &strtab) const {
break;
}
}
+
+ConstString Mangled::GetBaseName() const {
+ const auto &demangled_info = GetDemangledInfo();
+ if (!demangled_info.has_value())
+ return {};
+
+ ConstString demangled_name = GetDemangledName();
+ if (!demangled_name)
+ return {};
+
+ const char *name_str = demangled_name.AsCString();
+ const auto &range = demangled_info->BasenameRange;
+ return ConstString(
+ llvm::StringRef(name_str + range.first, range.second - range.first));
+}
diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 060732f421f8..bc63a41c90d1 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -844,8 +844,6 @@ public:
}
bool RemoveIfOrphaned(const Module *module_ptr) {
- if (!module_ptr)
- return false;
std::lock_guard<std::recursive_mutex> guard(GetMutex());
RemoveFromMap(*module_ptr, /*if_orphaned=*/true);
return m_list.RemoveIfOrphaned(module_ptr);
@@ -982,7 +980,7 @@ private:
};
struct SharedModuleListInfo {
- SharedModuleList module_list;
+ ModuleList module_list;
ModuleListProperties module_list_properties;
};
}
@@ -1000,7 +998,7 @@ static SharedModuleListInfo &GetSharedModuleListInfo()
return *g_shared_module_list_info;
}
-static SharedModuleList &GetSharedModuleList() {
+static ModuleList &GetSharedModuleList() {
return GetSharedModuleListInfo().module_list;
}
@@ -1010,8 +1008,8 @@ ModuleListProperties &ModuleList::GetGlobalModuleListProperties() {
bool ModuleList::ModuleIsInCache(const Module *module_ptr) {
if (module_ptr) {
- SharedModuleList &shared_module_list = GetSharedModuleList();
- return shared_module_list.FindModule(*module_ptr).get() != nullptr;
+ ModuleList &shared_module_list = GetSharedModuleList();
+ return shared_module_list.FindModule(module_ptr).get() != nullptr;
}
return false;
}
@@ -1034,8 +1032,9 @@ 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) {
- SharedModuleList &shared_module_list = GetSharedModuleList();
- std::lock_guard<std::recursive_mutex> guard(shared_module_list.GetMutex());
+ ModuleList &shared_module_list = GetSharedModuleList();
+ std::lock_guard<std::recursive_mutex> guard(
+ shared_module_list.m_modules_mutex);
char path[PATH_MAX];
Status error;
diff --git a/lldb/source/Core/ProtocolServer.cpp b/lldb/source/Core/ProtocolServer.cpp
index 41636cdacdec..38668f39795a 100644
--- a/lldb/source/Core/ProtocolServer.cpp
+++ b/lldb/source/Core/ProtocolServer.cpp
@@ -8,24 +8,29 @@
#include "lldb/Core/ProtocolServer.h"
#include "lldb/Core/PluginManager.h"
+#include "llvm/Support/Error.h"
using namespace lldb_private;
using namespace lldb;
-ProtocolServer *ProtocolServer::GetOrCreate(llvm::StringRef name) {
- static std::mutex g_mutex;
+static std::pair<llvm::StringMap<ProtocolServerUP> &, std::mutex &> Servers() {
static llvm::StringMap<ProtocolServerUP> g_protocol_server_instances;
+ static std::mutex g_mutex;
+ return {g_protocol_server_instances, g_mutex};
+}
+
+ProtocolServer *ProtocolServer::GetOrCreate(llvm::StringRef name) {
+ auto [protocol_server_instances, mutex] = Servers();
- std::lock_guard<std::mutex> guard(g_mutex);
+ std::lock_guard<std::mutex> guard(mutex);
- auto it = g_protocol_server_instances.find(name);
- if (it != g_protocol_server_instances.end())
+ auto it = protocol_server_instances.find(name);
+ if (it != protocol_server_instances.end())
return it->second.get();
if (ProtocolServerCreateInstance create_callback =
PluginManager::GetProtocolCreateCallbackForPluginName(name)) {
- auto pair =
- g_protocol_server_instances.try_emplace(name, create_callback());
+ auto pair = protocol_server_instances.try_emplace(name, create_callback());
return pair.first->second.get();
}
@@ -45,3 +50,18 @@ std::vector<llvm::StringRef> ProtocolServer::GetSupportedProtocols() {
return supported_protocols;
}
+
+llvm::Error ProtocolServer::Terminate() {
+ llvm::Error error = llvm::Error::success();
+
+ auto [protocol_server_instances, mutex] = Servers();
+ std::lock_guard<std::mutex> guard(mutex);
+ for (auto &instance : protocol_server_instances) {
+ if (llvm::Error instance_error = instance.second->Stop())
+ error = llvm::joinErrors(std::move(error), std::move(instance_error));
+ }
+
+ protocol_server_instances.clear();
+
+ return error;
+}
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index ed4e4e4e341a..332cf2c86024 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -67,7 +67,8 @@ void DWARFExpression::UpdateValue(uint64_t const_value,
}
void DWARFExpression::DumpLocation(Stream *s, lldb::DescriptionLevel level,
- ABI *abi) const {
+ ABI *abi,
+ llvm::DIDumpOptions options) const {
auto *MCRegInfo = abi ? &abi->GetMCRegisterInfo() : nullptr;
auto GetRegName = [&MCRegInfo](uint64_t DwarfRegNum,
bool IsEH) -> llvm::StringRef {
@@ -79,10 +80,9 @@ void DWARFExpression::DumpLocation(Stream *s, lldb::DescriptionLevel level,
return llvm::StringRef(RegName);
return {};
};
- llvm::DIDumpOptions DumpOpts;
- DumpOpts.GetNameForDWARFReg = GetRegName;
+ options.GetNameForDWARFReg = GetRegName;
llvm::DWARFExpression E(m_data.GetAsLLVM(), m_data.GetAddressByteSize());
- llvm::printDwarfExpression(&E, s->AsRawOstream(), DumpOpts, nullptr);
+ llvm::printDwarfExpression(&E, s->AsRawOstream(), options, nullptr);
}
RegisterKind DWARFExpression::GetRegisterKind() const { return m_reg_kind; }
@@ -2078,7 +2078,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
case DW_OP_implicit_pointer: {
dwarf4_location_description_kind = Implicit;
- return llvm::createStringError("Could not evaluate %s.",
+ return llvm::createStringError("could not evaluate %s",
DW_OP_value_to_name(op));
}
diff --git a/lldb/source/Expression/DWARFExpressionList.cpp b/lldb/source/Expression/DWARFExpressionList.cpp
index ef7333518f00..91c174013603 100644
--- a/lldb/source/Expression/DWARFExpressionList.cpp
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -254,7 +254,7 @@ llvm::Expected<Value> DWARFExpressionList::Evaluate(
}
if (!pc.IsValid()) {
- return llvm::createStringError("Invalid PC in frame.");
+ return llvm::createStringError("invalid PC in frame");
}
addr_t pc_load_addr = pc.GetLoadAddress(exe_ctx->GetTargetPtr());
const DWARFExpression *entry =
diff --git a/lldb/source/Expression/Expression.cpp b/lldb/source/Expression/Expression.cpp
index 796851ff15ca..16ecb1d7deef 100644
--- a/lldb/source/Expression/Expression.cpp
+++ b/lldb/source/Expression/Expression.cpp
@@ -34,10 +34,10 @@ Expression::Expression(ExecutionContextScope &exe_scope)
llvm::Expected<FunctionCallLabel>
lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
- llvm::SmallVector<llvm::StringRef, 4> components;
- label.split(components, ":", /*MaxSplit=*/3);
+ llvm::SmallVector<llvm::StringRef, 5> components;
+ label.split(components, ":", /*MaxSplit=*/4);
- if (components.size() != 4)
+ if (components.size() != 5)
return llvm::createStringError("malformed function call label.");
if (components[0] != FunctionCallLabelPrefix)
@@ -45,8 +45,10 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
"expected function call label prefix '{0}' but found '{1}' instead.",
FunctionCallLabelPrefix, components[0]));
- llvm::StringRef module_label = components[1];
- llvm::StringRef die_label = components[2];
+ llvm::StringRef discriminator = components[1];
+ llvm::StringRef module_label = components[2];
+ llvm::StringRef die_label = components[3];
+ llvm::StringRef lookup_name = components[4];
lldb::user_id_t module_id = 0;
if (!llvm::to_integer(module_label, module_id))
@@ -58,20 +60,23 @@ lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
return llvm::createStringError(
llvm::formatv("failed to parse symbol ID from '{0}'.", die_label));
- return FunctionCallLabel{/*.module_id=*/module_id,
+ return FunctionCallLabel{/*.discriminator=*/discriminator,
+ /*.module_id=*/module_id,
/*.symbol_id=*/die_id,
- /*.lookup_name=*/components[3]};
+ /*.lookup_name=*/lookup_name};
}
std::string lldb_private::FunctionCallLabel::toString() const {
- return llvm::formatv("{0}:{1:x}:{2:x}:{3}", FunctionCallLabelPrefix,
- module_id, symbol_id, lookup_name)
+ return llvm::formatv("{0}:{1}:{2:x}:{3:x}:{4}", FunctionCallLabelPrefix,
+ discriminator, module_id, symbol_id, lookup_name)
.str();
}
void llvm::format_provider<FunctionCallLabel>::format(
const FunctionCallLabel &label, raw_ostream &OS, StringRef Style) {
- OS << llvm::formatv("FunctionCallLabel{ module_id: {0:x}, symbol_id: {1:x}, "
- "lookup_name: {2} }",
- label.module_id, label.symbol_id, label.lookup_name);
+ OS << llvm::formatv("FunctionCallLabel{ discriminator: {0}, module_id: "
+ "{1:x}, symbol_id: {2:x}, "
+ "lookup_name: {3} }",
+ label.discriminator, label.module_id, label.symbol_id,
+ label.lookup_name);
}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index d557084acb74..25d4a87b89ef 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -543,62 +543,7 @@ lldb::SectionType IRExecutionUnit::GetSectionTypeFromSectionName(
else if (name.starts_with("__debug_") || name.starts_with(".debug_")) {
const uint32_t name_idx = name[0] == '_' ? 8 : 7;
llvm::StringRef dwarf_name(name.substr(name_idx));
- switch (dwarf_name[0]) {
- case 'a':
- if (dwarf_name == "abbrev")
- sect_type = lldb::eSectionTypeDWARFDebugAbbrev;
- else if (dwarf_name == "aranges")
- sect_type = lldb::eSectionTypeDWARFDebugAranges;
- else if (dwarf_name == "addr")
- sect_type = lldb::eSectionTypeDWARFDebugAddr;
- break;
-
- case 'f':
- if (dwarf_name == "frame")
- sect_type = lldb::eSectionTypeDWARFDebugFrame;
- break;
-
- case 'i':
- if (dwarf_name == "info")
- sect_type = lldb::eSectionTypeDWARFDebugInfo;
- break;
-
- case 'l':
- if (dwarf_name == "line")
- sect_type = lldb::eSectionTypeDWARFDebugLine;
- else if (dwarf_name == "loc")
- sect_type = lldb::eSectionTypeDWARFDebugLoc;
- else if (dwarf_name == "loclists")
- sect_type = lldb::eSectionTypeDWARFDebugLocLists;
- break;
-
- case 'm':
- if (dwarf_name == "macinfo")
- sect_type = lldb::eSectionTypeDWARFDebugMacInfo;
- break;
-
- case 'p':
- if (dwarf_name == "pubnames")
- sect_type = lldb::eSectionTypeDWARFDebugPubNames;
- else if (dwarf_name == "pubtypes")
- sect_type = lldb::eSectionTypeDWARFDebugPubTypes;
- break;
-
- case 's':
- if (dwarf_name == "str")
- sect_type = lldb::eSectionTypeDWARFDebugStr;
- else if (dwarf_name == "str_offsets")
- sect_type = lldb::eSectionTypeDWARFDebugStrOffsets;
- break;
-
- case 'r':
- if (dwarf_name == "ranges")
- sect_type = lldb::eSectionTypeDWARFDebugRanges;
- break;
-
- default:
- break;
- }
+ sect_type = ObjectFile::GetDWARFSectionTypeFromName(dwarf_name);
} else if (name.starts_with("__apple_") || name.starts_with(".apple_"))
sect_type = lldb::eSectionTypeInvalid;
else if (name == "__objc_imageinfo")
@@ -778,7 +723,7 @@ private:
/// Returns address of the function referred to by the special function call
/// label \c label.
static llvm::Expected<lldb::addr_t>
-ResolveFunctionCallLabel(const FunctionCallLabel &label,
+ResolveFunctionCallLabel(FunctionCallLabel &label,
const lldb_private::SymbolContext &sc,
bool &symbol_was_missing_weak) {
symbol_was_missing_weak = false;
diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp
index 150699352a2e..f978217fa8f2 100644
--- a/lldb/source/Expression/IRMemoryMap.cpp
+++ b/lldb/source/Expression/IRMemoryMap.cpp
@@ -637,10 +637,19 @@ void IRMemoryMap::WriteScalarToMemory(lldb::addr_t process_address,
}
void IRMemoryMap::WritePointerToMemory(lldb::addr_t process_address,
- lldb::addr_t address, Status &error) {
+ lldb::addr_t pointer, Status &error) {
error.Clear();
- Scalar scalar(address);
+ /// Only ask the Process to fix `pointer` if the address belongs to the
+ /// process. An address belongs to the process if the Allocation policy is not
+ /// eAllocationPolicyHostOnly.
+ auto it = FindAllocation(pointer, 1);
+ if (it == m_allocations.end() ||
+ it->second.m_policy != AllocationPolicy::eAllocationPolicyHostOnly)
+ if (auto process_sp = GetProcessWP().lock())
+ pointer = process_sp->FixAnyAddress(pointer);
+
+ Scalar scalar(pointer);
WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
}
diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index 5ed30fbb231d..1b1922e71076 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -10,10 +10,8 @@
#include <iomanip>
#include <optional>
-#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Editline.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/StreamFile.h"
#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/CompletionRequest.h"
@@ -100,11 +98,6 @@ bool IsOnlySpaces(const EditLineStringType &content) {
return true;
}
-static size_t ColumnWidth(llvm::StringRef str) {
- std::string stripped = ansi::StripAnsiTerminalCodes(str);
- return llvm::sys::locale::columnWidth(stripped);
-}
-
static int GetOperation(HistoryOperation op) {
// The naming used by editline for the history operations is counter
// intuitive to how it's used in LLDB's editline implementation.
@@ -219,20 +212,19 @@ private:
const char *GetHistoryFilePath() {
// Compute the history path lazily.
if (m_path.empty() && m_history && !m_prefix.empty()) {
- llvm::SmallString<128> lldb_history_file;
- FileSystem::Instance().GetHomeDirectory(lldb_history_file);
- llvm::sys::path::append(lldb_history_file, ".lldb");
+ FileSpec lldb_dir = HostInfo::GetUserLLDBDir();
// LLDB stores its history in ~/.lldb/. If for some reason this directory
// isn't writable or cannot be created, history won't be available.
- if (!llvm::sys::fs::create_directory(lldb_history_file)) {
+ if (!llvm::sys::fs::create_directory(lldb_dir.GetPath())) {
#if LLDB_EDITLINE_USE_WCHAR
std::string filename = m_prefix + "-widehistory";
#else
std::string filename = m_prefix + "-history";
#endif
- llvm::sys::path::append(lldb_history_file, filename);
- m_path = std::string(lldb_history_file.str());
+ FileSpec lldb_history_file =
+ lldb_dir.CopyByAppendingPathComponent(filename);
+ m_path = lldb_history_file.GetPath();
}
}
@@ -332,8 +324,8 @@ std::string Editline::PromptForIndex(int line_index) {
if (m_set_continuation_prompt.length() > 0) {
continuation_prompt = m_set_continuation_prompt;
// Ensure that both prompts are the same length through space padding
- const size_t prompt_width = ColumnWidth(prompt);
- const size_t cont_prompt_width = ColumnWidth(continuation_prompt);
+ const size_t prompt_width = ansi::ColumnWidth(prompt);
+ const size_t cont_prompt_width = ansi::ColumnWidth(continuation_prompt);
const size_t padded_prompt_width =
std::max(prompt_width, cont_prompt_width);
if (prompt_width < padded_prompt_width)
@@ -358,7 +350,9 @@ void Editline::SetCurrentLine(int line_index) {
m_current_prompt = PromptForIndex(line_index);
}
-size_t Editline::GetPromptWidth() { return ColumnWidth(PromptForIndex(0)); }
+size_t Editline::GetPromptWidth() {
+ return ansi::ColumnWidth(PromptForIndex(0));
+}
bool Editline::IsEmacs() {
const char *editor;
@@ -448,7 +442,7 @@ void Editline::DisplayInput(int firstIndex) {
int Editline::CountRowsForLine(const EditLineStringType &content) {
std::string prompt =
PromptForIndex(0); // Prompt width is constant during an edit session
- int line_length = (int)(content.length() + ColumnWidth(prompt));
+ int line_length = (int)(content.length() + ansi::ColumnWidth(prompt));
return (line_length / m_terminal_width) + 1;
}
diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp
index 23b6dc9fe850..8fd1ca069dc0 100644
--- a/lldb/source/Host/common/File.cpp
+++ b/lldb/source/Host/common/File.cpp
@@ -36,6 +36,7 @@
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
using namespace lldb;
using namespace lldb_private;
@@ -247,6 +248,32 @@ uint32_t File::GetPermissions(Status &error) const {
return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
}
+NativeFile::NativeFile() = default;
+
+NativeFile::NativeFile(FILE *fh, bool transfer_ownership)
+ : m_stream(fh), 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
+ // stream outputs to a console.
+ int fd = _fileno(fh);
+ is_windows_console =
+ ::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
+#endif
+}
+
+NativeFile::NativeFile(int fd, OpenOptions options, bool transfer_ownership)
+ : m_descriptor(fd), m_own_descriptor(transfer_ownership),
+ m_options(options) {
+#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
+ // file outputs to a console.
+ is_windows_console =
+ ::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
+#endif
+}
+
bool NativeFile::IsValid() const {
std::scoped_lock<std::mutex, std::mutex> lock(m_descriptor_mutex, m_stream_mutex);
return DescriptorIsValidUnlocked() || StreamIsValidUnlocked();
@@ -629,6 +656,13 @@ Status NativeFile::Write(const void *buf, size_t &num_bytes) {
}
if (ValueGuard stream_guard = StreamIsValid()) {
+#ifdef _WIN32
+ if (is_windows_console) {
+ llvm::raw_fd_ostream(_fileno(m_stream), false)
+ .write((char *)buf, num_bytes);
+ return error;
+ }
+#endif
bytes_written = ::fwrite(buf, 1, num_bytes, m_stream);
if (bytes_written == 0) {
diff --git a/lldb/source/Host/common/HostInfoBase.cpp b/lldb/source/Host/common/HostInfoBase.cpp
index 89dfe4a9e9ba..a02ac77df66a 100644
--- a/lldb/source/Host/common/HostInfoBase.cpp
+++ b/lldb/source/Host/common/HostInfoBase.cpp
@@ -61,6 +61,10 @@ struct HostInfoBaseFields {
FileSpec m_lldb_clang_resource_dir;
llvm::once_flag m_lldb_system_plugin_dir_once;
FileSpec m_lldb_system_plugin_dir;
+ llvm::once_flag m_lldb_user_home_dir_once;
+ FileSpec m_lldb_user_home_dir;
+ llvm::once_flag m_lldb_user_lldb_dir_once;
+ FileSpec m_lldb_user_lldb_dir;
llvm::once_flag m_lldb_user_plugin_dir_once;
FileSpec m_lldb_user_plugin_dir;
llvm::once_flag m_lldb_process_tmp_dir_once;
@@ -161,6 +165,26 @@ FileSpec HostInfoBase::GetSystemPluginDir() {
return g_fields->m_lldb_system_plugin_dir;
}
+FileSpec HostInfoBase::GetUserHomeDir() {
+ llvm::call_once(g_fields->m_lldb_user_home_dir_once, []() {
+ if (!HostInfo::ComputeUserHomeDirectory(g_fields->m_lldb_user_home_dir))
+ g_fields->m_lldb_user_home_dir = FileSpec();
+ LLDB_LOG(GetLog(LLDBLog::Host), "user home dir -> `{0}`",
+ g_fields->m_lldb_user_home_dir);
+ });
+ return g_fields->m_lldb_user_home_dir;
+}
+
+FileSpec HostInfoBase::GetUserLLDBDir() {
+ llvm::call_once(g_fields->m_lldb_user_lldb_dir_once, []() {
+ if (!HostInfo::ComputeUserLLDBHomeDirectory(g_fields->m_lldb_user_lldb_dir))
+ g_fields->m_lldb_user_lldb_dir = FileSpec();
+ LLDB_LOG(GetLog(LLDBLog::Host), "user lldb home dir -> `{0}`",
+ g_fields->m_lldb_user_lldb_dir);
+ });
+ return g_fields->m_lldb_user_lldb_dir;
+}
+
FileSpec HostInfoBase::GetUserPluginDir() {
llvm::call_once(g_fields->m_lldb_user_plugin_dir_once, []() {
if (!HostInfo::ComputeUserPluginsDirectory(
@@ -316,6 +340,20 @@ bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
return false;
}
+bool HostInfoBase::ComputeUserHomeDirectory(FileSpec &file_spec) {
+ FileSpec temp_file("~");
+ FileSystem::Instance().Resolve(temp_file);
+ file_spec.SetDirectory(temp_file.GetPathAsConstString());
+ return true;
+}
+
+bool HostInfoBase::ComputeUserLLDBHomeDirectory(FileSpec &file_spec) {
+ FileSpec home_dir_spec = GetUserHomeDir();
+ home_dir_spec.AppendPathComponent(".lldb");
+ file_spec.SetDirectory(home_dir_spec.GetPathAsConstString());
+ return true;
+}
+
bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
// TODO(zturner): Figure out how to compute the user plugins directory for
// all platforms.
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index 61f94190c956..79e1322a870e 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -39,7 +39,7 @@
#include <Foundation/Foundation.h>
#include <mach-o/dyld.h>
#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
- MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_0
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_0
#if __has_include(<mach-o/dyld_introspection.h>)
#include <mach-o/dyld_introspection.h>
#define SDK_HAS_NEW_DYLD_INTROSPECTION_SPIS
@@ -78,8 +78,8 @@ std::optional<std::string> HostInfoMacOSX::GetOSBuildString() {
static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) {
@autoreleasepool {
NSDictionary *version_info =
- [NSDictionary dictionaryWithContentsOfFile:
- @"/System/Library/CoreServices/SystemVersion.plist"];
+ [NSDictionary dictionaryWithContentsOfFile:
+ @"/System/Library/CoreServices/SystemVersion.plist"];
NSString *version_value = [version_info objectForKey: Key];
const char *version_str = [version_value UTF8String];
version.tryParse(version_str);
@@ -225,9 +225,9 @@ bool HostInfoMacOSX::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
}
bool HostInfoMacOSX::ComputeUserPluginsDirectory(FileSpec &file_spec) {
- FileSpec temp_file("~/Library/Application Support/LLDB/PlugIns");
- FileSystem::Instance().Resolve(temp_file);
- file_spec.SetDirectory(temp_file.GetPathAsConstString());
+ FileSpec home_dir_spec = GetUserHomeDir();
+ home_dir_spec.AppendPathComponent("Library/Application Support/LLDB/PlugIns");
+ file_spec.SetDirectory(home_dir_spec.GetPathAsConstString());
return true;
}
diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp
index 4277b8edb38e..e8973a3fb937 100644
--- a/lldb/source/Host/windows/Host.cpp
+++ b/lldb/source/Host/windows/Host.cpp
@@ -22,10 +22,8 @@
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/ManagedStatic.h"
// Windows includes
#include <tlhelp32.h>
@@ -308,52 +306,28 @@ Environment Host::GetEnvironment() {
return env;
}
-/// Manages the lifecycle of a Windows Event's Source.
-/// The destructor will call DeregisterEventSource.
-/// This class is meant to be used with \ref llvm::ManagedStatic.
-class WindowsEventLog {
-public:
- WindowsEventLog() : handle(RegisterEventSource(nullptr, L"lldb")) {}
-
- ~WindowsEventLog() {
- if (handle)
- DeregisterEventSource(handle);
- }
-
- HANDLE GetHandle() const { return handle; }
-
-private:
- HANDLE handle;
-};
-
-static llvm::ManagedStatic<WindowsEventLog> event_log;
-
void Host::SystemLog(Severity severity, llvm::StringRef message) {
if (message.empty())
return;
- HANDLE h = event_log->GetHandle();
- if (!h)
- return;
-
- llvm::SmallVector<wchar_t, 1> argsUTF16;
- if (UTF8ToUTF16(message.str(), argsUTF16))
- return;
+ std::string log_msg;
+ llvm::raw_string_ostream stream(log_msg);
- WORD event_type;
switch (severity) {
case lldb::eSeverityWarning:
- event_type = EVENTLOG_WARNING_TYPE;
+ stream << "[Warning] ";
break;
case lldb::eSeverityError:
- event_type = EVENTLOG_ERROR_TYPE;
+ stream << "[Error] ";
break;
case lldb::eSeverityInfo:
default:
- event_type = EVENTLOG_INFORMATION_TYPE;
+ stream << "[Info] ";
+ break;
}
- LPCWSTR messages[1] = {argsUTF16.data()};
- ReportEventW(h, event_type, 0, 0, nullptr, std::size(messages), 0, messages,
- nullptr);
+ stream << message;
+ stream.flush();
+
+ OutputDebugStringA(log_msg.c_str());
}
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 650b754fd8ac..d909c5650c95 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -52,6 +52,7 @@
#include "lldb/Core/Telemetry.h"
#include "lldb/Host/StreamFile.h"
#include "lldb/Utility/ErrorMessages.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/State.h"
@@ -1801,13 +1802,13 @@ CommandObject *CommandInterpreter::BuildAliasResult(
// Make sure we aren't going outside the bounds of the cmd string:
if (strpos < start_fudge) {
- result.AppendError("Unmatched quote at command beginning.");
+ result.AppendError("unmatched quote at command beginning");
return nullptr;
}
llvm::StringRef arg_text = entry.ref();
if (strpos - start_fudge + arg_text.size() + len_fudge >
raw_input_string.size()) {
- result.AppendError("Unmatched quote at command end.");
+ result.AppendError("unmatched quote at command end");
return nullptr;
}
raw_input_string = raw_input_string.erase(
@@ -2090,7 +2091,7 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
command_string = command_line;
original_command_string = command_line;
if (m_repeat_command.empty()) {
- result.AppendError("No auto repeat.");
+ result.AppendError("no auto repeat");
return false;
}
@@ -2502,22 +2503,18 @@ int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
return position;
}
-static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
- llvm::StringRef suffix = {}) {
+static void GetHomeInitFile(FileSpec &init_file, llvm::StringRef suffix = {}) {
std::string init_file_name = ".lldbinit";
if (!suffix.empty()) {
init_file_name.append("-");
init_file_name.append(suffix.str());
}
- FileSystem::Instance().GetHomeDirectory(init_file);
- llvm::sys::path::append(init_file, init_file_name);
-
- FileSystem::Instance().Resolve(init_file);
+ init_file =
+ HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(init_file_name);
}
-static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
- LanguageType language) {
+static void GetHomeREPLInitFile(FileSpec &init_file, LanguageType language) {
if (language == eLanguageTypeUnknown) {
LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
if (auto main_repl_language = repl_languages.GetSingularLanguage())
@@ -2531,9 +2528,9 @@ static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
llvm::Twine(Language::GetNameForLanguageType(language)) +
llvm::Twine("-repl"))
.str();
- FileSystem::Instance().GetHomeDirectory(init_file);
- llvm::sys::path::append(init_file, init_file_name);
- FileSystem::Instance().Resolve(init_file);
+
+ init_file =
+ HostInfo::GetUserHomeDir().CopyByAppendingPathComponent(init_file_name);
}
static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
@@ -2588,10 +2585,10 @@ void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
SourceInitFile(FileSpec(init_file.str()), result);
break;
case eLoadCWDlldbinitWarn: {
- llvm::SmallString<128> home_init_file;
+ FileSpec home_init_file;
GetHomeInitFile(home_init_file);
if (llvm::sys::path::parent_path(init_file) ==
- llvm::sys::path::parent_path(home_init_file)) {
+ llvm::sys::path::parent_path(home_init_file.GetPath())) {
result.SetStatus(eReturnStatusSuccessFinishNoResult);
} else {
result.AppendError(InitFileWarning);
@@ -2611,24 +2608,24 @@ void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result,
return;
}
- llvm::SmallString<128> init_file;
+ FileSpec init_file;
if (is_repl)
GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
- if (init_file.empty())
+ if (init_file.GetPath().empty())
GetHomeInitFile(init_file);
if (!m_skip_app_init_files) {
llvm::StringRef program_name =
HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
- llvm::SmallString<128> program_init_file;
+ FileSpec program_init_file;
GetHomeInitFile(program_init_file, program_name);
if (FileSystem::Instance().Exists(program_init_file))
init_file = program_init_file;
}
- SourceInitFile(FileSpec(init_file.str()), result);
+ SourceInitFile(init_file, result);
}
void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) {
diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp
index 129646ebddb9..22eeceb2ef7e 100644
--- a/lldb/source/Interpreter/CommandObject.cpp
+++ b/lldb/source/Interpreter/CommandObject.cpp
@@ -217,7 +217,7 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) {
if (process == nullptr) {
// A process that is not running is considered paused.
if (GetFlags().Test(eCommandProcessMustBeLaunched)) {
- result.AppendError("Process must exist.");
+ result.AppendError("process must exist");
return false;
}
} else {
@@ -236,7 +236,7 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) {
case eStateExited:
case eStateUnloaded:
if (GetFlags().Test(eCommandProcessMustBeLaunched)) {
- result.AppendError("Process must be launched.");
+ result.AppendError("process must be launched");
return false;
}
break;
@@ -255,7 +255,7 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) {
if (GetFlags().Test(eCommandProcessMustBeTraced)) {
Target *target = m_exe_ctx.GetTargetPtr();
if (target && !target->GetTrace()) {
- result.AppendError("Process is not being traced.");
+ result.AppendError("process is not being traced");
return false;
}
}
@@ -359,7 +359,8 @@ bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word,
StreamString usage_help;
GetOptions()->GenerateOptionUsage(
usage_help, *this,
- GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
+ GetCommandInterpreter().GetDebugger().GetUseColor());
if (!usage_help.Empty()) {
llvm::StringRef usage_text = usage_help.GetString();
if (usage_text.contains_insensitive(search_word))
@@ -672,7 +673,8 @@ void CommandObject::GenerateHelpText(Stream &output_strm) {
if (options != nullptr) {
options->GenerateOptionUsage(
output_strm, *this,
- GetCommandInterpreter().GetDebugger().GetTerminalWidth());
+ GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
+ GetCommandInterpreter().GetDebugger().GetUseColor());
}
llvm::StringRef long_help = GetHelpLong();
if (!long_help.empty()) {
diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp
index 4cf68db46615..cae617813d2f 100644
--- a/lldb/source/Interpreter/Options.cpp
+++ b/lldb/source/Interpreter/Options.cpp
@@ -19,6 +19,7 @@
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/DiagnosticsRendering.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/STLExtras.h"
@@ -261,7 +262,8 @@ Option *Options::GetLongOptions() {
void Options::OutputFormattedUsageText(Stream &strm,
const OptionDefinition &option_def,
- uint32_t output_max_columns) {
+ uint32_t output_max_columns,
+ bool use_color) {
std::string actual_text;
if (option_def.validator) {
const char *condition = option_def.validator->ShortConditionString();
@@ -271,14 +273,16 @@ void Options::OutputFormattedUsageText(Stream &strm,
actual_text.append("] ");
}
}
- actual_text.append(option_def.usage_text);
+ actual_text.append(
+ ansi::FormatAnsiTerminalCodes(option_def.usage_text, use_color));
+ const size_t visible_length = ansi::ColumnWidth(actual_text);
// Will it all fit on one line?
- if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) <
+ if (static_cast<uint32_t>(visible_length + strm.GetIndentLevel()) <
output_max_columns) {
// Output it as a single line.
- strm.Indent(actual_text);
+ strm.Indent(ansi::FormatAnsiTerminalCodes(actual_text, use_color));
strm.EOL();
} else {
// We need to break it up into multiple lines.
@@ -286,7 +290,7 @@ void Options::OutputFormattedUsageText(Stream &strm,
int text_width = output_max_columns - strm.GetIndentLevel() - 1;
int start = 0;
int end = start;
- int final_end = actual_text.length();
+ int final_end = visible_length;
int sub_len;
while (end < final_end) {
@@ -312,7 +316,8 @@ void Options::OutputFormattedUsageText(Stream &strm,
strm.Indent();
assert(start < final_end);
assert(start + sub_len <= final_end);
- strm.Write(actual_text.c_str() + start, sub_len);
+ strm.PutCString(ansi::FormatAnsiTerminalCodes(
+ llvm::StringRef(actual_text.c_str() + start, sub_len), use_color));
start = end + 1;
}
strm.EOL();
@@ -385,7 +390,7 @@ static bool PrintOption(const OptionDefinition &opt_def,
}
void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,
- uint32_t screen_width) {
+ uint32_t screen_width, bool use_color) {
auto opt_defs = GetDefinitions();
const uint32_t save_indent_level = strm.GetIndentLevel();
llvm::StringRef name = cmd.GetCommandName();
@@ -527,7 +532,7 @@ void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,
strm.IndentMore(5);
if (opt_def.usage_text)
- OutputFormattedUsageText(strm, opt_def, screen_width);
+ OutputFormattedUsageText(strm, opt_def, screen_width, use_color);
if (!opt_def.enum_values.empty()) {
strm.Indent();
strm.Printf("Values: ");
@@ -628,6 +633,7 @@ bool Options::HandleOptionCompletion(CompletionRequest &request,
auto opt_defs = GetDefinitions();
llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix();
+ const bool use_color = interpreter.GetDebugger().GetUseColor();
for (size_t i = 0; i < opt_element_vector.size(); i++) {
size_t opt_pos = static_cast<size_t>(opt_element_vector[i].opt_pos);
@@ -647,7 +653,8 @@ bool Options::HandleOptionCompletion(CompletionRequest &request,
if (!def.short_option)
continue;
opt_str[1] = def.short_option;
- request.AddCompletion(opt_str, def.usage_text);
+ request.AddCompletion(opt_str, ansi::FormatAnsiTerminalCodes(
+ def.usage_text, use_color));
}
return true;
@@ -659,7 +666,8 @@ bool Options::HandleOptionCompletion(CompletionRequest &request,
full_name.erase(full_name.begin() + 2, full_name.end());
full_name.append(def.long_option);
- request.AddCompletion(full_name, def.usage_text);
+ request.AddCompletion(full_name, ansi::FormatAnsiTerminalCodes(
+ def.usage_text, use_color));
}
return true;
} else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) {
@@ -670,7 +678,9 @@ bool Options::HandleOptionCompletion(CompletionRequest &request,
const OptionDefinition &opt = opt_defs[opt_defs_index];
llvm::StringRef long_option = opt.long_option;
if (cur_opt_str.starts_with("--") && cur_opt_str != long_option) {
- request.AddCompletion("--" + long_option.str(), opt.usage_text);
+ request.AddCompletion(
+ "--" + long_option.str(),
+ ansi::FormatAnsiTerminalCodes(opt.usage_text, use_color));
return true;
} else
request.AddCompletion(request.GetCursorArgumentPrefix());
@@ -686,7 +696,9 @@ bool Options::HandleOptionCompletion(CompletionRequest &request,
for (auto &def : opt_defs) {
llvm::StringRef long_option(def.long_option);
if (long_option.starts_with(cur_opt_str))
- request.AddCompletion("--" + long_option.str(), def.usage_text);
+ request.AddCompletion(
+ "--" + long_option.str(),
+ ansi::FormatAnsiTerminalCodes(def.usage_text, use_color));
}
}
return true;
@@ -1282,7 +1294,7 @@ llvm::Expected<Args> Options::Parse(const Args &args,
Status error;
Option *long_options = GetLongOptions();
if (long_options == nullptr) {
- return llvm::createStringError("Invalid long options.");
+ return llvm::createStringError("invalid long options");
}
std::string short_options = BuildShortOptions(long_options);
diff --git a/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp
index 2bcb2c0de97a..bb0c4ba3f1b5 100644
--- a/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp
+++ b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp
@@ -1921,6 +1921,13 @@ UnwindPlanSP ABISysV_arm::CreateFunctionEntryUnwindPlan() {
UnwindPlanSP ABISysV_arm::CreateDefaultUnwindPlan() {
// TODO: Handle thumb
+ // If we had a Target argument, could at least check
+ // target.GetArchitecture().GetTriple().isArmMClass()
+ // which is always thumb.
+ // To handle thumb properly, we'd need to fetch the current
+ // CPSR state at unwind time to tell if the processor is
+ // in thumb mode in this stack frame. There's no way to
+ // express something like that in an UnwindPlan today.
uint32_t fp_reg_num = dwarf_r11;
uint32_t pc_reg_num = dwarf_pc;
diff --git a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp
index 81c72122cb7e..721c4bcfe634 100644
--- a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp
+++ b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp
@@ -9,10 +9,18 @@
#include "Plugins/Architecture/Arm/ArchitectureArm.h"
#include "Plugins/Process/Utility/ARMDefines.h"
#include "Plugins/Process/Utility/InstructionUtils.h"
+#include "Utility/ARM_DWARF_Registers.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/RegisterNumber.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Target/UnwindLLDB.h"
#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
using namespace lldb_private;
using namespace lldb;
@@ -150,3 +158,181 @@ addr_t ArchitectureArm::GetOpcodeLoadAddress(addr_t opcode_addr,
}
return opcode_addr & ~(1ull);
}
+
+// The ARM M-Profile Armv7-M Architecture Reference Manual,
+// subsection "B1.5 Armv7-M exception model", see the parts
+// describing "Exception entry behavior" and "Exception
+// return behavior".
+// When an exception happens on this processor, certain registers are
+// saved below the stack pointer, the stack pointer is decremented,
+// a special value is put in the link register to indicate the
+// exception has been taken, and an exception handler function
+// is invoked.
+//
+// Detect that special value in $lr, and if present, add
+// unwind rules for the registers that were saved above this
+// stack frame's CFA. Overwrite any register locations that
+// the current_unwindplan has for these registers; they are
+// not correct when we're invoked this way.
+UnwindPlanSP ArchitectureArm::GetArchitectureUnwindPlan(
+ Thread &thread, RegisterContextUnwind *regctx,
+ std::shared_ptr<const UnwindPlan> current_unwindplan) {
+
+ ProcessSP process_sp = thread.GetProcess();
+ if (!process_sp)
+ return {};
+
+ const ArchSpec arch = process_sp->GetTarget().GetArchitecture();
+ if (!arch.GetTriple().isArmMClass() || arch.GetAddressByteSize() != 4)
+ return {};
+
+ // Get the caller's LR value from regctx (the LR value
+ // at function entry to this function).
+ RegisterNumber ra_regnum(thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_RA);
+ uint32_t ra_regnum_lldb = ra_regnum.GetAsKind(eRegisterKindLLDB);
+
+ if (ra_regnum_lldb == LLDB_INVALID_REGNUM)
+ return {};
+
+ UnwindLLDB::ConcreteRegisterLocation regloc = {};
+ bool got_concrete_location = false;
+ if (regctx->SavedLocationForRegister(ra_regnum_lldb, regloc) ==
+ UnwindLLDB::RegisterSearchResult::eRegisterFound) {
+ got_concrete_location = true;
+ } else {
+ RegisterNumber pc_regnum(thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+ uint32_t pc_regnum_lldb = pc_regnum.GetAsKind(eRegisterKindLLDB);
+ if (regctx->SavedLocationForRegister(pc_regnum_lldb, regloc) ==
+ UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ got_concrete_location = true;
+ }
+
+ if (!got_concrete_location)
+ return {};
+
+ addr_t callers_return_address = LLDB_INVALID_ADDRESS;
+ const RegisterInfo *reg_info = regctx->GetRegisterInfoAtIndex(ra_regnum_lldb);
+ if (reg_info) {
+ RegisterValue reg_value;
+ if (regctx->ReadRegisterValueFromRegisterLocation(regloc, reg_info,
+ reg_value)) {
+ callers_return_address = reg_value.GetAsUInt32();
+ }
+ }
+
+ if (callers_return_address == LLDB_INVALID_ADDRESS)
+ return {};
+
+ // ARMv7-M ARM says that the LR will be set to
+ // one of these values when an exception has taken
+ // place:
+ // if HaveFPExt() then
+ // if CurrentMode==Mode_Handler then
+ // LR = Ones(27):NOT(CONTROL.FPCA):'0001';
+ // else
+ // LR = Ones(27):NOT(CONTROL.FPCA):'1':CONTROL.SPSEL:'01';
+ // else
+ // if CurrentMode==Mode_Handler then
+ // LR = Ones(28):'0001';
+ // else
+ // LR = Ones(29):CONTROL.SPSEL:'01';
+
+ // Top 27 bits are set for an exception return.
+ const uint32_t exception_return = -1U & ~0b11111U;
+ // Bit4 is 1 if only GPRs were saved.
+ const uint32_t gprs_only = 0b10000;
+ // Bit<1:0> are '01'.
+ const uint32_t lowbits = 0b01;
+
+ if ((callers_return_address & exception_return) != exception_return)
+ return {};
+ if ((callers_return_address & lowbits) != lowbits)
+ return {};
+
+ const bool fp_regs_saved = !(callers_return_address & gprs_only);
+
+ const RegisterKind plan_regkind = current_unwindplan->GetRegisterKind();
+ UnwindPlanSP new_plan = std::make_shared<UnwindPlan>(plan_regkind);
+ new_plan->SetSourceName("Arm Cortex-M exception return UnwindPlan");
+ new_plan->SetSourcedFromCompiler(eLazyBoolNo);
+ new_plan->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
+ new_plan->SetUnwindPlanForSignalTrap(eLazyBoolYes);
+
+ int stored_regs_size = fp_regs_saved ? 0x68 : 0x20;
+
+ uint32_t gpr_regs[] = {dwarf_r0, dwarf_r1, dwarf_r2, dwarf_r3,
+ dwarf_r12, dwarf_lr, dwarf_pc, dwarf_cpsr};
+ const int gpr_reg_count = std::size(gpr_regs);
+ uint32_t fpr_regs[] = {dwarf_s0, dwarf_s1, dwarf_s2, dwarf_s3,
+ dwarf_s4, dwarf_s5, dwarf_s6, dwarf_s7,
+ dwarf_s8, dwarf_s9, dwarf_s10, dwarf_s11,
+ dwarf_s12, dwarf_s13, dwarf_s14, dwarf_s15};
+ const int fpr_reg_count = std::size(fpr_regs);
+
+ RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
+ std::vector<uint32_t> saved_regs;
+ for (int i = 0; i < gpr_reg_count; i++) {
+ uint32_t regno = gpr_regs[i];
+ reg_ctx_sp->ConvertBetweenRegisterKinds(eRegisterKindDWARF, gpr_regs[i],
+ plan_regkind, regno);
+ saved_regs.push_back(regno);
+ }
+ if (fp_regs_saved) {
+ for (int i = 0; i < fpr_reg_count; i++) {
+ uint32_t regno = fpr_regs[i];
+ reg_ctx_sp->ConvertBetweenRegisterKinds(eRegisterKindDWARF, fpr_regs[i],
+ plan_regkind, regno);
+ saved_regs.push_back(regno);
+ }
+ }
+
+ addr_t cfa;
+ if (!regctx->GetCFA(cfa))
+ return {};
+
+ // The CPSR value saved to stack is actually (from Armv7-M ARM)
+ // "XPSR<31:10>:frameptralign:XPSR<8:0>"
+ // Bit 9 indicates that the stack pointer was aligned (to
+ // an 8-byte alignment) when the exception happened, and we must
+ // account for that when restoring the original stack pointer value.
+ Status error;
+ uint32_t callers_xPSR =
+ process_sp->ReadUnsignedIntegerFromMemory(cfa + 0x1c, 4, 0, error);
+ const bool align_stack = callers_xPSR & (1U << 9);
+ uint32_t callers_sp = cfa + stored_regs_size;
+ if (align_stack)
+ callers_sp |= 4;
+
+ Log *log = GetLog(LLDBLog::Unwind);
+ LLDB_LOGF(log,
+ "ArchitectureArm::GetArchitectureUnwindPlan found caller return "
+ "addr of 0x%" PRIx64 ", for frame with CFA 0x%" PRIx64
+ ", fp_regs_saved %d, stored_regs_size 0x%x, align stack %d",
+ callers_return_address, cfa, fp_regs_saved, stored_regs_size,
+ align_stack);
+
+ uint32_t sp_regnum = dwarf_sp;
+ reg_ctx_sp->ConvertBetweenRegisterKinds(eRegisterKindDWARF, dwarf_sp,
+ plan_regkind, sp_regnum);
+
+ const int row_count = current_unwindplan->GetRowCount();
+ for (int i = 0; i < row_count; i++) {
+ UnwindPlan::Row row = *current_unwindplan->GetRowAtIndex(i);
+ uint32_t offset = 0;
+ const size_t saved_reg_count = saved_regs.size();
+ for (size_t j = 0; j < saved_reg_count; j++) {
+ // The locations could be set with
+ // SetRegisterLocationToIsConstant(regno, cfa+offset)
+ // expressing it in terms of CFA addr+offset - this UnwindPlan
+ // is only used once, with this specific CFA. I'm not sure
+ // which will be clearer for someone reading the unwind log.
+ row.SetRegisterLocationToAtCFAPlusOffset(saved_regs[j], offset, true);
+ offset += 4;
+ }
+ row.SetRegisterLocationToIsCFAPlusOffset(sp_regnum, callers_sp - cfa, true);
+ new_plan->AppendRow(row);
+ }
+ return new_plan;
+}
diff --git a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h
index f579d6b62505..52277dc5dbae 100644
--- a/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h
+++ b/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h
@@ -10,6 +10,7 @@
#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_ARM_ARCHITECTUREARM_H
#include "lldb/Core/Architecture.h"
+#include "lldb/Target/Thread.h"
namespace lldb_private {
@@ -29,6 +30,10 @@ public:
lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr,
AddressClass addr_class) const override;
+ lldb::UnwindPlanSP GetArchitectureUnwindPlan(
+ lldb_private::Thread &thread, lldb_private::RegisterContextUnwind *regctx,
+ std::shared_ptr<const UnwindPlan> current_unwindplan) override;
+
private:
static std::unique_ptr<Architecture> Create(const ArchSpec &arch);
ArchitectureArm() = default;
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index d92e16366f0a..66d0a50985be 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -559,7 +559,7 @@ public:
lldb::InstructionControlFlowKind
GetControlFlowKind(const lldb_private::ExecutionContext *exe_ctx) override {
DisassemblerScope disasm(*this, exe_ctx);
- if (disasm){
+ if (disasm) {
if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86)
return x86::GetControlFlowKind(/*is_64b=*/false, m_opcode);
else if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
@@ -1249,12 +1249,15 @@ private:
};
std::unique_ptr<DisassemblerLLVMC::MCDisasmInstance>
-DisassemblerLLVMC::MCDisasmInstance::Create(const char *triple, const char *cpu,
+DisassemblerLLVMC::MCDisasmInstance::Create(const char *triple_name,
+ const char *cpu,
const char *features_str,
unsigned flavor,
DisassemblerLLVMC &owner) {
using Instance = std::unique_ptr<DisassemblerLLVMC::MCDisasmInstance>;
+ llvm::Triple triple(triple_name);
+
std::string Status;
const llvm::Target *curr_target =
llvm::TargetRegistry::lookupTarget(triple, Status);
@@ -1605,9 +1608,8 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
// thumb instruction disassembler.
if (llvm_arch == llvm::Triple::arm) {
std::string thumb_triple(thumb_arch.GetTriple().getTriple());
- m_alternate_disasm_up =
- MCDisasmInstance::Create(thumb_triple.c_str(), "", features_str.c_str(),
- flavor, *this);
+ m_alternate_disasm_up = MCDisasmInstance::Create(
+ thumb_triple.c_str(), "", features_str.c_str(), flavor, *this);
if (!m_alternate_disasm_up)
m_disasm_up.reset();
diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
index 42ea5aacecb4..8b1c3c3f467f 100644
--- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
+++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
@@ -45,7 +45,8 @@ protected:
lldb::addr_t GetLoadAddress(lldb::ModuleSP executable);
private:
- std::map<lldb::ModuleSP, lldb::addr_t> m_loaded_modules;
+ std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
+ m_loaded_modules;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 86ff010e760f..097a4661e0c9 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -536,23 +536,19 @@ static void SetupLangOpts(CompilerInstance &compiler,
lldb::StackFrameSP frame_sp = exe_scope.CalculateStackFrame();
lldb::ProcessSP process_sp = exe_scope.CalculateProcess();
- // Defaults to lldb::eLanguageTypeUnknown.
- lldb::LanguageType frame_lang = expr.Language().AsLanguageType();
-
- // Make sure the user hasn't provided a preferred execution language with
- // `expression --language X -- ...`
- if (frame_sp && frame_lang == lldb::eLanguageTypeUnknown)
- frame_lang = frame_sp->GetLanguage().AsLanguageType();
+ lldb::LanguageType language = expr.Language().AsLanguageType();
- if (process_sp && frame_lang != lldb::eLanguageTypeUnknown) {
- LLDB_LOGF(log, "Frame has language of type %s",
- lldb_private::Language::GetNameForLanguageType(frame_lang));
- }
+ if (process_sp)
+ LLDB_LOG(
+ log,
+ "Frame has language of type {0}\nPicked {1} for expression evaluation.",
+ lldb_private::Language::GetNameForLanguageType(
+ frame_sp ? frame_sp->GetLanguage().AsLanguageType()
+ : lldb::eLanguageTypeUnknown),
+ lldb_private::Language::GetNameForLanguageType(language));
- lldb::LanguageType language = expr.Language().AsLanguageType();
LangOptions &lang_opts = compiler.getLangOpts();
- // FIXME: should this switch on frame_lang?
switch (language) {
case lldb::eLanguageTypeC:
case lldb::eLanguageTypeC89:
diff --git a/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
index 926555380334..8bcb4e5535d2 100644
--- a/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
+++ b/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp
@@ -147,17 +147,15 @@ EmulateInstructionMIPS::EmulateInstructionMIPS(
if (arch_flags & ArchSpec::eMIPSAse_dspr2)
features += "+dspr2,";
- m_reg_info.reset(target->createMCRegInfo(triple.getTriple()));
+ m_reg_info.reset(target->createMCRegInfo(triple));
assert(m_reg_info.get());
m_insn_info.reset(target->createMCInstrInfo());
assert(m_insn_info.get());
llvm::MCTargetOptions MCOptions;
- m_asm_info.reset(
- target->createMCAsmInfo(*m_reg_info, triple.getTriple(), MCOptions));
- m_subtype_info.reset(
- target->createMCSubtargetInfo(triple.getTriple(), cpu, features));
+ m_asm_info.reset(target->createMCAsmInfo(*m_reg_info, triple, MCOptions));
+ m_subtype_info.reset(target->createMCSubtargetInfo(triple, cpu, features));
assert(m_asm_info.get() && m_subtype_info.get());
m_context = std::make_unique<llvm::MCContext>(
@@ -174,7 +172,7 @@ EmulateInstructionMIPS::EmulateInstructionMIPS(
features += "+micromips,";
m_alt_subtype_info.reset(
- target->createMCSubtargetInfo(triple.getTriple(), cpu, features));
+ target->createMCSubtargetInfo(triple, cpu, features));
assert(m_alt_subtype_info.get());
m_alt_disasm.reset(
@@ -1005,11 +1003,10 @@ bool EmulateInstructionMIPS::SetInstruction(const Opcode &insn_opcode,
uint64_t next_inst_addr = (m_addr & (~1ull)) + current_inst_size;
Address next_addr(next_inst_addr);
- const size_t bytes_read =
- target->ReadMemory(next_addr, /* Address of next instruction */
- buf, sizeof(uint32_t), error,
- false, /* force_live_memory */
- &load_addr);
+ const size_t bytes_read = target->ReadMemory(
+ next_addr, /* Address of next instruction */
+ buf, sizeof(uint32_t), error, false, /* force_live_memory */
+ &load_addr);
if (bytes_read == 0)
return true;
diff --git a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
index 780cc68fb75e..ad55d0ba97ad 100644
--- a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
+++ b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
@@ -151,17 +151,15 @@ EmulateInstructionMIPS64::EmulateInstructionMIPS64(
if (arch_flags & ArchSpec::eMIPSAse_micromips)
features += "+micromips,";
- m_reg_info.reset(target->createMCRegInfo(triple.getTriple()));
+ m_reg_info.reset(target->createMCRegInfo(triple));
assert(m_reg_info.get());
m_insn_info.reset(target->createMCInstrInfo());
assert(m_insn_info.get());
llvm::MCTargetOptions MCOptions;
- m_asm_info.reset(
- target->createMCAsmInfo(*m_reg_info, triple.getTriple(), MCOptions));
- m_subtype_info.reset(
- target->createMCSubtargetInfo(triple.getTriple(), cpu, features));
+ m_asm_info.reset(target->createMCAsmInfo(*m_reg_info, triple, MCOptions));
+ m_subtype_info.reset(target->createMCSubtargetInfo(triple, cpu, features));
assert(m_asm_info.get() && m_subtype_info.get());
m_context = std::make_unique<llvm::MCContext>(
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index b4207439f528..277de8f44482 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -604,126 +604,6 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier(
return false;
}
-namespace {
-class NodeAllocator {
- llvm::BumpPtrAllocator Alloc;
-
-public:
- void reset() { Alloc.Reset(); }
-
- template <typename T, typename... Args> T *makeNode(Args &&...args) {
- return new (Alloc.Allocate(sizeof(T), alignof(T)))
- T(std::forward<Args>(args)...);
- }
-
- void *allocateNodeArray(size_t sz) {
- return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
- alignof(llvm::itanium_demangle::Node *));
- }
-};
-
-template <typename Derived>
-class ManglingSubstitutor
- : public llvm::itanium_demangle::AbstractManglingParser<Derived,
- NodeAllocator> {
- using Base =
- llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
-
-public:
- ManglingSubstitutor() : Base(nullptr, nullptr) {}
-
- template <typename... Ts>
- ConstString substitute(llvm::StringRef Mangled, Ts &&...Vals) {
- this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
- return substituteImpl(Mangled);
- }
-
-protected:
- void reset(llvm::StringRef Mangled) {
- Base::reset(Mangled.begin(), Mangled.end());
- Written = Mangled.begin();
- Result.clear();
- Substituted = false;
- }
-
- ConstString substituteImpl(llvm::StringRef Mangled) {
- Log *log = GetLog(LLDBLog::Language);
- if (this->parse() == nullptr) {
- LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
- return ConstString();
- }
- if (!Substituted)
- return ConstString();
-
- // Append any trailing unmodified input.
- appendUnchangedInput();
- LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
- return ConstString(Result);
- }
-
- void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
- if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
- return;
-
- // We found a match. Append unmodified input up to this point.
- appendUnchangedInput();
-
- // And then perform the replacement.
- Result += To;
- Written += From.size();
- Substituted = true;
- }
-
-private:
- /// Input character until which we have constructed the respective output
- /// already.
- const char *Written = "";
-
- llvm::SmallString<128> Result;
-
- /// Whether we have performed any substitutions.
- bool Substituted = false;
-
- const char *currentParserPos() const { return this->First; }
-
- void appendUnchangedInput() {
- Result +=
- llvm::StringRef(Written, std::distance(Written, currentParserPos()));
- Written = currentParserPos();
- }
-};
-
-/// Given a mangled function `Mangled`, replace all the primitive function type
-/// arguments of `Search` with type `Replace`.
-class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
- llvm::StringRef Search;
- llvm::StringRef Replace;
-
-public:
- void reset(llvm::StringRef Mangled, llvm::StringRef Search,
- llvm::StringRef Replace) {
- ManglingSubstitutor::reset(Mangled);
- this->Search = Search;
- this->Replace = Replace;
- }
-
- llvm::itanium_demangle::Node *parseType() {
- trySubstitute(Search, Replace);
- return ManglingSubstitutor::parseType();
- }
-};
-
-class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
-public:
- llvm::itanium_demangle::Node *
- parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
- trySubstitute("C1", "C2");
- trySubstitute("D1", "D2");
- return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
- }
-};
-} // namespace
-
std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
const ConstString mangled_name) const {
std::vector<ConstString> alternates;
@@ -751,29 +631,49 @@ std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
alternates.push_back(ConstString(fixed_scratch));
}
- TypeSubstitutor TS;
+ auto *log = GetLog(LLDBLog::Language);
+
// `char` is implementation defined as either `signed` or `unsigned`. As a
// result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
// char, 'h'-unsigned char. If we're looking for symbols with a signed char
// parameter, try finding matches which have the general case 'c'.
- if (ConstString char_fixup =
- TS.substitute(mangled_name.GetStringRef(), "a", "c"))
- alternates.push_back(char_fixup);
+ if (auto char_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "a", "c")) {
+ // LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
+ if (*char_fixup_or_err)
+ alternates.push_back(*char_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(log, char_fixup_or_err.takeError(),
+ "Failed to substitute 'char' type mangling: {0}");
// long long parameter mangling 'x', may actually just be a long 'l' argument
- if (ConstString long_fixup =
- TS.substitute(mangled_name.GetStringRef(), "x", "l"))
- alternates.push_back(long_fixup);
+ if (auto long_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "x", "l")) {
+ if (*long_fixup_or_err)
+ alternates.push_back(*long_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(log, long_fixup_or_err.takeError(),
+ "Failed to substitute 'long long' type mangling: {0}");
// unsigned long long parameter mangling 'y', may actually just be unsigned
// long 'm' argument
- if (ConstString ulong_fixup =
- TS.substitute(mangled_name.GetStringRef(), "y", "m"))
- alternates.push_back(ulong_fixup);
-
- if (ConstString ctor_fixup =
- CtorDtorSubstitutor().substitute(mangled_name.GetStringRef()))
- alternates.push_back(ctor_fixup);
+ if (auto ulong_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "y", "m")) {
+ if (*ulong_fixup_or_err)
+ alternates.push_back(*ulong_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(
+ log, ulong_fixup_or_err.takeError(),
+ "Failed to substitute 'unsigned long long' type mangling: {0}");
+
+ if (auto ctor_fixup_or_err = SubstituteStructorAliases_ItaniumMangle(
+ mangled_name.GetStringRef())) {
+ if (*ctor_fixup_or_err) {
+ alternates.push_back(*ctor_fixup_or_err);
+ }
+ } else
+ LLDB_LOG_ERROR(log, ctor_fixup_or_err.takeError(),
+ "Failed to substitute structor alias manglings: {0}");
return alternates;
}
@@ -849,31 +749,27 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibcxxStringSummaryProviderASCII,
"std::string summary provider",
"^std::__[[:alnum:]]+::basic_string<char, "
- "std::__[[:alnum:]]+::char_traits<char>, "
- "std::__[[:alnum:]]+::allocator<char> >$",
+ "std::__[[:alnum:]]+::char_traits<char>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxStringSummaryProviderASCII,
"std::string summary provider",
"^std::__[[:alnum:]]+::basic_string<unsigned char, "
- "std::__[[:alnum:]]+::char_traits<unsigned char>, "
- "std::__[[:alnum:]]+::allocator<unsigned char> >$",
+ "std::__[[:alnum:]]+::char_traits<unsigned char>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxStringSummaryProviderUTF16,
"std::u16string summary provider",
"^std::__[[:alnum:]]+::basic_string<char16_t, "
- "std::__[[:alnum:]]+::char_traits<char16_t>, "
- "std::__[[:alnum:]]+::allocator<char16_t> >$",
+ "std::__[[:alnum:]]+::char_traits<char16_t>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxStringSummaryProviderUTF32,
"std::u32string summary provider",
"^std::__[[:alnum:]]+::basic_string<char32_t, "
- "std::__[[:alnum:]]+::char_traits<char32_t>, "
- "std::__[[:alnum:]]+::allocator<char32_t> >$",
+ "std::__[[:alnum:]]+::char_traits<char32_t>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
@@ -884,8 +780,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibcxxWStringSummaryProvider,
"std::wstring summary provider",
"^std::__[[:alnum:]]+::basic_string<wchar_t, "
- "std::__[[:alnum:]]+::char_traits<wchar_t>, "
- "std::__[[:alnum:]]+::allocator<wchar_t> >$",
+ "std::__[[:alnum:]]+::char_traits<wchar_t>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
@@ -1401,24 +1296,16 @@ static void RegisterStdStringSummaryProvider(
category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp);
- // std::basic_string<char>
category_sp->AddTypeSummary(
makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()),
summary_sp);
- // std::basic_string<char,std::char_traits<char>,std::allocator<char> >
- category_sp->AddTypeSummary(
- makeSpecifier(llvm::formatv("std::basic_string<{0},std::char_traits<{0}>,"
- "std::allocator<{0}> >",
- char_ty)
- .str()),
- summary_sp);
- // std::basic_string<char, std::char_traits<char>, std::allocator<char> >
+
category_sp->AddTypeSummary(
- makeSpecifier(
- llvm::formatv("std::basic_string<{0}, std::char_traits<{0}>, "
- "std::allocator<{0}> >",
+ std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+ llvm::formatv("^std::basic_string<{0}, ?std::char_traits<{0}>,.*>$",
char_ty)
- .str()),
+ .str(),
+ eFormatterMatchRegex),
summary_sp);
}
@@ -1463,20 +1350,17 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact,
string_summary_sp);
cpp_category_sp->AddTypeSummary(
- "std::__cxx11::basic_string<char, std::char_traits<char>, "
- "std::allocator<char> >",
- eFormatterMatchExact, string_summary_sp);
- cpp_category_sp->AddTypeSummary("std::__cxx11::basic_string<unsigned char, "
- "std::char_traits<unsigned char>, "
- "std::allocator<unsigned char> >",
- eFormatterMatchExact, string_summary_sp);
+ "^std::__cxx11::basic_string<char, std::char_traits<char>,.*>$",
+ eFormatterMatchRegex, string_summary_sp);
+ cpp_category_sp->AddTypeSummary("^std::__cxx11::basic_string<unsigned char, "
+ "std::char_traits<unsigned char>,.*>$",
+ eFormatterMatchRegex, string_summary_sp);
cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", eFormatterMatchExact,
string_summary_sp);
cpp_category_sp->AddTypeSummary(
- "std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, "
- "std::allocator<wchar_t> >",
- eFormatterMatchExact, string_summary_sp);
+ "^std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>,.*>$",
+ eFormatterMatchRegex, string_summary_sp);
SyntheticChildren::Flags stl_synth_flags;
stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
@@ -2442,6 +2326,160 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
}
}
+namespace {
+class NodeAllocator {
+ llvm::BumpPtrAllocator Alloc;
+
+public:
+ void reset() { Alloc.Reset(); }
+
+ template <typename T, typename... Args> T *makeNode(Args &&...args) {
+ return new (Alloc.Allocate(sizeof(T), alignof(T)))
+ T(std::forward<Args>(args)...);
+ }
+
+ void *allocateNodeArray(size_t sz) {
+ return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
+ alignof(llvm::itanium_demangle::Node *));
+ }
+};
+
+template <typename Derived>
+class ManglingSubstitutor
+ : public llvm::itanium_demangle::AbstractManglingParser<Derived,
+ NodeAllocator> {
+ using Base =
+ llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
+
+public:
+ ManglingSubstitutor() : Base(nullptr, nullptr) {}
+
+ template <typename... Ts>
+ llvm::Expected<ConstString> substitute(llvm::StringRef Mangled,
+ Ts &&...Vals) {
+ this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
+ return substituteImpl(Mangled);
+ }
+
+protected:
+ void reset(llvm::StringRef Mangled) {
+ Base::reset(Mangled.begin(), Mangled.end());
+ Written = Mangled.begin();
+ Result.clear();
+ Substituted = false;
+ }
+
+ llvm::Expected<ConstString> substituteImpl(llvm::StringRef Mangled) {
+ if (this->parse() == nullptr)
+ return llvm::createStringError(
+ llvm::formatv("Failed to substitute mangling in '{0}'", Mangled));
+
+ if (!Substituted)
+ return ConstString();
+
+ // Append any trailing unmodified input.
+ appendUnchangedInput();
+ return ConstString(Result);
+ }
+
+ void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
+ if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
+ return;
+
+ // We found a match. Append unmodified input up to this point.
+ appendUnchangedInput();
+
+ // And then perform the replacement.
+ Result += To;
+ Written += From.size();
+ Substituted = true;
+ }
+
+private:
+ /// Input character until which we have constructed the respective output
+ /// already.
+ const char *Written = "";
+
+ llvm::SmallString<128> Result;
+
+ /// Whether we have performed any substitutions.
+ bool Substituted = false;
+
+ const char *currentParserPos() const { return this->First; }
+
+ void appendUnchangedInput() {
+ Result +=
+ llvm::StringRef(Written, std::distance(Written, currentParserPos()));
+ Written = currentParserPos();
+ }
+};
+
+/// Given a mangled function `Mangled`, replace all the primitive function type
+/// arguments of `Search` with type `Replace`.
+class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
+ llvm::StringRef Search;
+ llvm::StringRef Replace;
+
+public:
+ void reset(llvm::StringRef Mangled, llvm::StringRef Search,
+ llvm::StringRef Replace) {
+ ManglingSubstitutor::reset(Mangled);
+ this->Search = Search;
+ this->Replace = Replace;
+ }
+
+ llvm::itanium_demangle::Node *parseType() {
+ trySubstitute(Search, Replace);
+ return ManglingSubstitutor::parseType();
+ }
+};
+
+class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
+ llvm::StringRef Search;
+ llvm::StringRef Replace;
+
+public:
+ void reset(llvm::StringRef Mangled, llvm::StringRef Search,
+ llvm::StringRef Replace) {
+ ManglingSubstitutor::reset(Mangled);
+ this->Search = Search;
+ this->Replace = Replace;
+ }
+
+ void reset(llvm::StringRef Mangled) { ManglingSubstitutor::reset(Mangled); }
+
+ llvm::itanium_demangle::Node *
+ parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
+ if (!Search.empty() && !Replace.empty()) {
+ trySubstitute(Search, Replace);
+ } else {
+ trySubstitute("D1", "D2");
+ trySubstitute("C1", "C2");
+ }
+ return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
+ }
+};
+} // namespace
+
+llvm::Expected<ConstString>
+CPlusPlusLanguage::SubstituteType_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to) {
+ return TypeSubstitutor().substitute(mangled_name, subst_from, subst_to);
+}
+
+llvm::Expected<ConstString> CPlusPlusLanguage::SubstituteStructor_ItaniumMangle(
+ llvm::StringRef mangled_name, llvm::StringRef subst_from,
+ llvm::StringRef subst_to) {
+ return CtorDtorSubstitutor().substitute(mangled_name, subst_from, subst_to);
+}
+
+llvm::Expected<ConstString>
+CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(
+ llvm::StringRef mangled_name) {
+ return CtorDtorSubstitutor().substitute(mangled_name);
+}
+
#define LLDB_PROPERTIES_language_cplusplus
#include "LanguageCPlusPlusProperties.inc"
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 4a30299dd265..9a528ca7b03f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -164,6 +164,76 @@ public:
ConstString FindBestAlternateFunctionMangledName(
const Mangled mangled, const SymbolContext &sym_ctx) const override;
+ /// Substitutes Itanium type encoding substrings given by \c subst_from
+ /// in \c mangled_name with \c subst_to.
+ ///
+ /// This function will only replace Itanium type encodings (i.e., <type>
+ /// productions in the Itanium ABI mangling grammar). However, no verifiction
+ /// is done on whether \c subst_from or \c subst_to is a valid type encoding.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \param[in] subst_from The substring to substitute.
+ ///
+ /// \param[in] subst_to The substring to insert.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteType_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to);
+
+ /// Substitutes Itanium structor encoding substrings given by \c subst_from
+ /// in \c mangled_name with \c subst_to.
+ ///
+ /// This function will only replace Itanium structor encodings (i.e.,
+ /// <ctor-dtor-name> productions in the Itanium ABI mangling grammar).
+ /// However, no verifiction is done on whether \c subst_from or \c subst_to is
+ /// a valid structor encoding.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \param[in] subst_from The substring to substitute.
+ ///
+ /// \param[in] subst_to The substring to insert.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteStructor_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to);
+
+ /// Tries replacing Itanium structor encoding substrings in \c mangled_name
+ /// with potential aliases.j
+ ///
+ /// This function will only replace Itanium structor encodings (i.e.,
+ /// <ctor-dtor-name> productions in the Itanium ABI mangling grammar).
+ ///
+ /// E.g., on some platforms, the C1/D1 variants are aliased to the C2/D2
+ /// variants. This function will try to replace occurrences of C1/D1 with
+ /// C2/D2.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteStructorAliases_ItaniumMangle(llvm::StringRef mangled_name);
+
llvm::StringRef GetInstanceVariableName() override { return "this"; }
FormatEntity::Entry GetFunctionNameFormat() const override;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index ea1edbfd3ac9..5289027fbd8a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -339,11 +339,18 @@ lldb::ChildCacheState LibCxxForwardListFrontEnd::Update() {
if (err.Fail() || !backend_addr)
return lldb::ChildCacheState::eRefetch;
- ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
+ auto list_base_sp = m_backend.GetChildAtIndex(0);
+ if (!list_base_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Anonymous strucutre index is in base class at index 0.
+ auto [impl_sp, is_compressed_pair] =
+ GetValueOrOldCompressedPair(*list_base_sp, /*anon_struct_idx=*/0,
+ "__before_begin_", "__before_begin_");
if (!impl_sp)
return ChildCacheState::eRefetch;
- if (isOldCompressedPairLayout(*impl_sp))
+ if (is_compressed_pair)
impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
if (!impl_sp)
@@ -366,17 +373,10 @@ llvm::Expected<uint32_t> LibCxxListFrontEnd::CalculateNumChildren() {
if (!m_head || !m_tail || m_node_address == 0)
return 0;
- ValueObjectSP size_node_sp(m_backend.GetChildMemberWithName("__size_"));
- if (!size_node_sp) {
- size_node_sp = m_backend.GetChildMemberWithName(
- "__size_alloc_"); // pre-compressed_pair rework
-
- if (!isOldCompressedPairLayout(*size_node_sp))
- return llvm::createStringError("Unexpected std::list layout: expected "
- "old __compressed_pair layout.");
-
+ auto [size_node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ m_backend, /*anon_struct_idx=*/1, "__size_", "__size_alloc_");
+ if (is_compressed_pair)
size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp);
- }
if (size_node_sp)
m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index a7874047942c..6053d042b29b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -49,11 +49,6 @@ static void consumeInlineNamespace(llvm::StringRef &name) {
}
}
-bool lldb_private::formatters::isOldCompressedPairLayout(
- ValueObject &pair_obj) {
- return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
-}
-
bool lldb_private::formatters::isStdTemplate(ConstString type_name,
llvm::StringRef type) {
llvm::StringRef name = type_name.GetStringRef();
@@ -105,6 +100,44 @@ lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
return value;
}
+std::pair<lldb::ValueObjectSP, bool>
+lldb_private::formatters::GetValueOrOldCompressedPair(
+ ValueObject &obj, size_t anon_struct_idx, llvm::StringRef child_name,
+ llvm::StringRef compressed_pair_name) {
+ auto is_old_compressed_pair = [](ValueObject &pair_obj) -> bool {
+ return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
+ };
+
+ // Try searching the child member in an anonymous structure first.
+ if (auto unwrapped = obj.GetChildAtIndex(anon_struct_idx)) {
+ ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));
+ if (node_sp)
+ return {node_sp, is_old_compressed_pair(*node_sp)};
+ }
+
+ // Older versions of libc++ don't wrap the children in anonymous structures.
+ // Try that instead.
+ ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));
+ if (node_sp)
+ return {node_sp, is_old_compressed_pair(*node_sp)};
+
+ // Try the even older __compressed_pair layout.
+
+ assert(!compressed_pair_name.empty());
+
+ node_sp = obj.GetChildMemberWithName(compressed_pair_name);
+
+ // Unrecognized layout (possibly older than LLDB supports).
+ if (!node_sp)
+ return {nullptr, false};
+
+ // Expected old compressed_pair layout, but got something else.
+ if (!is_old_compressed_pair(*node_sp))
+ return {nullptr, false};
+
+ return {node_sp, true};
+}
+
bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
@@ -205,11 +238,12 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
if (!valobj_sp)
return false;
- ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
if (!ptr_sp)
return false;
- if (isOldCompressedPairLayout(*ptr_sp))
+ if (is_compressed_pair)
ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
if (!ptr_sp)
@@ -379,13 +413,14 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
if (!valobj_sp)
return lldb::ChildCacheState::eRefetch;
- ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
if (!ptr_sp)
return lldb::ChildCacheState::eRefetch;
// Retrieve the actual pointer and the deleter, and clone them to give them
// user-friendly names.
- if (isOldCompressedPairLayout(*ptr_sp)) {
+ if (is_compressed_pair) {
if (ValueObjectSP value_pointer_sp =
GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
@@ -424,17 +459,15 @@ enum class StringLayout { CSD, DSC };
}
static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
- if (auto rep_sp = valobj.GetChildMemberWithName("__rep_"))
- return rep_sp;
-
- ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
- if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
+ auto [valobj_r_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ valobj, /*anon_struct_idx=*/0, "__rep_", "__r_");
+ if (!valobj_r_sp)
return nullptr;
- if (!isOldCompressedPairLayout(*valobj_r_sp))
- return nullptr;
+ if (is_compressed_pair)
+ return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
- return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
+ return valobj_r_sp;
}
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index d88a6ecb1fa8..819f8a985f9b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -25,7 +25,22 @@ GetChildMemberWithName(ValueObject &obj,
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair);
lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair);
-bool isOldCompressedPairLayout(ValueObject &pair_obj);
+
+/// Returns the ValueObjectSP of the child of \c obj. If \c obj has no
+/// child named \c child_name, returns the __compressed_pair child instead
+/// with \c compressed_pair_name, if one exists.
+///
+/// Latest libc++ wrap the compressed children in an anonymous structure.
+/// The \c anon_struct_idx indicates the location of this struct.
+///
+/// The returned boolean is \c true if the returned child was has an old-style
+/// libc++ __compressed_pair layout.
+///
+/// If no child was found returns a nullptr.
+std::pair<lldb::ValueObjectSP, bool>
+GetValueOrOldCompressedPair(ValueObject &obj, size_t anon_struct_idx,
+ llvm::StringRef child_name,
+ llvm::StringRef compressed_pair_name);
bool isStdTemplate(ConstString type_name, llvm::StringRef type);
bool LibcxxStringSummaryProviderASCII(
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index 41441dfbc718..85766966f155 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -200,7 +200,8 @@ public:
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
private:
- llvm::Expected<uint32_t> CalculateNumChildrenForOldCompressedPairLayout();
+ llvm::Expected<uint32_t>
+ CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair);
/// Returns the ValueObject for the __tree_node type that
/// holds the key/value pair of the node at index \ref idx.
@@ -254,16 +255,8 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
llvm::Expected<uint32_t>
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
- CalculateNumChildrenForOldCompressedPairLayout() {
- ValueObjectSP node_sp(m_tree->GetChildMemberWithName("__pair3_"));
- if (!node_sp)
- return 0;
-
- if (!isOldCompressedPairLayout(*node_sp))
- return llvm::createStringError("Unexpected std::map layout: expected "
- "old __compressed_pair layout.");
-
- node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
+ CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair) {
+ auto node_sp = GetFirstValueOfLibCXXCompressedPair(pair);
if (!node_sp)
return 0;
@@ -281,12 +274,16 @@ llvm::Expected<uint32_t> lldb_private::formatters::
if (m_tree == nullptr)
return 0;
- if (auto node_sp = m_tree->GetChildMemberWithName("__size_")) {
- m_count = node_sp->GetValueAsUnsigned(0);
- return m_count;
- }
+ auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *m_tree, /*anon_struct_idx=*/2, "__size_", "__pair3_");
+ if (!size_sp)
+ return llvm::createStringError("Unexpected std::map layout");
- return CalculateNumChildrenForOldCompressedPairLayout();
+ if (is_compressed_pair)
+ return CalculateNumChildrenForOldCompressedPairLayout(*size_sp);
+
+ m_count = size_sp->GetValueAsUnsigned(0);
+ return m_count;
}
ValueObjectSP
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 501fd0945b82..f88a5319068a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -130,22 +130,17 @@ CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
GetNodeType() {
- auto node_sp = m_backend.GetChildAtNamePath({"__table_", "__first_node_"});
-
- if (!node_sp) {
- auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
- if (!p1_sp)
- return {};
+ auto table_sp = m_backend.GetChildMemberWithName("__table_");
+ if (!table_sp)
+ return {};
- if (!isOldCompressedPairLayout(*p1_sp))
- return {};
+ auto [node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *table_sp, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
+ if (is_compressed_pair)
+ node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
- node_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
- if (!node_sp)
- return {};
- }
-
- assert(node_sp);
+ if (!node_sp)
+ return {};
return node_sp->GetCompilerType().GetTypeTemplateArgument(0).GetPointeeType();
}
@@ -223,19 +218,15 @@ lldb::ValueObjectSP lldb_private::formatters::
llvm::Expected<size_t>
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
CalculateNumChildrenImpl(ValueObject &table) {
- if (auto size_sp = table.GetChildMemberWithName("__size_"))
+ auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ table, /*anon_struct_idx=*/2, "__size_", "__p2_");
+ if (!is_compressed_pair && size_sp)
return size_sp->GetValueAsUnsigned(0);
- ValueObjectSP p2_sp = table.GetChildMemberWithName("__p2_");
- if (!p2_sp)
- return llvm::createStringError(
- "Unexpected std::unordered_map layout: __p2_ member not found.");
+ if (!is_compressed_pair)
+ return llvm::createStringError("Unsupported std::unordered_map layout.");
- if (!isOldCompressedPairLayout(*p2_sp))
- return llvm::createStringError("Unexpected std::unordered_map layout: old "
- "__compressed_pair layout not found.");
-
- ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
+ ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*size_sp);
if (!num_elements_sp)
return llvm::createStringError(
@@ -246,19 +237,13 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
}
static ValueObjectSP GetTreePointer(ValueObject &table) {
- ValueObjectSP tree_sp = table.GetChildMemberWithName("__first_node_");
- if (!tree_sp) {
- ValueObjectSP p1_sp = table.GetChildMemberWithName("__p1_");
- if (!p1_sp)
- return nullptr;
-
- if (!isOldCompressedPairLayout(*p1_sp))
- return nullptr;
-
- tree_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
- if (!tree_sp)
- return nullptr;
- }
+ auto [tree_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ table, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
+ if (is_compressed_pair)
+ tree_sp = GetFirstValueOfLibCXXCompressedPair(*tree_sp);
+
+ if (!tree_sp)
+ return nullptr;
return tree_sp->GetChildMemberWithName("__next_");
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 4bcdf01c221a..202cebf9bf85 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -84,7 +84,7 @@ llvm::Expected<uint32_t> lldb_private::formatters::
LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
if (!m_start || !m_finish)
return llvm::createStringError(
- "Failed to determine start/end of vector data.");
+ "failed to determine start/end of vector data");
uint64_t start_val = m_start->GetValueAsUnsigned(0);
uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
@@ -94,18 +94,18 @@ llvm::Expected<uint32_t> lldb_private::formatters::
return 0;
if (start_val == 0)
- return llvm::createStringError("Invalid value for start of vector.");
+ return llvm::createStringError("invalid value for start of vector");
if (finish_val == 0)
- return llvm::createStringError("Invalid value for end of vector.");
+ return llvm::createStringError("invalid value for end of vector");
if (start_val > finish_val)
return llvm::createStringError(
- "Start of vector data begins after end pointer.");
+ "start of vector data begins after end pointer");
size_t num_children = (finish_val - start_val);
if (num_children % m_element_size)
- return llvm::createStringError("Size not multiple of element size.");
+ return llvm::createStringError("size not multiple of element size");
return num_children / m_element_size;
}
@@ -126,17 +126,15 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
}
static ValueObjectSP GetDataPointer(ValueObject &root) {
- if (auto cap_sp = root.GetChildMemberWithName("__cap_"))
- return cap_sp;
-
- ValueObjectSP cap_sp = root.GetChildMemberWithName("__end_cap_");
+ auto [cap_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ root, /*anon_struct_idx=*/2, "__cap_", "__end_cap_");
if (!cap_sp)
return nullptr;
- if (!isOldCompressedPairLayout(*cap_sp))
- return nullptr;
+ if (is_compressed_pair)
+ return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
- return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
+ return cap_sp;
}
lldb::ChildCacheState
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
index cfc98d27f56d..99e73ca46fa2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
@@ -70,7 +70,7 @@ llvm::Expected<uint32_t> lldb_private::formatters::
MsvcStlVectorSyntheticFrontEnd::CalculateNumChildren() {
if (!m_start || !m_finish)
return llvm::createStringError(
- "Failed to determine start/end of vector data.");
+ "failed to determine start/end of vector data");
uint64_t start_val = m_start->GetValueAsUnsigned(0);
uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
@@ -80,18 +80,18 @@ llvm::Expected<uint32_t> lldb_private::formatters::
return 0;
if (start_val == 0)
- return llvm::createStringError("Invalid value for start of vector.");
+ return llvm::createStringError("invalid value for start of vector");
if (finish_val == 0)
- return llvm::createStringError("Invalid value for end of vector.");
+ return llvm::createStringError("invalid value for end of vector");
if (start_val > finish_val)
return llvm::createStringError(
- "Start of vector data begins after end pointer.");
+ "start of vector data begins after end pointer");
size_t num_children = (finish_val - start_val);
if (num_children % m_element_size)
- return llvm::createStringError("Size not multiple of element size.");
+ return llvm::createStringError("size not multiple of element size");
return num_children / m_element_size;
}
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index f69358de6a28..931baf5927a0 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -2037,6 +2037,19 @@ static char FindArmAarch64MappingSymbol(const char *symbol_name) {
return '\0';
}
+static char FindRISCVMappingSymbol(const char *symbol_name) {
+ if (!symbol_name)
+ return '\0';
+
+ if (strcmp(symbol_name, "$d") == 0) {
+ return 'd';
+ }
+ if (strcmp(symbol_name, "$x") == 0) {
+ return 'x';
+ }
+ return '\0';
+}
+
#define STO_MIPS_ISA (3 << 6)
#define STO_MICROMIPS (2 << 6)
#define IS_MICROMIPS(ST_OTHER) (((ST_OTHER)&STO_MIPS_ISA) == STO_MICROMIPS)
@@ -2102,6 +2115,12 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
if (!symbol_name)
symbol_name = "";
+ // Skip local symbols starting with ".L" because these are compiler
+ // generated local labels used for internal purposes (e.g. debugging,
+ // optimization) and are not relevant for symbol resolution or external
+ // linkage.
+ if (llvm::StringRef(symbol_name).starts_with(".L"))
+ continue;
// No need to add non-section symbols that have no names
if (symbol.getType() != STT_SECTION &&
(symbol_name == nullptr || symbol_name[0] == '\0'))
@@ -2190,7 +2209,6 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
int64_t symbol_value_offset = 0;
uint32_t additional_flags = 0;
-
if (arch.IsValid()) {
if (arch.GetMachine() == llvm::Triple::arm) {
if (symbol.getBinding() == STB_LOCAL) {
@@ -2235,6 +2253,27 @@ ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id,
if (mapping_symbol)
continue;
}
+ } else if (arch.GetTriple().isRISCV()) {
+ if (symbol.getBinding() == STB_LOCAL) {
+ char mapping_symbol = FindRISCVMappingSymbol(symbol_name);
+ if (symbol_type == eSymbolTypeCode) {
+ // Only handle $d and $x mapping symbols.
+ // Other mapping symbols are ignored as they don't affect address
+ // classification.
+ switch (mapping_symbol) {
+ case 'x':
+ // $x - marks a RISCV instruction sequence
+ address_class_map[symbol.st_value] = AddressClass::eCode;
+ break;
+ case 'd':
+ // $d - marks a RISCV data item sequence
+ address_class_map[symbol.st_value] = AddressClass::eData;
+ break;
+ }
+ }
+ if (mapping_symbol)
+ continue;
+ }
}
if (arch.GetMachine() == llvm::Triple::arm) {
diff --git a/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp b/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
index cb8ba05d461d..69885aa53ca3 100644
--- a/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
+++ b/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.cpp
@@ -12,6 +12,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Target.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "llvm/ADT/DenseSet.h"
@@ -233,6 +234,40 @@ void ObjectFileJSON::CreateSections(SectionList &unified_section_list) {
}
}
+bool ObjectFileJSON::SetLoadAddress(Target &target, lldb::addr_t value,
+ bool value_is_offset) {
+ Log *log(GetLog(LLDBLog::DynamicLoader));
+ if (!m_sections_up)
+ return true;
+
+ addr_t slide = value;
+ if (!value_is_offset) {
+ addr_t lowest_addr = LLDB_INVALID_ADDRESS;
+ for (const SectionSP &section_sp : *m_sections_up) {
+ addr_t section_load_addr = section_sp->GetFileAddress();
+ lowest_addr = std::min(lowest_addr, section_load_addr);
+ }
+ if (lowest_addr == LLDB_INVALID_ADDRESS)
+ return false;
+ slide = value - lowest_addr;
+ }
+
+ // Apply slide to each section's file address.
+ for (const SectionSP &section_sp : *m_sections_up) {
+ addr_t section_load_addr = section_sp->GetFileAddress();
+ if (section_load_addr != LLDB_INVALID_ADDRESS) {
+ LLDB_LOGF(
+ log,
+ "ObjectFileJSON::SetLoadAddress section %s to load addr 0x%" PRIx64,
+ section_sp->GetName().AsCString(), section_load_addr + slide);
+ target.SetSectionLoadAddress(section_sp, section_load_addr + slide,
+ /*warn_multiple=*/true);
+ }
+ }
+
+ return true;
+}
+
bool ObjectFileJSON::MagicBytesMatch(DataBufferSP data_sp,
lldb::addr_t data_offset,
lldb::addr_t data_length) {
diff --git a/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h b/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h
index b72565f46886..029c8ff18893 100644
--- a/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h
+++ b/lldb/source/Plugins/ObjectFile/JSON/ObjectFileJSON.h
@@ -86,6 +86,9 @@ public:
Strata CalculateStrata() override { return eStrataUser; }
+ bool SetLoadAddress(Target &target, lldb::addr_t value,
+ bool value_is_offset) override;
+
static bool MagicBytesMatch(lldb::DataBufferSP data_sp, lldb::addr_t offset,
lldb::addr_t length);
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index d7cb60e3f0c3..924e34053d41 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -2785,7 +2785,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
const char *symbol_name_non_abi_mangled = NULL;
SectionSP symbol_section;
- uint32_t symbol_byte_size = 0;
bool add_nlist = true;
bool is_debug = ((nlist.n_type & N_STAB) != 0);
bool demangled_is_synthesized = false;
@@ -3437,61 +3436,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
if (symbol_section) {
const addr_t section_file_addr =
symbol_section->GetFileAddress();
- if (symbol_byte_size == 0 &&
- function_starts_count > 0) {
- addr_t symbol_lookup_file_addr = nlist.n_value;
- // Do an exact address match for non-ARM addresses,
- // else get the closest since the symbol might be a
- // thumb symbol which has an address with bit zero
- // set
- FunctionStarts::Entry *func_start_entry =
- function_starts.FindEntry(symbol_lookup_file_addr,
- !is_arm);
- if (is_arm && func_start_entry) {
- // Verify that the function start address is the
- // symbol address (ARM) or the symbol address + 1
- // (thumb)
- if (func_start_entry->addr !=
- symbol_lookup_file_addr &&
- func_start_entry->addr !=
- (symbol_lookup_file_addr + 1)) {
- // Not the right entry, NULL it out...
- func_start_entry = NULL;
- }
- }
- if (func_start_entry) {
- func_start_entry->data = true;
-
- addr_t symbol_file_addr = func_start_entry->addr;
- uint32_t symbol_flags = 0;
- if (is_arm) {
- if (symbol_file_addr & 1)
- symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- }
-
- const FunctionStarts::Entry *next_func_start_entry =
- function_starts.FindNextEntry(func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr +
- symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr =
- next_func_start_entry->addr;
- // Be sure the clear the Thumb address bit when
- // we calculate the size from the current and
- // next address
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size =
- section_end_file_addr - symbol_file_addr;
- }
- }
- }
symbol_value -= section_file_addr;
}
@@ -3620,9 +3564,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
}
sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc);
- if (symbol_byte_size > 0)
- sym[sym_idx].SetByteSize(symbol_byte_size);
-
if (demangled_is_synthesized)
sym[sym_idx].SetDemangledNameIsSynthesized(true);
++sym_idx;
@@ -3711,7 +3652,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
SymbolType type = eSymbolTypeInvalid;
SectionSP symbol_section;
- lldb::addr_t symbol_byte_size = 0;
bool add_nlist = true;
bool is_gsym = false;
bool demangled_is_synthesized = false;
@@ -4297,47 +4237,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
if (symbol_section) {
const addr_t section_file_addr = symbol_section->GetFileAddress();
- if (symbol_byte_size == 0 && function_starts_count > 0) {
- addr_t symbol_lookup_file_addr = nlist.n_value;
- // Do an exact address match for non-ARM addresses, else get the
- // closest since the symbol might be a thumb symbol which has an
- // address with bit zero set.
- FunctionStarts::Entry *func_start_entry =
- function_starts.FindEntry(symbol_lookup_file_addr, !is_arm);
- if (is_arm && func_start_entry) {
- // Verify that the function start address is the symbol address
- // (ARM) or the symbol address + 1 (thumb).
- if (func_start_entry->addr != symbol_lookup_file_addr &&
- func_start_entry->addr != (symbol_lookup_file_addr + 1)) {
- // Not the right entry, NULL it out...
- func_start_entry = nullptr;
- }
- }
- if (func_start_entry) {
- func_start_entry->data = true;
-
- addr_t symbol_file_addr = func_start_entry->addr;
- if (is_arm)
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
-
- const FunctionStarts::Entry *next_func_start_entry =
- function_starts.FindNextEntry(func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- // Be sure the clear the Thumb address bit when we calculate the
- // size from the current and next address
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
- }
- }
symbol_value -= section_file_addr;
}
@@ -4444,9 +4343,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
if (nlist.n_desc & N_WEAK_REF)
sym[sym_idx].SetIsWeak(true);
- if (symbol_byte_size > 0)
- sym[sym_idx].SetByteSize(symbol_byte_size);
-
if (demangled_is_synthesized)
sym[sym_idx].SetDemangledNameIsSynthesized(true);
@@ -4565,23 +4461,7 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
Address symbol_addr;
if (module_sp->ResolveFileAddress(symbol_file_addr, symbol_addr)) {
SectionSP symbol_section(symbol_addr.GetSection());
- uint32_t symbol_byte_size = 0;
if (symbol_section) {
- const addr_t section_file_addr = symbol_section->GetFileAddress();
- const FunctionStarts::Entry *next_func_start_entry =
- function_starts.FindNextEntry(func_start_entry);
- const addr_t section_end_file_addr =
- section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry) {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(
- next_symbol_file_addr - symbol_file_addr,
- section_end_file_addr - symbol_file_addr);
- } else {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
sym[sym_idx].SetID(synthetic_sym_id++);
// Don't set the name for any synthetic symbols, the Symbol
// object will generate one if needed when the name is accessed
@@ -4593,8 +4473,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
add_symbol_addr(symbol_addr.GetFileAddress());
if (symbol_flags)
sym[sym_idx].SetFlags(symbol_flags);
- if (symbol_byte_size)
- sym[sym_idx].SetByteSize(symbol_byte_size);
++sym_idx;
}
}
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index 777b20e9bb0f..492b44186720 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -71,6 +71,47 @@ GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
return std::string(toStringRef(llvm::ArrayRef(str_storage)));
}
+/// An "init expr" refers to a constant expression used to determine the initial
+/// value of certain elements within a module during instantiation. These
+/// expressions are restricted to operations that can be evaluated at module
+/// instantiation time. Currently we only support simple constant opcodes.
+static lldb::offset_t GetWasmOffsetFromInitExpr(DataExtractor &data,
+ lldb::offset_t &offset) {
+ lldb::offset_t init_expr_offset = LLDB_INVALID_OFFSET;
+
+ uint8_t opcode = data.GetU8(&offset);
+ switch (opcode) {
+ case llvm::wasm::WASM_OPCODE_I32_CONST:
+ case llvm::wasm::WASM_OPCODE_I64_CONST:
+ init_expr_offset = data.GetSLEB128(&offset);
+ break;
+ case llvm::wasm::WASM_OPCODE_GLOBAL_GET:
+ init_expr_offset = data.GetULEB128(&offset);
+ break;
+ case llvm::wasm::WASM_OPCODE_F32_CONST:
+ case llvm::wasm::WASM_OPCODE_F64_CONST:
+ // Not a meaningful offset.
+ data.GetFloat(&offset);
+ break;
+ case llvm::wasm::WASM_OPCODE_REF_NULL:
+ // Not a meaningful offset.
+ data.GetULEB128(&offset);
+ break;
+ }
+
+ // Make sure the opcodes we read aren't part of an extended init expr.
+ opcode = data.GetU8(&offset);
+ if (opcode == llvm::wasm::WASM_OPCODE_END)
+ return init_expr_offset;
+
+ // Extended init expressions are not supported, but we still have to parse
+ // them to skip over them and read the next segment.
+ do {
+ opcode = data.GetU8(&offset);
+ } while (opcode != llvm::wasm::WASM_OPCODE_END);
+ return LLDB_INVALID_OFFSET;
+}
+
/// Checks whether the data buffer starts with a valid Wasm module header.
static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize)
@@ -261,17 +302,20 @@ bool ObjectFileWasm::ParseHeader() {
return true;
}
-static llvm::Expected<std::vector<AddressRange>>
-ParseFunctions(SectionSP code_section_sp) {
- DataExtractor data;
- code_section_sp->GetSectionData(data);
+struct WasmFunction {
+ lldb::offset_t section_offset = LLDB_INVALID_OFFSET;
+ uint32_t size = 0;
+};
+
+static llvm::Expected<std::vector<WasmFunction>>
+ParseFunctions(DataExtractor &data) {
lldb::offset_t offset = 0;
llvm::Expected<uint32_t> function_count = GetULEB32(data, offset);
if (!function_count)
return function_count.takeError();
- std::vector<AddressRange> functions;
+ std::vector<WasmFunction> functions;
functions.reserve(*function_count);
for (uint32_t i = 0; i < *function_count; ++i) {
@@ -281,7 +325,7 @@ ParseFunctions(SectionSP code_section_sp) {
// llvm-objdump considers the ULEB with the function size to be part of the
// function. We can't do that here because that would break symbolic
// breakpoints, as that address is never executed.
- functions.emplace_back(code_section_sp, offset, *function_size);
+ functions.push_back({offset, *function_size});
std::optional<lldb::offset_t> next_offset =
llvm::checkedAddUnsigned<lldb::offset_t>(offset, *function_size);
@@ -294,17 +338,22 @@ ParseFunctions(SectionSP code_section_sp) {
}
struct WasmSegment {
- WasmSegment(SectionSP section_sp, lldb::offset_t offset, uint32_t size)
- : address_range(section_sp, offset, size) {};
+ enum SegmentType {
+ Active,
+ Passive,
+ };
+
std::string name;
- AddressRange address_range;
-};
+ SegmentType type = Passive;
+ lldb::offset_t section_offset = LLDB_INVALID_OFFSET;
+ uint32_t size = 0;
+ uint32_t memory_index = 0;
+ lldb::offset_t init_expr_offset = 0;
-static llvm::Expected<std::vector<WasmSegment>>
-ParseData(SectionSP data_section_sp) {
- DataExtractor data;
- data_section_sp->GetSectionData(data);
+ lldb::offset_t GetFileOffset() const { return section_offset & 0xffffffff; }
+};
+static llvm::Expected<std::vector<WasmSegment>> ParseData(DataExtractor &data) {
lldb::offset_t offset = 0;
llvm::Expected<uint32_t> segment_count = GetULEB32(data, offset);
@@ -319,27 +368,34 @@ ParseData(SectionSP data_section_sp) {
if (!flags)
return flags.takeError();
+ WasmSegment segment;
+
// Data segments have a mode that identifies them as either passive or
// active. An active data segment copies its contents into a memory during
// instantiation, as specified by a memory index and a constant expression
// defining an offset into that memory.
+ segment.type = (*flags & llvm::wasm::WASM_DATA_SEGMENT_IS_PASSIVE)
+ ? WasmSegment::Passive
+ : WasmSegment::Active;
+
if (*flags & llvm::wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX) {
+ assert(segment.type == WasmSegment::Active);
llvm::Expected<uint32_t> memidx = GetULEB32(data, offset);
if (!memidx)
return memidx.takeError();
+ segment.memory_index = *memidx;
}
- if ((*flags & llvm::wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
- // Skip over the constant expression.
- for (uint8_t b = 0; b != llvm::wasm::WASM_OPCODE_END;)
- b = data.GetU8(&offset);
- }
+ if (segment.type == WasmSegment::Active)
+ segment.init_expr_offset = GetWasmOffsetFromInitExpr(data, offset);
llvm::Expected<uint32_t> segment_size = GetULEB32(data, offset);
if (!segment_size)
return segment_size.takeError();
- segments.emplace_back(data_section_sp, offset, *segment_size);
+ segment.section_offset = offset;
+ segment.size = *segment_size;
+ segments.push_back(segment);
std::optional<lldb::offset_t> next_offset =
llvm::checkedAddUnsigned<lldb::offset_t>(offset, *segment_size);
@@ -352,13 +408,11 @@ ParseData(SectionSP data_section_sp) {
}
static llvm::Expected<std::vector<Symbol>>
-ParseNames(SectionSP name_section_sp,
- const std::vector<AddressRange> &function_ranges,
+ParseNames(SectionSP code_section_sp, DataExtractor &name_data,
+ const std::vector<WasmFunction> &functions,
std::vector<WasmSegment> &segments) {
- DataExtractor name_section_data;
- name_section_sp->GetSectionData(name_section_data);
- llvm::DataExtractor data = name_section_data.GetAsLLVM();
+ llvm::DataExtractor data = name_data.GetAsLLVM();
llvm::DataExtractor::Cursor c(0);
std::vector<Symbol> symbols;
while (c && c.tell() < data.size()) {
@@ -380,12 +434,13 @@ ParseNames(SectionSP name_section_sp,
llvm::Expected<std::string> name = GetWasmString(data, c);
if (!name)
return name.takeError();
- if (*idx >= function_ranges.size())
+ if (*idx >= functions.size())
continue;
symbols.emplace_back(
- symbols.size(), Mangled(*name), lldb::eSymbolTypeCode,
+ symbols.size(), *name, lldb::eSymbolTypeCode,
/*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false,
- /*is_artificial=*/false, function_ranges[*idx],
+ /*is_artificial=*/false, code_section_sp,
+ functions[i].section_offset, functions[i].size,
/*size_is_valid=*/true, /*contains_linker_annotations=*/false,
/*flags=*/0);
}
@@ -405,12 +460,6 @@ ParseNames(SectionSP name_section_sp,
continue;
// Update the segment name.
segments[i].name = *name;
- symbols.emplace_back(
- symbols.size(), Mangled(*name), lldb::eSymbolTypeData,
- /*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false,
- /*is_artificial=*/false, segments[i].address_range,
- /*size_is_valid=*/true, /*contains_linker_annotations=*/false,
- /*flags=*/0);
}
} break;
@@ -432,80 +481,11 @@ ParseNames(SectionSP name_section_sp,
}
void ObjectFileWasm::ParseSymtab(Symtab &symtab) {
- assert(m_sections_up && "sections must be parsed");
- Log *log = GetLog(LLDBLog::Object);
-
- // The name section contains names and indexes. First parse the data from the
- // relevant sections so we can access it by its index.
- std::vector<AddressRange> functions;
- std::vector<WasmSegment> segments;
-
- // Parse the code section.
- if (SectionSP code_section_sp =
- m_sections_up->FindSectionByType(lldb::eSectionTypeCode, false)) {
- llvm::Expected<std::vector<AddressRange>> maybe_functions =
- ParseFunctions(code_section_sp);
- if (!maybe_functions) {
- LLDB_LOG_ERROR(log, maybe_functions.takeError(),
- "Failed to parse Wasm code section: {0}");
- return;
- }
- functions = *maybe_functions;
- }
-
- // Parse the data section.
- SectionSP data_section_sp =
- m_sections_up->FindSectionByType(lldb::eSectionTypeData, false);
- if (data_section_sp) {
- llvm::Expected<std::vector<WasmSegment>> maybe_segments =
- ParseData(data_section_sp);
- if (!maybe_segments) {
- LLDB_LOG_ERROR(log, maybe_segments.takeError(),
- "Failed to parse Wasm data section: {0}");
- return;
- }
- segments = *maybe_segments;
- }
-
- // Parse the name section.
- SectionSP name_section_sp =
- m_sections_up->FindSectionByType(lldb::eSectionTypeWasmName, false);
- if (!name_section_sp) {
- LLDB_LOG(log, "Failed to parse Wasm symbol table: no names section");
- return;
- }
-
- llvm::Expected<std::vector<Symbol>> symbols =
- ParseNames(name_section_sp, functions, segments);
- if (!symbols) {
- LLDB_LOG_ERROR(log, symbols.takeError(), "Failed to parse Wasm names: {0}");
- return;
- }
-
- for (const Symbol &symbol : *symbols)
+ for (const Symbol &symbol : m_symbols)
symtab.AddSymbol(symbol);
- lldb::user_id_t segment_id = 0;
- for (const WasmSegment &segment : segments) {
- const lldb::addr_t segment_addr =
- segment.address_range.GetBaseAddress().GetFileAddress();
- const size_t segment_size = segment.address_range.GetByteSize();
- SectionSP segment_sp = std::make_shared<Section>(
- /*parent_section_sp=*/data_section_sp, GetModule(),
- /*obj_file=*/this,
- ++segment_id << 8, // 1-based segment index, shifted by 8 bits to avoid
- // collision with section IDs.
- ConstString(segment.name), eSectionTypeData,
- /*file_vm_addr=*/segment_addr,
- /*vm_size=*/segment_size,
- /*file_offset=*/segment_addr,
- /*file_size=*/segment_size,
- /*log2align=*/0, /*flags=*/0);
- m_sections_up->AddSection(segment_sp);
- GetModule()->GetSectionList()->AddSection(segment_sp);
- }
-
symtab.Finalize();
+ m_symbols.clear();
}
static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
@@ -516,7 +496,27 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
return eSectionTypeOther;
}
+std::optional<ObjectFileWasm::section_info>
+ObjectFileWasm::GetSectionInfo(uint32_t section_id) {
+ for (const section_info &sect_info : m_sect_infos) {
+ if (sect_info.id == section_id)
+ return sect_info;
+ }
+ return std::nullopt;
+}
+
+std::optional<ObjectFileWasm::section_info>
+ObjectFileWasm::GetSectionInfo(llvm::StringRef section_name) {
+ for (const section_info &sect_info : m_sect_infos) {
+ if (sect_info.name == section_name)
+ return sect_info;
+ }
+ return std::nullopt;
+}
+
void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
+ Log *log = GetLog(LLDBLog::Object);
+
if (m_sections_up)
return;
@@ -530,7 +530,7 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
SectionType section_type = eSectionTypeOther;
ConstString section_name;
offset_t file_offset = sect_info.offset & 0xffffffff;
- addr_t vm_addr = file_offset;
+ addr_t vm_addr = sect_info.offset;
size_t vm_size = sect_info.size;
if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
@@ -542,9 +542,6 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
// For this reason Section::GetFileAddress() must return zero for the
// Code section.
vm_addr = 0;
- } else if (llvm::wasm::WASM_SEC_DATA == sect_info.id) {
- section_type = eSectionTypeData;
- section_name = ConstString("data");
} else {
section_type = GetSectionTypeFromName(sect_info.name.GetStringRef());
if (section_type == eSectionTypeOther)
@@ -556,23 +553,107 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
}
}
- SectionSP section_sp(
- new Section(GetModule(), // Module to which this section belongs.
- this, // ObjectFile to which this section belongs and
- // should read section data from.
- section_type, // Section ID.
- section_name, // Section name.
- section_type, // Section type.
- vm_addr, // VM address.
- vm_size, // VM size in bytes of this section.
- file_offset, // Offset of this section in the file.
- sect_info.size, // Size of the section as found in the file.
- 0, // Alignment of the section
- 0, // Flags for this section.
- 1)); // Number of host bytes per target byte
+ SectionSP section_sp = std::make_shared<Section>(
+ GetModule(), // Module to which this section belongs.
+ this, // ObjectFile to which this section belongs and
+ // should read section data from.
+ section_type, // Section ID.
+ section_name, // Section name.
+ section_type, // Section type.
+ vm_addr, // VM address.
+ vm_size, // VM size in bytes of this section.
+ file_offset, // Offset of this section in the file.
+ sect_info.size, // Size of the section as found in the file.
+ 0, // Alignment of the section
+ 0, // Flags for this section.
+ 1); // Number of host bytes per target byte
m_sections_up->AddSection(section_sp);
unified_section_list.AddSection(section_sp);
}
+
+ // The name section contains names and indexes. First parse the data from the
+ // relevant sections so we can access it by its index.
+ std::vector<WasmFunction> functions;
+ std::vector<WasmSegment> segments;
+
+ // Parse the code section.
+ if (std::optional<section_info> info =
+ GetSectionInfo(llvm::wasm::WASM_SEC_CODE)) {
+ DataExtractor code_data = ReadImageData(info->offset, info->size);
+ llvm::Expected<std::vector<WasmFunction>> maybe_functions =
+ ParseFunctions(code_data);
+ if (!maybe_functions) {
+ LLDB_LOG_ERROR(log, maybe_functions.takeError(),
+ "Failed to parse Wasm code section: {0}");
+ } else {
+ functions = *maybe_functions;
+ }
+ }
+
+ // Parse the data section.
+ std::optional<section_info> data_info =
+ GetSectionInfo(llvm::wasm::WASM_SEC_DATA);
+ if (data_info) {
+ DataExtractor data_data = ReadImageData(data_info->offset, data_info->size);
+ llvm::Expected<std::vector<WasmSegment>> maybe_segments =
+ ParseData(data_data);
+ if (!maybe_segments) {
+ LLDB_LOG_ERROR(log, maybe_segments.takeError(),
+ "Failed to parse Wasm data section: {0}");
+ } else {
+ segments = *maybe_segments;
+ }
+ }
+
+ if (std::optional<section_info> info = GetSectionInfo("name")) {
+ DataExtractor names_data = ReadImageData(info->offset, info->size);
+ llvm::Expected<std::vector<Symbol>> symbols = ParseNames(
+ m_sections_up->FindSectionByType(lldb::eSectionTypeCode, false),
+ names_data, functions, segments);
+ if (!symbols) {
+ LLDB_LOG_ERROR(log, symbols.takeError(),
+ "Failed to parse Wasm names: {0}");
+ } else {
+ m_symbols = *symbols;
+ }
+ }
+
+ lldb::user_id_t segment_id = 0;
+ for (const WasmSegment &segment : segments) {
+ if (segment.type == WasmSegment::Active) {
+ // FIXME: Support segments with a memory index.
+ if (segment.memory_index != 0) {
+ LLDB_LOG(log, "Skipping segment {0}: non-zero memory index is "
+ "currently unsupported");
+ continue;
+ }
+
+ if (segment.init_expr_offset == LLDB_INVALID_OFFSET) {
+ LLDB_LOG(log, "Skipping segment {0}: unsupported init expression");
+ continue;
+ }
+ }
+
+ const lldb::addr_t file_vm_addr =
+ segment.type == WasmSegment::Active
+ ? segment.init_expr_offset
+ : data_info->offset + segment.section_offset;
+ const lldb::offset_t file_offset =
+ data_info->GetFileOffset() + segment.GetFileOffset();
+ SectionSP segment_sp = std::make_shared<Section>(
+ GetModule(),
+ /*obj_file=*/this,
+ ++segment_id << 8, // 1-based segment index, shifted by 8 bits to avoid
+ // collision with section IDs.
+ ConstString(segment.name), eSectionTypeData,
+ /*file_vm_addr=*/file_vm_addr,
+ /*vm_size=*/segment.size,
+ /*file_offset=*/file_offset,
+ /*file_size=*/segment.size,
+ /*log2align=*/0, /*flags=*/0);
+ m_sections_up->AddSection(segment_sp);
+ GetModule()->GetSectionList()->AddSection(segment_sp);
+ }
}
bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
@@ -697,7 +778,7 @@ void ObjectFileWasm::Dump(Stream *s) {
}
void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
- const section_info_t &sh) {
+ const section_info &sh) {
ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
<< llvm::format_hex(sh.offset, 10) << " "
<< llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
index 531b5f0437a4..86ecbf26803c 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
@@ -128,20 +128,25 @@ private:
/// Read a range of bytes from the Wasm module.
DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size);
- typedef struct section_info {
+ struct section_info {
lldb::offset_t offset;
uint32_t size;
uint32_t id;
ConstString name;
- } section_info_t;
+ lldb::offset_t GetFileOffset() const { return offset & 0xffffffff; }
+ };
+
+ std::optional<section_info> GetSectionInfo(uint32_t section_id);
+ std::optional<section_info> GetSectionInfo(llvm::StringRef section_name);
/// Wasm section header dump routines.
/// \{
- void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info_t &sh);
+ void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info &sh);
void DumpSectionHeaders(llvm::raw_ostream &ostream);
/// \}
- std::vector<section_info_t> m_sect_infos;
+ std::vector<section_info> m_sect_infos;
+ std::vector<Symbol> m_symbols;
ArchSpec m_arch;
UUID m_uuid;
};
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
index fdafacf410d6..c1bc6a3f036b 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -76,7 +76,7 @@ NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
::memset(&m_fpr, 0, sizeof(m_fpr));
::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
- ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
+ ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
// 16 is just a maximum value, query hardware for actual watchpoint count
m_max_hwp_supported = 16;
@@ -283,522 +283,43 @@ bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const {
return false;
}
-uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- Status error;
-
- // Read hardware breakpoint and watchpoint information.
- error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return 0;
-
- LLDB_LOG(log, "{0}", m_max_hbp_supported);
- return m_max_hbp_supported;
-}
-
-uint32_t
-NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
- size_t size) {
- Log *log = GetLog(POSIXLog::Breakpoints);
- LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return LLDB_INVALID_INDEX32;
-
- uint32_t control_value = 0, bp_index = 0;
-
- // Setup address and control values.
- // Use size to get a hint of arm vs thumb modes.
- switch (size) {
- case 2:
- control_value = (0x3 << 5) | 7;
- addr &= ~1;
- break;
- case 4:
- control_value = (0xfu << 5) | 7;
- addr &= ~3;
- break;
- default:
- return LLDB_INVALID_INDEX32;
- }
-
- // Iterate over stored breakpoints and find a free bp_index
- bp_index = LLDB_INVALID_INDEX32;
- for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
- if ((m_hbr_regs[i].control & 1) == 0) {
- bp_index = i; // Mark last free slot
- } else if (m_hbr_regs[i].address == addr) {
- return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
- }
- }
-
- if (bp_index == LLDB_INVALID_INDEX32)
- return LLDB_INVALID_INDEX32;
-
- // Update breakpoint in local cache
- m_hbr_regs[bp_index].real_addr = addr;
- m_hbr_regs[bp_index].address = addr;
- m_hbr_regs[bp_index].control = control_value;
-
- // PTRACE call to set corresponding hardware breakpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
- bp_index);
-
- if (error.Fail()) {
- m_hbr_regs[bp_index].address = 0;
- m_hbr_regs[bp_index].control &= ~1;
-
- return LLDB_INVALID_INDEX32;
- }
-
- return bp_index;
-}
-
-bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
- Log *log = GetLog(POSIXLog::Breakpoints);
- LLDB_LOG(log, "hw_idx: {0}", hw_idx);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return false;
-
- if (hw_idx >= m_max_hbp_supported)
- return false;
-
- // Create a backup we can revert to in case of failure.
- lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address;
- uint32_t tempControl = m_hbr_regs[hw_idx].control;
-
- m_hbr_regs[hw_idx].control &= ~1;
- m_hbr_regs[hw_idx].address = 0;
-
- // PTRACE call to clear corresponding hardware breakpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
- hw_idx);
-
- if (error.Fail()) {
- m_hbr_regs[hw_idx].control = tempControl;
- m_hbr_regs[hw_idx].address = tempAddr;
-
- return false;
- }
-
- return true;
-}
-
-Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
- uint32_t &bp_index, lldb::addr_t trap_addr) {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- lldb::addr_t break_addr;
-
- for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
- break_addr = m_hbr_regs[bp_index].address;
-
- if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
- m_hbr_regs[bp_index].hit_addr = trap_addr;
- return Status();
- }
- }
-
- bp_index = LLDB_INVALID_INDEX32;
- return Status();
-}
-
-Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
- Log *log = GetLog(POSIXLog::Breakpoints);
-
- LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
- Status error;
-
- // Read hardware breakpoint and watchpoint information.
- error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return error;
-
- lldb::addr_t tempAddr = 0;
- uint32_t tempControl = 0;
-
- for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
- if (m_hbr_regs[i].control & 0x01) {
- // Create a backup we can revert to in case of failure.
- tempAddr = m_hbr_regs[i].address;
- tempControl = m_hbr_regs[i].control;
-
- // Clear breakpoints in local cache
- m_hbr_regs[i].control &= ~1;
- m_hbr_regs[i].address = 0;
-
- // Ptrace call to update hardware debug registers
- error =
- WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, i);
-
- if (error.Fail()) {
- m_hbr_regs[i].control = tempControl;
- m_hbr_regs[i].address = tempAddr;
-
- return error;
- }
- }
- }
-
- return Status();
-}
-
-uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
- Log *log = GetLog(POSIXLog::Watchpoints);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return 0;
-
- LLDB_LOG(log, "{0}", m_max_hwp_supported);
- return m_max_hwp_supported;
-}
-
-uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
- lldb::addr_t addr, size_t size, uint32_t watch_flags) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
- watch_flags);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return LLDB_INVALID_INDEX32;
-
- uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 0;
- lldb::addr_t real_addr = addr;
-
- // Check if we are setting watchpoint other than read/write/access Also
- // update watchpoint flag to match Arm write-read bit configuration.
- switch (watch_flags) {
- case 1:
- watch_flags = 2;
- break;
- case 2:
- watch_flags = 1;
- break;
- case 3:
- break;
- default:
- return LLDB_INVALID_INDEX32;
- }
-
- // Can't watch zero bytes
- // Can't watch more than 4 bytes per WVR/WCR pair
-
- if (size == 0 || size > 4)
- return LLDB_INVALID_INDEX32;
-
- // Check 4-byte alignment for hardware watchpoint target address. Below is a
- // hack to recalculate address and size in order to make sure we can watch
- // non 4-byte aligned addresses as well.
- if (addr & 0x03) {
- uint8_t watch_mask = (addr & 0x03) + size;
-
- if (watch_mask > 0x04)
- return LLDB_INVALID_INDEX32;
- else if (watch_mask <= 0x02)
- size = 2;
- else
- size = 4;
-
- addr = addr & (~0x03);
- }
-
- // We can only watch up to four bytes that follow a 4 byte aligned address
- // per watchpoint register pair, so make sure we can properly encode this.
- addr_word_offset = addr % 4;
- byte_mask = ((1u << size) - 1u) << addr_word_offset;
-
- // Check if we need multiple watchpoint register
- if (byte_mask > 0xfu)
- return LLDB_INVALID_INDEX32;
-
- // Setup control value
- // Make the byte_mask into a valid Byte Address Select mask
- control_value = byte_mask << 5;
-
- // Turn on appropriate watchpoint flags read or write
- control_value |= (watch_flags << 3);
-
- // Enable this watchpoint and make it stop in privileged or user mode;
- control_value |= 7;
-
- // Make sure bits 1:0 are clear in our address
- addr &= ~((lldb::addr_t)3);
-
- // Iterate over stored watchpoints and find a free wp_index
- wp_index = LLDB_INVALID_INDEX32;
- for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
- if ((m_hwp_regs[i].control & 1) == 0) {
- wp_index = i; // Mark last free slot
- } else if (m_hwp_regs[i].address == addr) {
- return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
- }
- }
-
- if (wp_index == LLDB_INVALID_INDEX32)
- return LLDB_INVALID_INDEX32;
-
- // Update watchpoint in local cache
- m_hwp_regs[wp_index].real_addr = real_addr;
- m_hwp_regs[wp_index].address = addr;
- m_hwp_regs[wp_index].control = control_value;
-
- // PTRACE call to set corresponding watchpoint register.
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
- wp_index);
-
- if (error.Fail()) {
- m_hwp_regs[wp_index].address = 0;
- m_hwp_regs[wp_index].control &= ~1;
-
- return LLDB_INVALID_INDEX32;
- }
-
- return wp_index;
-}
-
-bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
- uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return false;
-
- if (wp_index >= m_max_hwp_supported)
- return false;
-
- // Create a backup we can revert to in case of failure.
- lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
- uint32_t tempControl = m_hwp_regs[wp_index].control;
-
- // Update watchpoint in local cache
- m_hwp_regs[wp_index].control &= ~1;
- m_hwp_regs[wp_index].address = 0;
-
- // Ptrace call to update hardware debug registers
- error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
- wp_index);
-
- if (error.Fail()) {
- m_hwp_regs[wp_index].control = tempControl;
- m_hwp_regs[wp_index].address = tempAddr;
-
- return false;
- }
-
- return true;
-}
-
-Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
- // Read hardware breakpoint and watchpoint information.
- Status error = ReadHardwareDebugInfo();
-
- if (error.Fail())
- return error;
-
- lldb::addr_t tempAddr = 0;
- uint32_t tempControl = 0;
-
- for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
- if (m_hwp_regs[i].control & 0x01) {
- // Create a backup we can revert to in case of failure.
- tempAddr = m_hwp_regs[i].address;
- tempControl = m_hwp_regs[i].control;
-
- // Clear watchpoints in local cache
- m_hwp_regs[i].control &= ~1;
- m_hwp_regs[i].address = 0;
-
- // Ptrace call to update hardware debug registers
- error =
- WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, i);
-
- if (error.Fail()) {
- m_hwp_regs[i].control = tempControl;
- m_hwp_regs[i].address = tempAddr;
-
- return error;
- }
- }
- }
-
- return Status();
-}
-
-uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
- case 0x01:
- return 1;
- case 0x03:
- return 2;
- case 0x07:
- return 3;
- case 0x0f:
- return 4;
- default:
- return 0;
- }
-}
-bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
- return true;
- else
- return false;
-}
-
-Status
-NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
-
- uint32_t watch_size;
- lldb::addr_t watch_addr;
-
- for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
- watch_size = GetWatchpointSize(wp_index);
- watch_addr = m_hwp_regs[wp_index].address;
-
- if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
- trap_addr < watch_addr + watch_size) {
- m_hwp_regs[wp_index].hit_addr = trap_addr;
- return Status();
- }
- }
-
- wp_index = LLDB_INVALID_INDEX32;
- return Status();
-}
-
-lldb::addr_t
-NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if (wp_index >= m_max_hwp_supported)
- return LLDB_INVALID_ADDRESS;
-
- if (WatchpointIsEnabled(wp_index))
- return m_hwp_regs[wp_index].real_addr;
- else
- return LLDB_INVALID_ADDRESS;
-}
-
-lldb::addr_t
-NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
- Log *log = GetLog(POSIXLog::Watchpoints);
- LLDB_LOG(log, "wp_index: {0}", wp_index);
-
- if (wp_index >= m_max_hwp_supported)
- return LLDB_INVALID_ADDRESS;
-
- if (WatchpointIsEnabled(wp_index))
- return m_hwp_regs[wp_index].hit_addr;
- else
- return LLDB_INVALID_ADDRESS;
-}
-
-Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
- Status error;
-
- if (!m_refresh_hwdebug_info) {
- return Status();
- }
+llvm::Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
+ if (!m_refresh_hwdebug_info)
+ return llvm::Error::success();
#ifdef __arm__
unsigned int cap_val;
-
- error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(),
- nullptr, &cap_val,
- sizeof(unsigned int));
+ Status error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val,
+ sizeof(unsigned int));
if (error.Fail())
- return error;
+ return error.ToError();
m_max_hwp_supported = (cap_val >> 8) & 0xff;
m_max_hbp_supported = cap_val & 0xff;
m_refresh_hwdebug_info = false;
- return error;
+ return error.ToError();
#else // __aarch64__
return arm64::ReadHardwareDebugInfo(m_thread.GetID(), m_max_hwp_supported,
- m_max_hbp_supported);
+ m_max_hbp_supported)
+ .ToError();
#endif // ifdef __arm__
}
-Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
- NativeRegisterContextDBReg::DREGType hwbType, int hwb_index) {
- Status error;
-
+llvm::Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType) {
#ifdef __arm__
- lldb::addr_t *addr_buf;
- uint32_t *ctrl_buf;
-
- if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) {
- addr_buf = &m_hwp_regs[hwb_index].address;
- ctrl_buf = &m_hwp_regs[hwb_index].control;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
- sizeof(unsigned int));
-
- if (error.Fail())
- return error;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
- sizeof(unsigned int));
- } else {
- addr_buf = &m_hbr_regs[hwb_index].address;
- ctrl_buf = &m_hbr_regs[hwb_index].control;
-
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
- sizeof(unsigned int));
+ uint32_t max_index = m_max_hbp_supported;
+ if (hwbType == eDREGTypeWATCH)
+ max_index = m_max_hwp_supported;
- if (error.Fail())
+ for (uint32_t idx = 0; idx < max_index; ++idx)
+ if (auto error = WriteHardwareDebugReg(hwbType, idx))
return error;
- error = NativeProcessLinux::PtraceWrapper(
- PTRACE_SETHBPREGS, m_thread.GetID(),
- (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
- sizeof(unsigned int));
- }
-
- return error;
+ return llvm::Error::success();
#else // __aarch64__
uint32_t max_supported =
(hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
@@ -806,12 +327,48 @@ Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
: m_max_hbp_supported;
auto &regs = (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
? m_hwp_regs
- : m_hbr_regs;
+ : m_hbp_regs;
return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported,
- regs);
+ regs)
+ .ToError();
#endif // ifdef __arm__
}
+#ifdef __arm__
+llvm::Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugReg(DREGType hwbType,
+ int hwb_index) {
+ Status error;
+ lldb::addr_t *addr_buf;
+ uint32_t *ctrl_buf;
+ int addr_idx = (hwb_index << 1) + 1;
+ int ctrl_idx = addr_idx + 1;
+
+ if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) {
+ addr_idx *= -1;
+ addr_buf = &m_hwp_regs[hwb_index].address;
+ ctrl_idx *= -1;
+ ctrl_buf = &m_hwp_regs[hwb_index].control;
+ } else {
+ addr_buf = &m_hbp_regs[hwb_index].address;
+ ctrl_buf = &m_hbp_regs[hwb_index].control;
+ }
+
+ error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)addr_idx,
+ addr_buf, sizeof(unsigned int));
+
+ if (error.Fail())
+ return error.ToError();
+
+ error = NativeProcessLinux::PtraceWrapper(
+ PTRACE_SETHBPREGS, m_thread.GetID(), (PTRACE_TYPE_ARG3)(intptr_t)ctrl_idx,
+ ctrl_buf, sizeof(unsigned int));
+
+ return error.ToError();
+}
+#endif // ifdef __arm__
+
uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
const RegisterInfo *reg_info) const {
return reg_info->byte_offset - GetGPRSize();
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
index 3a31d68d7a3c..cf36859b16ad 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
@@ -12,7 +12,7 @@
#define lldb_NativeRegisterContextLinux_arm_h
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
-#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
@@ -21,7 +21,8 @@ namespace process_linux {
class NativeProcessLinux;
-class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
+class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux,
+ public NativeRegisterContextDBReg_arm {
public:
NativeRegisterContextLinux_arm(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
@@ -42,39 +43,6 @@ public:
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
- // Hardware breakpoints/watchpoint management functions
-
- uint32_t NumSupportedHardwareBreakpoints() override;
-
- uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
-
- bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
-
- Status ClearAllHardwareBreakpoints() override;
-
- Status GetHardwareBreakHitIndex(uint32_t &bp_index,
- lldb::addr_t trap_addr) override;
-
- uint32_t NumSupportedHardwareWatchpoints() override;
-
- uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
- uint32_t watch_flags) override;
-
- bool ClearHardwareWatchpoint(uint32_t hw_index) override;
-
- Status ClearAllHardwareWatchpoints() override;
-
- Status GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr) override;
-
- lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
-
- lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
-
- uint32_t GetWatchpointSize(uint32_t wp_index);
-
- bool WatchpointIsEnabled(uint32_t wp_index);
-
protected:
Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
uint32_t size, RegisterValue &value) override;
@@ -100,23 +68,18 @@ private:
uint32_t m_gpr_arm[k_num_gpr_registers_arm];
RegisterInfoPOSIX_arm::FPU m_fpr;
- std::array<NativeRegisterContextDBReg::DREG, 16>
- m_hbr_regs; // Arm native linux hardware breakpoints
- std::array<NativeRegisterContextDBReg::DREG, 16>
- m_hwp_regs; // Arm native linux hardware watchpoints
-
- uint32_t m_max_hwp_supported;
- uint32_t m_max_hbp_supported;
bool m_refresh_hwdebug_info;
bool IsGPR(unsigned reg) const;
bool IsFPR(unsigned reg) const;
- Status ReadHardwareDebugInfo();
+ llvm::Error ReadHardwareDebugInfo() override;
- Status WriteHardwareDebugRegs(NativeRegisterContextDBReg::DREGType hwbType,
- int hwb_index);
+ llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
+#ifdef __arm__
+ llvm::Error WriteHardwareDebugReg(DREGType hwbType, int hwb_index);
+#endif
uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 5d99c22dafe1..b1e326ec064e 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lldb_library(lldbPluginProcessUtility
MemoryTagManagerAArch64MTE.cpp
NativeProcessSoftwareSingleStep.cpp
NativeRegisterContextDBReg.cpp
+ NativeRegisterContextDBReg_arm.cpp
NativeRegisterContextDBReg_arm64.cpp
NativeRegisterContextDBReg_loongarch.cpp
NativeRegisterContextDBReg_x86.cpp
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
index 19601b7f35d4..f35027e93514 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
@@ -44,15 +44,16 @@ uint32_t NativeRegisterContextDBReg::SetHardwareBreakpoint(lldb::addr_t addr,
return LLDB_INVALID_INDEX32;
}
- uint32_t control_value = 0, bp_index = 0;
-
if (!ValidateBreakpoint(size, addr))
return LLDB_INVALID_INDEX32;
- control_value = MakeBreakControlValue(size);
+ uint32_t control_value = MakeBreakControlValue(size);
+ auto details = AdjustBreakpoint({size, addr});
+ size = details.size;
+ addr = details.addr;
// Iterate over stored breakpoints and find a free bp_index
- bp_index = LLDB_INVALID_INDEX32;
+ uint32_t bp_index = LLDB_INVALID_INDEX32;
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
if (!BreakpointIsEnabled(i))
bp_index = i; // Mark last free slot
@@ -222,7 +223,7 @@ uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(
addr = adjusted->addr;
// Check if we are setting watchpoint other than read/write/access Also
- // update watchpoint flag to match AArch64/LoongArch write-read bit
+ // update watchpoint flag to match ARM/AArch64/LoongArch write-read bit
// configuration.
switch (watch_flags) {
case lldb::eWatchpointKindWrite:
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
index 9b6ecd382c3f..2dd11dcf74de 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
@@ -12,6 +12,7 @@
#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
#include <array>
+#include <optional>
// Common utilities for hardware breakpoints and hardware watchpoints on AArch64
// and LoongArch.
@@ -76,19 +77,25 @@ protected:
// On AArch64 and Loongarch the hardware breakpoint length size is 4, and the
// target address must 4-byte alignment.
- bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
+ virtual bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
return (size == 4) && !(addr & 0x3);
}
+
struct WatchpointDetails {
size_t size;
lldb::addr_t addr;
};
virtual std::optional<WatchpointDetails>
AdjustWatchpoint(const WatchpointDetails &details) = 0;
+
+ using BreakpointDetails = WatchpointDetails;
+ virtual BreakpointDetails AdjustBreakpoint(const BreakpointDetails &details) {
+ return details;
+ }
+
virtual uint32_t MakeBreakControlValue(size_t size) = 0;
virtual uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) = 0;
virtual uint32_t GetWatchpointSize(uint32_t wp_index) = 0;
-
virtual llvm::Error ReadHardwareDebugInfo() = 0;
virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0;
virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) {
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
new file mode 100644
index 000000000000..803fed54d6b0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
@@ -0,0 +1,117 @@
+//===-- NativeRegisterContextDBReg_arm.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextDBReg_arm.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+uint32_t NativeRegisterContextDBReg_arm::GetWatchpointSize(uint32_t wp_index) {
+ Log *log = GetLog(LLDBLog::Watchpoints);
+ LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+ switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
+ case 0x01:
+ return 1;
+ case 0x03:
+ return 2;
+ case 0x07:
+ return 3;
+ case 0x0f:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+std::optional<NativeRegisterContextDBReg::WatchpointDetails>
+NativeRegisterContextDBReg_arm::AdjustWatchpoint(
+ const WatchpointDetails &details) {
+ auto [size, addr] = details;
+
+ if (size == 0 || size > 4)
+ return {};
+
+ // Check 4-byte alignment for hardware watchpoint target address. Below is a
+ // hack to recalculate address and size in order to make sure we can watch
+ // non 4-byte aligned addresses as well.
+ if (addr & 0x03) {
+ uint8_t watch_mask = (addr & 0x03) + size;
+ if (watch_mask > 0x04)
+ return {};
+ else if (watch_mask <= 0x02)
+ size = 2;
+ else
+ size = 4;
+
+ addr = addr & (~0x03);
+ }
+
+ return WatchpointDetails{size, addr};
+}
+
+NativeRegisterContextDBReg::BreakpointDetails
+NativeRegisterContextDBReg_arm::AdjustBreakpoint(
+ const BreakpointDetails &details) {
+ BreakpointDetails bd = details;
+ // Use size to get a hint of arm vs thumb modes.
+ // LLDB usually aligns this client side, but other clients may not.
+ switch (bd.size) {
+ case 2:
+ bd.addr &= ~1;
+ break;
+ case 4:
+ bd.addr &= ~3;
+ break;
+ default:
+ // We assume that ValidateBreakpoint would have caught this earlier.
+ llvm_unreachable("Invalid breakpoint size!");
+ }
+
+ return bd;
+}
+
+uint32_t NativeRegisterContextDBReg_arm::MakeBreakControlValue(size_t size) {
+ switch (size) {
+ case 2:
+ return (0x3 << 5) | 7;
+ case 4:
+ return (0xfu << 5) | 7;
+ default:
+ // ValidateBreakpoint would have rejected this earlier.
+ llvm_unreachable("Invalid breakpoint size.");
+ }
+}
+
+uint32_t
+NativeRegisterContextDBReg_arm::MakeWatchControlValue(size_t size,
+ uint32_t watch_flags) {
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair, so make sure we can properly encode this.
+ // We assume that the address was 4 byte aligned by AdjustWatchpoint.
+ uint32_t byte_mask = (1u << size) - 1u;
+
+ // Check if we need multiple watchpoint register
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Setup control value
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t control_value = byte_mask << 5;
+
+ // Turn on appropriate watchpoint flags read or write
+ control_value |= (watch_flags << 3);
+
+ // Enable this watchpoint and make it stop in privileged or user mode;
+ control_value |= 7;
+
+ return control_value;
+}
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
new file mode 100644
index 000000000000..253ae96c90c9
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
@@ -0,0 +1,42 @@
+//===-- NativeRegisterContextDBReg_arm.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextDBReg_arm_h
+#define lldb_NativeRegisterContextDBReg_arm_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+
+namespace lldb_private {
+
+class NativeRegisterContextDBReg_arm : public NativeRegisterContextDBReg {
+public:
+ NativeRegisterContextDBReg_arm()
+ : NativeRegisterContextDBReg(/*enable_bit=*/0x1U) {}
+
+private:
+ uint32_t GetWatchpointSize(uint32_t wp_index) override;
+
+ std::optional<WatchpointDetails>
+ AdjustWatchpoint(const WatchpointDetails &details) override;
+
+ BreakpointDetails AdjustBreakpoint(const BreakpointDetails &details) override;
+
+ uint32_t MakeBreakControlValue(size_t size) override;
+
+ uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) override;
+
+ bool ValidateBreakpoint(size_t size,
+ [[maybe_unused]] lldb::addr_t addr) override {
+ // Break on 4 or 2 byte instructions.
+ return size == 4 || size == 2;
+ }
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextDBReg_arm_h
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
index fbf128553fd5..3b8d6a84c964 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
@@ -79,7 +79,7 @@ static lldb_private::RegisterInfo g_register_infos_mte[] = {
DEFINE_EXTENSION_REG(mte_ctrl)};
static lldb_private::RegisterInfo g_register_infos_tls[] = {
- DEFINE_EXTENSION_REG(tpidr),
+ DEFINE_EXTENSION_REG_GENERIC(tpidr, LLDB_REGNUM_GENERIC_TP),
// Only present when SME is present
DEFINE_EXTENSION_REG(tpidr2)};
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
index c9c4d7ceae55..829fa076d221 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
@@ -456,6 +456,7 @@ static uint32_t g_d29_invalidates[] = {fpu_v29, fpu_s29, LLDB_INVALID_REGNUM};
static uint32_t g_d30_invalidates[] = {fpu_v30, fpu_s30, LLDB_INVALID_REGNUM};
static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
+// clang-format off
// Generates register kinds array with DWARF, EH frame and generic kind
#define MISC_KIND(reg, type, generic_kind) \
{ \
@@ -470,6 +471,11 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
LLDB_INVALID_REGNUM, lldb_kind \
}
+#define GENERIC_KIND(genenric_kind) \
+ { \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, genenric_kind, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM \
+ }
// Generates register kinds array for registers with only lldb kind
#define KIND_ALL_INVALID \
{ \
@@ -484,8 +490,6 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
#define MISC_FPU_KIND(lldb_kind) LLDB_KIND(lldb_kind)
#define MISC_EXC_KIND(lldb_kind) LLDB_KIND(lldb_kind)
-// clang-format off
-
// Defines a 64-bit general purpose register
#define DEFINE_GPR64(reg, generic_kind) \
{ \
@@ -540,6 +544,12 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM};
#reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \
KIND_ALL_INVALID, nullptr, nullptr, nullptr, \
}
+
+#define DEFINE_EXTENSION_REG_GENERIC(reg, generic_kind) \
+ { \
+ #reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \
+ GENERIC_KIND(generic_kind), nullptr, nullptr, nullptr, \
+ }
static lldb_private::RegisterInfo g_register_infos_arm64_le[] = {
// DEFINE_GPR64(name, GENERIC KIND)
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 88eeddf17878..8f5f1242116f 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -99,7 +99,7 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec &core_file)
- : PostMortemProcess(target_sp, listener_sp, core_file) {}
+ : PostMortemProcess(target_sp, listener_sp, core_file), m_uuids() {}
// Destructor
ProcessElfCore::~ProcessElfCore() {
@@ -257,12 +257,12 @@ Status ProcessElfCore::DoLoadCore() {
// the main executable using data we found in the core file notes.
lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
if (!exe_module_sp) {
- // The first entry in the NT_FILE might be our executable
if (!m_nt_file_entries.empty()) {
+ llvm::StringRef executable_path = GetMainExecutablePath();
ModuleSpec exe_module_spec;
exe_module_spec.GetArchitecture() = arch;
- exe_module_spec.GetUUID() = m_nt_file_entries[0].uuid;
- exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path,
+ exe_module_spec.GetUUID() = FindModuleUUID(executable_path);
+ exe_module_spec.GetFileSpec().SetFile(executable_path,
FileSpec::Style::native);
if (exe_module_spec.GetFileSpec()) {
exe_module_sp =
@@ -277,21 +277,38 @@ Status ProcessElfCore::DoLoadCore() {
void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
Log *log = GetLog(LLDBLog::Process);
+ m_uuids.clear();
for (NT_FILE_Entry &entry : m_nt_file_entries) {
- entry.uuid = FindBuidIdInCoreMemory(entry.start);
- if (log && entry.uuid.IsValid())
- LLDB_LOGF(log, "%s found UUID @ %16.16" PRIx64 ": %s \"%s\"",
- __FUNCTION__, entry.start, entry.uuid.GetAsString().c_str(),
- entry.path.c_str());
+ UUID uuid = FindBuidIdInCoreMemory(entry.start);
+ if (uuid.IsValid()) {
+ // Assert that either the path is not in the map or the UUID matches
+ assert(m_uuids.count(entry.path) == 0 || m_uuids[entry.path] == uuid);
+ m_uuids[entry.path] = uuid;
+ if (log)
+ LLDB_LOGF(log, "%s found UUID @ %16.16" PRIx64 ": %s \"%s\"",
+ __FUNCTION__, entry.start, uuid.GetAsString().c_str(),
+ entry.path.c_str());
+ }
}
}
+llvm::StringRef ProcessElfCore::GetMainExecutablePath() {
+ if (m_nt_file_entries.empty())
+ return "";
+
+ // The first entry in the NT_FILE might be our executable
+ llvm::StringRef executable_path = m_nt_file_entries[0].path;
+ // Prefer the NT_FILE entry matching m_executable_name as main executable.
+ for (const NT_FILE_Entry &file_entry : m_nt_file_entries)
+ if (llvm::StringRef(file_entry.path).ends_with("/" + m_executable_name)) {
+ executable_path = file_entry.path;
+ break;
+ }
+ return executable_path;
+}
+
UUID ProcessElfCore::FindModuleUUID(const llvm::StringRef path) {
- // Returns the gnu uuid from matched NT_FILE entry
- for (NT_FILE_Entry &entry : m_nt_file_entries)
- if (path == entry.path && entry.uuid.IsValid())
- return entry.uuid;
- return UUID();
+ return m_uuids[std::string(path)];
}
lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
@@ -935,6 +952,7 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) {
return status.ToError();
thread_data.name.assign (prpsinfo.pr_fname, strnlen (prpsinfo.pr_fname, sizeof (prpsinfo.pr_fname)));
SetID(prpsinfo.pr_pid);
+ m_executable_name = prpsinfo.pr_fname;
break;
}
case ELF::NT_SIGINFO: {
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index a91c04a277f6..576c6858477a 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -17,6 +17,7 @@
#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H
#include <list>
+#include <unordered_map>
#include <vector>
#include "lldb/Target/PostMortemProcess.h"
@@ -115,10 +116,6 @@ private:
lldb::addr_t end;
lldb::addr_t file_ofs;
std::string path;
- // Add a UUID member for convenient access. The UUID value is not in the
- // NT_FILE entries, we will find it in core memory and store it here for
- // easy access.
- lldb_private::UUID uuid;
};
// For ProcessElfCore only
@@ -152,6 +149,12 @@ private:
// NT_FILE entries found from the NOTE segment
std::vector<NT_FILE_Entry> m_nt_file_entries;
+ // Map from file path to UUID for quick lookup
+ std::unordered_map<std::string, lldb_private::UUID> m_uuids;
+
+ // Executable name found from the ELF PRPSINFO
+ std::string m_executable_name;
+
// Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
llvm::Error ParseThreadContextsFromNoteSegment(
const elf::ELFProgramHeader &segment_header,
@@ -165,6 +168,9 @@ private:
lldb_private::UUID FindModuleUUID(const llvm::StringRef path) override;
+ // Returns the main executable path
+ llvm::StringRef GetMainExecutablePath();
+
// Returns the value of certain type of note of a given start address
lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address);
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
index 3a62081827c6..c9e90ebf8a4d 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
@@ -23,6 +23,10 @@ RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(
gpregset.GetByteSize());
m_gpr.SetData(m_gpr_buffer);
m_gpr.SetByteOrder(gpregset.GetByteOrder());
+
+ const llvm::Triple &target_triple =
+ m_register_info_up->GetTargetArchitecture().GetTriple();
+ m_fpr = getRegset(notes, target_triple, ARM_VFP_Desc);
}
RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm() = default;
@@ -43,14 +47,25 @@ bool RegisterContextCorePOSIX_arm::WriteFPR() {
bool RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &value) {
- lldb::offset_t offset = reg_info->byte_offset;
- if (offset + reg_info->byte_size <= GetGPRSize()) {
- uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
- if (offset == reg_info->byte_offset + reg_info->byte_size) {
- value = v;
- return true;
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM)
+ return false;
+
+ if (IsGPR(reg)) {
+ lldb::offset_t offset = reg_info->byte_offset;
+ if (m_gpr.ValidOffsetForDataOfSize(offset, reg_info->byte_size)) {
+ value = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ return offset == reg_info->byte_offset + reg_info->byte_size;
}
+ } else if (IsFPR(reg)) {
+ assert(reg_info->byte_offset >= GetGPRSize());
+ lldb::offset_t offset = reg_info->byte_offset - GetGPRSize();
+ if (m_fpr.ValidOffsetForDataOfSize(offset, reg_info->byte_size))
+ return value
+ .SetValueFromData(*reg_info, m_fpr, offset, /*partial_data_ok=*/false)
+ .Success();
}
+
return false;
}
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
index 8d773a046bca..e466ee242181 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
@@ -48,6 +48,7 @@ protected:
private:
lldb::DataBufferSP m_gpr_buffer;
lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM_H
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
index 59382a12cde0..a5b0d788a190 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
@@ -152,6 +152,11 @@ constexpr RegsetDesc AARCH64_GCS_Desc[] = {
{llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_GCS},
};
+constexpr RegsetDesc ARM_VFP_Desc[] = {
+ {llvm::Triple::FreeBSD, llvm::Triple::arm, llvm::ELF::NT_ARM_VFP},
+ {llvm::Triple::Linux, llvm::Triple::arm, llvm::ELF::NT_ARM_VFP},
+};
+
constexpr RegsetDesc PPC_VMX_Desc[] = {
{llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
{llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 85e141d41747..91f3a6ce383b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5773,7 +5773,7 @@ public:
CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter)
: CommandObjectRaw(interpreter, "process plugin packet monitor",
"Send a qRcmd packet through the GDB remote protocol "
- "and print the response."
+ "and print the response. "
"The argument passed to this command will be hex "
"encoded into a valid 'qRcmd' packet, sent and the "
"response will be printed.") {}
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index 6037c8d2514b..a780b3f59ade 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -799,6 +799,23 @@ Status ProcessMachCore::DoGetMemoryRegionInfo(addr_t load_addr,
region_info.SetMapped(MemoryRegionInfo::eNo);
}
return Status();
+ } else {
+ // The corefile has no LC_SEGMENT at this virtual address,
+ // but see if there is a binary whose Section has been
+ // loaded at that address in the current Target.
+ Address addr;
+ if (GetTarget().ResolveLoadAddress(load_addr, addr)) {
+ SectionSP section_sp(addr.GetSection());
+ if (section_sp) {
+ region_info.GetRange().SetRangeBase(
+ section_sp->GetLoadBaseAddress(&GetTarget()));
+ region_info.GetRange().SetByteSize(section_sp->GetByteSize());
+ if (region_info.GetRange().Contains(load_addr)) {
+ region_info.SetLLDBPermissions(section_sp->GetPermissions());
+ return Status();
+ }
+ }
+ }
}
region_info.GetRange().SetRangeBase(load_addr);
diff --git a/lldb/source/Plugins/Process/scripted/CMakeLists.txt b/lldb/source/Plugins/Process/scripted/CMakeLists.txt
index 590166591a41..1516ad3132e3 100644
--- a/lldb/source/Plugins/Process/scripted/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/scripted/CMakeLists.txt
@@ -1,6 +1,7 @@
add_lldb_library(lldbPluginScriptedProcess PLUGIN
ScriptedProcess.cpp
ScriptedThread.cpp
+ ScriptedFrame.cpp
LINK_COMPONENTS
BinaryFormat
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
new file mode 100644
index 000000000000..6519df9185df
--- /dev/null
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
@@ -0,0 +1,191 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "ScriptedFrame.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+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,
+ StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_object) {
+ if (!thread.IsValid())
+ return llvm::createStringError("Invalid scripted thread.");
+
+ thread.CheckInterpreterAndScriptObject();
+
+ auto scripted_frame_interface =
+ thread.GetInterface()->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())
+ return llvm::createStringError(
+ "failed to get scripted thread class name");
+ frame_class_name = *class_name;
+ }
+
+ ExecutionContext exe_ctx(thread);
+ auto obj_or_err = scripted_frame_interface->CreatePluginObject(
+ frame_class_name, exe_ctx, args_sp, script_object);
+
+ if (!obj_or_err)
+ return llvm::createStringError(
+ "failed to create script object: %s",
+ llvm::toString(obj_or_err.takeError()).c_str());
+
+ StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
+
+ if (!owned_script_object_sp->IsValid())
+ return llvm::createStringError("created script object is invalid");
+
+ lldb::user_id_t frame_id = scripted_frame_interface->GetID();
+
+ lldb::addr_t pc = scripted_frame_interface->GetPC();
+ SymbolContext sc;
+ Address symbol_addr;
+ if (pc != LLDB_INVALID_ADDRESS) {
+ symbol_addr.SetLoadAddress(pc, &thread.GetProcess()->GetTarget());
+ symbol_addr.CalculateSymbolContext(&sc);
+ }
+
+ std::optional<SymbolContext> maybe_sym_ctx =
+ scripted_frame_interface->GetSymbolContext();
+ 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);
+}
+
+ScriptedFrame::ScriptedFrame(ScriptedThread &thread,
+ 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,
+ /*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) {}
+
+ScriptedFrame::~ScriptedFrame() {}
+
+const char *ScriptedFrame::GetFunctionName() {
+ CheckInterpreterAndScriptObject();
+ std::optional<std::string> function_name = GetInterface()->GetFunctionName();
+ if (!function_name)
+ return nullptr;
+ return ConstString(function_name->c_str()).AsCString();
+}
+
+const char *ScriptedFrame::GetDisplayFunctionName() {
+ CheckInterpreterAndScriptObject();
+ std::optional<std::string> function_name =
+ GetInterface()->GetDisplayFunctionName();
+ if (!function_name)
+ return nullptr;
+ return ConstString(function_name->c_str()).AsCString();
+}
+
+bool ScriptedFrame::IsInlined() { return GetInterface()->IsInlined(); }
+
+bool ScriptedFrame::IsArtificial() const {
+ return GetInterface()->IsArtificial();
+}
+
+bool ScriptedFrame::IsHidden() { return GetInterface()->IsHidden(); }
+
+lldb::ScriptedFrameInterfaceSP ScriptedFrame::GetInterface() const {
+ return m_scripted_frame_interface_sp;
+}
+
+std::shared_ptr<DynamicRegisterInfo> ScriptedFrame::GetDynamicRegisterInfo() {
+ CheckInterpreterAndScriptObject();
+
+ if (!m_register_info_sp) {
+ 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);
+
+ m_register_info_sp = DynamicRegisterInfo::Create(
+ *reg_info, process_sp->GetTarget().GetArchitecture());
+ }
+
+ return m_register_info_sp;
+}
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.h b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
new file mode 100644
index 000000000000..6e01e2fd7653
--- /dev/null
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.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_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 <string>
+
+namespace lldb_private {
+class ScriptedThread;
+}
+
+namespace lldb_private {
+
+class ScriptedFrame : public lldb_private::StackFrame {
+
+public:
+ ScriptedFrame(ScriptedThread &thread,
+ 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;
+
+ static llvm::Expected<std::shared_ptr<ScriptedFrame>>
+ Create(ScriptedThread &thread, StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_object = nullptr);
+
+ bool IsInlined() override;
+ bool IsArtificial() const override;
+ bool IsHidden() override;
+ const char *GetFunctionName() override;
+ const char *GetDisplayFunctionName() override;
+
+private:
+ void CheckInterpreterAndScriptObject() const;
+ lldb::ScriptedFrameInterfaceSP GetInterface() const;
+
+ ScriptedFrame(const ScriptedFrame &) = delete;
+ const ScriptedFrame &operator=(const ScriptedFrame &) = delete;
+
+ std::shared_ptr<DynamicRegisterInfo> GetDynamicRegisterInfo();
+
+ lldb::ScriptedFrameInterfaceSP m_scripted_frame_interface_sp;
+ lldb_private::StructuredData::GenericSP m_script_object_sp;
+ std::shared_ptr<DynamicRegisterInfo> m_register_info_sp;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
index d0d1508e8517..491efac5aade 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "ScriptedThread.h"
+#include "ScriptedFrame.h"
#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
@@ -173,40 +174,101 @@ bool ScriptedThread::LoadArtificialStackFrames() {
.str(),
error, LLDBLog::Thread);
- StackFrameListSP frames = GetStackFrameList();
-
- for (size_t idx = 0; idx < arr_size; idx++) {
+ auto create_frame_from_dict =
+ [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
+ Status error;
std::optional<StructuredData::Dictionary *> maybe_dict =
arr_sp->GetItemAtIndexAsDictionary(idx);
- if (!maybe_dict)
- return ScriptedInterface::ErrorWithMessage<bool>(
+ if (!maybe_dict) {
+ ScriptedInterface::ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
llvm::Twine(
"Couldn't get artificial stackframe dictionary at index (" +
llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
.str(),
error, LLDBLog::Thread);
+ return error.ToError();
+ }
StructuredData::Dictionary *dict = *maybe_dict;
lldb::addr_t pc;
- if (!dict->GetValueForKeyAsInteger("pc", pc))
- return ScriptedInterface::ErrorWithMessage<bool>(
+ if (!dict->GetValueForKeyAsInteger("pc", pc)) {
+ ScriptedInterface::ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
"Couldn't find value for key 'pc' in stackframe dictionary.", error,
LLDBLog::Thread);
+ return error.ToError();
+ }
Address symbol_addr;
symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
bool cfa_is_valid = false;
+ const bool artificial = false;
const bool behaves_like_zeroth_frame = false;
SymbolContext sc;
symbol_addr.CalculateSymbolContext(&sc);
- StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(
- this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
- StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc);
+ return std::make_shared<StackFrame>(this->shared_from_this(), idx, idx, cfa,
+ cfa_is_valid, pc,
+ StackFrame::Kind::Synthetic, artificial,
+ behaves_like_zeroth_frame, &sc);
+ };
+
+ auto create_frame_from_script_object =
+ [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
+ Status error;
+ StructuredData::ObjectSP object_sp = arr_sp->GetItemAtIndex(idx);
+ if (!object_sp || !object_sp->GetAsGeneric()) {
+ ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Couldn't get artificial stackframe object at index (" +
+ llvm::Twine(idx) +
+ llvm::Twine(") from stackframe array."))
+ .str(),
+ error, LLDBLog::Thread);
+ return error.ToError();
+ }
+
+ auto frame_or_error =
+ ScriptedFrame::Create(*this, nullptr, object_sp->GetAsGeneric());
+
+ if (!frame_or_error) {
+ ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
+ return error.ToError();
+ }
+
+ StackFrameSP frame_sp = frame_or_error.get();
+ lldbassert(frame_sp && "Couldn't initialize scripted frame.");
+
+ return frame_sp;
+ };
+
+ StackFrameListSP frames = GetStackFrameList();
+
+ for (size_t idx = 0; idx < arr_size; idx++) {
+ StackFrameSP synth_frame_sp = nullptr;
+
+ auto frame_from_dict_or_err = create_frame_from_dict(idx);
+ if (!frame_from_dict_or_err) {
+ auto frame_from_script_obj_or_err = create_frame_from_script_object(idx);
+
+ if (!frame_from_script_obj_or_err) {
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Couldn't add artificial frame (" + llvm::Twine(idx) +
+ llvm::Twine(") to ScriptedThread StackFrameList."))
+ .str(),
+ error, LLDBLog::Thread);
+ } else {
+ llvm::consumeError(frame_from_dict_or_err.takeError());
+ synth_frame_sp = *frame_from_script_obj_or_err;
+ }
+ } else {
+ synth_frame_sp = *frame_from_dict_or_err;
+ }
if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
return ScriptedInterface::ErrorWithMessage<bool>(
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.h b/lldb/source/Plugins/Process/scripted/ScriptedThread.h
index cd224d60ceef..ee5ace405967 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.h
@@ -15,11 +15,12 @@
#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/Target//DynamicRegisterInfo.h"
+#include "lldb/Target/DynamicRegisterInfo.h"
#include "lldb/Target/Thread.h"
namespace lldb_private {
class ScriptedProcess;
+class ScriptedFrame;
}
namespace lldb_private {
@@ -61,6 +62,8 @@ public:
StructuredData::ObjectSP FetchThreadExtendedInfo() override;
private:
+ friend class ScriptedFrame;
+
void CheckInterpreterAndScriptObject() const;
lldb::ScriptedThreadInterfaceSP GetInterface() const;
diff --git a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
index c359663239dc..dc18c8e06803 100644
--- a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
@@ -10,14 +10,15 @@
#include "Resource.h"
#include "Tool.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Protocol/MCP/MCPError.h"
-#include "lldb/Protocol/MCP/Tool.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Protocol/MCP/Server.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/Threading.h"
#include <thread>
-#include <variant>
using namespace lldb_private;
using namespace lldb_private::mcp;
@@ -26,24 +27,10 @@ using namespace llvm;
LLDB_PLUGIN_DEFINE(ProtocolServerMCP)
-static constexpr size_t kChunkSize = 1024;
static constexpr llvm::StringLiteral kName = "lldb-mcp";
static constexpr llvm::StringLiteral kVersion = "0.1.0";
-ProtocolServerMCP::ProtocolServerMCP()
- : ProtocolServer(),
- lldb_protocol::mcp::Server(std::string(kName), std::string(kVersion)) {
- AddNotificationHandler("notifications/initialized",
- [](const lldb_protocol::mcp::Notification &) {
- LLDB_LOG(GetLog(LLDBLog::Host),
- "MCP initialization complete");
- });
-
- AddTool(
- std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
-
- AddResourceProvider(std::make_unique<DebuggerResourceProvider>());
-}
+ProtocolServerMCP::ProtocolServerMCP() : ProtocolServer() {}
ProtocolServerMCP::~ProtocolServerMCP() { llvm::consumeError(Stop()); }
@@ -53,6 +40,8 @@ void ProtocolServerMCP::Initialize() {
}
void ProtocolServerMCP::Terminate() {
+ if (llvm::Error error = ProtocolServer::Terminate())
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(error), "{0}");
PluginManager::UnregisterPlugin(CreateInstance);
}
@@ -64,57 +53,37 @@ llvm::StringRef ProtocolServerMCP::GetPluginDescriptionStatic() {
return "MCP Server.";
}
+void ProtocolServerMCP::Extend(lldb_protocol::mcp::Server &server) const {
+ server.AddNotificationHandler("notifications/initialized",
+ [](const lldb_protocol::mcp::Notification &) {
+ LLDB_LOG(GetLog(LLDBLog::Host),
+ "MCP initialization complete");
+ });
+ server.AddTool(
+ std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
+ server.AddResourceProvider(std::make_unique<DebuggerResourceProvider>());
+}
+
void ProtocolServerMCP::AcceptCallback(std::unique_ptr<Socket> socket) {
- LLDB_LOG(GetLog(LLDBLog::Host), "New MCP client ({0}) connected",
- m_clients.size() + 1);
+ Log *log = GetLog(LLDBLog::Host);
+ std::string client_name = llvm::formatv("client_{0}", m_instances.size() + 1);
+ LLDB_LOG(log, "New MCP client connected: {0}", client_name);
lldb::IOObjectSP io_sp = std::move(socket);
- auto client_up = std::make_unique<Client>();
- client_up->io_sp = io_sp;
- Client *client = client_up.get();
-
- Status status;
- auto read_handle_up = m_loop.RegisterReadObject(
- io_sp,
- [this, client](MainLoopBase &loop) {
- if (llvm::Error error = ReadCallback(*client)) {
- LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(error), "{0}");
- client->read_handle_up.reset();
- }
- },
- status);
- if (status.Fail())
+ auto transport_up = std::make_unique<lldb_protocol::mcp::Transport>(
+ io_sp, io_sp, [client_name](llvm::StringRef message) {
+ LLDB_LOG(GetLog(LLDBLog::Host), "{0}: {1}", client_name, message);
+ });
+ auto instance_up = std::make_unique<lldb_protocol::mcp::Server>(
+ std::string(kName), std::string(kVersion), std::move(transport_up),
+ m_loop);
+ Extend(*instance_up);
+ llvm::Error error = instance_up->Run();
+ if (error) {
+ LLDB_LOG_ERROR(log, std::move(error), "Failed to run MCP server: {0}");
return;
-
- client_up->read_handle_up = std::move(read_handle_up);
- m_clients.emplace_back(std::move(client_up));
-}
-
-llvm::Error ProtocolServerMCP::ReadCallback(Client &client) {
- char chunk[kChunkSize];
- size_t bytes_read = sizeof(chunk);
- if (Status status = client.io_sp->Read(chunk, bytes_read); status.Fail())
- return status.takeError();
- client.buffer.append(chunk, bytes_read);
-
- for (std::string::size_type pos;
- (pos = client.buffer.find('\n')) != std::string::npos;) {
- llvm::Expected<std::optional<lldb_protocol::mcp::Message>> message =
- HandleData(StringRef(client.buffer.data(), pos));
- client.buffer = client.buffer.erase(0, pos + 1);
- if (!message)
- return message.takeError();
-
- if (*message) {
- std::string Output;
- llvm::raw_string_ostream OS(Output);
- OS << llvm::formatv("{0}", toJSON(**message)) << '\n';
- size_t num_bytes = Output.size();
- return client.io_sp->Write(Output.data(), num_bytes).takeError();
- }
}
-
- return llvm::Error::success();
+ m_instances.push_back(std::move(instance_up));
}
llvm::Error ProtocolServerMCP::Start(ProtocolServer::Connection connection) {
@@ -138,7 +107,19 @@ llvm::Error ProtocolServerMCP::Start(ProtocolServer::Connection connection) {
if (llvm::Error error = handles.takeError())
return error;
+ auto listening_uris = m_listener->GetListeningConnectionURI();
+ if (listening_uris.empty())
+ return createStringError("failed to get listening connections");
+ std::string address =
+ llvm::join(m_listener->GetListeningConnectionURI(), ", ");
+
+ ServerInfo info{listening_uris[0]};
+ llvm::Expected<ServerInfoHandle> handle = ServerInfo::Write(info);
+ if (!handle)
+ return handle.takeError();
+
m_running = true;
+ m_server_info_handle = std::move(*handle);
m_listen_handlers = std::move(*handles);
m_loop_thread = std::thread([=] {
llvm::set_thread_name("protocol-server.mcp");
@@ -158,27 +139,15 @@ llvm::Error ProtocolServerMCP::Stop() {
// Stop the main loop.
m_loop.AddPendingCallback(
- [](MainLoopBase &loop) { loop.RequestTermination(); });
+ [](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
// Wait for the main loop to exit.
if (m_loop_thread.joinable())
m_loop_thread.join();
- {
- std::lock_guard<std::mutex> guard(m_mutex);
- m_listener.reset();
- m_listen_handlers.clear();
- m_clients.clear();
- }
+ m_listen_handlers.clear();
+ m_server_info_handle = ServerInfoHandle();
+ m_instances.clear();
return llvm::Error::success();
}
-
-lldb_protocol::mcp::Capabilities ProtocolServerMCP::GetCapabilities() {
- lldb_protocol::mcp::Capabilities capabilities;
- capabilities.tools.listChanged = true;
- // FIXME: Support sending notifications when a debugger/target are
- // added/removed.
- capabilities.resources.listChanged = false;
- return capabilities;
-}
diff --git a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
index 7fe909a728b8..0251664a2acc 100644
--- a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
+++ b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
@@ -18,8 +18,7 @@
namespace lldb_private::mcp {
-class ProtocolServerMCP : public ProtocolServer,
- public lldb_protocol::mcp::Server {
+class ProtocolServerMCP : public ProtocolServer {
public:
ProtocolServerMCP();
virtual ~ProtocolServerMCP() override;
@@ -39,26 +38,25 @@ public:
Socket *GetSocket() const override { return m_listener.get(); }
+protected:
+ // This adds tools and resource providers that
+ // are specific to this server. Overridable by the unit tests.
+ virtual void Extend(lldb_protocol::mcp::Server &server) const;
+
private:
void AcceptCallback(std::unique_ptr<Socket> socket);
- lldb_protocol::mcp::Capabilities GetCapabilities() override;
-
bool m_running = false;
- MainLoop m_loop;
+ lldb_protocol::mcp::ServerInfoHandle m_server_info_handle;
+ lldb_private::MainLoop m_loop;
std::thread m_loop_thread;
+ std::mutex m_mutex;
std::unique_ptr<Socket> m_listener;
- std::vector<MainLoopBase::ReadHandleUP> m_listen_handlers;
- struct Client {
- lldb::IOObjectSP io_sp;
- MainLoopBase::ReadHandleUP read_handle_up;
- std::string buffer;
- };
- llvm::Error ReadCallback(Client &client);
- std::vector<std::unique_ptr<Client>> m_clients;
+ std::vector<MainLoopBase::ReadHandleUP> m_listen_handlers;
+ std::vector<std::unique_ptr<lldb_protocol::mcp::Server>> m_instances;
};
} // namespace lldb_private::mcp
diff --git a/lldb/source/Plugins/Protocol/MCP/Resource.cpp b/lldb/source/Plugins/Protocol/MCP/Resource.cpp
index e94d2cdd65e0..581424510d4c 100644
--- a/lldb/source/Plugins/Protocol/MCP/Resource.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/Resource.cpp
@@ -8,7 +8,6 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Protocol/MCP/MCPError.h"
-#include "lldb/Target/Platform.h"
using namespace lldb_private;
using namespace lldb_private::mcp;
@@ -124,7 +123,7 @@ DebuggerResourceProvider::GetResources() const {
return resources;
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
auto [protocol, path] = uri.split("://");
@@ -161,7 +160,7 @@ DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
return ReadDebuggerResource(uri, debugger_idx);
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
lldb::user_id_t debugger_id) {
lldb::DebuggerSP debugger_sp = Debugger::FindDebuggerWithID(debugger_id);
@@ -173,17 +172,17 @@ DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
debugger_resource.name = debugger_sp->GetInstanceName();
debugger_resource.num_targets = debugger_sp->GetTargetList().GetNumTargets();
- lldb_protocol::mcp::ResourceContents contents;
+ lldb_protocol::mcp::TextResourceContents contents;
contents.uri = uri;
contents.mimeType = kMimeTypeJSON;
contents.text = llvm::formatv("{0}", toJSON(debugger_resource));
- lldb_protocol::mcp::ResourceResult result;
+ lldb_protocol::mcp::ReadResourceResult result;
result.contents.push_back(contents);
return result;
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
lldb::user_id_t debugger_id,
size_t target_idx) {
@@ -209,12 +208,12 @@ DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
if (lldb::PlatformSP platform_sp = target_sp->GetPlatform())
target_resource.platform = platform_sp->GetName();
- lldb_protocol::mcp::ResourceContents contents;
+ lldb_protocol::mcp::TextResourceContents contents;
contents.uri = uri;
contents.mimeType = kMimeTypeJSON;
contents.text = llvm::formatv("{0}", toJSON(target_resource));
- lldb_protocol::mcp::ResourceResult result;
+ lldb_protocol::mcp::ReadResourceResult result;
result.contents.push_back(contents);
return result;
}
diff --git a/lldb/source/Plugins/Protocol/MCP/Resource.h b/lldb/source/Plugins/Protocol/MCP/Resource.h
index e2382a74f796..0c6576602905 100644
--- a/lldb/source/Plugins/Protocol/MCP/Resource.h
+++ b/lldb/source/Plugins/Protocol/MCP/Resource.h
@@ -11,7 +11,11 @@
#include "lldb/Protocol/MCP/Protocol.h"
#include "lldb/Protocol/MCP/Resource.h"
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
#include <vector>
namespace lldb_private::mcp {
@@ -21,9 +25,8 @@ public:
using ResourceProvider::ResourceProvider;
virtual ~DebuggerResourceProvider() = default;
- virtual std::vector<lldb_protocol::mcp::Resource>
- GetResources() const override;
- virtual llvm::Expected<lldb_protocol::mcp::ResourceResult>
+ std::vector<lldb_protocol::mcp::Resource> GetResources() const override;
+ llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
ReadResource(llvm::StringRef uri) const override;
private:
@@ -31,9 +34,9 @@ private:
static lldb_protocol::mcp::Resource GetTargetResource(size_t target_idx,
Target &target);
- static llvm::Expected<lldb_protocol::mcp::ResourceResult>
+ static llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
ReadDebuggerResource(llvm::StringRef uri, lldb::user_id_t debugger_id);
- static llvm::Expected<lldb_protocol::mcp::ResourceResult>
+ static llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
ReadTargetResource(llvm::StringRef uri, lldb::user_id_t debugger_id,
size_t target_idx);
};
diff --git a/lldb/source/Plugins/Protocol/MCP/Tool.cpp b/lldb/source/Plugins/Protocol/MCP/Tool.cpp
index 143470702a6f..2f451bf76e81 100644
--- a/lldb/source/Plugins/Protocol/MCP/Tool.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/Tool.cpp
@@ -7,9 +7,9 @@
//===----------------------------------------------------------------------===//
#include "Tool.h"
-#include "lldb/Core/Module.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Protocol/MCP/Protocol.h"
using namespace lldb_private;
using namespace lldb_protocol;
@@ -29,10 +29,10 @@ bool fromJSON(const llvm::json::Value &V, CommandToolArguments &A,
O.mapOptional("arguments", A.arguments);
}
-/// Helper function to create a TextResult from a string output.
-static lldb_protocol::mcp::TextResult createTextResult(std::string output,
- bool is_error = false) {
- lldb_protocol::mcp::TextResult text_result;
+/// Helper function to create a CallToolResult from a string output.
+static lldb_protocol::mcp::CallToolResult
+createTextResult(std::string output, bool is_error = false) {
+ lldb_protocol::mcp::CallToolResult text_result;
text_result.content.emplace_back(
lldb_protocol::mcp::TextContent{{std::move(output)}});
text_result.isError = is_error;
@@ -41,7 +41,7 @@ static lldb_protocol::mcp::TextResult createTextResult(std::string output,
} // namespace
-llvm::Expected<lldb_protocol::mcp::TextResult>
+llvm::Expected<lldb_protocol::mcp::CallToolResult>
CommandTool::Call(const lldb_protocol::mcp::ToolArguments &args) {
if (!std::holds_alternative<json::Value>(args))
return createStringError("CommandTool requires arguments");
diff --git a/lldb/source/Plugins/Protocol/MCP/Tool.h b/lldb/source/Plugins/Protocol/MCP/Tool.h
index b7b1756eb38d..1886525b9168 100644
--- a/lldb/source/Plugins/Protocol/MCP/Tool.h
+++ b/lldb/source/Plugins/Protocol/MCP/Tool.h
@@ -9,11 +9,11 @@
#ifndef LLDB_PLUGINS_PROTOCOL_MCP_TOOL_H
#define LLDB_PLUGINS_PROTOCOL_MCP_TOOL_H
-#include "lldb/Core/Debugger.h"
#include "lldb/Protocol/MCP/Protocol.h"
#include "lldb/Protocol/MCP/Tool.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
-#include <string>
+#include <optional>
namespace lldb_private::mcp {
@@ -22,10 +22,10 @@ public:
using lldb_protocol::mcp::Tool::Tool;
~CommandTool() = default;
- virtual llvm::Expected<lldb_protocol::mcp::TextResult>
+ llvm::Expected<lldb_protocol::mcp::CallToolResult>
Call(const lldb_protocol::mcp::ToolArguments &args) override;
- virtual std::optional<llvm::json::Value> GetSchema() const override;
+ std::optional<llvm::json::Value> GetSchema() const override;
};
} // namespace lldb_private::mcp
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
index 04370940423a..09103573b89c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
@@ -22,6 +22,7 @@ endif()
add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces PLUGIN
OperatingSystemPythonInterface.cpp
ScriptInterpreterPythonInterfaces.cpp
+ ScriptedFramePythonInterface.cpp
ScriptedPlatformPythonInterface.cpp
ScriptedProcessPythonInterface.cpp
ScriptedPythonInterface.cpp
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
index 02dc06507caf..3814f4661507 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 "ScriptedFramePythonInterface.h"
#include "ScriptedPlatformPythonInterface.h"
#include "ScriptedProcessPythonInterface.h"
#include "ScriptedStopHookPythonInterface.h"
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
new file mode 100644
index 000000000000..20ca7a2c0135
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
@@ -0,0 +1,157 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/Host/Config.h"
+#include "lldb/Target/ExecutionContext.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 "ScriptedFramePythonInterface.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ScriptedFramePythonInterface::ScriptedFramePythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedFrameInterface(), ScriptedPythonInterface(interpreter) {}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedFramePythonInterface::CreatePluginObject(
+ const llvm::StringRef class_name, ExecutionContext &exe_ctx,
+ StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) {
+ ExecutionContextRefSP exe_ctx_ref_sp =
+ std::make_shared<ExecutionContextRef>(exe_ctx);
+ StructuredDataImpl sd_impl(args_sp);
+ return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj,
+ exe_ctx_ref_sp, sd_impl);
+}
+
+lldb::user_id_t ScriptedFramePythonInterface::GetID() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_id", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return LLDB_INVALID_FRAME_ID;
+
+ return obj->GetUnsignedIntegerValue(LLDB_INVALID_FRAME_ID);
+}
+
+lldb::addr_t ScriptedFramePythonInterface::GetPC() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_pc", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return LLDB_INVALID_ADDRESS;
+
+ return obj->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS);
+}
+
+std::optional<SymbolContext> ScriptedFramePythonInterface::GetSymbolContext() {
+ Status error;
+ auto sym_ctx = Dispatch<SymbolContext>("get_symbol_context", error);
+
+ if (error.Fail()) {
+ return ErrorWithMessage<SymbolContext>(LLVM_PRETTY_FUNCTION,
+ error.AsCString(), error);
+ }
+
+ return sym_ctx;
+}
+
+std::optional<std::string> ScriptedFramePythonInterface::GetFunctionName() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_function_name", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetStringValue().str();
+}
+
+std::optional<std::string>
+ScriptedFramePythonInterface::GetDisplayFunctionName() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_display_function_name", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetStringValue().str();
+}
+
+bool ScriptedFramePythonInterface::IsInlined() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_inlined", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+
+ return obj->GetBooleanValue();
+}
+
+bool ScriptedFramePythonInterface::IsArtificial() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_artificial", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+
+ return obj->GetBooleanValue();
+}
+
+bool ScriptedFramePythonInterface::IsHidden() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_hidden", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+
+ return obj->GetBooleanValue();
+}
+
+StructuredData::DictionarySP ScriptedFramePythonInterface::GetRegisterInfo() {
+ Status error;
+ StructuredData::DictionarySP dict =
+ Dispatch<StructuredData::DictionarySP>("get_register_info", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
+ error))
+ return {};
+
+ return dict;
+}
+
+std::optional<std::string> ScriptedFramePythonInterface::GetRegisterContext() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_register_context", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetAsString()->GetValue().str();
+}
+
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
new file mode 100644
index 000000000000..3aff237ae65d
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SCRIPTEDFRAMEPYTHONINTERFACE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPYTHONINTERFACE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "ScriptedPythonInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameInterface.h"
+#include <optional>
+
+namespace lldb_private {
+class ScriptedFramePythonInterface : public ScriptedFrameInterface,
+ public ScriptedPythonInterface {
+public:
+ ScriptedFramePythonInterface(ScriptInterpreterPythonImpl &interpreter);
+
+ llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
+ StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_obj = nullptr) override;
+
+ llvm::SmallVector<AbstractMethodRequirement>
+ GetAbstractMethodRequirements() const override {
+ return llvm::SmallVector<AbstractMethodRequirement>({{"get_id"}});
+ }
+
+ lldb::user_id_t GetID() override;
+
+ lldb::addr_t GetPC() override;
+
+ std::optional<SymbolContext> GetSymbolContext() override;
+
+ std::optional<std::string> GetFunctionName() override;
+
+ std::optional<std::string> GetDisplayFunctionName() override;
+
+ bool IsInlined() override;
+
+ bool IsArtificial() override;
+
+ bool IsHidden() override;
+
+ StructuredData::DictionarySP GetRegisterInfo() override;
+
+ std::optional<std::string> GetRegisterContext() override;
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index b49d1d82fe53..8083ccae0402 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -167,7 +167,8 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<
if (!sb_mem_reg_info) {
error = Status::FromErrorStringWithFormat(
- "Couldn't cast lldb::SBMemoryRegionInfo to lldb::MemoryRegionInfoSP.");
+ "Couldn't cast lldb::SBMemoryRegionInfo to "
+ "lldb_private::MemoryRegionInfo.");
return {};
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
index 8af89d761764..fd4d231a747f 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
@@ -144,4 +144,21 @@ StructuredData::ArraySP ScriptedThreadPythonInterface::GetExtendedInfo() {
return arr;
}
+std::optional<std::string>
+ScriptedThreadPythonInterface::GetScriptedFramePluginName() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_scripted_frame_plugin", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetStringValue().str();
+}
+
+lldb::ScriptedFrameInterfaceSP
+ScriptedThreadPythonInterface::CreateScriptedFrameInterface() {
+ return m_interpreter.CreateScriptedFrameInterface();
+}
+
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h
index 1fb23b39c707..043557a82746 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h
@@ -51,6 +51,11 @@ public:
std::optional<std::string> GetRegisterContext() override;
StructuredData::ArraySP GetExtendedInfo() override;
+
+ std::optional<std::string> GetScriptedFramePluginName() override;
+
+protected:
+ lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 9330a634489a..73c5c72932ff 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -1521,6 +1521,11 @@ ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() {
return std::make_shared<ScriptedThreadPythonInterface>(*this);
}
+ScriptedFrameInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedFrameInterface() {
+ return std::make_shared<ScriptedFramePythonInterface>(*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 83b64b85faeb..dedac280788f 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -99,6 +99,8 @@ public:
lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
+ lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
+
lldb::ScriptedThreadPlanInterfaceSP
CreateScriptedThreadPlanInterface() override;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index a429ea848b7f..5ffb4423969c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -252,7 +252,7 @@ static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
}
static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
- char const *name = die.GetMangledName(/*substitute_name_allowed*/ false);
+ const char *name = die.GetMangledName(/*substitute_name_allowed*/ false);
if (!name)
return {};
@@ -286,7 +286,9 @@ static std::string MakeLLDBFuncAsmLabel(const DWARFDIE &die) {
if (die_id == LLDB_INVALID_UID)
return {};
- return FunctionCallLabel{/*module_id=*/module_id,
+ // Note, discriminator is added by Clang during mangling.
+ return FunctionCallLabel{/*discriminator=*/{},
+ /*module_id=*/module_id,
/*symbol_id=*/die_id,
/*.lookup_name=*/name}
.toString();
@@ -2230,6 +2232,18 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
for (DelayedAddObjCClassProperty &property : delayed_properties)
property.Finalize();
}
+ } else if (Language::LanguageIsObjC(
+ static_cast<LanguageType>(die.GetAttributeValueAsUnsigned(
+ DW_AT_APPLE_runtime_class, eLanguageTypeUnknown)))) {
+ /// The forward declaration was C++ but the definition is Objective-C.
+ /// We currently don't handle such situations. In such cases, keep the
+ /// forward declaration without a definition to avoid violating Clang AST
+ /// invariants.
+ LLDB_LOG(GetLog(LLDBLog::Expressions),
+ "WARNING: Type completion aborted because forward declaration for "
+ "'{0}' is C++ while definition is Objective-C.",
+ llvm::StringRef(die.GetName()));
+ return {};
}
if (!bases.empty()) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index b15e0c15fedb..d3d0110d5e30 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -7,11 +7,14 @@
//===----------------------------------------------------------------------===//
#include "SymbolFileDWARF.h"
+#include "clang/Basic/ABI.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/Threading.h"
@@ -23,6 +26,7 @@
#include "lldb/Core/Progress.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Value.h"
+#include "lldb/Expression/Expression.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/RegularExpression.h"
@@ -79,6 +83,7 @@
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
@@ -2484,34 +2489,148 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
return false;
}
-DWARFDIE
-SymbolFileDWARF::FindFunctionDefinition(const FunctionCallLabel &label) {
- DWARFDIE definition;
- Module::LookupInfo info(ConstString(label.lookup_name),
- lldb::eFunctionNameTypeFull,
- lldb::eLanguageTypeUnknown);
-
- m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
- if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
- return IterationAction::Continue;
+static llvm::StringRef ClangToItaniumCtorKind(clang::CXXCtorType kind) {
+ switch (kind) {
+ case clang::CXXCtorType::Ctor_Complete:
+ return "C1";
+ case clang::CXXCtorType::Ctor_Base:
+ return "C2";
+ case clang::CXXCtorType::Ctor_Unified:
+ return "C4";
+ case clang::CXXCtorType::Ctor_CopyingClosure:
+ case clang::CXXCtorType::Ctor_DefaultClosure:
+ case clang::CXXCtorType::Ctor_Comdat:
+ llvm_unreachable("Unexpected constructor kind.");
+ }
+}
- // We don't check whether the specification DIE for this function
- // corresponds to the declaration DIE because the declaration might be in
- // a type-unit but the definition in the compile-unit (and it's
- // specifcation would point to the declaration in the compile-unit). We
- // rely on the mangled name within the module to be enough to find us the
- // unique definition.
- definition = entry;
- return IterationAction::Stop;
- });
+static llvm::StringRef ClangToItaniumDtorKind(clang::CXXDtorType kind) {
+ switch (kind) {
+ case clang::CXXDtorType::Dtor_Deleting:
+ return "D0";
+ case clang::CXXDtorType::Dtor_Complete:
+ return "D1";
+ case clang::CXXDtorType::Dtor_Base:
+ return "D2";
+ case clang::CXXDtorType::Dtor_Unified:
+ return "D4";
+ case clang::CXXDtorType::Dtor_Comdat:
+ llvm_unreachable("Unexpected destructor kind.");
+ }
+}
+
+static llvm::StringRef
+GetItaniumCtorDtorVariant(llvm::StringRef discriminator) {
+ const bool is_ctor = discriminator.consume_front("C");
+ if (!is_ctor && !discriminator.consume_front("D"))
+ return {};
+
+ uint64_t structor_kind;
+ if (!llvm::to_integer(discriminator, structor_kind))
+ return {};
+
+ if (is_ctor) {
+ if (structor_kind > clang::CXXCtorType::Ctor_Unified)
+ return {};
+
+ return ClangToItaniumCtorKind(
+ static_cast<clang::CXXCtorType>(structor_kind));
+ }
+
+ if (structor_kind > clang::CXXDtorType::Dtor_Unified)
+ return {};
+
+ return ClangToItaniumDtorKind(static_cast<clang::CXXDtorType>(structor_kind));
+}
+
+llvm::Expected<DWARFDIE>
+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);
+
+ m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+ if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
+ return IterationAction::Continue;
+
+ found = entry;
+ return IterationAction::Stop;
+ });
+
+ return found;
+ };
+
+ DWARFDIE definition = do_lookup(label.lookup_name);
+ if (definition.IsValid())
+ return definition;
+
+ // This is not a structor lookup. Nothing else to be done here.
+ if (label.discriminator.empty())
+ return llvm::createStringError(
+ "no definition DIE found in this SymbolFile");
+
+ // We're doing a structor lookup. Maybe we didn't find the structor variant
+ // because the complete object structor was aliased to the base object
+ // structor. Try finding the alias instead.
+ //
+ // TODO: there are other reasons for why a subprogram definition might be
+ // missing. Ideally DWARF would tell us more details about which structor
+ // variant a DIE corresponds to and whether it's an alias.
+ auto subst_or_err =
+ CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(
+ label.lookup_name);
+ if (!subst_or_err)
+ return subst_or_err.takeError();
+
+ definition = do_lookup(*subst_or_err);
+
+ if (!definition.IsValid())
+ return llvm::createStringError(
+ "failed to find definition DIE for structor alias in fallback lookup");
return definition;
}
llvm::Expected<SymbolContext>
-SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
+SymbolFileDWARF::ResolveFunctionCallLabel(FunctionCallLabel &label) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ if (!label.discriminator.empty()) {
+ llvm::StringRef from = label.discriminator[0] == 'C' ? "C4" : "D4";
+
+ llvm::StringRef variant = GetItaniumCtorDtorVariant(label.discriminator);
+ if (variant.empty())
+ return llvm::createStringError(
+ "failed to get Itanium variant for discriminator");
+
+ if (from == variant)
+ return llvm::createStringError(
+ "tried substituting unified structor variant into label");
+
+ // If we failed to substitute unified mangled name, don't try to do a lookup
+ // using the unified name because there may be multiple definitions for it
+ // in the index, and we wouldn't know which one to choose.
+ auto subst_or_err = CPlusPlusLanguage::SubstituteStructor_ItaniumMangle(
+ label.lookup_name, from, variant);
+ if (!subst_or_err)
+ return llvm::joinErrors(
+ llvm::createStringError(llvm::formatv(
+ "failed to substitute {0} for {1} in mangled name {2}:", from,
+ variant, label.lookup_name)),
+ subst_or_err.takeError());
+
+ if (!*subst_or_err)
+ return llvm::createStringError(
+ llvm::formatv("got invalid substituted mangled named (substituted "
+ "{0} for {1} in mangled name {2})",
+ from, variant, label.lookup_name));
+
+ label.lookup_name = subst_or_err->GetStringRef();
+ }
+
DWARFDIE die = GetDIE(label.symbol_id);
if (!die.IsValid())
return llvm::createStringError(
@@ -2520,11 +2639,13 @@ SymbolFileDWARF::ResolveFunctionCallLabel(const FunctionCallLabel &label) {
// Label was created using a declaration DIE. Need to fetch the definition
// to resolve the function call.
if (die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0)) {
- auto definition = FindFunctionDefinition(label);
- if (!definition)
- return llvm::createStringError("failed to find definition DIE");
+ auto die_or_err = FindFunctionDefinition(label, die);
+ if (!die_or_err)
+ return llvm::joinErrors(
+ llvm::createStringError("failed to find definition DIE:"),
+ die_or_err.takeError());
- die = std::move(definition);
+ die = std::move(*die_or_err);
}
SymbolContextList sc_list;
@@ -4502,9 +4623,8 @@ void SymbolFileDWARF::GetCompileOptions(
}
}
-std::pair<uint32_t, uint32_t> SymbolFileDWARF::GetDwoFileCounts() {
- uint32_t total_dwo_count = 0;
- uint32_t loaded_dwo_count = 0;
+DWOStats SymbolFileDWARF::GetDwoStats() {
+ DWOStats stats;
DWARFDebugInfo &info = DebugInfo();
const size_t num_cus = info.GetNumUnits();
@@ -4517,16 +4637,21 @@ std::pair<uint32_t, uint32_t> SymbolFileDWARF::GetDwoFileCounts() {
if (!dwarf_cu->GetDWOId().has_value())
continue;
- total_dwo_count++;
+ stats.dwo_file_count++;
// If we have a DWO symbol file, that means we were able to successfully
// load it.
SymbolFile *dwo_symfile =
dwarf_cu->GetDwoSymbolFile(/*load_all_debug_info=*/false);
if (dwo_symfile) {
- loaded_dwo_count++;
+ stats.loaded_dwo_file_count++;
}
+
+ // Check if this unit has a DWO load error, false by default.
+ const Status &dwo_error = dwarf_cu->GetDwoError();
+ if (dwo_error.Fail())
+ stats.dwo_error_count++;
}
- return {loaded_dwo_count, total_dwo_count};
+ return stats;
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index d7db8a3c0869..85306d8b4fb5 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -283,10 +283,11 @@ public:
bool GetSeparateDebugInfo(StructuredData::Dictionary &d, bool errors_only,
bool load_all_debug_info = false) override;
- // Gets a pair of loaded and total dwo file counts.
- // For split-dwarf files, this reports the counts for successfully loaded DWO
- // CUs and total DWO CUs. For non-split-dwarf files, this reports 0 for both.
- std::pair<uint32_t, uint32_t> GetDwoFileCounts() override;
+ /// Gets statistics about dwo files associated with this symbol file.
+ /// For split-dwarf files, this reports the counts for successfully loaded DWO
+ /// CUs, total DWO CUs, and the number of DWO CUs with loading errors.
+ /// For non-split-dwarf files, this reports 0 for all.
+ DWOStats GetDwoStats() override;
DWARFContext &GetDWARFContext() { return m_context; }
@@ -378,7 +379,9 @@ private:
/// SymbolFile.
///
/// \returns A valid definition DIE on success.
- DWARFDIE FindFunctionDefinition(const FunctionCallLabel &label);
+ llvm::Expected<DWARFDIE>
+ FindFunctionDefinition(const FunctionCallLabel &label,
+ const DWARFDIE &declaration);
protected:
SymbolFileDWARF(const SymbolFileDWARF &) = delete;
@@ -445,7 +448,7 @@ protected:
DIEArray &&variable_dies);
llvm::Expected<SymbolContext>
- ResolveFunctionCallLabel(const FunctionCallLabel &label) override;
+ ResolveFunctionCallLabel(FunctionCallLabel &label) override;
// Given a die_offset, figure out the symbol context representing that die.
bool ResolveFunction(const DWARFDIE &die, bool include_inlines,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index 9d7452a1988f..8b8229a7020c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1603,8 +1603,8 @@ void SymbolFileDWARFDebugMap::GetCompileOptions(
});
}
-llvm::Expected<SymbolContext> SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(
- const FunctionCallLabel &label) {
+llvm::Expected<SymbolContext>
+SymbolFileDWARFDebugMap::ResolveFunctionCallLabel(FunctionCallLabel &label) {
const uint64_t oso_idx = GetOSOIndexFromUserID(label.symbol_id);
SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx);
if (!oso_dwarf)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index e1f1df23951c..bce1ed2671af 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -145,7 +145,7 @@ public:
GetCompileOptions(std::unordered_map<lldb::CompUnitSP, Args> &args) override;
llvm::Expected<SymbolContext>
- ResolveFunctionCallLabel(const FunctionCallLabel &label) override;
+ ResolveFunctionCallLabel(FunctionCallLabel &label) override;
protected:
enum { kHaveInitializedOSOs = (1 << 0), kNumFlags };
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 709281cb3270..933c4361d93d 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -1169,6 +1169,7 @@ clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id,
clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) {
clang::QualType element_type = GetOrCreateType(ar.ElementType);
+ TypeSystemClang::RequireCompleteType(ToCompilerType(element_type));
SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
m_clang.GetSymbolFile()->GetBackingSymbolFile());
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 112eb06e462f..e99c585d7eb1 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1624,6 +1624,8 @@ size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {
for (uint64_t uid : remove_uids) {
m_inline_sites.erase(uid);
}
+
+ func.GetBlock(false).SetBlockInfoHasBeenParsed(true, true);
return count;
}
@@ -1655,22 +1657,62 @@ void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
clang->GetNativePDBParser()->Dump(s, filter);
}
-void SymbolFileNativePDB::CacheFunctionNames() {
- if (!m_func_full_names.IsEmpty())
+void SymbolFileNativePDB::CacheGlobalBaseNames() {
+ if (!m_func_full_names.IsEmpty() || !m_global_variable_base_names.IsEmpty())
return;
// (segment, code offset) -> gid
- std::map<std::pair<uint16_t, uint32_t>, uint32_t> addr_ids;
+ std::map<std::pair<uint16_t, uint32_t>, uint32_t> func_addr_ids;
- // First, find all function references in the globals table.
+ // First, look through all items in the globals table.
for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
- CVSymbol ref_sym = m_index->symrecords().readRecord(gid);
- auto kind = ref_sym.kind();
+ CVSymbol sym = m_index->symrecords().readRecord(gid);
+ auto kind = sym.kind();
+
+ // If this is a global variable, we only need to look at the name
+ llvm::StringRef name;
+ switch (kind) {
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32: {
+ DataSym data =
+ llvm::cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym));
+ name = data.Name;
+ break;
+ }
+ case SymbolKind::S_GTHREAD32:
+ case SymbolKind::S_LTHREAD32: {
+ ThreadLocalDataSym data = llvm::cantFail(
+ SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym));
+ name = data.Name;
+ break;
+ }
+ case SymbolKind::S_CONSTANT: {
+ ConstantSym data =
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(sym));
+ name = data.Name;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (!name.empty()) {
+ llvm::StringRef base = MSVCUndecoratedNameParser::DropScope(name);
+ if (base.empty())
+ base = name;
+
+ m_global_variable_base_names.Append(ConstString(base), gid);
+ continue;
+ }
+
if (kind != S_PROCREF && kind != S_LPROCREF)
continue;
+ // For functions, we need to follow the reference to the procedure and look
+ // at the type
+
ProcRefSym ref =
- llvm::cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(ref_sym));
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(sym));
if (ref.Name.empty())
continue;
@@ -1694,7 +1736,7 @@ void SymbolFileNativePDB::CacheFunctionNames() {
// The function/procedure symbol only contains the demangled name.
// The mangled names are in the publics table. Save the address of this
// function to lookup the mangled name later.
- addr_ids.emplace(std::make_pair(proc.Segment, proc.CodeOffset), gid);
+ func_addr_ids.emplace(std::make_pair(proc.Segment, proc.CodeOffset), gid);
llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(proc.Name);
if (basename.empty())
@@ -1729,43 +1771,47 @@ void SymbolFileNativePDB::CacheFunctionNames() {
continue;
// Check if this symbol is for one of our functions.
- auto it = addr_ids.find({pub.Segment, pub.Offset});
- if (it != addr_ids.end())
+ auto it = func_addr_ids.find({pub.Segment, pub.Offset});
+ if (it != func_addr_ids.end())
m_func_full_names.Append(ConstString(pub.Name), it->second);
}
// Sort them before value searching is working properly.
- m_func_full_names.Sort();
+ m_func_full_names.Sort(std::less<uint32_t>());
m_func_full_names.SizeToFit();
- m_func_method_names.Sort();
+ m_func_method_names.Sort(std::less<uint32_t>());
m_func_method_names.SizeToFit();
- m_func_base_names.Sort();
+ m_func_base_names.Sort(std::less<uint32_t>());
m_func_base_names.SizeToFit();
+ m_global_variable_base_names.Sort(std::less<uint32_t>());
+ m_global_variable_base_names.SizeToFit();
}
void SymbolFileNativePDB::FindGlobalVariables(
ConstString name, const CompilerDeclContext &parent_decl_ctx,
uint32_t max_matches, VariableList &variables) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
- std::vector<SymbolAndOffset> results = m_index->globals().findRecordsByName(
- name.GetStringRef(), m_index->symrecords());
- for (const SymbolAndOffset &result : results) {
- switch (result.second.kind()) {
- case SymbolKind::S_GDATA32:
- case SymbolKind::S_LDATA32:
- case SymbolKind::S_GTHREAD32:
- case SymbolKind::S_LTHREAD32:
- case SymbolKind::S_CONSTANT: {
- PdbGlobalSymId global(result.first, false);
- if (VariableSP var = GetOrCreateGlobalVariable(global))
- variables.AddVariable(var);
- break;
- }
- default:
+ CacheGlobalBaseNames();
+
+ std::vector<uint32_t> results;
+ m_global_variable_base_names.GetValues(name, results);
+
+ size_t n_matches = 0;
+ for (uint32_t gid : results) {
+ PdbGlobalSymId global(gid, false);
+
+ if (parent_decl_ctx.IsValid() &&
+ GetDeclContextContainingUID(toOpaqueUid(global)) != parent_decl_ctx)
continue;
- }
+
+ VariableSP var = GetOrCreateGlobalVariable(global);
+ if (!var)
+ continue;
+ variables.AddVariable(var);
+
+ if (++n_matches >= max_matches)
+ break;
}
}
@@ -1783,7 +1829,7 @@ void SymbolFileNativePDB::FindFunctions(
name_type_mask & eFunctionNameTypeBase ||
name_type_mask & eFunctionNameTypeMethod))
return;
- CacheFunctionNames();
+ CacheGlobalBaseNames();
std::set<uint32_t> resolved_ids; // avoid duplicate lookups
auto resolve_from = [&](UniqueCStringMap<uint32_t> &Names) {
@@ -2426,7 +2472,7 @@ void SymbolFileNativePDB::BuildParentMap() {
// After calling Append(), the type-name map needs to be sorted again to be
// able to look up a type by its name.
- m_type_base_names.Sort();
+ m_type_base_names.Sort(std::less<uint32_t>());
// Now that we know the forward -> full mapping of all type indices, we can
// re-write all the indices. At the end of this process, we want a mapping
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index cfa00416d967..095b40c72c52 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -260,7 +260,10 @@ private:
std::vector<CompilerContext> GetContextForType(llvm::codeview::TypeIndex ti);
- void CacheFunctionNames();
+ /// Caches the basenames of symbols found in the globals stream.
+ ///
+ /// This includes functions and global variables
+ void CacheGlobalBaseNames();
void CacheUdtDeclarations();
llvm::Expected<Declaration> ResolveUdtDeclaration(PdbTypeSymId type_id);
@@ -306,6 +309,9 @@ private:
lldb_private::UniqueCStringMap<uint32_t> m_func_base_names;
/// method basename -> Global ID(s)
lldb_private::UniqueCStringMap<uint32_t> m_func_method_names;
+
+ /// global variable basename -> Global ID(s)
+ lldb_private::UniqueCStringMap<uint32_t> m_global_variable_base_names;
};
} // namespace npdb
diff --git a/lldb/source/Protocol/MCP/CMakeLists.txt b/lldb/source/Protocol/MCP/CMakeLists.txt
index a73e7e6a7cab..5258cb61a7d1 100644
--- a/lldb/source/Protocol/MCP/CMakeLists.txt
+++ b/lldb/source/Protocol/MCP/CMakeLists.txt
@@ -3,10 +3,12 @@ add_lldb_library(lldbProtocolMCP NO_PLUGIN_DEPENDENCIES
Protocol.cpp
Server.cpp
Tool.cpp
+ Transport.cpp
LINK_COMPONENTS
Support
LINK_LIBS
+ lldbHost
lldbUtility
)
diff --git a/lldb/source/Protocol/MCP/Protocol.cpp b/lldb/source/Protocol/MCP/Protocol.cpp
index 65ddfaee7016..0988f456adc2 100644
--- a/lldb/source/Protocol/MCP/Protocol.cpp
+++ b/lldb/source/Protocol/MCP/Protocol.cpp
@@ -167,32 +167,6 @@ bool operator==(const Notification &a, const Notification &b) {
return a.method == b.method && a.params == b.params;
}
-llvm::json::Value toJSON(const ToolCapability &TC) {
- return llvm::json::Object{{"listChanged", TC.listChanged}};
-}
-
-bool fromJSON(const llvm::json::Value &V, ToolCapability &TC,
- llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("listChanged", TC.listChanged);
-}
-
-llvm::json::Value toJSON(const ResourceCapability &RC) {
- return llvm::json::Object{{"listChanged", RC.listChanged},
- {"subscribe", RC.subscribe}};
-}
-
-bool fromJSON(const llvm::json::Value &V, ResourceCapability &RC,
- llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("listChanged", RC.listChanged) &&
- O.map("subscribe", RC.subscribe);
-}
-
-llvm::json::Value toJSON(const Capabilities &C) {
- return llvm::json::Object{{"tools", C.tools}, {"resources", C.resources}};
-}
-
bool fromJSON(const llvm::json::Value &V, Resource &R, llvm::json::Path P) {
llvm::json::ObjectMapper O(V, P);
return O && O.map("uri", R.uri) && O.map("name", R.name) &&
@@ -209,30 +183,25 @@ llvm::json::Value toJSON(const Resource &R) {
return Result;
}
-bool fromJSON(const llvm::json::Value &V, Capabilities &C, llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("tools", C.tools);
-}
-
-llvm::json::Value toJSON(const ResourceContents &RC) {
+llvm::json::Value toJSON(const TextResourceContents &RC) {
llvm::json::Object Result{{"uri", RC.uri}, {"text", RC.text}};
if (!RC.mimeType.empty())
Result.insert({"mimeType", RC.mimeType});
return Result;
}
-bool fromJSON(const llvm::json::Value &V, ResourceContents &RC,
+bool fromJSON(const llvm::json::Value &V, TextResourceContents &RC,
llvm::json::Path P) {
llvm::json::ObjectMapper O(V, P);
return O && O.map("uri", RC.uri) && O.map("text", RC.text) &&
O.mapOptional("mimeType", RC.mimeType);
}
-llvm::json::Value toJSON(const ResourceResult &RR) {
+llvm::json::Value toJSON(const ReadResourceResult &RR) {
return llvm::json::Object{{"contents", RR.contents}};
}
-bool fromJSON(const llvm::json::Value &V, ResourceResult &RR,
+bool fromJSON(const llvm::json::Value &V, ReadResourceResult &RR,
llvm::json::Path P) {
llvm::json::ObjectMapper O(V, P);
return O && O.map("contents", RR.contents);
@@ -247,15 +216,6 @@ bool fromJSON(const llvm::json::Value &V, TextContent &TC, llvm::json::Path P) {
return O && O.map("text", TC.text);
}
-llvm::json::Value toJSON(const TextResult &TR) {
- return llvm::json::Object{{"content", TR.content}, {"isError", TR.isError}};
-}
-
-bool fromJSON(const llvm::json::Value &V, TextResult &TR, llvm::json::Path P) {
- llvm::json::ObjectMapper O(V, P);
- return O && O.map("content", TR.content) && O.map("isError", TR.isError);
-}
-
llvm::json::Value toJSON(const ToolDefinition &TD) {
llvm::json::Object Result{{"name", TD.name}};
if (!TD.description.empty())
@@ -325,4 +285,159 @@ bool fromJSON(const llvm::json::Value &V, Message &M, llvm::json::Path P) {
return false;
}
+json::Value toJSON(const Implementation &I) {
+ json::Object result{{"name", I.name}, {"version", I.version}};
+
+ if (!I.title.empty())
+ result.insert({"title", I.title});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, Implementation &I, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("name", I.name) && O.mapOptional("title", I.title) &&
+ O.mapOptional("version", I.version);
+}
+
+json::Value toJSON(const ClientCapabilities &C) { return json::Object{}; }
+
+bool fromJSON(const json::Value &, ClientCapabilities &, json::Path) {
+ return true;
+}
+
+json::Value toJSON(const ServerCapabilities &C) {
+ json::Object result{};
+
+ if (C.supportsToolsList)
+ result.insert({"tools", json::Object{{"listChanged", true}}});
+
+ if (C.supportsResourcesList || C.supportsResourcesSubscribe) {
+ json::Object resources;
+ if (C.supportsResourcesList)
+ resources.insert({"listChanged", true});
+ if (C.supportsResourcesSubscribe)
+ resources.insert({"subscribe", true});
+ result.insert({"resources", std::move(resources)});
+ }
+
+ if (C.supportsCompletions)
+ result.insert({"completions", json::Object{}});
+
+ if (C.supportsLogging)
+ result.insert({"logging", json::Object{}});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, ServerCapabilities &C, json::Path P) {
+ const json::Object *O = V.getAsObject();
+ if (!O) {
+ P.report("expected object");
+ return false;
+ }
+
+ if (O->find("tools") != O->end())
+ C.supportsToolsList = true;
+
+ return true;
+}
+
+json::Value toJSON(const InitializeParams &P) {
+ return json::Object{
+ {"protocolVersion", P.protocolVersion},
+ {"capabilities", P.capabilities},
+ {"clientInfo", P.clientInfo},
+ };
+}
+
+bool fromJSON(const json::Value &V, InitializeParams &I, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("protocolVersion", I.protocolVersion) &&
+ O.map("capabilities", I.capabilities) &&
+ O.map("clientInfo", I.clientInfo);
+}
+
+json::Value toJSON(const InitializeResult &R) {
+ json::Object result{{"protocolVersion", R.protocolVersion},
+ {"capabilities", R.capabilities},
+ {"serverInfo", R.serverInfo}};
+
+ if (!R.instructions.empty())
+ result.insert({"instructions", R.instructions});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, InitializeResult &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("protocolVersion", R.protocolVersion) &&
+ O.map("capabilities", R.capabilities) &&
+ O.map("serverInfo", R.serverInfo) &&
+ O.mapOptional("instructions", R.instructions);
+}
+
+json::Value toJSON(const ListToolsResult &R) {
+ return json::Object{{"tools", R.tools}};
+}
+
+bool fromJSON(const json::Value &V, ListToolsResult &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("tools", R.tools);
+}
+
+json::Value toJSON(const CallToolResult &R) {
+ json::Object result{{"content", R.content}};
+
+ if (R.isError)
+ result.insert({"isError", R.isError});
+ if (R.structuredContent)
+ result.insert({"structuredContent", *R.structuredContent});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, CallToolResult &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("content", R.content) &&
+ O.mapOptional("isError", R.isError) &&
+ mapRaw(V, "structuredContent", R.structuredContent, P);
+}
+
+json::Value toJSON(const CallToolParams &R) {
+ json::Object result{{"name", R.name}};
+
+ if (R.arguments)
+ result.insert({"arguments", *R.arguments});
+
+ return result;
+}
+
+bool fromJSON(const json::Value &V, CallToolParams &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("name", R.name) && mapRaw(V, "arguments", R.arguments, P);
+}
+
+json::Value toJSON(const ReadResourceParams &R) {
+ return json::Object{{"uri", R.uri}};
+}
+
+bool fromJSON(const json::Value &V, ReadResourceParams &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("uri", R.uri);
+}
+
+json::Value toJSON(const ListResourcesResult &R) {
+ return json::Object{{"resources", R.resources}};
+}
+
+bool fromJSON(const json::Value &V, ListResourcesResult &R, json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("resources", R.resources);
+}
+
+json::Value toJSON(const Void &R) { return json::Object{}; }
+
+bool fromJSON(const json::Value &V, Void &R, json::Path P) { return true; }
+
} // namespace lldb_protocol::mcp
diff --git a/lldb/source/Protocol/MCP/Server.cpp b/lldb/source/Protocol/MCP/Server.cpp
index a9c1482e3e37..f3489c620832 100644
--- a/lldb/source/Protocol/MCP/Server.cpp
+++ b/lldb/source/Protocol/MCP/Server.cpp
@@ -7,13 +7,115 @@
//===----------------------------------------------------------------------===//
#include "lldb/Protocol/MCP/Server.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/JSONTransport.h"
#include "lldb/Protocol/MCP/MCPError.h"
+#include "lldb/Protocol/MCP/Protocol.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/Signals.h"
-using namespace lldb_protocol::mcp;
using namespace llvm;
+using namespace lldb_private;
+using namespace lldb_protocol::mcp;
+
+ServerInfoHandle::ServerInfoHandle() : ServerInfoHandle("") {}
+
+ServerInfoHandle::ServerInfoHandle(StringRef filename) : m_filename(filename) {
+ if (!m_filename.empty())
+ sys::RemoveFileOnSignal(m_filename);
+}
+
+ServerInfoHandle::~ServerInfoHandle() {
+ if (m_filename.empty())
+ return;
+
+ sys::fs::remove(m_filename);
+ sys::DontRemoveFileOnSignal(m_filename);
+ m_filename.clear();
+}
+
+ServerInfoHandle::ServerInfoHandle(ServerInfoHandle &&other)
+ : m_filename(other.m_filename) {
+ *this = std::move(other);
+}
+
+ServerInfoHandle &
+ServerInfoHandle::operator=(ServerInfoHandle &&other) noexcept {
+ m_filename = other.m_filename;
+ other.m_filename.clear();
+ return *this;
+}
+
+json::Value lldb_protocol::mcp::toJSON(const ServerInfo &SM) {
+ return json::Object{{"connection_uri", SM.connection_uri}};
+}
+
+bool lldb_protocol::mcp::fromJSON(const json::Value &V, ServerInfo &SM,
+ json::Path P) {
+ json::ObjectMapper O(V, P);
+ return O && O.map("connection_uri", SM.connection_uri);
+}
-Server::Server(std::string name, std::string version)
- : m_name(std::move(name)), m_version(std::move(version)) {
+Expected<ServerInfoHandle> ServerInfo::Write(const ServerInfo &info) {
+ std::string buf = formatv("{0}", toJSON(info)).str();
+ size_t num_bytes = buf.size();
+
+ FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir();
+
+ Status error(sys::fs::create_directory(user_lldb_dir.GetPath()));
+ if (error.Fail())
+ return error.takeError();
+
+ FileSpec mcp_registry_entry_path = user_lldb_dir.CopyByAppendingPathComponent(
+ formatv("lldb-mcp-{0}.json", getpid()).str());
+
+ const File::OpenOptions flags = File::eOpenOptionWriteOnly |
+ File::eOpenOptionCanCreate |
+ File::eOpenOptionTruncate;
+ Expected<lldb::FileUP> file =
+ FileSystem::Instance().Open(mcp_registry_entry_path, flags);
+ if (!file)
+ return file.takeError();
+ if (llvm::Error error = (*file)->Write(buf.data(), num_bytes).takeError())
+ return error;
+ return ServerInfoHandle{mcp_registry_entry_path.GetPath()};
+}
+
+Expected<std::vector<ServerInfo>> ServerInfo::Load() {
+ namespace path = llvm::sys::path;
+ FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir();
+ FileSystem &fs = FileSystem::Instance();
+ std::error_code EC;
+ vfs::directory_iterator it = fs.DirBegin(user_lldb_dir, EC);
+ vfs::directory_iterator end;
+ std::vector<ServerInfo> infos;
+ for (; it != end && !EC; it.increment(EC)) {
+ auto &entry = *it;
+ auto path = entry.path();
+ auto name = path::filename(path);
+ if (!name.starts_with("lldb-mcp-") || !name.ends_with(".json"))
+ continue;
+
+ auto buffer = fs.CreateDataBuffer(path);
+ auto info = json::parse<ServerInfo>(toStringRef(buffer->GetData()));
+ if (!info)
+ return info.takeError();
+
+ infos.emplace_back(std::move(*info));
+ }
+
+ return infos;
+}
+
+Server::Server(std::string name, std::string version,
+ std::unique_ptr<MCPTransport> transport_up,
+ lldb_private::MainLoop &loop)
+ : m_name(std::move(name)), m_version(std::move(version)),
+ m_transport_up(std::move(transport_up)), m_loop(loop) {
AddRequestHandlers();
}
@@ -30,7 +132,7 @@ void Server::AddRequestHandlers() {
this, std::placeholders::_1));
}
-llvm::Expected<Response> Server::Handle(Request request) {
+llvm::Expected<Response> Server::Handle(const Request &request) {
auto it = m_request_handlers.find(request.method);
if (it != m_request_handlers.end()) {
llvm::Expected<Response> response = it->second(request);
@@ -44,7 +146,7 @@ llvm::Expected<Response> Server::Handle(Request request) {
llvm::formatv("no handler for request: {0}", request.method).str());
}
-void Server::Handle(Notification notification) {
+void Server::Handle(const Notification &notification) {
auto it = m_notification_handlers.find(notification.method);
if (it != m_notification_handlers.end()) {
it->second(notification);
@@ -52,49 +154,7 @@ void Server::Handle(Notification notification) {
}
}
-llvm::Expected<std::optional<Message>>
-Server::HandleData(llvm::StringRef data) {
- auto message = llvm::json::parse<Message>(/*JSON=*/data);
- if (!message)
- return message.takeError();
-
- if (const Request *request = std::get_if<Request>(&(*message))) {
- llvm::Expected<Response> response = Handle(*request);
-
- // Handle failures by converting them into an Error message.
- if (!response) {
- Error protocol_error;
- llvm::handleAllErrors(
- response.takeError(),
- [&](const MCPError &err) { protocol_error = err.toProtocolError(); },
- [&](const llvm::ErrorInfoBase &err) {
- protocol_error.code = MCPError::kInternalError;
- protocol_error.message = err.message();
- });
- Response error_response;
- error_response.id = request->id;
- error_response.result = std::move(protocol_error);
- return error_response;
- }
-
- return *response;
- }
-
- if (const Notification *notification =
- std::get_if<Notification>(&(*message))) {
- Handle(*notification);
- return std::nullopt;
- }
-
- if (std::get_if<Response>(&(*message)))
- return llvm::createStringError("unexpected MCP message: response");
-
- llvm_unreachable("all message types handled");
-}
-
void Server::AddTool(std::unique_ptr<Tool> tool) {
- std::lock_guard<std::mutex> guard(m_mutex);
-
if (!tool)
return;
m_tools[tool->GetName()] = std::move(tool);
@@ -102,42 +162,39 @@ void Server::AddTool(std::unique_ptr<Tool> tool) {
void Server::AddResourceProvider(
std::unique_ptr<ResourceProvider> resource_provider) {
- std::lock_guard<std::mutex> guard(m_mutex);
-
if (!resource_provider)
return;
m_resource_providers.push_back(std::move(resource_provider));
}
void Server::AddRequestHandler(llvm::StringRef method, RequestHandler handler) {
- std::lock_guard<std::mutex> guard(m_mutex);
m_request_handlers[method] = std::move(handler);
}
void Server::AddNotificationHandler(llvm::StringRef method,
NotificationHandler handler) {
- std::lock_guard<std::mutex> guard(m_mutex);
m_notification_handlers[method] = std::move(handler);
}
llvm::Expected<Response> Server::InitializeHandler(const Request &request) {
Response response;
- response.result = llvm::json::Object{
- {"protocolVersion", mcp::kProtocolVersion},
- {"capabilities", GetCapabilities()},
- {"serverInfo",
- llvm::json::Object{{"name", m_name}, {"version", m_version}}}};
+ InitializeResult result;
+ result.protocolVersion = mcp::kProtocolVersion;
+ result.capabilities = GetCapabilities();
+ result.serverInfo.name = m_name;
+ result.serverInfo.version = m_version;
+ response.result = std::move(result);
return response;
}
llvm::Expected<Response> Server::ToolsListHandler(const Request &request) {
Response response;
- llvm::json::Array tools;
+ ListToolsResult result;
for (const auto &tool : m_tools)
- tools.emplace_back(toJSON(tool.second->GetDefinition()));
+ result.tools.emplace_back(tool.second->GetDefinition());
- response.result = llvm::json::Object{{"tools", std::move(tools)}};
+ response.result = std::move(result);
return response;
}
@@ -147,16 +204,12 @@ llvm::Expected<Response> Server::ToolsCallHandler(const Request &request) {
if (!request.params)
return llvm::createStringError("no tool parameters");
+ CallToolParams params;
+ json::Path::Root root("params");
+ if (!fromJSON(request.params, params, root))
+ return root.getError();
- const json::Object *param_obj = request.params->getAsObject();
- if (!param_obj)
- return llvm::createStringError("no tool parameters");
-
- const json::Value *name = param_obj->get("name");
- if (!name)
- return llvm::createStringError("no tool name");
-
- llvm::StringRef tool_name = name->getAsString().value_or("");
+ llvm::StringRef tool_name = params.name;
if (tool_name.empty())
return llvm::createStringError("no tool name");
@@ -165,10 +218,10 @@ llvm::Expected<Response> Server::ToolsCallHandler(const Request &request) {
return llvm::createStringError(llvm::formatv("no tool \"{0}\"", tool_name));
ToolArguments tool_args;
- if (const json::Value *args = param_obj->get("arguments"))
- tool_args = *args;
+ if (params.arguments)
+ tool_args = *params.arguments;
- llvm::Expected<TextResult> text_result = it->second->Call(tool_args);
+ llvm::Expected<CallToolResult> text_result = it->second->Call(tool_args);
if (!text_result)
return text_result.takeError();
@@ -180,15 +233,13 @@ llvm::Expected<Response> Server::ToolsCallHandler(const Request &request) {
llvm::Expected<Response> Server::ResourcesListHandler(const Request &request) {
Response response;
- llvm::json::Array resources;
-
- std::lock_guard<std::mutex> guard(m_mutex);
+ ListResourcesResult result;
for (std::unique_ptr<ResourceProvider> &resource_provider_up :
- m_resource_providers) {
+ m_resource_providers)
for (const Resource &resource : resource_provider_up->GetResources())
- resources.push_back(resource);
- }
- response.result = llvm::json::Object{{"resources", std::move(resources)}};
+ result.resources.push_back(resource);
+
+ response.result = std::move(result);
return response;
}
@@ -199,22 +250,18 @@ llvm::Expected<Response> Server::ResourcesReadHandler(const Request &request) {
if (!request.params)
return llvm::createStringError("no resource parameters");
- const json::Object *param_obj = request.params->getAsObject();
- if (!param_obj)
- return llvm::createStringError("no resource parameters");
-
- const json::Value *uri = param_obj->get("uri");
- if (!uri)
- return llvm::createStringError("no resource uri");
+ ReadResourceParams params;
+ json::Path::Root root("params");
+ if (!fromJSON(request.params, params, root))
+ return root.getError();
- llvm::StringRef uri_str = uri->getAsString().value_or("");
+ llvm::StringRef uri_str = params.uri;
if (uri_str.empty())
return llvm::createStringError("no resource uri");
- std::lock_guard<std::mutex> guard(m_mutex);
for (std::unique_ptr<ResourceProvider> &resource_provider_up :
m_resource_providers) {
- llvm::Expected<ResourceResult> result =
+ llvm::Expected<ReadResourceResult> result =
resource_provider_up->ReadResource(uri_str);
if (result.errorIsA<UnsupportedURI>()) {
llvm::consumeError(result.takeError());
@@ -232,3 +279,71 @@ llvm::Expected<Response> Server::ResourcesReadHandler(const Request &request) {
llvm::formatv("no resource handler for uri: {0}", uri_str).str(),
MCPError::kResourceNotFound);
}
+
+ServerCapabilities Server::GetCapabilities() {
+ lldb_protocol::mcp::ServerCapabilities capabilities;
+ capabilities.supportsToolsList = true;
+ // FIXME: Support sending notifications when a debugger/target are
+ // added/removed.
+ capabilities.supportsResourcesList = false;
+ return capabilities;
+}
+
+llvm::Error Server::Run() {
+ auto handle = m_transport_up->RegisterMessageHandler(m_loop, *this);
+ if (!handle)
+ return handle.takeError();
+
+ lldb_private::Status status = m_loop.Run();
+ if (status.Fail())
+ return status.takeError();
+
+ return llvm::Error::success();
+}
+
+void Server::Received(const Request &request) {
+ auto SendResponse = [this](const Response &response) {
+ if (llvm::Error error = m_transport_up->Send(response))
+ m_transport_up->Log(llvm::toString(std::move(error)));
+ };
+
+ llvm::Expected<Response> response = Handle(request);
+ if (response)
+ return SendResponse(*response);
+
+ lldb_protocol::mcp::Error protocol_error;
+ llvm::handleAllErrors(
+ response.takeError(),
+ [&](const MCPError &err) { protocol_error = err.toProtocolError(); },
+ [&](const llvm::ErrorInfoBase &err) {
+ protocol_error.code = MCPError::kInternalError;
+ protocol_error.message = err.message();
+ });
+ Response error_response;
+ error_response.id = request.id;
+ error_response.result = std::move(protocol_error);
+ SendResponse(error_response);
+}
+
+void Server::Received(const Response &response) {
+ m_transport_up->Log("unexpected MCP message: response");
+}
+
+void Server::Received(const Notification &notification) {
+ Handle(notification);
+}
+
+void Server::OnError(llvm::Error error) {
+ m_transport_up->Log(llvm::toString(std::move(error)));
+ TerminateLoop();
+}
+
+void Server::OnClosed() {
+ m_transport_up->Log("EOF");
+ TerminateLoop();
+}
+
+void Server::TerminateLoop() {
+ m_loop.AddPendingCallback(
+ [](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
+}
diff --git a/lldb/source/Protocol/MCP/Transport.cpp b/lldb/source/Protocol/MCP/Transport.cpp
new file mode 100644
index 000000000000..cccdc3b5bd65
--- /dev/null
+++ b/lldb/source/Protocol/MCP/Transport.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/Protocol/MCP/Transport.h"
+#include "llvm/ADT/StringRef.h"
+#include <utility>
+
+using namespace lldb_protocol::mcp;
+using namespace llvm;
+
+Transport::Transport(lldb::IOObjectSP in, lldb::IOObjectSP out,
+ LogCallback log_callback)
+ : JSONRPCTransport(in, out), m_log_callback(std::move(log_callback)) {}
+
+void Transport::Log(StringRef message) {
+ if (m_log_callback)
+ m_log_callback(message);
+}
diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp
index 7efce2a03550..9a79b3c62762 100644
--- a/lldb/source/Symbol/ObjectFile.cpp
+++ b/lldb/source/Symbol/ObjectFile.cpp
@@ -663,7 +663,7 @@ ObjectFile::GetDWARFSectionTypeFromName(llvm::StringRef name) {
.Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo)
.Case("str", eSectionTypeDWARFDebugStr)
.Case("str.dwo", eSectionTypeDWARFDebugStrDwo)
- .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets)
+ .Cases("str_offsets", "str_offs", eSectionTypeDWARFDebugStrOffsets)
.Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo)
.Case("tu_index", eSectionTypeDWARFDebugTuIndex)
.Case("types", eSectionTypeDWARFDebugTypes)
diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp
index b86fef6bf03e..3c5107434014 100644
--- a/lldb/source/Target/ABI.cpp
+++ b/lldb/source/Target/ABI.cpp
@@ -232,13 +232,13 @@ bool ABI::GetFallbackRegisterLocation(
}
std::unique_ptr<llvm::MCRegisterInfo> ABI::MakeMCRegisterInfo(const ArchSpec &arch) {
- std::string triple = arch.GetTriple().getTriple();
+ const llvm::Triple &triple = arch.GetTriple();
std::string lookup_error;
const llvm::Target *target =
llvm::TargetRegistry::lookupTarget(triple, lookup_error);
if (!target) {
LLDB_LOG(GetLog(LLDBLog::Process),
- "Failed to create an llvm target for {0}: {1}", triple,
+ "Failed to create an llvm target for {0}: {1}", triple.str(),
lookup_error);
return nullptr;
}
diff --git a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
index 7f82581cc601..aef895def793 100644
--- a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
+++ b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp
@@ -8,13 +8,20 @@
#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
+#include "lldb/Core/Module.h"
#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/Target/Process.h"
+#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-private.h"
using namespace lldb;
using namespace lldb_private;
+static bool IsStoppedInDarwinSanitizer(Thread &thread, Module &module) {
+ return module.GetFileSpec().GetFilename().GetStringRef().starts_with(
+ "libclang_rt.");
+}
+
InstrumentationRuntimeStopInfo::InstrumentationRuntimeStopInfo(
Thread &thread, std::string description,
StructuredData::ObjectSP additional_data)
@@ -34,3 +41,38 @@ InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
return StopInfoSP(
new InstrumentationRuntimeStopInfo(thread, description, additionalData));
}
+
+std::optional<uint32_t>
+InstrumentationRuntimeStopInfo::GetSuggestedStackFrameIndex(
+ bool inlined_stack) {
+ ThreadSP thread_sp = GetThread();
+ if (!thread_sp)
+ return std::nullopt;
+
+ // Defensive upper-bound of when we stop walking up the frames in
+ // case we somehow ended up looking at an infinite recursion.
+ constexpr size_t max_stack_depth = 128;
+
+ // Start at parent frame.
+ size_t stack_idx = 1;
+ StackFrameSP most_relevant_frame_sp =
+ thread_sp->GetStackFrameAtIndex(stack_idx);
+
+ while (most_relevant_frame_sp && stack_idx <= max_stack_depth) {
+ auto const &sc =
+ most_relevant_frame_sp->GetSymbolContext(lldb::eSymbolContextModule);
+
+ if (!sc.module_sp)
+ return std::nullopt;
+
+ // Found a frame outside of the sanitizer runtime libraries.
+ // That's the one we want to display.
+ if (!IsStoppedInDarwinSanitizer(*thread_sp, *sc.module_sp))
+ return stack_idx;
+
+ ++stack_idx;
+ most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(stack_idx);
+ }
+
+ return stack_idx;
+}
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index ff9e5fc12059..3176852f0b72 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -4269,6 +4269,14 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr,
// appropriately. We also need to stop processing actions, since they
// aren't expecting the target to be running.
+ // Clear the selected frame which may have been set as part of utility
+ // expressions that have been run as part of this stop. If we didn't
+ // clear this, then StopInfo::GetSuggestedStackFrameIndex would not
+ // take affect when we next called SelectMostRelevantFrame.
+ // PerformAction should not be the one setting a selected frame, instead
+ // this should be done via GetSuggestedStackFrameIndex.
+ thread_sp->ClearSelectedFrameIndex();
+
// FIXME: we might have run.
if (stop_info_sp->HasTargetRunSinceMe()) {
SetRestarted(true);
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index bcf1297f2114..787eb94be3b4 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -293,6 +293,9 @@ void RegisterContextUnwind::InitializeZerothFrame() {
return;
}
+ // Give the Architecture a chance to replace the UnwindPlan.
+ TryAdoptArchitectureUnwindPlan();
+
UnwindLogMsg("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64
" afa is 0x%" PRIx64 " using %s UnwindPlan",
(uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()),
@@ -482,6 +485,9 @@ void RegisterContextUnwind::InitializeNonZerothFrame() {
}
}
+ // Give the Architecture a chance to replace the UnwindPlan.
+ TryAdoptArchitectureUnwindPlan();
+
UnwindLogMsg("initialized frame cfa is 0x%" PRIx64 " afa is 0x%" PRIx64,
(uint64_t)m_cfa, (uint64_t)m_afa);
return;
@@ -686,6 +692,9 @@ void RegisterContextUnwind::InitializeNonZerothFrame() {
}
}
+ // Give the Architecture a chance to replace the UnwindPlan.
+ TryAdoptArchitectureUnwindPlan();
+
UnwindLogMsg("initialized frame current pc is 0x%" PRIx64
" cfa is 0x%" PRIx64 " afa is 0x%" PRIx64,
(uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()),
@@ -1717,6 +1726,41 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
+UnwindPlanSP RegisterContextUnwind::TryAdoptArchitectureUnwindPlan() {
+ if (!m_full_unwind_plan_sp)
+ return {};
+ ProcessSP process_sp = m_thread.GetProcess();
+ if (!process_sp)
+ return {};
+
+ UnwindPlanSP arch_override_plan_sp;
+ if (Architecture *arch = process_sp->GetTarget().GetArchitecturePlugin())
+ arch_override_plan_sp =
+ arch->GetArchitectureUnwindPlan(m_thread, this, m_full_unwind_plan_sp);
+
+ if (arch_override_plan_sp) {
+ m_full_unwind_plan_sp = arch_override_plan_sp;
+ PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
+ m_registers.clear();
+ if (GetLog(LLDBLog::Unwind)) {
+ UnwindLogMsg(
+ "Replacing Full Unwindplan with Architecture UnwindPlan, '%s'",
+ m_full_unwind_plan_sp->GetSourceName().AsCString());
+ const UnwindPlan::Row *active_row =
+ m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
+ if (active_row) {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(),
+ &m_thread,
+ m_start_pc.GetLoadAddress(&process_sp->GetTarget()));
+ UnwindLogMsg("%s", active_row_strm.GetData());
+ }
+ }
+ }
+
+ return {};
+}
+
// TryFallbackUnwindPlan() -- this method is a little tricky.
//
// When this is called, the frame above -- the caller frame, the "previous"
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 40049d40aa41..2ed58c5331df 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -57,14 +57,14 @@ using namespace lldb_private;
StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
user_id_t unwind_frame_index, addr_t cfa,
bool cfa_is_valid, addr_t pc, StackFrame::Kind kind,
- bool behaves_like_zeroth_frame,
+ bool artificial, bool behaves_like_zeroth_frame,
const SymbolContext *sc_ptr)
: m_thread_wp(thread_sp), m_frame_index(frame_idx),
m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(),
m_id(pc, cfa, nullptr, thread_sp->GetProcess().get()),
m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
- m_stack_frame_kind(kind),
+ m_stack_frame_kind(kind), m_artificial(artificial),
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
m_variable_list_sp(), m_variable_list_value_objects(),
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
@@ -92,7 +92,7 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
m_id(pc, cfa, nullptr, thread_sp->GetProcess().get()),
m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
m_frame_base_error(), m_cfa_is_valid(true),
- m_stack_frame_kind(StackFrame::Kind::Regular),
+ m_stack_frame_kind(StackFrame::Kind::Regular), m_artificial(false),
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
m_variable_list_sp(), m_variable_list_value_objects(),
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
@@ -120,7 +120,7 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
nullptr, thread_sp->GetProcess().get()),
m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
m_frame_base_error(), m_cfa_is_valid(true),
- m_stack_frame_kind(StackFrame::Kind::Regular),
+ m_stack_frame_kind(StackFrame::Kind::Regular), m_artificial(false),
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
m_variable_list_sp(), m_variable_list_value_objects(),
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
@@ -266,6 +266,7 @@ bool StackFrame::ChangePC(addr_t pc) {
const char *StackFrame::Disassemble() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
if (!m_disassembly.Empty())
return m_disassembly.GetData();
@@ -440,10 +441,10 @@ VariableList *StackFrame::GetVariableList(bool get_file_globals,
const bool get_child_variables = true;
const bool can_create = true;
const bool stop_if_child_block_is_inlined_function = true;
- frame_block->AppendBlockVariables(can_create, get_child_variables,
- stop_if_child_block_is_inlined_function,
- [](Variable *v) { return true; },
- m_variable_list_sp.get());
+ frame_block->AppendBlockVariables(
+ can_create, get_child_variables,
+ stop_if_child_block_is_inlined_function,
+ [](Variable *v) { return true; }, m_variable_list_sp.get());
}
}
@@ -1227,10 +1228,12 @@ StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp,
VariableList *var_list = GetVariableList(true, nullptr);
if (var_list) {
// Make sure the variable is a frame variable
- const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get());
+ const uint32_t var_idx =
+ var_list->FindIndexForVariable(variable_sp.get());
const uint32_t num_variables = var_list->GetSize();
if (var_idx < num_variables) {
- valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
+ valobj_sp =
+ m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
if (!valobj_sp) {
if (m_variable_list_value_objects.GetSize() < num_variables)
m_variable_list_value_objects.Resize(num_variables);
@@ -1261,10 +1264,12 @@ bool StackFrame::IsHistorical() const {
return m_stack_frame_kind == StackFrame::Kind::History;
}
-bool StackFrame::IsArtificial() const {
- return m_stack_frame_kind == StackFrame::Kind::Artificial;
+bool StackFrame::IsSynthetic() const {
+ return m_stack_frame_kind == StackFrame::Kind::Synthetic;
}
+bool StackFrame::IsArtificial() const { return m_artificial; }
+
bool StackFrame::IsHidden() {
if (auto recognized_frame_sp = GetRecognizedFrame())
return recognized_frame_sp->ShouldHide();
@@ -1764,11 +1769,9 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
if (clobbered_reg_matcher(operands[0])) {
origin_operand = &operands[1];
- }
- else if (clobbered_reg_matcher(operands[1])) {
+ } else if (clobbered_reg_matcher(operands[1])) {
origin_operand = &operands[0];
- }
- else {
+ } else {
continue;
}
@@ -1794,8 +1797,7 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
if (!source_path) {
continue;
}
- source_path =
- GetValueForDereferincingOffset(frame, source_path, offset);
+ source_path = GetValueForDereferincingOffset(frame, source_path, offset);
}
if (source_path) {
@@ -1805,7 +1807,7 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
return ValueObjectSP();
}
-}
+} // namespace
lldb::ValueObjectSP StackFrame::GuessValueForRegisterAndOffset(ConstString reg,
int64_t offset) {
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp
index aedfc52cfb4c..fa5d159c0c91 100644
--- a/lldb/source/Target/StackFrameList.cpp
+++ b/lldb/source/Target/StackFrameList.cpp
@@ -321,13 +321,14 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
addr_t pc = calleeInfo.address;
// If the callee address refers to the call instruction, we do not want to
// subtract 1 from this value.
+ const bool artificial = true;
const bool behaves_like_zeroth_frame =
calleeInfo.address_type == CallEdge::AddrType::Call;
SymbolContext sc;
callee->CalculateSymbolContext(&sc);
auto synth_frame = std::make_shared<StackFrame>(
m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa,
- cfa_is_valid, pc, StackFrame::Kind::Artificial,
+ cfa_is_valid, pc, StackFrame::Kind::Regular, artificial,
behaves_like_zeroth_frame, &sc);
m_frames.push_back(synth_frame);
LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc);
@@ -470,7 +471,8 @@ bool StackFrameList::FetchFramesUpTo(uint32_t end_idx,
const bool cfa_is_valid = true;
unwind_frame_sp = std::make_shared<StackFrame>(
m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid,
- pc, StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
+ pc, StackFrame::Kind::Regular, false, behaves_like_zeroth_frame,
+ nullptr);
// Create synthetic tail call frames between the previous frame and the
// newly-found frame. The new frame's index may change after this call,
@@ -942,3 +944,5 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
strm.IndentLess();
return num_frames_displayed;
}
+
+void StackFrameList::ClearSelectedFrameIndex() { m_selected_frame_idx.reset(); }
diff --git a/lldb/source/Target/StackID.cpp b/lldb/source/Target/StackID.cpp
index b1795970802a..f879276527dd 100644
--- a/lldb/source/Target/StackID.cpp
+++ b/lldb/source/Target/StackID.cpp
@@ -63,16 +63,7 @@ bool lldb_private::operator==(const StackID &lhs, const StackID &rhs) {
}
bool lldb_private::operator!=(const StackID &lhs, const StackID &rhs) {
- if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
- return true;
-
- SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
- SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
-
- if (lhs_scope == nullptr && rhs_scope == nullptr)
- return lhs.GetPC() != rhs.GetPC();
-
- return lhs_scope != rhs_scope;
+ return !(lhs == rhs);
}
bool lldb_private::operator<(const StackID &lhs, const StackID &rhs) {
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 909f335687b2..8ad8d507268e 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -73,8 +73,9 @@ json::Value ModuleStats::ToJSON() const {
debug_info_had_incomplete_types);
module.try_emplace("symbolTableStripped", symtab_stripped);
module.try_emplace("symbolTableSymbolCount", symtab_symbol_count);
- module.try_emplace("dwoFileCount", dwo_file_count);
- module.try_emplace("loadedDwoFileCount", loaded_dwo_file_count);
+ module.try_emplace("dwoFileCount", dwo_stats.dwo_file_count);
+ module.try_emplace("loadedDwoFileCount", dwo_stats.loaded_dwo_file_count);
+ module.try_emplace("dwoErrorCount", dwo_stats.dwo_error_count);
if (!symbol_locator_time.map.empty()) {
json::Object obj;
@@ -324,8 +325,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(
uint32_t num_modules_with_incomplete_types = 0;
uint32_t num_stripped_modules = 0;
uint32_t symtab_symbol_count = 0;
- uint32_t total_loaded_dwo_file_count = 0;
- uint32_t total_dwo_file_count = 0;
+ DWOStats total_dwo_stats;
for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
Module *module = target != nullptr
? target->GetImages().GetModuleAtIndex(image_idx).get()
@@ -357,10 +357,9 @@ llvm::json::Value DebuggerStats::ReportStatistics(
for (const auto &symbol_module : symbol_modules.Modules())
module_stat.symfile_modules.push_back((intptr_t)symbol_module.get());
}
- std::tie(module_stat.loaded_dwo_file_count, module_stat.dwo_file_count) =
- sym_file->GetDwoFileCounts();
- total_dwo_file_count += module_stat.dwo_file_count;
- total_loaded_dwo_file_count += module_stat.loaded_dwo_file_count;
+ DWOStats current_dwo_stats = sym_file->GetDwoStats();
+ module_stat.dwo_stats += current_dwo_stats;
+ total_dwo_stats += current_dwo_stats;
module_stat.debug_info_index_loaded_from_cache =
sym_file->GetDebugInfoIndexWasLoadedFromCache();
if (module_stat.debug_info_index_loaded_from_cache)
@@ -435,8 +434,9 @@ llvm::json::Value DebuggerStats::ReportStatistics(
{"totalDebugInfoEnabled", num_debug_info_enabled_modules},
{"totalSymbolTableStripped", num_stripped_modules},
{"totalSymbolTableSymbolCount", symtab_symbol_count},
- {"totalLoadedDwoFileCount", total_loaded_dwo_file_count},
- {"totalDwoFileCount", total_dwo_file_count},
+ {"totalLoadedDwoFileCount", total_dwo_stats.loaded_dwo_file_count},
+ {"totalDwoFileCount", total_dwo_stats.dwo_file_count},
+ {"totalDwoErrorCount", total_dwo_stats.dwo_error_count},
};
if (include_targets) {
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index ddf8c62e969e..f47dae2b2465 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -108,8 +108,7 @@ public:
void StoreBPInfo() {
ThreadSP thread_sp(m_thread_wp.lock());
if (thread_sp) {
- BreakpointSiteSP bp_site_sp(
- thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
if (bp_site_sp) {
uint32_t num_constituents = bp_site_sp->GetNumberOfConstituents();
if (num_constituents == 1) {
@@ -139,8 +138,7 @@ public:
bool IsValidForOperatingSystemThread(Thread &thread) override {
ProcessSP process_sp(thread.GetProcess());
if (process_sp) {
- BreakpointSiteSP bp_site_sp(
- process_sp->GetBreakpointSiteList().FindByID(m_value));
+ BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
if (bp_site_sp)
return bp_site_sp->ValidForThisThread(thread);
}
@@ -154,8 +152,7 @@ public:
if (thread_sp) {
if (!m_should_stop_is_valid) {
// Only check once if we should stop at a breakpoint
- BreakpointSiteSP bp_site_sp(
- thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
if (bp_site_sp) {
ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
StoppointCallbackContext context(event_ptr, exe_ctx, true);
@@ -186,8 +183,7 @@ public:
if (m_description.empty()) {
ThreadSP thread_sp(m_thread_wp.lock());
if (thread_sp) {
- BreakpointSiteSP bp_site_sp(
- thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
if (bp_site_sp) {
StreamString strm;
// If we have just hit an internal breakpoint, and it has a kind
@@ -247,6 +243,35 @@ public:
return m_description.c_str();
}
+ uint32_t GetStopReasonDataCount() const override {
+ lldb::BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
+ if (bp_site_sp)
+ return bp_site_sp->GetNumberOfConstituents() * 2;
+ return 0; // Breakpoint must have cleared itself...
+ }
+
+ uint64_t GetStopReasonDataAtIndex(uint32_t idx) override {
+ lldb::BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
+ if (bp_site_sp) {
+ uint32_t bp_index = idx / 2;
+ BreakpointLocationSP bp_loc_sp(
+ bp_site_sp->GetConstituentAtIndex(bp_index));
+ if (bp_loc_sp) {
+ if (idx & 1) {
+ // FIXME: This might be a Facade breakpoint, so we need to fetch
+ // the one that the thread actually hit, not the native loc ID.
+
+ // Odd idx, return the breakpoint location ID
+ return bp_loc_sp->GetID();
+ } else {
+ // Even idx, return the breakpoint ID
+ return bp_loc_sp->GetBreakpoint().GetID();
+ }
+ }
+ }
+ return LLDB_INVALID_BREAK_ID;
+ }
+
std::optional<uint32_t>
GetSuggestedStackFrameIndex(bool inlined_stack) override {
if (!inlined_stack)
@@ -255,8 +280,7 @@ public:
ThreadSP thread_sp(m_thread_wp.lock());
if (!thread_sp)
return {};
- BreakpointSiteSP bp_site_sp(
- thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
if (!bp_site_sp)
return {};
@@ -297,8 +321,7 @@ protected:
return;
}
- BreakpointSiteSP bp_site_sp(
- thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
std::unordered_set<break_id_t> precondition_breakpoints;
// Breakpoints that fail their condition check are not considered to
// have been hit. If the only locations at this site have failed their
@@ -629,6 +652,20 @@ protected:
}
private:
+ BreakpointSiteSP GetBreakpointSiteSP() const {
+ if (m_value == LLDB_INVALID_BREAK_ID)
+ return {};
+
+ ThreadSP thread_sp = GetThread();
+ if (!thread_sp)
+ return {};
+ ProcessSP process_sp = thread_sp->GetProcess();
+ if (!process_sp)
+ return {};
+
+ return process_sp->GetBreakpointSiteList().FindByID(m_value);
+ }
+
bool m_should_stop;
bool m_should_stop_is_valid;
bool m_should_perform_action; // Since we are trying to preserve the "state"
@@ -699,6 +736,13 @@ public:
StopReason GetStopReason() const override { return eStopReasonWatchpoint; }
+ uint32_t GetStopReasonDataCount() const override { return 1; }
+ uint64_t GetStopReasonDataAtIndex(uint32_t idx) override {
+ if (idx == 0)
+ return GetValue();
+ return 0;
+ }
+
const char *GetDescription() override {
if (m_description.empty()) {
StreamString strm;
@@ -1139,6 +1183,13 @@ public:
bool ShouldSelect() const override { return IsShouldStopSignal(); }
+ uint32_t GetStopReasonDataCount() const override { return 1; }
+ uint64_t GetStopReasonDataAtIndex(uint32_t idx) override {
+ if (idx == 0)
+ return GetValue();
+ return 0;
+ }
+
private:
// In siginfo_t terms, if m_value is si_signo, m_code is si_code.
std::optional<int> m_code;
@@ -1171,6 +1222,14 @@ public:
}
return m_description.c_str();
}
+
+ uint32_t GetStopReasonDataCount() const override { return 1; }
+ uint64_t GetStopReasonDataAtIndex(uint32_t idx) override {
+ if (idx == 0)
+ return GetValue();
+ else
+ return 0;
+ }
};
// StopInfoTrace
@@ -1249,6 +1308,13 @@ public:
else
return m_description.c_str();
}
+ uint32_t GetStopReasonDataCount() const override { return 1; }
+ uint64_t GetStopReasonDataAtIndex(uint32_t idx) override {
+ if (idx == 0)
+ return GetValue();
+ else
+ return 0;
+ }
};
// StopInfoProcessorTrace
@@ -1390,6 +1456,14 @@ public:
const char *GetDescription() override { return "fork"; }
+ uint32_t GetStopReasonDataCount() const override { return 1; }
+ uint64_t GetStopReasonDataAtIndex(uint32_t idx) override {
+ if (idx == 0)
+ return GetValue();
+ else
+ return 0;
+ }
+
protected:
void PerformAction(Event *event_ptr) override {
// Only perform the action once
@@ -1424,6 +1498,13 @@ public:
const char *GetDescription() override { return "vfork"; }
+ uint32_t GetStopReasonDataCount() const override { return 1; }
+ uint64_t GetStopReasonDataAtIndex(uint32_t idx) override {
+ if (idx == 0)
+ return GetValue();
+ return 0;
+ }
+
protected:
void PerformAction(Event *event_ptr) override {
// Only perform the action once
diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp
index 8f14cf6e3943..1b8dae39735d 100644
--- a/lldb/source/Utility/ArchSpec.cpp
+++ b/lldb/source/Utility/ArchSpec.cpp
@@ -260,9 +260,9 @@ static_assert(sizeof(g_core_definitions) / sizeof(CoreDefinition) ==
struct ArchDefinitionEntry {
ArchSpec::Core core;
uint32_t cpu;
- uint32_t sub;
- uint32_t cpu_mask;
- uint32_t sub_mask;
+ uint32_t sub = LLDB_INVALID_CPUTYPE;
+ uint32_t cpu_mask = UINT32_MAX;
+ uint32_t sub_mask = UINT32_MAX;
};
struct ArchDefinition {
@@ -357,7 +357,8 @@ static const ArchDefinitionEntry g_macho_arch_entries[] = {
{ArchSpec::eCore_riscv32, llvm::MachO::CPU_TYPE_RISCV, CPU_ANY, UINT32_MAX, SUBTYPE_MASK},
// Catch any unknown mach architectures so we can always use the object and symbol mach-o files
{ArchSpec::eCore_uknownMach32, 0, 0, 0xFF000000u, 0x00000000u},
- {ArchSpec::eCore_uknownMach64, llvm::MachO::CPU_ARCH_ABI64, 0, 0xFF000000u, 0x00000000u}};
+ {ArchSpec::eCore_uknownMach64, llvm::MachO::CPU_ARCH_ABI64, 0, 0xFF000000u, 0x00000000u}
+};
// clang-format on
static const ArchDefinition g_macho_arch_def = {eArchTypeMachO,
@@ -369,72 +370,41 @@ static const ArchDefinition g_macho_arch_def = {eArchTypeMachO,
// convert cpu type and subtypes to architecture names, and to convert
// architecture names to cpu types and subtypes. The ordering is important and
// allows the precedence to be set when the table is built.
+// clang-format off
static const ArchDefinitionEntry g_elf_arch_entries[] = {
- {ArchSpec::eCore_sparc_generic, llvm::ELF::EM_SPARC, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // Sparc
- {ArchSpec::eCore_x86_32_i386, llvm::ELF::EM_386, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // Intel 80386
- {ArchSpec::eCore_x86_32_i486, llvm::ELF::EM_IAMCU, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // Intel MCU // FIXME: is this correct?
- {ArchSpec::eCore_ppc_generic, llvm::ELF::EM_PPC, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC
- {ArchSpec::eCore_ppc64le_generic, llvm::ELF::EM_PPC64,
- ArchSpec::eCore_ppc64le_generic, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64le
- {ArchSpec::eCore_ppc64_generic, llvm::ELF::EM_PPC64,
- ArchSpec::eCore_ppc64_generic, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC64
- {ArchSpec::eCore_arm_generic, llvm::ELF::EM_ARM, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM
- {ArchSpec::eCore_arm_aarch64, llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM64
- {ArchSpec::eCore_s390x_generic, llvm::ELF::EM_S390, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // SystemZ
- {ArchSpec::eCore_sparc9_generic, llvm::ELF::EM_SPARCV9,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // SPARC V9
- {ArchSpec::eCore_x86_64_x86_64, llvm::ELF::EM_X86_64, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // AMD64
- {ArchSpec::eCore_mips32, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips32,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32
- {ArchSpec::eCore_mips32r2, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips32r2, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32r2
- {ArchSpec::eCore_mips32r6, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips32r6, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32r6
- {ArchSpec::eCore_mips32el, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips32el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32el
- {ArchSpec::eCore_mips32r2el, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips32r2el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32r2el
- {ArchSpec::eCore_mips32r6el, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips32r6el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips32r6el
- {ArchSpec::eCore_mips64, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips64,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64
- {ArchSpec::eCore_mips64r2, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips64r2, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64r2
- {ArchSpec::eCore_mips64r6, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips64r6, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64r6
- {ArchSpec::eCore_mips64el, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips64el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64el
- {ArchSpec::eCore_mips64r2el, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips64r2el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64r2el
- {ArchSpec::eCore_mips64r6el, llvm::ELF::EM_MIPS,
- ArchSpec::eMIPSSubType_mips64r6el, 0xFFFFFFFFu, 0xFFFFFFFFu}, // mips64r6el
- {ArchSpec::eCore_msp430, llvm::ELF::EM_MSP430, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // MSP430
- {ArchSpec::eCore_hexagon_generic, llvm::ELF::EM_HEXAGON,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // HEXAGON
- {ArchSpec::eCore_arc, llvm::ELF::EM_ARC_COMPACT2, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARC
- {ArchSpec::eCore_avr, llvm::ELF::EM_AVR, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu,
- 0xFFFFFFFFu}, // AVR
- {ArchSpec::eCore_riscv32, llvm::ELF::EM_RISCV,
- ArchSpec::eRISCVSubType_riscv32, 0xFFFFFFFFu, 0xFFFFFFFFu}, // riscv32
- {ArchSpec::eCore_riscv64, llvm::ELF::EM_RISCV,
- ArchSpec::eRISCVSubType_riscv64, 0xFFFFFFFFu, 0xFFFFFFFFu}, // riscv64
- {ArchSpec::eCore_loongarch32, llvm::ELF::EM_LOONGARCH,
- ArchSpec::eLoongArchSubType_loongarch32, 0xFFFFFFFFu,
- 0xFFFFFFFFu}, // loongarch32
- {ArchSpec::eCore_loongarch64, llvm::ELF::EM_LOONGARCH,
- ArchSpec::eLoongArchSubType_loongarch64, 0xFFFFFFFFu,
- 0xFFFFFFFFu}, // loongarch64
+ {ArchSpec::eCore_sparc_generic, llvm::ELF::EM_SPARC }, // Sparc
+ {ArchSpec::eCore_x86_32_i386, llvm::ELF::EM_386 }, // Intel 80386
+ {ArchSpec::eCore_x86_32_i486, llvm::ELF::EM_IAMCU }, // Intel MCU // FIXME: is this correct?
+ {ArchSpec::eCore_ppc_generic, llvm::ELF::EM_PPC }, // PowerPC
+ {ArchSpec::eCore_ppc64le_generic, llvm::ELF::EM_PPC64, ArchSpec::eCore_ppc64le_generic}, // PowerPC64le
+ {ArchSpec::eCore_ppc64_generic, llvm::ELF::EM_PPC64, ArchSpec::eCore_ppc64_generic}, // PowerPC64
+ {ArchSpec::eCore_arm_generic, llvm::ELF::EM_ARM }, // ARM
+ {ArchSpec::eCore_arm_aarch64, llvm::ELF::EM_AARCH64 }, // ARM64
+ {ArchSpec::eCore_s390x_generic, llvm::ELF::EM_S390 }, // SystemZ
+ {ArchSpec::eCore_sparc9_generic, llvm::ELF::EM_SPARCV9 }, // SPARC V9
+ {ArchSpec::eCore_x86_64_x86_64, llvm::ELF::EM_X86_64 }, // AMD64
+ {ArchSpec::eCore_mips32, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips32}, // mips32
+ {ArchSpec::eCore_mips32r2, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips32r2}, // mips32r2
+ {ArchSpec::eCore_mips32r6, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips32r6}, // mips32r6
+ {ArchSpec::eCore_mips32el, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips32el}, // mips32el
+ {ArchSpec::eCore_mips32r2el, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips32r2el}, // mips32r2el
+ {ArchSpec::eCore_mips32r6el, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips32r6el}, // mips32r6el
+ {ArchSpec::eCore_mips64, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips64},
+ {ArchSpec::eCore_mips64r2, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips64r2}, // mips64r2
+ {ArchSpec::eCore_mips64r6, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips64r6}, // mips64r6
+ {ArchSpec::eCore_mips64el, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips64el}, // mips64el
+ {ArchSpec::eCore_mips64r2el, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips64r2el}, // mips64r2el
+ {ArchSpec::eCore_mips64r6el, llvm::ELF::EM_MIPS, ArchSpec::eMIPSSubType_mips64r6el}, // mips64r6el
+ {ArchSpec::eCore_msp430, llvm::ELF::EM_MSP430 }, // MSP430
+ {ArchSpec::eCore_hexagon_generic, llvm::ELF::EM_HEXAGON }, // HEXAGON
+ {ArchSpec::eCore_arc, llvm::ELF::EM_ARC_COMPACT2}, // ARC
+ {ArchSpec::eCore_avr, llvm::ELF::EM_AVR }, // AVR
+ {ArchSpec::eCore_riscv32, llvm::ELF::EM_RISCV, ArchSpec::eRISCVSubType_riscv32}, // riscv32
+ {ArchSpec::eCore_riscv64, llvm::ELF::EM_RISCV, ArchSpec::eRISCVSubType_riscv64}, // riscv64
+ {ArchSpec::eCore_loongarch32, llvm::ELF::EM_LOONGARCH, ArchSpec::eLoongArchSubType_loongarch32}, // loongarch32
+ {ArchSpec::eCore_loongarch64, llvm::ELF::EM_LOONGARCH, ArchSpec::eLoongArchSubType_loongarch64}, // loongarch64
};
+// clang-format on
static const ArchDefinition g_elf_arch_def = {
eArchTypeELF,
@@ -442,25 +412,18 @@ static const ArchDefinition g_elf_arch_def = {
g_elf_arch_entries,
"elf",
};
-
+// clang-format off
static const ArchDefinitionEntry g_coff_arch_entries[] = {
- {ArchSpec::eCore_x86_32_i386, llvm::COFF::IMAGE_FILE_MACHINE_I386,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // Intel 80x86
- {ArchSpec::eCore_ppc_generic, llvm::COFF::IMAGE_FILE_MACHINE_POWERPC,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC
- {ArchSpec::eCore_ppc_generic, llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // PowerPC (with FPU)
- {ArchSpec::eCore_arm_generic, llvm::COFF::IMAGE_FILE_MACHINE_ARM,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARM
- {ArchSpec::eCore_arm_armv7, llvm::COFF::IMAGE_FILE_MACHINE_ARMNT,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARMv7
- {ArchSpec::eCore_thumb, llvm::COFF::IMAGE_FILE_MACHINE_THUMB,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // ARMv7
- {ArchSpec::eCore_x86_64_x86_64, llvm::COFF::IMAGE_FILE_MACHINE_AMD64,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}, // AMD64
- {ArchSpec::eCore_arm_arm64, llvm::COFF::IMAGE_FILE_MACHINE_ARM64,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu} // ARM64
+ {ArchSpec::eCore_x86_32_i386, llvm::COFF::IMAGE_FILE_MACHINE_I386}, // Intel 80x86
+ {ArchSpec::eCore_ppc_generic, llvm::COFF::IMAGE_FILE_MACHINE_POWERPC}, // PowerPC
+ {ArchSpec::eCore_ppc_generic, llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP}, // PowerPC (with FPU)
+ {ArchSpec::eCore_arm_generic, llvm::COFF::IMAGE_FILE_MACHINE_ARM}, // ARM
+ {ArchSpec::eCore_arm_armv7, llvm::COFF::IMAGE_FILE_MACHINE_ARMNT}, // ARMv7
+ {ArchSpec::eCore_thumb, llvm::COFF::IMAGE_FILE_MACHINE_THUMB}, // ARMv7
+ {ArchSpec::eCore_x86_64_x86_64, llvm::COFF::IMAGE_FILE_MACHINE_AMD64}, // AMD64
+ {ArchSpec::eCore_arm_arm64, llvm::COFF::IMAGE_FILE_MACHINE_ARM64} // ARM64
};
+// clang-format on
static const ArchDefinition g_coff_arch_def = {
eArchTypeCOFF,
@@ -469,11 +432,12 @@ static const ArchDefinition g_coff_arch_def = {
"pe-coff",
};
+// clang-format off
static const ArchDefinitionEntry g_xcoff_arch_entries[] = {
- {ArchSpec::eCore_ppc_generic, llvm::XCOFF::TCPU_COM, LLDB_INVALID_CPUTYPE,
- 0xFFFFFFFFu, 0xFFFFFFFFu},
- {ArchSpec::eCore_ppc64_generic, llvm::XCOFF::TCPU_PPC64,
- LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu}};
+ {ArchSpec::eCore_ppc_generic, llvm::XCOFF::TCPU_COM},
+ {ArchSpec::eCore_ppc64_generic, llvm::XCOFF::TCPU_PPC64}
+};
+// clang-format on
static const ArchDefinition g_xcoff_arch_def = {
eArchTypeXCOFF,
@@ -695,13 +659,9 @@ uint32_t ArchSpec::GetMachOCPUSubType() const {
return LLDB_INVALID_CPUTYPE;
}
-uint32_t ArchSpec::GetDataByteSize() const {
- return 1;
-}
+uint32_t ArchSpec::GetDataByteSize() const { return 1; }
-uint32_t ArchSpec::GetCodeByteSize() const {
- return 1;
-}
+uint32_t ArchSpec::GetCodeByteSize() const { return 1; }
llvm::Triple::ArchType ArchSpec::GetMachine() const {
const CoreDefinition *core_def = FindCoreDefinition(m_core);
@@ -1170,8 +1130,8 @@ static bool cores_match(const ArchSpec::Core core1, const ArchSpec::Core core2,
break;
// v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization
- // Cortex-M0 - ARMv6-M - armv6m
- // Cortex-M3 - ARMv7-M - armv7m
+ // Cortex-M0 - ARMv6-M - armv6m
+ // Cortex-M3 - ARMv7-M - armv7m
// Cortex-M4 - ARMv7E-M - armv7em
case ArchSpec::eCore_arm_armv7em:
if (!enforce_exact_match) {
@@ -1188,8 +1148,8 @@ static bool cores_match(const ArchSpec::Core core1, const ArchSpec::Core core2,
break;
// v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization
- // Cortex-M0 - ARMv6-M - armv6m
- // Cortex-M3 - ARMv7-M - armv7m
+ // Cortex-M0 - ARMv6-M - armv6m
+ // Cortex-M3 - ARMv7-M - armv7m
// Cortex-M4 - ARMv7E-M - armv7em
case ArchSpec::eCore_arm_armv7m:
if (!enforce_exact_match) {
@@ -1206,8 +1166,8 @@ static bool cores_match(const ArchSpec::Core core1, const ArchSpec::Core core2,
break;
// v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization
- // Cortex-M0 - ARMv6-M - armv6m
- // Cortex-M3 - ARMv7-M - armv7m
+ // Cortex-M0 - ARMv6-M - armv6m
+ // Cortex-M3 - ARMv7-M - armv7m
// Cortex-M4 - ARMv7E-M - armv7em
case ArchSpec::eCore_arm_armv6m:
if (!enforce_exact_match) {
@@ -1434,7 +1394,6 @@ bool lldb_private::operator<(const ArchSpec &lhs, const ArchSpec &rhs) {
return lhs_core < rhs_core;
}
-
bool lldb_private::operator==(const ArchSpec &lhs, const ArchSpec &rhs) {
return lhs.GetCore() == rhs.GetCore();
}
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index b1cd824c2299..70564663a62c 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -37,4 +37,13 @@ BitFieldExtractionNode::Accept(Visitor *v) const {
return v->Visit(this);
}
+llvm::Expected<lldb::ValueObjectSP>
+IntegerLiteralNode::Accept(Visitor *v) const {
+ return v->Visit(this);
+}
+
+llvm::Expected<lldb::ValueObjectSP> FloatLiteralNode::Accept(Visitor *v) const {
+ return v->Visit(this);
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index 6f28434c646c..c6cf41ee9e9e 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "lldb/ValueObject/DILEval.h"
+#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/ValueObject/DILAST.h"
@@ -330,40 +332,135 @@ Interpreter::Visit(const ArraySubscriptNode *node) {
return lhs_or_err;
lldb::ValueObjectSP base = *lhs_or_err;
- // Check to see if 'base' has a synthetic value; if so, try using that.
+ StreamString var_expr_path_strm;
uint64_t child_idx = node->GetIndex();
- if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue()) {
- llvm::Expected<uint32_t> num_children =
- synthetic->GetNumChildren(child_idx + 1);
- if (!num_children)
- return llvm::make_error<DILDiagnosticError>(
- m_expr, toString(num_children.takeError()), node->GetLocation());
- if (child_idx >= *num_children) {
- std::string message = llvm::formatv(
- "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ lldb::ValueObjectSP child_valobj_sp;
+
+ bool is_incomplete_array = false;
+ CompilerType base_type = base->GetCompilerType().GetNonReferenceType();
+ base->GetExpressionPath(var_expr_path_strm);
+
+ if (base_type.IsPointerType()) {
+ bool is_objc_pointer = true;
+
+ if (base->GetCompilerType().GetMinimumLanguage() != lldb::eLanguageTypeObjC)
+ is_objc_pointer = false;
+ else if (!base->GetCompilerType().IsPointerType())
+ is_objc_pointer = false;
+
+ if (!m_use_synthetic && is_objc_pointer) {
+ std::string err_msg = llvm::formatv(
+ "\"({0}) {1}\" is an Objective-C pointer, and cannot be subscripted",
base->GetTypeName().AsCString("<invalid type>"),
- base->GetName().AsCString());
- return llvm::make_error<DILDiagnosticError>(m_expr, message,
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
node->GetLocation());
}
- if (lldb::ValueObjectSP child_valobj_sp =
- synthetic->GetChildAtIndex(child_idx))
+ if (is_objc_pointer) {
+ lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
+ if (!synthetic || synthetic == base) {
+ std::string err_msg =
+ llvm::formatv("\"({0}) {1}\" is not an array type",
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ if (static_cast<uint32_t>(child_idx) >=
+ synthetic->GetNumChildrenIgnoringErrors()) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ if (m_use_dynamic != lldb::eNoDynamicValues) {
+ if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic))
+ child_valobj_sp = std::move(dynamic_sp);
+ }
return child_valobj_sp;
- }
+ }
- auto base_type = base->GetCompilerType().GetNonReferenceType();
- if (!base_type.IsPointerType() && !base_type.IsArrayType())
- return llvm::make_error<DILDiagnosticError>(
- m_expr, "subscripted value is not an array or pointer",
- node->GetLocation());
- if (base_type.IsPointerToVoid())
- return llvm::make_error<DILDiagnosticError>(
- m_expr, "subscript of pointer to incomplete type 'void'",
- node->GetLocation());
+ child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "failed to use pointer as array for index {0} for "
+ "\"({1}) {2}\"",
+ child_idx, base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ if (base_type.IsPointerToVoid())
+ err_msg = "subscript of pointer to incomplete type 'void'";
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ } else if (base_type.IsArrayType(nullptr, nullptr, &is_incomplete_array)) {
+ child_valobj_sp = base->GetChildAtIndex(child_idx);
+ if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic))
+ child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation());
+ }
+ } else if (base_type.IsScalarType()) {
+ child_valobj_sp =
+ base->GetSyntheticBitFieldChild(child_idx, child_idx, true);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "bitfield range {0}-{1} is not valid for \"({2}) {3}\"", child_idx,
+ child_idx, base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation(), 1);
+ }
+ } else {
+ lldb::ValueObjectSP synthetic = base->GetSyntheticValue();
+ if (!m_use_synthetic || !synthetic || synthetic == base) {
+ std::string err_msg =
+ llvm::formatv("\"{0}\" is not an array type",
+ base->GetTypeName().AsCString("<invalid type>"));
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation(), 1);
+ }
+ if (static_cast<uint32_t>(child_idx) >=
+ synthetic->GetNumChildrenIgnoringErrors(child_idx + 1)) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation(), 1);
+ }
+ child_valobj_sp = synthetic->GetChildAtIndex(child_idx);
+ if (!child_valobj_sp) {
+ std::string err_msg = llvm::formatv(
+ "array index {0} is not valid for \"({1}) {2}\"", child_idx,
+ base->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetData());
+ return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg),
+ node->GetLocation(), 1);
+ }
+ }
- if (base_type.IsArrayType()) {
- if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(child_idx))
- return child_valobj_sp;
+ if (child_valobj_sp) {
+ if (m_use_dynamic != lldb::eNoDynamicValues) {
+ if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic))
+ child_valobj_sp = std::move(dynamic_sp);
+ }
+ return child_valobj_sp;
}
int64_t signed_child_idx = node->GetIndex();
@@ -402,4 +499,107 @@ Interpreter::Visit(const BitFieldExtractionNode *node) {
return child_valobj_sp;
}
+static llvm::Expected<lldb::TypeSystemSP>
+GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) {
+ SymbolContext symbol_context =
+ ctx->GetSymbolContext(lldb::eSymbolContextCompUnit);
+ lldb::LanguageType language = symbol_context.comp_unit->GetLanguage();
+
+ symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule);
+ return symbol_context.module_sp->GetTypeSystemForLanguage(language);
+}
+
+static CompilerType GetBasicType(lldb::TypeSystemSP type_system,
+ lldb::BasicType basic_type) {
+ if (type_system)
+ return type_system.get()->GetBasicTypeFromAST(basic_type);
+
+ return CompilerType();
+}
+
+llvm::Expected<CompilerType>
+Interpreter::PickIntegerType(lldb::TypeSystemSP type_system,
+ std::shared_ptr<ExecutionContextScope> ctx,
+ const IntegerLiteralNode *literal) {
+ // Binary, Octal, Hexadecimal and literals with a U suffix are allowed to be
+ // an unsigned integer.
+ bool unsigned_is_allowed = literal->IsUnsigned() || literal->GetRadix() != 10;
+ llvm::APInt apint = literal->GetValue();
+
+ llvm::SmallVector<std::pair<lldb::BasicType, lldb::BasicType>, 3> candidates;
+ if (literal->GetTypeSuffix() <= IntegerTypeSuffix::None)
+ candidates.emplace_back(lldb::eBasicTypeInt,
+ unsigned_is_allowed ? lldb::eBasicTypeUnsignedInt
+ : lldb::eBasicTypeInvalid);
+ if (literal->GetTypeSuffix() <= IntegerTypeSuffix::Long)
+ candidates.emplace_back(lldb::eBasicTypeLong,
+ unsigned_is_allowed ? lldb::eBasicTypeUnsignedLong
+ : lldb::eBasicTypeInvalid);
+ candidates.emplace_back(lldb::eBasicTypeLongLong,
+ lldb::eBasicTypeUnsignedLongLong);
+ for (auto [signed_, unsigned_] : candidates) {
+ CompilerType signed_type = type_system->GetBasicTypeFromAST(signed_);
+ if (!signed_type)
+ continue;
+ llvm::Expected<uint64_t> size = signed_type.GetBitSize(ctx.get());
+ if (!size)
+ return size.takeError();
+ if (!literal->IsUnsigned() && apint.isIntN(*size - 1))
+ return signed_type;
+ if (unsigned_ != lldb::eBasicTypeInvalid && apint.isIntN(*size))
+ return type_system->GetBasicTypeFromAST(unsigned_);
+ }
+
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr,
+ "integer literal is too large to be represented in any integer type",
+ literal->GetLocation());
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const IntegerLiteralNode *node) {
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_exe_ctx_scope);
+ if (!type_system)
+ return type_system.takeError();
+
+ llvm::Expected<CompilerType> type =
+ PickIntegerType(*type_system, m_exe_ctx_scope, node);
+ if (!type)
+ return type.takeError();
+
+ Scalar scalar = node->GetValue();
+ // APInt from StringRef::getAsInteger comes with just enough bitwidth to
+ // hold the value. This adjusts APInt bitwidth to match the compiler type.
+ llvm::Expected<uint64_t> type_bitsize =
+ type->GetBitSize(m_exe_ctx_scope.get());
+ if (!type_bitsize)
+ return type_bitsize.takeError();
+ scalar.TruncOrExtendTo(*type_bitsize, false);
+ return ValueObject::CreateValueObjectFromScalar(m_target, scalar, *type,
+ "result");
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const FloatLiteralNode *node) {
+ llvm::Expected<lldb::TypeSystemSP> type_system =
+ GetTypeSystemFromCU(m_exe_ctx_scope);
+ if (!type_system)
+ return type_system.takeError();
+
+ bool isFloat =
+ &node->GetValue().getSemantics() == &llvm::APFloat::IEEEsingle();
+ lldb::BasicType basic_type =
+ isFloat ? lldb::eBasicTypeFloat : lldb::eBasicTypeDouble;
+ CompilerType type = GetBasicType(*type_system, basic_type);
+
+ if (!type)
+ return llvm::make_error<DILDiagnosticError>(
+ m_expr, "unable to create a const literal", node->GetLocation());
+
+ Scalar scalar = node->GetValue();
+ return ValueObject::CreateValueObjectFromScalar(m_target, scalar, type,
+ "result");
+}
+
} // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
index eaefaf484bc1..0b2288a9d923 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -28,18 +28,23 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
return "coloncolon";
case Kind::eof:
return "eof";
+ case Kind::float_constant:
+ return "float_constant";
case Kind::identifier:
return "identifier";
+ case Kind::integer_constant:
+ return "integer_constant";
case Kind::l_paren:
return "l_paren";
case Kind::l_square:
return "l_square";
case Kind::minus:
return "minus";
- case Kind::numeric_constant:
- return "numeric_constant";
case Kind::period:
return "period";
+ return "l_square";
+ case Kind::plus:
+ return "plus";
case Kind::r_paren:
return "r_paren";
case Kind::r_square:
@@ -70,13 +75,32 @@ static std::optional<llvm::StringRef> IsWord(llvm::StringRef expr,
return candidate;
}
-static bool IsNumberBodyChar(char ch) { return IsDigit(ch) || IsLetter(ch); }
+static bool IsNumberBodyChar(char ch) {
+ return IsDigit(ch) || IsLetter(ch) || ch == '.';
+}
-static std::optional<llvm::StringRef> IsNumber(llvm::StringRef expr,
- llvm::StringRef &remainder) {
- if (IsDigit(remainder[0])) {
- llvm::StringRef number = remainder.take_while(IsNumberBodyChar);
- remainder = remainder.drop_front(number.size());
+static std::optional<llvm::StringRef> IsNumber(llvm::StringRef &remainder,
+ bool &isFloat) {
+ llvm::StringRef tail = remainder;
+ llvm::StringRef body = tail.take_while(IsNumberBodyChar);
+ size_t dots = body.count('.');
+ if (dots > 1 || dots == body.size())
+ return std::nullopt;
+ if (IsDigit(body.front()) || (body[0] == '.' && IsDigit(body[1]))) {
+ isFloat = dots == 1;
+ tail = tail.drop_front(body.size());
+ bool isHex = body.contains_insensitive('x');
+ bool hasExp = !isHex && body.contains_insensitive('e');
+ bool hasHexExp = isHex && body.contains_insensitive('p');
+ if (hasExp || hasHexExp) {
+ isFloat = true; // This marks numbers like 0x1p1 and 1e1 as float
+ if (body.ends_with_insensitive("e") || body.ends_with_insensitive("p"))
+ if (tail.consume_front("+") || tail.consume_front("-"))
+ tail = tail.drop_while(IsNumberBodyChar);
+ }
+ size_t number_length = remainder.size() - tail.size();
+ llvm::StringRef number = remainder.take_front(number_length);
+ remainder = remainder.drop_front(number_length);
return number;
}
return std::nullopt;
@@ -106,18 +130,21 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
return Token(Token::eof, "", (uint32_t)expr.size());
uint32_t position = cur_pos - expr.begin();
- std::optional<llvm::StringRef> maybe_number = IsNumber(expr, remainder);
- if (maybe_number)
- return Token(Token::numeric_constant, maybe_number->str(), position);
+ bool isFloat = false;
+ std::optional<llvm::StringRef> maybe_number = IsNumber(remainder, isFloat);
+ if (maybe_number) {
+ auto kind = isFloat ? Token::float_constant : Token::integer_constant;
+ return Token(kind, maybe_number->str(), position);
+ }
std::optional<llvm::StringRef> maybe_word = IsWord(expr, remainder);
if (maybe_word)
return Token(Token::identifier, maybe_word->str(), position);
constexpr std::pair<Token::Kind, const char *> operators[] = {
- {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
- {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
- {Token::period, "."}, {Token::r_paren, ")"}, {Token::r_square, "]"},
- {Token::star, "*"},
+ {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"},
+ {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"},
+ {Token::period, "."}, {Token::plus, "+"}, {Token::r_paren, ")"},
+ {Token::r_square, "]"}, {Token::star, "*"},
};
for (auto [kind, str] : operators) {
if (remainder.consume_front(str))
diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp
index eac41fab9076..8c4f7fdb25be 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -179,10 +179,13 @@ ASTNodeUP DILParser::ParsePostfixExpression() {
// Parse a primary_expression.
//
// primary_expression:
+// numeric_literal
// id_expression
// "(" expression ")"
//
ASTNodeUP DILParser::ParsePrimaryExpression() {
+ if (CurToken().IsOneOf({Token::integer_constant, Token::float_constant}))
+ return ParseNumericLiteral();
if (CurToken().IsOneOf(
{Token::coloncolon, Token::identifier, Token::l_paren})) {
// Save the source location for the diagnostics message.
@@ -346,6 +349,7 @@ void DILParser::BailOut(const std::string &error, uint32_t loc,
m_dil_lexer.ResetTokenIdx(m_dil_lexer.NumLexedTokens() - 1);
}
+// FIXME: Remove this once subscript operator uses ScalarLiteralNode.
// Parse a integer_literal.
//
// integer_literal:
@@ -370,6 +374,69 @@ std::optional<int64_t> DILParser::ParseIntegerConstant() {
return std::nullopt;
}
+// Parse a numeric_literal.
+//
+// numeric_literal:
+// ? Token::integer_constant ?
+// ? Token::floating_constant ?
+//
+ASTNodeUP DILParser::ParseNumericLiteral() {
+ ASTNodeUP numeric_constant;
+ if (CurToken().Is(Token::integer_constant))
+ numeric_constant = ParseIntegerLiteral();
+ else
+ numeric_constant = ParseFloatingPointLiteral();
+ if (!numeric_constant) {
+ BailOut(llvm::formatv("Failed to parse token as numeric-constant: {0}",
+ CurToken()),
+ CurToken().GetLocation(), CurToken().GetSpelling().length());
+ return std::make_unique<ErrorNode>();
+ }
+ m_dil_lexer.Advance();
+ return numeric_constant;
+}
+
+ASTNodeUP DILParser::ParseIntegerLiteral() {
+ Token token = CurToken();
+ auto spelling = token.GetSpelling();
+ llvm::StringRef spelling_ref = spelling;
+
+ auto radix = llvm::getAutoSenseRadix(spelling_ref);
+ IntegerTypeSuffix type = IntegerTypeSuffix::None;
+ bool is_unsigned = false;
+ if (spelling_ref.consume_back_insensitive("u"))
+ is_unsigned = true;
+ if (spelling_ref.consume_back_insensitive("ll"))
+ type = IntegerTypeSuffix::LongLong;
+ else if (spelling_ref.consume_back_insensitive("l"))
+ type = IntegerTypeSuffix::Long;
+ // Suffix 'u' can be only specified only once, before or after 'l'
+ if (!is_unsigned && spelling_ref.consume_back_insensitive("u"))
+ is_unsigned = true;
+
+ llvm::APInt raw_value;
+ if (!spelling_ref.getAsInteger(radix, raw_value))
+ return std::make_unique<IntegerLiteralNode>(token.GetLocation(), raw_value,
+ radix, is_unsigned, type);
+ return nullptr;
+}
+
+ASTNodeUP DILParser::ParseFloatingPointLiteral() {
+ Token token = CurToken();
+ auto spelling = token.GetSpelling();
+ llvm::StringRef spelling_ref = spelling;
+
+ llvm::APFloat raw_float(llvm::APFloat::IEEEdouble());
+ if (spelling_ref.consume_back_insensitive("f"))
+ raw_float = llvm::APFloat(llvm::APFloat::IEEEsingle());
+
+ auto StatusOrErr = raw_float.convertFromString(
+ spelling_ref, llvm::APFloat::rmNearestTiesToEven);
+ if (!errorToBool(StatusOrErr.takeError()))
+ return std::make_unique<FloatLiteralNode>(token.GetLocation(), raw_float);
+ return nullptr;
+}
+
void DILParser::Expect(Token::Kind kind) {
if (CurToken().IsNot(kind)) {
BailOut(llvm::formatv("expected {0}, got: {1}", kind, CurToken()),